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 // Test program to record from default audio input and playback to default audio output. 18 // It will generate feedback (Larsen effect) if played through on-device speakers, 19 // or acts as a delay if played through headset. 20 21 #include <SLES/OpenSLES.h> 22 #include <SLES/OpenSLES_Android.h> 23 #include <assert.h> 24 #include <pthread.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \ 31 (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0) 32 33 // default values 34 static SLuint32 rxBufCount = 2; // -r# 35 static SLuint32 txBufCount = 2; // -t# 36 static SLuint32 bufSizeInFrames = 512; // -f# 37 static SLuint32 channels = 1; // -c# 38 static SLuint32 sampleRate = 44100; // -s# 39 static SLuint32 exitAfterSeconds = 60; // -e# 40 static SLuint32 freeBufCount = 0; // calculated 41 static SLuint32 bufSizeInBytes = 0; // calculated 42 43 // Storage area for the buffer queues 44 static char **rxBuffers; 45 static char **txBuffers; 46 static char **freeBuffers; 47 48 // Buffer indices 49 static SLuint32 rxFront; // oldest recording 50 static SLuint32 rxRear; // next to be recorded 51 static SLuint32 txFront; // oldest playing 52 static SLuint32 txRear; // next to be played 53 static SLuint32 freeFront; // oldest free 54 static SLuint32 freeRear; // next to be freed 55 56 static SLAndroidSimpleBufferQueueItf recorderBufferQueue; 57 static SLBufferQueueItf playerBufferQueue; 58 59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 60 61 // Called after audio recorder fills a buffer with data 62 static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context) 63 { 64 SLresult result; 65 66 pthread_mutex_lock(&mutex); 67 68 // We should only be called when a recording buffer is done 69 assert(rxFront <= rxBufCount); 70 assert(rxRear <= rxBufCount); 71 assert(rxFront != rxRear); 72 char *buffer = rxBuffers[rxFront]; 73 74 // Remove buffer from record queue 75 if (++rxFront > rxBufCount) { 76 rxFront = 0; 77 } 78 79 // Enqueue the just-filled buffer for the player 80 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes); 81 if (SL_RESULT_SUCCESS == result) { 82 83 // There was room in the play queue, update our model of it 84 assert(txFront <= txBufCount); 85 assert(txRear <= txBufCount); 86 SLuint32 txRearNext = txRear+1; 87 if (txRearNext > txBufCount) { 88 txRearNext = 0; 89 } 90 assert(txRearNext != txFront); 91 txBuffers[txRear] = buffer; 92 txRear = txRearNext; 93 94 } else { 95 96 // Here if record has a filled buffer to play, but play queue is full. 97 assert(SL_RESULT_BUFFER_INSUFFICIENT == result); 98 write(1, "?", 1); 99 100 // We could either try again later, or discard. For now we discard and re-use buffer. 101 // Enqueue this same buffer for the recorder to fill again. 102 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes); 103 ASSERT_EQ(SL_RESULT_SUCCESS, result); 104 105 // Update our model of the record queue 106 SLuint32 rxRearNext = rxRear+1; 107 if (rxRearNext > rxBufCount) { 108 rxRearNext = 0; 109 } 110 assert(rxRearNext != rxFront); 111 rxBuffers[rxRear] = buffer; 112 rxRear = rxRearNext; 113 114 } 115 116 pthread_mutex_unlock(&mutex); 117 } 118 119 120 // Called after audio player empties a buffer of data 121 static void playerCallback(SLBufferQueueItf caller, void *context) 122 { 123 SLresult result; 124 125 pthread_mutex_lock(&mutex); 126 127 // Get the buffer that just finished playing 128 assert(txFront <= txBufCount); 129 assert(txRear <= txBufCount); 130 assert(txFront != txRear); 131 char *buffer = txBuffers[txFront]; 132 if (++txFront > txBufCount) { 133 txFront = 0; 134 } 135 136 // First try to enqueue the free buffer for recording 137 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes); 138 if (SL_RESULT_SUCCESS == result) { 139 140 // There was room in the record queue, update our model of it 141 assert(rxFront <= rxBufCount); 142 assert(rxRear <= rxBufCount); 143 SLuint32 rxRearNext = rxRear+1; 144 if (rxRearNext > rxBufCount) { 145 rxRearNext = 0; 146 } 147 assert(rxRearNext != rxFront); 148 rxBuffers[rxRear] = buffer; 149 rxRear = rxRearNext; 150 151 } else { 152 153 // Here if record queue is full 154 assert(SL_RESULT_BUFFER_INSUFFICIENT == result); 155 156 // Instead enqueue the free buffer on the free queue 157 assert(freeFront <= freeBufCount); 158 assert(freeRear <= freeBufCount); 159 SLuint32 freeRearNext = freeRear+1; 160 if (freeRearNext > freeBufCount) { 161 freeRearNext = 0; 162 } 163 // There must always be room in the free queue 164 assert(freeRearNext != freeFront); 165 freeBuffers[freeRear] = buffer; 166 freeRear = freeRearNext; 167 168 } 169 170 pthread_mutex_unlock(&mutex); 171 } 172 173 // Main program 174 int main(int argc, char **argv) 175 { 176 // process command-line options 177 int i; 178 for (i = 1; i < argc; ++i) { 179 char *arg = argv[i]; 180 if (arg[0] != '-') { 181 break; 182 } 183 // -r# number of slots in receive buffer queue 184 if (!strncmp(arg, "-r", 2)) { 185 rxBufCount = atoi(&arg[2]); 186 if (rxBufCount < 1 || rxBufCount > 16) { 187 fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0], 188 (unsigned) rxBufCount); 189 } 190 // -t# number of slots in transmit buffer queue 191 } else if (!strncmp(arg, "-t", 2)) { 192 txBufCount = atoi(&arg[2]); 193 if (txBufCount < 1 || txBufCount > 16) { 194 fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0], 195 (unsigned) txBufCount); 196 } 197 // -f# size of each buffer in frames 198 } else if (!strncmp(arg, "-f", 2)) { 199 bufSizeInFrames = atoi(&arg[2]); 200 if (bufSizeInFrames == 0) { 201 fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0], 202 (unsigned) bufSizeInFrames); 203 } 204 // -c1 mono or -c2 stereo 205 } else if (!strncmp(arg, "-c", 2)) { 206 channels = atoi(&arg[2]); 207 if (channels < 1 || channels > 2) { 208 fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0], 209 (unsigned) channels); 210 channels = 2; 211 } 212 // -s# sample rate in Hz 213 } else if (!strncmp(arg, "-s", 2)) { 214 sampleRate = atoi(&arg[2]); 215 switch (sampleRate) { 216 case 8000: 217 case 11025: 218 case 12000: 219 case 16000: 220 case 22050: 221 case 24000: 222 case 32000: 223 case 44100: 224 case 48000: 225 break; 226 default: 227 fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0], 228 (unsigned) sampleRate); 229 break; 230 } 231 // -e# exit after this many seconds 232 } else if (!strncmp(arg, "-e", 2)) { 233 exitAfterSeconds = atoi(&arg[2]); 234 } else 235 fprintf(stderr, "%s: unknown option %s\n", argv[0], arg); 236 } 237 // no other arguments allowed 238 if (i < argc) { 239 fprintf(stderr, "usage: %s -r# -t# -f# -s# -c#\n", argv[0]); 240 fprintf(stderr, " -r# receive buffer queue count for microphone input, default 1\n"); 241 fprintf(stderr, " -t# transmit buffer queue count for speaker output, default 2\n"); 242 fprintf(stderr, " -f# number of frames per buffer, default 512\n"); 243 fprintf(stderr, " -s# sample rate in Hz, default 44100\n"); 244 fprintf(stderr, " -c1 mono\n"); 245 fprintf(stderr, " -c2 stereo, default\n"); 246 } 247 // compute total free buffers as -r plus -t 248 freeBufCount = rxBufCount + txBufCount; 249 // compute buffer size 250 bufSizeInBytes = channels * bufSizeInFrames * sizeof(short); 251 252 // Initialize free buffers 253 freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *)); 254 unsigned j; 255 for (j = 0; j < freeBufCount; ++j) { 256 freeBuffers[j] = (char *) malloc(bufSizeInBytes); 257 } 258 freeFront = 0; 259 freeRear = freeBufCount; 260 freeBuffers[j] = NULL; 261 262 // Initialize record queue 263 rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *)); 264 rxFront = 0; 265 rxRear = 0; 266 267 // Initialize play queue 268 txBuffers = (char **) calloc(txBufCount+1, sizeof(char *)); 269 txFront = 0; 270 txRear = 0; 271 272 SLresult result; 273 274 // create engine 275 SLObjectItf engineObject; 276 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 277 ASSERT_EQ(SL_RESULT_SUCCESS, result); 278 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 279 ASSERT_EQ(SL_RESULT_SUCCESS, result); 280 SLEngineItf engineEngine; 281 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 282 ASSERT_EQ(SL_RESULT_SUCCESS, result); 283 284 // create output mix 285 SLObjectItf outputmixObject; 286 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL); 287 ASSERT_EQ(SL_RESULT_SUCCESS, result); 288 result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE); 289 ASSERT_EQ(SL_RESULT_SUCCESS, result); 290 291 // create an audio player with buffer queue source and output mix sink 292 SLDataSource audiosrc; 293 SLDataSink audiosnk; 294 SLDataFormat_PCM pcm; 295 SLDataLocator_OutputMix locator_outputmix; 296 SLDataLocator_BufferQueue locator_bufferqueue_tx; 297 locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 298 locator_bufferqueue_tx.numBuffers = txBufCount; 299 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 300 locator_outputmix.outputMix = outputmixObject; 301 pcm.formatType = SL_DATAFORMAT_PCM; 302 pcm.numChannels = channels; 303 pcm.samplesPerSec = sampleRate * 1000; 304 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 305 pcm.containerSize = 16; 306 pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER : 307 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); 308 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 309 audiosrc.pLocator = &locator_bufferqueue_tx; 310 audiosrc.pFormat = &pcm; 311 audiosnk.pLocator = &locator_outputmix; 312 audiosnk.pFormat = NULL; 313 SLObjectItf playerObject = NULL; 314 SLObjectItf recorderObject = NULL; 315 SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE}; 316 SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE}; 317 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk, 318 1, ids_tx, flags_tx); 319 if (SL_RESULT_CONTENT_UNSUPPORTED == result) { 320 fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result); 321 goto cleanup; 322 } 323 ASSERT_EQ(SL_RESULT_SUCCESS, result); 324 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 325 ASSERT_EQ(SL_RESULT_SUCCESS, result); 326 SLPlayItf playerPlay; 327 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 328 ASSERT_EQ(SL_RESULT_SUCCESS, result); 329 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue); 330 ASSERT_EQ(SL_RESULT_SUCCESS, result); 331 result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL); 332 ASSERT_EQ(SL_RESULT_SUCCESS, result); 333 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 334 ASSERT_EQ(SL_RESULT_SUCCESS, result); 335 336 // Create an audio recorder with microphone device source and buffer queue sink. 337 // The buffer queue as sink is an Android-specific extension. 338 339 SLDataLocator_IODevice locator_iodevice; 340 SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx; 341 locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE; 342 locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT; 343 locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; 344 locator_iodevice.device = NULL; 345 audiosrc.pLocator = &locator_iodevice; 346 audiosrc.pFormat = NULL; 347 locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 348 locator_bufferqueue_rx.numBuffers = rxBufCount; 349 audiosnk.pLocator = &locator_bufferqueue_rx; 350 audiosnk.pFormat = &pcm; 351 { 352 SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 353 SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE}; 354 result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc, 355 &audiosnk, 1, ids_rx, flags_rx); 356 if (SL_RESULT_SUCCESS != result) { 357 fprintf(stderr, "Could not create audio recorder (result %x), " 358 "check sample rate and channel count\n", result); 359 goto cleanup; 360 } 361 } 362 ASSERT_EQ(SL_RESULT_SUCCESS, result); 363 result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE); 364 ASSERT_EQ(SL_RESULT_SUCCESS, result); 365 SLRecordItf recorderRecord; 366 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord); 367 ASSERT_EQ(SL_RESULT_SUCCESS, result); 368 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 369 &recorderBufferQueue); 370 ASSERT_EQ(SL_RESULT_SUCCESS, result); 371 result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL); 372 ASSERT_EQ(SL_RESULT_SUCCESS, result); 373 374 // Enqueue some empty buffers for the recorder 375 for (j = 0; j < rxBufCount; ++j) { 376 377 // allocate a free buffer 378 assert(freeFront != freeRear); 379 char *buffer = freeBuffers[freeFront]; 380 if (++freeFront > freeBufCount) { 381 freeFront = 0; 382 } 383 384 // put on record queue 385 SLuint32 rxRearNext = rxRear + 1; 386 if (rxRearNext > rxBufCount) { 387 rxRearNext = 0; 388 } 389 assert(rxRearNext != rxFront); 390 rxBuffers[rxRear] = buffer; 391 rxRear = rxRearNext; 392 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, 393 buffer, bufSizeInBytes); 394 ASSERT_EQ(SL_RESULT_SUCCESS, result); 395 } 396 397 // Kick off the recorder 398 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING); 399 ASSERT_EQ(SL_RESULT_SUCCESS, result); 400 401 // Wait patiently 402 do { 403 usleep(1000000); 404 write(1, ".", 1); 405 SLBufferQueueState playerBQState; 406 result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState); 407 ASSERT_EQ(SL_RESULT_SUCCESS, result); 408 SLAndroidSimpleBufferQueueState recorderBQState; 409 result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState); 410 ASSERT_EQ(SL_RESULT_SUCCESS, result); 411 } while (--exitAfterSeconds); 412 413 // Tear down the objects and exit 414 cleanup: 415 if (NULL != playerObject) { 416 (*playerObject)->Destroy(playerObject); 417 } 418 if (NULL != recorderObject) { 419 (*recorderObject)->Destroy(recorderObject); 420 } 421 (*outputmixObject)->Destroy(outputmixObject); 422 (*engineObject)->Destroy(engineObject); 423 424 return EXIT_SUCCESS; 425 } 426