playbq.c revision 9a6c9db763121c3b11765c6c8cf935983c0385bf
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 assert(NULL == param); 46 if (!eof) { 47 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 48 sf_count_t count; 49 count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer); 50 if (0 >= count) { 51 eof = SL_BOOLEAN_TRUE; 52 } else { 53 SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels * 54 sizeof(short)); 55 assert(SL_RESULT_SUCCESS == result); 56 if (++which >= numBuffers) 57 which = 0; 58 } 59 } 60} 61 62int main(int argc, char **argv) 63{ 64 SLboolean enableReverb = SL_BOOLEAN_FALSE; 65 SLpermille rate = 1000; 66 67 // process command-line options 68 int i; 69 for (i = 1; i < argc; ++i) { 70 char *arg = argv[i]; 71 if (arg[0] != '-') 72 break; 73 if (!strncmp(arg, "-f", 2)) { 74 framesPerBuffer = atoi(&arg[2]); 75 } else if (!strncmp(arg, "-n", 2)) { 76 numBuffers = atoi(&arg[2]); 77 } else if (!strncmp(arg, "-p", 2)) { 78 rate = atoi(&arg[2]); 79 } else if (!strcmp(arg, "-r")) { 80 enableReverb = SL_BOOLEAN_TRUE; 81 } else { 82 fprintf(stderr, "option %s ignored\n", arg); 83 } 84 } 85 86 if (argc - i != 1) { 87 fprintf(stderr, "usage: [-f#] [-n] [-p#] [-r] %s filename\n", argv[0]); 88 return EXIT_FAILURE; 89 } 90 91 const char *filename = argv[i]; 92 //memset(&sfinfo, 0, sizeof(SF_INFO)); 93 sfinfo.format = 0; 94 sndfile = sf_open(filename, SFM_READ, &sfinfo); 95 if (NULL == sndfile) { 96 perror(filename); 97 return EXIT_FAILURE; 98 } 99 100 // verify the file format 101 switch (sfinfo.channels) { 102 case 1: 103 case 2: 104 break; 105 default: 106 fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 107 break; 108 } 109 switch (sfinfo.samplerate) { 110 case 8000: 111 case 11025: 112 case 12000: 113 case 16000: 114 case 22050: 115 case 24000: 116 case 32000: 117 case 44100: 118 case 48000: 119 break; 120 default: 121 fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 122 break; 123 } 124 switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 125 case SF_FORMAT_WAV: 126 break; 127 default: 128 fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 129 break; 130 } 131 switch (sfinfo.format & SF_FORMAT_SUBMASK) { 132 case SF_FORMAT_PCM_16: 133 case SF_FORMAT_PCM_U8: 134 case SF_FORMAT_ULAW: 135 case SF_FORMAT_ALAW: 136 case SF_FORMAT_IMA_ADPCM: 137 break; 138 default: 139 fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 140 break; 141 } 142 143 buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers); 144 145 // create engine 146 SLresult result; 147 SLObjectItf engineObject; 148 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 149 assert(SL_RESULT_SUCCESS == result); 150 SLEngineItf engineEngine; 151 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 152 assert(SL_RESULT_SUCCESS == result); 153 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 154 assert(SL_RESULT_SUCCESS == result); 155 156 // create output mix 157 SLObjectItf outputMixObject; 158 SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 159 SLboolean req[1] = {SL_BOOLEAN_TRUE}; 160 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 161 ids, req); 162 assert(SL_RESULT_SUCCESS == result); 163 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 164 assert(SL_RESULT_SUCCESS == result); 165 166 // configure environmental reverb on output mix 167 SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 168 if (enableReverb) { 169 result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 170 &mixEnvironmentalReverb); 171 assert(SL_RESULT_SUCCESS == result); 172 SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 173 result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 174 &settings); 175 assert(SL_RESULT_SUCCESS == result); 176 } 177 178 // configure audio source 179 SLDataLocator_BufferQueue loc_bufq; 180 loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 181 loc_bufq.numBuffers = numBuffers; 182 SLDataFormat_PCM format_pcm; 183 format_pcm.formatType = SL_DATAFORMAT_PCM; 184 format_pcm.numChannels = sfinfo.channels; 185 format_pcm.samplesPerSec = sfinfo.samplerate * 1000; 186 format_pcm.bitsPerSample = 16; 187 format_pcm.containerSize = format_pcm.bitsPerSample; 188 format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 189 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 190 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 191 SLDataSource audioSrc; 192 audioSrc.pLocator = &loc_bufq; 193 audioSrc.pFormat = &format_pcm; 194 195 // configure audio sink 196 SLDataLocator_OutputMix loc_outmix; 197 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 198 loc_outmix.outputMix = outputMixObject; 199 SLDataSink audioSnk; 200 audioSnk.pLocator = &loc_outmix; 201 audioSnk.pFormat = NULL; 202 203 // create audio player 204 SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 205 SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 206 SLObjectItf playerObject; 207 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 208 &audioSnk, enableReverb ? 3 : 2, ids2, req2); 209 assert(SL_RESULT_SUCCESS == result); 210 211 // realize the player 212 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 213 assert(SL_RESULT_SUCCESS == result); 214 215 // get the effect send interface and enable effect send reverb for this player 216 if (enableReverb) { 217 SLEffectSendItf playerEffectSend; 218 result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 219 assert(SL_RESULT_SUCCESS == result); 220 result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 221 SL_BOOLEAN_TRUE, (SLmillibel) 0); 222 assert(SL_RESULT_SUCCESS == result); 223 } 224 225 // get the playback rate interface and configure the rate 226 SLPlaybackRateItf playerPlaybackRate; 227 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, &playerPlaybackRate); 228 assert(SL_RESULT_SUCCESS == result); 229 SLpermille defaultRate; 230 result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 231 assert(SL_RESULT_SUCCESS == result); 232 SLuint32 defaultProperties; 233 result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 234 assert(SL_RESULT_SUCCESS == result); 235 printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, defaultProperties); 236 if (rate != defaultRate) { 237 result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, rate); 238 if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 239 fprintf(stderr, "playback rate %d is unsupported\n", rate); 240 } else if (SL_RESULT_PARAMETER_INVALID == result) { 241 fprintf(stderr, "playback rate %d is invalid", rate); 242 } else { 243 assert(SL_RESULT_SUCCESS == result); 244 } 245 } 246 247 // get the play interface 248 SLPlayItf playerPlay; 249 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 250 assert(SL_RESULT_SUCCESS == result); 251 252 // get the buffer queue interface 253 SLBufferQueueItf playerBufferQueue; 254 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 255 &playerBufferQueue); 256 assert(SL_RESULT_SUCCESS == result); 257 258 // loop until EOF or no more buffers 259 for (which = 0; which < numBuffers; ++which) { 260 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 261 sf_count_t frames = framesPerBuffer; 262 sf_count_t count; 263 count = sf_readf_short(sndfile, buffer, frames); 264 if (0 >= count) { 265 eof = SL_BOOLEAN_TRUE; 266 break; 267 } 268 269 // enqueue a buffer 270 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels * 271 sizeof(short)); 272 assert(SL_RESULT_SUCCESS == result); 273 } 274 if (which >= numBuffers) 275 which = 0; 276 277 // register a callback on the buffer queue 278 result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 279 assert(SL_RESULT_SUCCESS == result); 280 281 // set the player's state to playing 282 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 283 assert(SL_RESULT_SUCCESS == result); 284 285 // wait until the buffer queue is empty 286 SLBufferQueueState bufqstate; 287 for (;;) { 288 result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 289 assert(SL_RESULT_SUCCESS == result); 290 if (0 >= bufqstate.count) { 291 break; 292 } 293 sleep(1); 294 } 295 296 // destroy audio player 297 (*playerObject)->Destroy(playerObject); 298 299 // destroy output mix 300 (*outputMixObject)->Destroy(outputMixObject); 301 302 // destroy engine 303 (*engineObject)->Destroy(engineObject); 304 305 return EXIT_SUCCESS; 306} 307