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