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