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