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