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
ExitOnErrorFunc(SLresult result,int line)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 */
RecCallback(SLRecordItf caller,void * pContext,SLuint32 event)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 */
RecBufferQueueCallback(SLAndroidSimpleBufferQueueItf queueItf,void * pContext)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 */
TestRecToBuffQueue(SLObjectItf sl,const char * path,SLAint64 durationInSeconds)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 //-----------------------------------------------------------------
main(int argc,char * const argv[])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