playbq.c revision c6853892c94800e72c0bd676d5d2136d48cea76e
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// Play an audio file using buffer queue 18 19#include <assert.h> 20#include <math.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25 26#include <SLES/OpenSLES.h> 27#ifdef ANDROID 28#include "sndfile.h" 29#else 30#include <sndfile.h> 31#endif 32 33unsigned numBuffers = 2; 34int framesPerBuffer = 512; 35SNDFILE *sndfile; 36SF_INFO sfinfo; 37unsigned which; // which buffer to use next 38SLboolean eof; // whether we have hit EOF on input yet 39short *buffers; 40 41// This callback is called each time a buffer finishes playing 42 43static void callback(SLBufferQueueItf bufq, void *param) 44{ 45 if (!eof) { 46 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 47 sf_count_t count; 48 count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer); 49 if (0 >= count) { 50 eof = SL_BOOLEAN_TRUE; 51 } else { 52 SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels * 53 sizeof(short)); 54 assert(SL_RESULT_SUCCESS == result); 55 if (++which >= numBuffers) 56 which = 0; 57 } 58 } 59} 60 61int main(int argc, char **argv) 62{ 63 SLboolean enableReverb = SL_BOOLEAN_FALSE; 64 65 // process command-line options 66 int i; 67 for (i = 1; i < argc; ++i) { 68 char *arg = argv[i]; 69 if (arg[0] != '-') 70 break; 71 if (!strncmp(arg, "-f", 2)) { 72 framesPerBuffer = atoi(&arg[2]); 73 } else if (!strncmp(arg, "-n", 2)) { 74 numBuffers = atoi(&arg[2]); 75 } else if (!strcmp(arg, "-r")) { 76 enableReverb = SL_BOOLEAN_TRUE; 77 } else { 78 fprintf(stderr, "option %s ignored\n", arg); 79 } 80 } 81 82 if (argc - i != 1) { 83 fprintf(stderr, "usage: [-r] %s filename\n", argv[0]); 84 return EXIT_FAILURE; 85 } 86 87 const char *filename = argv[i]; 88 //memset(&sfinfo, 0, sizeof(SF_INFO)); 89 sfinfo.format = 0; 90 sndfile = sf_open(filename, SFM_READ, &sfinfo); 91 if (NULL == sndfile) { 92 perror(filename); 93 return EXIT_FAILURE; 94 } 95 96 // verify the file format 97 switch (sfinfo.channels) { 98 case 1: 99 case 2: 100 break; 101 default: 102 fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 103 break; 104 } 105 switch (sfinfo.samplerate) { 106 case 8000: 107 case 11025: 108 case 12000: 109 case 16000: 110 case 22050: 111 case 24000: 112 case 32000: 113 case 44100: 114 case 48000: 115 break; 116 default: 117 fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 118 break; 119 } 120 switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 121 case SF_FORMAT_WAV: 122 break; 123 default: 124 fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 125 break; 126 } 127 switch (sfinfo.format & SF_FORMAT_SUBMASK) { 128 case SF_FORMAT_PCM_16: 129 case SF_FORMAT_PCM_U8: 130 case SF_FORMAT_ULAW: 131 case SF_FORMAT_ALAW: 132 case SF_FORMAT_IMA_ADPCM: 133 break; 134 default: 135 fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 136 break; 137 } 138 139 buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers); 140 141 // create engine 142 SLresult result; 143 SLObjectItf engineObject; 144 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 145 assert(SL_RESULT_SUCCESS == result); 146 SLEngineItf engineEngine; 147 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 148 assert(SL_RESULT_SUCCESS == result); 149 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 150 assert(SL_RESULT_SUCCESS == result); 151 152 // create output mix 153 SLObjectItf outputMixObject; 154 SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 155 SLboolean req[1] = {SL_BOOLEAN_TRUE}; 156 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 157 ids, req); 158 assert(SL_RESULT_SUCCESS == result); 159 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 160 assert(SL_RESULT_SUCCESS == result); 161 162 // configure environmental reverb on output mix 163 SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 164 if (enableReverb) { 165 result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 166 &mixEnvironmentalReverb); 167 assert(SL_RESULT_SUCCESS == result); 168 SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 169 result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 170 &settings); 171 assert(SL_RESULT_SUCCESS == result); 172 } 173 174 // configure audio source 175 SLDataLocator_BufferQueue loc_bufq; 176 loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 177 loc_bufq.numBuffers = numBuffers; 178 SLDataFormat_PCM format_pcm; 179 format_pcm.formatType = SL_DATAFORMAT_PCM; 180 format_pcm.numChannels = sfinfo.channels; 181 format_pcm.samplesPerSec = sfinfo.samplerate * 1000; 182 format_pcm.bitsPerSample = 16; 183 format_pcm.containerSize = format_pcm.bitsPerSample; 184 format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 185 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 186 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 187 SLDataSource audioSrc; 188 audioSrc.pLocator = &loc_bufq; 189 audioSrc.pFormat = &format_pcm; 190 191 // configure audio sink 192 SLDataLocator_OutputMix loc_outmix; 193 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 194 loc_outmix.outputMix = outputMixObject; 195 SLDataSink audioSnk; 196 audioSnk.pLocator = &loc_outmix; 197 audioSnk.pFormat = NULL; 198 199 // create audio player 200 SLInterfaceID ids2[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND}; 201 SLboolean req2[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 202 SLObjectItf playerObject; 203 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 204 &audioSnk, enableReverb ? 2 : 1, ids2, req2); 205 assert(SL_RESULT_SUCCESS == result); 206 207 // realize the player 208 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 209 assert(SL_RESULT_SUCCESS == result); 210 211 // get the effect send interface and enable effect send reverb for this player 212 if (enableReverb) { 213 SLEffectSendItf playerEffectSend; 214 result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 215 assert(SL_RESULT_SUCCESS == result); 216 result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 217 SL_BOOLEAN_TRUE, (SLmillibel) 0); 218 assert(SL_RESULT_SUCCESS == result); 219 } 220 221 // get the play interface 222 SLPlayItf playerPlay; 223 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 224 assert(SL_RESULT_SUCCESS == result); 225 226 // get the buffer queue interface 227 SLBufferQueueItf playerBufferQueue; 228 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 229 &playerBufferQueue); 230 assert(SL_RESULT_SUCCESS == result); 231 232 // loop until EOF or no more buffers 233 for (which = 0; which < numBuffers; ++which) { 234 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 235 sf_count_t frames = framesPerBuffer; 236 sf_count_t count; 237 count = sf_readf_short(sndfile, buffer, frames); 238 if (0 >= count) { 239 eof = SL_BOOLEAN_TRUE; 240 break; 241 } 242 243 // enqueue a buffer 244 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels * 245 sizeof(short)); 246 assert(SL_RESULT_SUCCESS == result); 247 } 248 if (which >= numBuffers) 249 which = 0; 250 251 // register a callback on the buffer queue 252 result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 253 assert(SL_RESULT_SUCCESS == result); 254 255 // set the player's state to playing 256 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 257 assert(SL_RESULT_SUCCESS == result); 258 259 // wait until the buffer queue is empty 260 SLBufferQueueState bufqstate; 261 for (;;) { 262 result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 263 assert(SL_RESULT_SUCCESS == result); 264 if (0 >= bufqstate.count) { 265 break; 266 } 267 sleep(1); 268 } 269 270 // destroy audio player 271 (*playerObject)->Destroy(playerObject); 272 273 // destroy output mix 274 (*outputMixObject)->Destroy(outputMixObject); 275 276 // destroy engine 277 (*engineObject)->Destroy(engineObject); 278 279 return EXIT_SUCCESS; 280} 281