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 /* Audio Record Test
     18 
     19 First run the program from shell:
     20   # slesTest_recBuffQueue /sdcard/myrec.raw 4
     21 
     22 These use adb on host to retrive the file:
     23   % adb pull /sdcard/myrec.raw myrec.raw
     24 
     25 How to examine the output with Audacity:
     26  Project / Import raw data
     27  Select myrec.raw file, then click Open button
     28  Choose these options:
     29   Signed 16-bit PCM
     30   Little-endian
     31   1 Channel (Mono)
     32   Sample rate 22050 Hz
     33  Click Import button
     34 
     35 */
     36 
     37 
     38 #include <stdlib.h>
     39 #include <stdio.h>
     40 #include <string.h>
     41 #include <unistd.h>
     42 #include <sys/time.h>
     43 #include <fcntl.h>
     44 
     45 #include "OpenSLES.h"
     46 #include "OpenSLES_Android.h"
     47 #include "OpenSLES_AndroidConfiguration.h"
     48 
     49 /* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION
     50  * on the AudioRecorder object */
     51 #define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2
     52 
     53 /* Size of the recording buffer queue */
     54 #define NB_BUFFERS_IN_QUEUE 1
     55 /* Size of each buffer in the queue */
     56 #define BUFFER_SIZE_IN_SAMPLES 1024
     57 #define BUFFER_SIZE_IN_BYTES   (2*BUFFER_SIZE_IN_SAMPLES)
     58 
     59 /* Local storage for Audio data */
     60 int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES];
     61 
     62 /* destination for recorded data */
     63 static FILE* gFp;
     64 
     65 //-----------------------------------------------------------------
     66 /* Exits the application if an error is encountered */
     67 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
     68 
     69 void ExitOnErrorFunc( SLresult result , int line)
     70 {
     71     if (SL_RESULT_SUCCESS != result) {
     72         fprintf(stdout, "%lu error code encountered at line %d, exiting\n", result, line);
     73         exit(EXIT_FAILURE);
     74     }
     75 }
     76 
     77 //-----------------------------------------------------------------
     78 /* Structure for passing information to callback function */
     79 typedef struct CallbackCntxt_ {
     80     SLPlayItf  playItf;
     81     SLuint32   size;
     82     SLint8*   pDataBase;    // Base address of local audio data storage
     83     SLint8*   pData;        // Current address of local audio data storage
     84 } CallbackCntxt;
     85 
     86 
     87 //-----------------------------------------------------------------
     88 /* Callback for recording buffer queue events */
     89 void RecCallback(
     90         SLRecordItf caller,
     91         void *pContext,
     92         SLuint32 event)
     93 {
     94     if (SL_RECORDEVENT_HEADATNEWPOS & event) {
     95         SLmillisecond pMsec = 0;
     96         (*caller)->GetPosition(caller, &pMsec);
     97         fprintf(stdout, "SL_RECORDEVENT_HEADATNEWPOS current position=%lums\n", pMsec);
     98     }
     99 
    100     if (SL_RECORDEVENT_HEADATMARKER & event) {
    101         SLmillisecond pMsec = 0;
    102         (*caller)->GetPosition(caller, &pMsec);
    103         fprintf(stdout, "SL_RECORDEVENT_HEADATMARKER current position=%lums\n", pMsec);
    104     }
    105 }
    106 
    107 //-----------------------------------------------------------------
    108 /* Callback for recording buffer queue events */
    109 void RecBufferQueueCallback(
    110         SLAndroidSimpleBufferQueueItf queueItf,
    111         void *pContext)
    112 {
    113     //fprintf(stdout, "RecBufferQueueCallback called\n");
    114 
    115     CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
    116 
    117     /* Save the recorded data  */
    118     fwrite(pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES, 1, gFp);
    119 
    120     /* Increase data pointer by buffer size */
    121     pCntxt->pData += BUFFER_SIZE_IN_BYTES;
    122 
    123     if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) {
    124         pCntxt->pData = pCntxt->pDataBase;
    125     }
    126 
    127     ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) );
    128 
    129     SLAndroidSimpleBufferQueueState recQueueState;
    130     ExitOnError( (*queueItf)->GetState(queueItf, &recQueueState) );
    131 
    132     /*fprintf(stderr, "\tRecBufferQueueCallback now has pCntxt->pData=%p queue: "
    133             "count=%lu playIndex=%lu\n",
    134             pCntxt->pData, recQueueState.count, recQueueState.index);*/
    135 }
    136 
    137 //-----------------------------------------------------------------
    138 
    139 /* Play an audio path by opening a file descriptor on that path  */
    140 void TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSeconds)
    141 {
    142     gFp = fopen(path, "w");
    143     if (NULL == gFp) {
    144         ExitOnError(SL_RESULT_RESOURCE_ERROR);
    145     }
    146 
    147     SLresult  result;
    148     SLEngineItf EngineItf;
    149 
    150     /* Objects this application uses: one audio recorder */
    151     SLObjectItf  recorder;
    152 
    153     /* Interfaces for the audio recorder */
    154     SLAndroidSimpleBufferQueueItf recBuffQueueItf;
    155     SLRecordItf               recordItf;
    156     SLAndroidConfigurationItf configItf;
    157 
    158     /* Source of audio data for the recording */
    159     SLDataSource           recSource;
    160     SLDataLocator_IODevice ioDevice;
    161 
    162     /* Data sink for recorded audio */
    163     SLDataSink                recDest;
    164     SLDataLocator_AndroidSimpleBufferQueue recBuffQueue;
    165     SLDataFormat_PCM          pcm;
    166 
    167     SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_RECORDER];
    168     SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_RECORDER];
    169 
    170     /* Get the SL Engine Interface which is implicit */
    171     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
    172     ExitOnError(result);
    173 
    174     /* Initialize arrays required[] and iidArray[] */
    175     for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_RECORDER ; i++) {
    176         required[i] = SL_BOOLEAN_FALSE;
    177         iidArray[i] = SL_IID_NULL;
    178     }
    179 
    180 
    181     /* ------------------------------------------------------ */
    182     /* Configuration of the recorder  */
    183 
    184     /* Request the AndroidSimpleBufferQueue and AndroidConfiguration interfaces */
    185     required[0] = SL_BOOLEAN_TRUE;
    186     iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
    187     required[1] = SL_BOOLEAN_TRUE;
    188     iidArray[1] = SL_IID_ANDROIDCONFIGURATION;
    189 
    190     /* Setup the data source */
    191     ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;
    192     ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT;
    193     ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
    194     ioDevice.device = NULL;
    195     recSource.pLocator = (void *) &ioDevice;
    196 
    197     /* Setup the data sink */
    198     recBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
    199     recBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE;
    200     /*    set up the format of the data in the buffer queue */
    201     pcm.formatType = SL_DATAFORMAT_PCM;
    202     pcm.numChannels = 1;
    203     pcm.samplesPerSec = SL_SAMPLINGRATE_22_05;
    204     pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
    205     pcm.containerSize = 16;
    206     pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
    207     pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    208 
    209     recDest.pLocator = (void *) &recBuffQueue;
    210     recDest.pFormat = (void * ) &pcm;
    211 
    212     /* Create the audio recorder */
    213     result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest,
    214             NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iidArray, required);
    215     ExitOnError(result);
    216     fprintf(stdout, "Recorder created\n");
    217 
    218     /* Get the Android configuration interface which is explicit */
    219     result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
    220     ExitOnError(result);
    221 
    222     /* Use the configuration interface to configure the recorder before it's realized */
    223     SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
    224     result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
    225             &presetValue, sizeof(SLuint32));
    226     ExitOnError(result);
    227     fprintf(stdout, "Recorder parametrized\n");
    228 
    229     presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
    230     SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big
    231     result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
    232             &presetSize, (void*)&presetValue);
    233     ExitOnError(result);
    234     if (presetValue != SL_ANDROID_RECORDING_PRESET_CAMCORDER) {
    235         fprintf(stderr, "Error retrieved recording preset\n");
    236         ExitOnError(SL_RESULT_INTERNAL_ERROR);
    237     }
    238 
    239     /* Realize the recorder in synchronous mode. */
    240     result = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
    241     ExitOnError(result);
    242     fprintf(stdout, "Recorder realized\n");
    243 
    244     /* Get the record interface which is implicit */
    245     result = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void*)&recordItf);
    246     ExitOnError(result);
    247 
    248     /* Set up the recorder callback to get events during the recording */
    249     result = (*recordItf)->SetMarkerPosition(recordItf, 2000);
    250     ExitOnError(result);
    251     result = (*recordItf)->SetPositionUpdatePeriod(recordItf, 500);
    252     ExitOnError(result);
    253     result = (*recordItf)->SetCallbackEventsMask(recordItf,
    254             SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS);
    255     ExitOnError(result);
    256     result = (*recordItf)->RegisterCallback(recordItf, RecCallback, NULL);
    257     ExitOnError(result);
    258     fprintf(stdout, "Recorder callback registered\n");
    259 
    260     /* Get the buffer queue interface which was explicitly requested */
    261     result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
    262             (void*)&recBuffQueueItf);
    263     ExitOnError(result);
    264 
    265     /* ------------------------------------------------------ */
    266     /* Initialize the callback and its context for the recording buffer queue */
    267     CallbackCntxt cntxt;
    268     cntxt.pDataBase = (int8_t*)&pcmData;
    269     cntxt.pData = cntxt.pDataBase;
    270     cntxt.size = sizeof(pcmData);
    271     result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, RecBufferQueueCallback, &cntxt);
    272     ExitOnError(result);
    273 
    274     /* Enqueue buffers to map the region of memory allocated to store the recorded data */
    275     fprintf(stdout,"Enqueueing buffer ");
    276     for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) {
    277         fprintf(stdout,"%d ", i);
    278         result = (*recBuffQueueItf)->Enqueue(recBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES);
    279         ExitOnError(result);
    280         cntxt.pData += BUFFER_SIZE_IN_BYTES;
    281     }
    282     fprintf(stdout,"\n");
    283     cntxt.pData = cntxt.pDataBase;
    284 
    285     /* ------------------------------------------------------ */
    286     /* Start recording */
    287     result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
    288     ExitOnError(result);
    289     fprintf(stdout, "Starting to record\n");
    290 
    291     /* Record for at least a second */
    292     if (durationInSeconds < 1) {
    293         durationInSeconds = 1;
    294     }
    295     usleep(durationInSeconds * 1000 * 1000);
    296 
    297     /* ------------------------------------------------------ */
    298     /* End of recording */
    299 
    300     /* Stop recording */
    301     result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
    302     ExitOnError(result);
    303     fprintf(stdout, "Stopped recording\n");
    304 
    305     /* Destroy the AudioRecorder object */
    306     (*recorder)->Destroy(recorder);
    307 
    308     fclose(gFp);
    309 }
    310 
    311 //-----------------------------------------------------------------
    312 int main(int argc, char* const argv[])
    313 {
    314     SLresult    result;
    315     SLObjectItf sl;
    316 
    317     fprintf(stdout, "OpenSL ES test %s: exercises SLRecordItf and SLAndroidSimpleBufferQueueItf ",
    318             argv[0]);
    319     fprintf(stdout, "on an AudioRecorder object\n");
    320 
    321     if (argc < 2) {
    322         fprintf(stdout, "Usage: \t%s destination_file duration_in_seconds\n", argv[0]);
    323         fprintf(stdout, "Example: \"%s /sdcard/myrec.raw 4\" \n", argv[0]);
    324         exit(EXIT_FAILURE);
    325     }
    326 
    327     SLEngineOption EngineOption[] = {
    328             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
    329     };
    330 
    331     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
    332     ExitOnError(result);
    333 
    334     /* Realizing the SL Engine in synchronous mode. */
    335     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
    336     ExitOnError(result);
    337 
    338     TestRecToBuffQueue(sl, argv[1], (SLAint64)atoi(argv[2]));
    339 
    340     /* Shutdown OpenSL ES */
    341     (*sl)->Destroy(sl);
    342 
    343     return EXIT_SUCCESS;
    344 }
    345