Home | History | Annotate | Download | only in examples
      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