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 #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