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 */
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 */
49 SLuint32 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 */
62 int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES];
63
64 /* destination for recorded data */
65 static FILE* gFp;
66
67 //-----------------------------------------------------------------
68 /* Exits the application if an error is encountered */
69 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
70
ExitOnErrorFunc(SLresult result,int line)71 void 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 */
81 typedef 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 */
RecCallback(SLRecordItf caller,void * pContext,SLuint32 event)91 void 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 */
RecBufferQueueCallback(SLAndroidSimpleBufferQueueItf queueItf,void * pContext)111 void 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 */
TestRecToBuffQueue(SLObjectItf sl,const char * path,SLAint64 durationInSeconds)142 void 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, presetValue);
244 ExitOnError(SL_RESULT_INTERNAL_ERROR);
245 }
246
247 /* Realize the recorder in synchronous mode. */
248 result = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
249 ExitOnError(result);
250 fprintf(stdout, "Recorder realized\n");
251
252 /* Get the record interface which is implicit */
253 result = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void*)&recordItf);
254 ExitOnError(result);
255
256 /* Set up the recorder callback to get events during the recording */
257 result = (*recordItf)->SetMarkerPosition(recordItf, 2000);
258 ExitOnError(result);
259 result = (*recordItf)->SetPositionUpdatePeriod(recordItf, 500);
260 ExitOnError(result);
261 result = (*recordItf)->SetCallbackEventsMask(recordItf,
262 SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS);
263 ExitOnError(result);
264 result = (*recordItf)->RegisterCallback(recordItf, RecCallback, NULL);
265 ExitOnError(result);
266 fprintf(stdout, "Recorder callback registered\n");
267
268 /* Get the buffer queue interface which was explicitly requested */
269 result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
270 (void*)&recBuffQueueItf);
271 ExitOnError(result);
272
273 /* ------------------------------------------------------ */
274 /* Initialize the callback and its context for the recording buffer queue */
275 CallbackCntxt cntxt;
276 cntxt.pDataBase = (int8_t*)&pcmData;
277 cntxt.pData = cntxt.pDataBase;
278 cntxt.size = sizeof(pcmData);
279 result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, RecBufferQueueCallback, &cntxt);
280 ExitOnError(result);
281
282 /* Enqueue buffers to map the region of memory allocated to store the recorded data */
283 fprintf(stdout,"Enqueueing buffer ");
284 for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) {
285 fprintf(stdout,"%d ", i);
286 result = (*recBuffQueueItf)->Enqueue(recBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES);
287 ExitOnError(result);
288 cntxt.pData += BUFFER_SIZE_IN_BYTES;
289 }
290 fprintf(stdout,"\n");
291 cntxt.pData = cntxt.pDataBase;
292
293 /* ------------------------------------------------------ */
294 /* Start recording */
295 result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
296 ExitOnError(result);
297 fprintf(stdout, "Starting to record\n");
298
299 /* Record for at least a second */
300 if (durationInSeconds < 1) {
301 durationInSeconds = 1;
302 }
303 usleep(durationInSeconds * 1000 * 1000);
304
305 /* ------------------------------------------------------ */
306 /* End of recording */
307
308 /* Stop recording */
309 result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
310 ExitOnError(result);
311 fprintf(stdout, "Stopped recording\n");
312
313 /* Destroy the AudioRecorder object */
314 (*recorder)->Destroy(recorder);
315
316 fclose(gFp);
317 }
318
319 //-----------------------------------------------------------------
main(int argc,char * const argv[])320 int main(int argc, char* const argv[])
321 {
322 SLresult result;
323 SLObjectItf sl;
324
325 const char *prog = argv[0];
326 fprintf(stdout, "OpenSL ES test %s: exercises SLRecordItf and SLAndroidSimpleBufferQueueItf ",
327 prog);
328 fprintf(stdout, "on an AudioRecorder object\n");
329
330 int i;
331 for (i = 1; i < argc; ++i) {
332 const char *arg = argv[i];
333 if (arg[0] != '-') {
334 break;
335 }
336 switch (arg[1]) {
337 case 'p': // preset number
338 presetValue = atoi(&arg[2]);
339 break;
340 default:
341 fprintf(stderr, "%s: unknown option %s\n", prog, arg);
342 break;
343 }
344 }
345
346 if (argc-i < 2) {
347 fprintf(stdout, "Usage: \t%s [-p#] destination_file duration_in_seconds\n", prog);
348 fprintf(stdout, "Example: \"%s /sdcard/myrec.raw 4\" \n", prog);
349 exit(EXIT_FAILURE);
350 }
351
352 SLEngineOption EngineOption[] = {
353 {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
354 };
355
356 result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
357 ExitOnError(result);
358
359 /* Realizing the SL Engine in synchronous mode. */
360 result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
361 ExitOnError(result);
362
363 TestRecToBuffQueue(sl, argv[i], (SLAint64)atoi(argv[i+1]));
364
365 /* Shutdown OpenSL ES */
366 (*sl)->Destroy(sl);
367
368 return EXIT_SUCCESS;
369 }
370