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 % adb shell slesTest_recBuffQueue /sdcard/myrec.wav 21 22These use adb on host to retrive the file: 23 % adb pull /sdcard/myrec.wav 24 25*/ 26 27 28#include <stdlib.h> 29#include <stdio.h> 30#include <string.h> 31#include <unistd.h> 32#include <sys/time.h> 33#include <fcntl.h> 34#include <system/audio.h> 35#include <audio_utils/primitives.h> 36#include <audio_utils/sndfile.h> 37 38#include <SLES/OpenSLES.h> 39#include <SLES/OpenSLES_Android.h> 40 41audio_format_t transferFormat = AUDIO_FORMAT_DEFAULT; 42uint32_t sampleRate = 48000; 43int channelCount = 1; 44bool useIndexChannelMask = false; 45size_t frameSize; 46 47/* Preset number to use for recording */ 48SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE; 49 50/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION 51 * on the AudioRecorder object */ 52#define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2 53 54/* Size of the recording buffer queue */ 55#define NB_BUFFERS_IN_QUEUE 1 56/* Size of each buffer in the queue */ 57#define BUFFER_SIZE_IN_BYTES 2048 58 59/* Local storage for Audio data */ 60int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES]; 61 62/* destination for recorded data */ 63SNDFILE *sndfile; 64 65//----------------------------------------------------------------- 66/* Exits the application if an error is encountered */ 67#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 68 69void ExitOnErrorFunc( SLresult result , int line) 70{ 71 if (SL_RESULT_SUCCESS != result) { 72 fprintf(stderr, "%u 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 */ 79typedef 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 */ 89void RecCallback( 90 SLRecordItf caller, 91 void *pContext __unused, 92 SLuint32 event) 93{ 94 if (SL_RECORDEVENT_HEADATNEWPOS & event) { 95 SLmillisecond pMsec = 0; 96 (*caller)->GetPosition(caller, &pMsec); 97 printf("SL_RECORDEVENT_HEADATNEWPOS current position=%ums\n", pMsec); 98 } 99 100 if (SL_RECORDEVENT_HEADATMARKER & event) { 101 SLmillisecond pMsec = 0; 102 (*caller)->GetPosition(caller, &pMsec); 103 printf("SL_RECORDEVENT_HEADATMARKER current position=%ums\n", pMsec); 104 } 105} 106 107//----------------------------------------------------------------- 108/* Callback for recording buffer queue events */ 109void RecBufferQueueCallback( 110 SLAndroidSimpleBufferQueueItf queueItf, 111 void *pContext) 112{ 113 //printf("RecBufferQueueCallback called\n"); 114 115 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 116 117 /* Save the recorded data */ 118 sf_count_t frameCount = BUFFER_SIZE_IN_BYTES / frameSize; 119 switch (transferFormat) { 120 case AUDIO_FORMAT_PCM_8_BIT: { 121 short temp[BUFFER_SIZE_IN_BYTES]; 122 memcpy_to_i16_from_u8(temp, (const unsigned char *) pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES); 123 (void) sf_writef_short(sndfile, (const short *) temp, frameCount); 124 } break; 125 case AUDIO_FORMAT_PCM_16_BIT: 126 (void) sf_writef_short(sndfile, (const short *) pCntxt->pDataBase, frameCount); 127 break; 128 case AUDIO_FORMAT_PCM_32_BIT: 129 (void) sf_writef_int(sndfile, (const int *) pCntxt->pDataBase, frameCount); 130 break; 131 case AUDIO_FORMAT_PCM_FLOAT: 132 (void) sf_writef_float(sndfile, (const float *) pCntxt->pDataBase, frameCount); 133 break; 134 default: 135 fprintf(stderr, "Unsupported transfer format %d\n", transferFormat); 136 exit(EXIT_FAILURE); 137 } 138 139 /* Increase data pointer by buffer size */ 140 pCntxt->pData += BUFFER_SIZE_IN_BYTES; 141 142 if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 143 pCntxt->pData = pCntxt->pDataBase; 144 } 145 146 ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 147 148 SLAndroidSimpleBufferQueueState recQueueState; 149 ExitOnError( (*queueItf)->GetState(queueItf, &recQueueState) ); 150 151 /*fprintf(stderr, "\tRecBufferQueueCallback now has pCntxt->pData=%p queue: " 152 "count=%u playIndex=%u\n", 153 pCntxt->pData, recQueueState.count, recQueueState.index);*/ 154 //printf("RecBufferQueueCallback returned\n"); 155} 156 157//----------------------------------------------------------------- 158 159/* Record to an audio path by opening a file descriptor on that path */ 160void TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSeconds) 161{ 162 SF_INFO info; 163 info.frames = 0; 164 info.samplerate = sampleRate; 165 info.channels = channelCount; 166 switch (transferFormat) { 167 case AUDIO_FORMAT_PCM_8_BIT: 168 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_U8; 169 break; 170 case AUDIO_FORMAT_PCM_16_BIT: 171 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 172 break; 173 case AUDIO_FORMAT_PCM_32_BIT: 174 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_32; 175 break; 176 case AUDIO_FORMAT_PCM_FLOAT: 177 info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; 178 break; 179 default: 180 fprintf(stderr, "Unsupported transfer format %d\n", transferFormat); 181 exit(EXIT_FAILURE); 182 } 183 sndfile = sf_open(path, SFM_WRITE, &info); 184 if (sndfile == NULL) { 185 ExitOnError(SL_RESULT_RESOURCE_ERROR); 186 } 187 188 SLresult result; 189 SLEngineItf EngineItf; 190 191 /* Objects this application uses: one audio recorder */ 192 SLObjectItf recorder; 193 194 /* Interfaces for the audio recorder */ 195 SLAndroidSimpleBufferQueueItf recBuffQueueItf; 196 SLRecordItf recordItf; 197 SLAndroidConfigurationItf configItf; 198 199 /* Source of audio data for the recording */ 200 SLDataSource recSource; 201 SLDataLocator_IODevice ioDevice; 202 203 /* Data sink for recorded audio */ 204 SLDataSink recDest; 205 SLDataLocator_AndroidSimpleBufferQueue recBuffQueue; 206 /* As mentioned in the Android extension API documentation this is identical to 207 * OpenSL ES 1.1 SLDataFormat_PCM_EX, and can be used for an instance of SLDataFormat_PCM. 208 */ 209 SLAndroidDataFormat_PCM_EX pcm; 210 211 SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_RECORDER]; 212 SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_RECORDER]; 213 214 /* Get the SL Engine Interface which is implicit */ 215 result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 216 ExitOnError(result); 217 218 /* Initialize arrays required[] and iidArray[] */ 219 for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_RECORDER ; i++) { 220 required[i] = SL_BOOLEAN_FALSE; 221 iidArray[i] = SL_IID_NULL; 222 } 223 224 225 /* ------------------------------------------------------ */ 226 /* Configuration of the recorder */ 227 228 /* Request the AndroidSimpleBufferQueue and AndroidConfiguration interfaces */ 229 required[0] = SL_BOOLEAN_TRUE; 230 iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 231 required[1] = SL_BOOLEAN_TRUE; 232 iidArray[1] = SL_IID_ANDROIDCONFIGURATION; 233 234 /* Setup the data source */ 235 ioDevice.locatorType = SL_DATALOCATOR_IODEVICE; 236 ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT; 237 ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; 238 ioDevice.device = NULL; 239 recSource.pLocator = (void *) &ioDevice; 240 recSource.pFormat = NULL; 241 242 /* Setup the data sink */ 243 recBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 244 recBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 245 /* set up the format of the data in the buffer queue */ 246 pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT || 247 transferFormat == AUDIO_FORMAT_PCM_8_BIT ? 248 SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM; 249 pcm.numChannels = channelCount; 250 pcm.sampleRate = sampleRate * 1000; // milliHz 251 pcm.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; 252 switch (transferFormat) { 253 case AUDIO_FORMAT_PCM_16_BIT: 254 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 255 pcm.containerSize = 16; 256 break; 257 case AUDIO_FORMAT_PCM_32_BIT: 258 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32; 259 pcm.containerSize = 32; 260 break; 261 case AUDIO_FORMAT_PCM_8_BIT: 262 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8; 263 pcm.containerSize = 8; 264 pcm.representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; 265 break; 266 case AUDIO_FORMAT_PCM_FLOAT: 267 pcm.bitsPerSample = 32; 268 pcm.containerSize = 32; 269 pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; 270 break; 271 default: 272 fprintf(stderr, "Unsupported transfer format %d\n", transferFormat); 273 exit(EXIT_FAILURE); 274 } 275 if (useIndexChannelMask) { 276 pcm.channelMask = (1 << channelCount) - 1; 277 } else { 278 switch (channelCount) { 279 case 1: 280 pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 281 break; 282 case 2: 283 pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 284 break; 285 default: 286 fprintf(stderr, "Unsupported channel count %d\n", channelCount); 287 exit(EXIT_FAILURE); 288 } 289 } 290 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 291 292 recDest.pLocator = (void *) &recBuffQueue; 293 recDest.pFormat = (void * ) &pcm; 294 295 /* Create the audio recorder */ 296 result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest, 297 NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iidArray, required); 298 ExitOnError(result); 299 printf("Recorder created\n"); 300 301 /* Get the Android configuration interface which is explicit */ 302 result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf); 303 ExitOnError(result); 304 305 /* Use the configuration interface to configure the recorder before it's realized */ 306 if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) { 307 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, 308 &presetValue, sizeof(SLuint32)); 309 ExitOnError(result); 310 printf("Recorder configured with preset %u\n", presetValue); 311 } else { 312 printf("Using default record preset\n"); 313 } 314 315 SLuint32 presetRetrieved = SL_ANDROID_RECORDING_PRESET_NONE; 316 SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big 317 result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, 318 &presetSize, (void*)&presetRetrieved); 319 ExitOnError(result); 320 if (presetValue == SL_ANDROID_RECORDING_PRESET_NONE) { 321 printf("The default record preset appears to be %u\n", presetRetrieved); 322 } else if (presetValue != presetRetrieved) { 323 fprintf(stderr, "Error retrieving recording preset as %u instead of %u\n", presetRetrieved, 324 presetValue); 325 ExitOnError(SL_RESULT_INTERNAL_ERROR); 326 } 327 328 /* Realize the recorder in synchronous mode. */ 329 result = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE); 330 ExitOnError(result); 331 printf("Recorder realized\n"); 332 333 /* Get the record interface which is implicit */ 334 result = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void*)&recordItf); 335 ExitOnError(result); 336 337 /* Set up the recorder callback to get events during the recording */ 338 result = (*recordItf)->SetMarkerPosition(recordItf, 2000); 339 ExitOnError(result); 340 result = (*recordItf)->SetPositionUpdatePeriod(recordItf, 500); 341 ExitOnError(result); 342 result = (*recordItf)->SetCallbackEventsMask(recordItf, 343 SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS); 344 ExitOnError(result); 345 result = (*recordItf)->RegisterCallback(recordItf, RecCallback, NULL); 346 ExitOnError(result); 347 printf("Recorder callback registered\n"); 348 349 /* Get the buffer queue interface which was explicitly requested */ 350 result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 351 (void*)&recBuffQueueItf); 352 ExitOnError(result); 353 354 /* ------------------------------------------------------ */ 355 /* Initialize the callback and its context for the recording buffer queue */ 356 CallbackCntxt cntxt; 357 cntxt.pDataBase = (int8_t*)&pcmData; 358 cntxt.pData = cntxt.pDataBase; 359 cntxt.size = sizeof(pcmData); 360 result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, RecBufferQueueCallback, &cntxt); 361 ExitOnError(result); 362 363 /* Enqueue buffers to map the region of memory allocated to store the recorded data */ 364 printf("Enqueueing buffer "); 365 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 366 printf("%d ", i); 367 result = (*recBuffQueueItf)->Enqueue(recBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 368 ExitOnError(result); 369 cntxt.pData += BUFFER_SIZE_IN_BYTES; 370 } 371 printf("\n"); 372 cntxt.pData = cntxt.pDataBase; 373 374 /* ------------------------------------------------------ */ 375 /* Start recording */ 376 result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING); 377 ExitOnError(result); 378 printf("Starting to record\n"); 379 380 /* Record for at least a second */ 381 if (durationInSeconds < 1) { 382 durationInSeconds = 1; 383 } 384 usleep(durationInSeconds * 1000 * 1000); 385 386 /* ------------------------------------------------------ */ 387 /* End of recording */ 388 389 /* Stop recording */ 390 result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED); 391 ExitOnError(result); 392 printf("Stopped recording\n"); 393 394 /* Destroy the AudioRecorder object */ 395 (*recorder)->Destroy(recorder); 396 397 sf_close(sndfile); 398} 399 400//----------------------------------------------------------------- 401int main(int argc, char* const argv[]) 402{ 403 int durationInSeconds = 10; 404 SLresult result; 405 SLObjectItf sl; 406 407 const char *prog = argv[0]; 408 printf("OpenSL ES test %s: exercises SLRecordItf and SLAndroidSimpleBufferQueueItf ", 409 prog); 410 printf("on an AudioRecorder object\n"); 411 412 int i; 413 for (i = 1; i < argc; ++i) { 414 const char *arg = argv[i]; 415 if (arg[0] != '-') { 416 break; 417 } 418 switch (arg[1]) { 419 case 'c': // channel count 420 channelCount = atoi(&arg[2]); 421 break; 422 case 'd': // duration in seconds 423 durationInSeconds = atoi(&arg[2]); 424 break; 425 case 'f': 426 transferFormat = AUDIO_FORMAT_PCM_FLOAT; 427 break; 428 case 'i': 429 useIndexChannelMask = true; 430 break; 431 case 'p': // preset number 432 presetValue = atoi(&arg[2]); 433 break; 434 case 'r': 435 sampleRate = atoi(&arg[2]); 436 break; 437 case '1': 438 transferFormat = AUDIO_FORMAT_PCM_8_BIT; 439 break; 440 case '2': 441 transferFormat = AUDIO_FORMAT_PCM_16_BIT; 442 break; 443 case '4': 444 transferFormat = AUDIO_FORMAT_PCM_32_BIT; 445 break; 446 default: 447 fprintf(stderr, "%s: unknown option %s\n", prog, arg); 448 break; 449 } 450 } 451 452 if (transferFormat == AUDIO_FORMAT_DEFAULT) { 453 transferFormat = AUDIO_FORMAT_PCM_16_BIT; 454 } 455 frameSize = audio_bytes_per_sample(transferFormat) * channelCount; 456 457 if (argc-i != 1) { 458 printf("Usage: \t%s [-c#] [-d#] [-i] [-p#] [-r#] [-1/2/4/f] destination_file\n", prog); 459 printf(" -c# channel count, defaults to 1\n"); 460 printf(" -d# duration in seconds, default to 10\n"); 461 printf(" -i index channel mask, not yet implemented\n"); 462 printf(" -p# is the preset value which defaults to SL_ANDROID_RECORDING_PRESET_NONE\n"); 463 printf(" possible values are:\n"); 464 printf(" -p%d SL_ANDROID_RECORDING_PRESET_NONE\n", 465 SL_ANDROID_RECORDING_PRESET_NONE); 466 printf(" -p%d SL_ANDROID_RECORDING_PRESET_GENERIC\n", 467 SL_ANDROID_RECORDING_PRESET_GENERIC); 468 printf(" -p%d SL_ANDROID_RECORDING_PRESET_CAMCORDER\n", 469 SL_ANDROID_RECORDING_PRESET_CAMCORDER); 470 printf(" -p%d SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION\n", 471 SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION); 472 printf(" -p%d SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION\n", 473 SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION); 474 printf(" -r# sample rate in Hz, defaults to 48000\n"); 475 printf(" -[1/2/4/f] sample format: 8-bit unsigned, 16-bit signed, 32-bit signed, float, " 476 "defaults to 16-bit signed\n"); 477 printf("Example: \"%s /sdcard/myrec.wav\" \n", prog); 478 exit(EXIT_FAILURE); 479 } 480 481 SLEngineOption EngineOption[] = { 482 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 483 }; 484 485 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 486 ExitOnError(result); 487 488 /* Realizing the SL Engine in synchronous mode. */ 489 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 490 ExitOnError(result); 491 492 TestRecToBuffQueue(sl, argv[i], durationInSeconds); 493 494 /* Shutdown OpenSL ES */ 495 (*sl)->Destroy(sl); 496 497 return EXIT_SUCCESS; 498} 499