3 Android OpenSL input/output module
4 Copyright (c) 2012, Victor Lazzarini
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of the <organization> nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "opensl_io.h"
31 //#define CONV16BIT 32768
32 //#define CONVMYFLT (1./32768.)
33 #define CONV16BIT 32640
34 #define CONVMYFLT (1./32640.)
36 static void* createThreadLock(void);
37 static int waitThreadLock(void *lock
);
38 static void notifyThreadLock(void *lock
);
39 static void destroyThreadLock(void *lock
);
40 static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq
, void *context
);
41 static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq
, void *context
);
43 // creates the OpenSL ES audio engine
44 static SLresult
openSLCreateEngine(OPENSL_STREAM
*p
)
48 result
= slCreateEngine(&(p
->engineObject
), 0, NULL
, 0, NULL
, NULL
);
49 if(result
!= SL_RESULT_SUCCESS
) goto engine_end
;
52 result
= (*p
->engineObject
)->Realize(p
->engineObject
, SL_BOOLEAN_FALSE
);
53 if(result
!= SL_RESULT_SUCCESS
) goto engine_end
;
55 // get the engine interface, which is needed in order to create other objects
56 result
= (*p
->engineObject
)->GetInterface(p
->engineObject
, SL_IID_ENGINE
, &(p
->engineEngine
));
57 if(result
!= SL_RESULT_SUCCESS
) goto engine_end
;
63 // opens the OpenSL ES device for output
64 static SLresult
openSLPlayOpen(OPENSL_STREAM
*p
)
68 SLuint32 channels
= p
->outchannels
;
71 // configure audio source
72 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
= {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
, 2};
77 sr
= SL_SAMPLINGRATE_8
;
80 sr
= SL_SAMPLINGRATE_11_025
;
83 sr
= SL_SAMPLINGRATE_16
;
86 sr
= SL_SAMPLINGRATE_22_05
;
89 sr
= SL_SAMPLINGRATE_24
;
92 sr
= SL_SAMPLINGRATE_32
;
95 sr
= SL_SAMPLINGRATE_44_1
;
98 sr
= SL_SAMPLINGRATE_48
;
101 sr
= SL_SAMPLINGRATE_64
;
104 sr
= SL_SAMPLINGRATE_88_2
;
107 sr
= SL_SAMPLINGRATE_96
;
110 sr
= SL_SAMPLINGRATE_192
;
116 const SLInterfaceID ids
[] = {SL_IID_VOLUME
};
117 const SLboolean req
[] = {SL_BOOLEAN_FALSE
};
118 result
= (*p
->engineEngine
)->CreateOutputMix(p
->engineEngine
, &(p
->outputMixObject
), 1, ids
, req
);
119 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
121 // realize the output mix
122 result
= (*p
->outputMixObject
)->Realize(p
->outputMixObject
, SL_BOOLEAN_FALSE
);
126 speakers
= SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
;
127 else speakers
= SL_SPEAKER_FRONT_CENTER
;
128 SLDataFormat_PCM format_pcm
= {SL_DATAFORMAT_PCM
,channels
, sr
,
129 SL_PCMSAMPLEFORMAT_FIXED_16
, SL_PCMSAMPLEFORMAT_FIXED_16
,
130 speakers
, SL_BYTEORDER_LITTLEENDIAN
};
132 SLDataSource audioSrc
= {&loc_bufq
, &format_pcm
};
134 // configure audio sink
135 SLDataLocator_OutputMix loc_outmix
= {SL_DATALOCATOR_OUTPUTMIX
, p
->outputMixObject
};
136 SLDataSink audioSnk
= {&loc_outmix
, NULL
};
138 // create audio player
139 const SLInterfaceID ids1
[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE
};
140 const SLboolean req1
[] = {SL_BOOLEAN_TRUE
};
141 result
= (*p
->engineEngine
)->CreateAudioPlayer(p
->engineEngine
, &(p
->bqPlayerObject
), &audioSrc
, &audioSnk
,
143 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
145 // realize the player
146 result
= (*p
->bqPlayerObject
)->Realize(p
->bqPlayerObject
, SL_BOOLEAN_FALSE
);
147 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
149 // get the play interface
150 result
= (*p
->bqPlayerObject
)->GetInterface(p
->bqPlayerObject
, SL_IID_PLAY
, &(p
->bqPlayerPlay
));
151 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
153 // get the buffer queue interface
154 result
= (*p
->bqPlayerObject
)->GetInterface(p
->bqPlayerObject
, SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
155 &(p
->bqPlayerBufferQueue
));
156 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
158 // register callback on the buffer queue
159 result
= (*p
->bqPlayerBufferQueue
)->RegisterCallback(p
->bqPlayerBufferQueue
, bqPlayerCallback
, p
);
160 if(result
!= SL_RESULT_SUCCESS
) goto end_openaudio
;
162 // set the player's state to playing
163 result
= (*p
->bqPlayerPlay
)->SetPlayState(p
->bqPlayerPlay
, SL_PLAYSTATE_PLAYING
);
168 return SL_RESULT_SUCCESS
;
171 // Open the OpenSL ES device for input
172 static SLresult
openSLRecOpen(OPENSL_STREAM
*p
){
176 SLuint32 channels
= p
->inchannels
;
183 sr
= SL_SAMPLINGRATE_8
;
186 sr
= SL_SAMPLINGRATE_11_025
;
189 sr
= SL_SAMPLINGRATE_16
;
192 sr
= SL_SAMPLINGRATE_22_05
;
195 sr
= SL_SAMPLINGRATE_24
;
198 sr
= SL_SAMPLINGRATE_32
;
201 sr
= SL_SAMPLINGRATE_44_1
;
204 sr
= SL_SAMPLINGRATE_48
;
207 sr
= SL_SAMPLINGRATE_64
;
210 sr
= SL_SAMPLINGRATE_88_2
;
213 sr
= SL_SAMPLINGRATE_96
;
216 sr
= SL_SAMPLINGRATE_192
;
222 // configure audio source
223 SLDataLocator_IODevice loc_dev
= {SL_DATALOCATOR_IODEVICE
, SL_IODEVICE_AUDIOINPUT
,
224 SL_DEFAULTDEVICEID_AUDIOINPUT
, NULL
};
225 SLDataSource audioSrc
= {&loc_dev
, NULL
};
227 // configure audio sink
230 speakers
= SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
;
231 else speakers
= SL_SPEAKER_FRONT_CENTER
;
232 SLDataLocator_AndroidSimpleBufferQueue loc_bq
= {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
, 2};
233 SLDataFormat_PCM format_pcm
= {SL_DATAFORMAT_PCM
, channels
, sr
,
234 SL_PCMSAMPLEFORMAT_FIXED_16
, SL_PCMSAMPLEFORMAT_FIXED_16
,
235 speakers
, SL_BYTEORDER_LITTLEENDIAN
};
236 SLDataSink audioSnk
= {&loc_bq
, &format_pcm
};
238 // create audio recorder
239 // (requires the RECORD_AUDIO permission)
240 const SLInterfaceID id
[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE
};
241 const SLboolean req
[1] = {SL_BOOLEAN_TRUE
};
242 result
= (*p
->engineEngine
)->CreateAudioRecorder(p
->engineEngine
, &(p
->recorderObject
), &audioSrc
,
243 &audioSnk
, 1, id
, req
);
244 if (SL_RESULT_SUCCESS
!= result
) goto end_recopen
;
246 // realize the audio recorder
247 result
= (*p
->recorderObject
)->Realize(p
->recorderObject
, SL_BOOLEAN_FALSE
);
248 if (SL_RESULT_SUCCESS
!= result
) goto end_recopen
;
250 // get the record interface
251 result
= (*p
->recorderObject
)->GetInterface(p
->recorderObject
, SL_IID_RECORD
, &(p
->recorderRecord
));
252 if (SL_RESULT_SUCCESS
!= result
) goto end_recopen
;
254 // get the buffer queue interface
255 result
= (*p
->recorderObject
)->GetInterface(p
->recorderObject
, SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
256 &(p
->recorderBufferQueue
));
257 if (SL_RESULT_SUCCESS
!= result
) goto end_recopen
;
259 // register callback on the buffer queue
260 result
= (*p
->recorderBufferQueue
)->RegisterCallback(p
->recorderBufferQueue
, bqRecorderCallback
,
262 if (SL_RESULT_SUCCESS
!= result
) goto end_recopen
;
263 result
= (*p
->recorderRecord
)->SetRecordState(p
->recorderRecord
, SL_RECORDSTATE_RECORDING
);
268 else return SL_RESULT_SUCCESS
;
273 // close the OpenSL IO and destroy the audio engine
274 static void openSLDestroyEngine(OPENSL_STREAM
*p
){
276 // destroy buffer queue audio player object, and invalidate all associated interfaces
277 if (p
->bqPlayerObject
!= NULL
) {
278 (*p
->bqPlayerObject
)->Destroy(p
->bqPlayerObject
);
279 p
->bqPlayerObject
= NULL
;
280 p
->bqPlayerPlay
= NULL
;
281 p
->bqPlayerBufferQueue
= NULL
;
282 p
->bqPlayerEffectSend
= NULL
;
285 // destroy audio recorder object, and invalidate all associated interfaces
286 if (p
->recorderObject
!= NULL
) {
287 (*p
->recorderObject
)->Destroy(p
->recorderObject
);
288 p
->recorderObject
= NULL
;
289 p
->recorderRecord
= NULL
;
290 p
->recorderBufferQueue
= NULL
;
293 // destroy output mix object, and invalidate all associated interfaces
294 if (p
->outputMixObject
!= NULL
) {
295 (*p
->outputMixObject
)->Destroy(p
->outputMixObject
);
296 p
->outputMixObject
= NULL
;
299 // destroy engine object, and invalidate all associated interfaces
300 if (p
->engineObject
!= NULL
) {
301 (*p
->engineObject
)->Destroy(p
->engineObject
);
302 p
->engineObject
= NULL
;
303 p
->engineEngine
= NULL
;
309 // open the android audio device for input and/or output
310 OPENSL_STREAM
*android_OpenAudioDevice(int sr
, int inchannels
, int outchannels
, int bufferframes
){
313 p
= (OPENSL_STREAM
*) calloc(sizeof(OPENSL_STREAM
),1);
315 p
->inchannels
= inchannels
;
316 p
->outchannels
= outchannels
;
318 p
->inlock
= createThreadLock();
319 p
->outlock
= createThreadLock();
321 if((p
->outBufSamples
= bufferframes
*outchannels
) != 0) {
322 if((p
->outputBuffer
[0] = (short *) calloc(p
->outBufSamples
, sizeof(short))) == NULL
||
323 (p
->outputBuffer
[1] = (short *) calloc(p
->outBufSamples
, sizeof(short))) == NULL
) {
324 android_CloseAudioDevice(p
);
329 if((p
->inBufSamples
= bufferframes
*inchannels
) != 0){
330 if((p
->inputBuffer
[0] = (short *) calloc(p
->inBufSamples
, sizeof(short))) == NULL
||
331 (p
->inputBuffer
[1] = (short *) calloc(p
->inBufSamples
, sizeof(short))) == NULL
){
332 android_CloseAudioDevice(p
);
337 p
->currentInputIndex
= 0;
338 p
->currentOutputBuffer
= 0;
339 p
->currentInputIndex
= p
->inBufSamples
;
340 p
->currentInputBuffer
= 0;
342 if(openSLCreateEngine(p
) != SL_RESULT_SUCCESS
) {
343 android_CloseAudioDevice(p
);
347 if(openSLRecOpen(p
) != SL_RESULT_SUCCESS
) {
348 android_CloseAudioDevice(p
);
352 if(openSLPlayOpen(p
) != SL_RESULT_SUCCESS
) {
353 android_CloseAudioDevice(p
);
357 notifyThreadLock(p
->outlock
);
358 notifyThreadLock(p
->inlock
);
364 // close the android audio device
365 void android_CloseAudioDevice(OPENSL_STREAM
*p
){
370 openSLDestroyEngine(p
);
372 if (p
->inlock
!= NULL
) {
373 notifyThreadLock(p
->inlock
);
374 destroyThreadLock(p
->inlock
);
378 if (p
->outlock
!= NULL
) {
379 notifyThreadLock(p
->outlock
);
380 destroyThreadLock(p
->outlock
);
384 if (p
->outputBuffer
[0] != NULL
) {
385 free(p
->outputBuffer
[0]);
386 p
->outputBuffer
[0] = NULL
;
389 if (p
->outputBuffer
[1] != NULL
) {
390 free(p
->outputBuffer
[1]);
391 p
->outputBuffer
[1] = NULL
;
394 if (p
->inputBuffer
[0] != NULL
) {
395 free(p
->inputBuffer
[0]);
396 p
->inputBuffer
[0] = NULL
;
399 if (p
->inputBuffer
[1] != NULL
) {
400 free(p
->inputBuffer
[1]);
401 p
->inputBuffer
[1] = NULL
;
407 // returns timestamp of the processed stream
408 double android_GetTimestamp(OPENSL_STREAM
*p
){
413 // this callback handler is called every time a buffer finishes recording
414 void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq
, void *context
)
416 OPENSL_STREAM
*p
= (OPENSL_STREAM
*) context
;
417 notifyThreadLock(p
->inlock
);
420 // gets a buffer of size samples from the device
421 int android_AudioIn(OPENSL_STREAM
*p
,float *buffer
,int size
){
423 int i
, bufsamps
, index
;
424 if(p
== NULL
) return 0;
425 bufsamps
= p
->inBufSamples
;
426 if(bufsamps
== 0) return 0;
427 index
= p
->currentInputIndex
;
429 inBuffer
= p
->inputBuffer
[p
->currentInputBuffer
];
430 for(i
=0; i
< size
; i
++){
431 if (index
>= bufsamps
) {
432 waitThreadLock(p
->inlock
);
433 (*p
->recorderBufferQueue
)->Enqueue(p
->recorderBufferQueue
,
434 inBuffer
,bufsamps
*sizeof(short));
435 p
->currentInputBuffer
= (p
->currentInputBuffer
? 0 : 1);
437 inBuffer
= p
->inputBuffer
[p
->currentInputBuffer
];
439 buffer
[i
] = (float) inBuffer
[index
++]*CONVMYFLT
;
441 p
->currentInputIndex
= index
;
442 if(p
->outchannels
== 0) p
->time
+= (double) size
/(p
->sr
*p
->inchannels
);
446 // this callback handler is called every time a buffer finishes playing
447 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq
, void *context
)
449 OPENSL_STREAM
*p
= (OPENSL_STREAM
*) context
;
450 notifyThreadLock(p
->outlock
);
453 // puts a buffer of size samples to the device
454 int android_AudioOut(OPENSL_STREAM
*p
, float *buffer
,int size
){
457 int i
, bufsamps
, index
;
458 if(p
== NULL
) return 0;
459 bufsamps
= p
->outBufSamples
;
460 if(bufsamps
== 0) return 0;
461 index
= p
->currentOutputIndex
;
462 outBuffer
= p
->outputBuffer
[p
->currentOutputBuffer
];
464 for(i
=0; i
< size
; i
++){
465 outBuffer
[index
++] = (short) (buffer
[i
]*CONV16BIT
);
466 if (index
>= p
->outBufSamples
) {
467 waitThreadLock(p
->outlock
);
468 (*p
->bqPlayerBufferQueue
)->Enqueue(p
->bqPlayerBufferQueue
,
469 outBuffer
,bufsamps
*sizeof(short));
470 p
->currentOutputBuffer
= (p
->currentOutputBuffer
? 0 : 1);
472 outBuffer
= p
->outputBuffer
[p
->currentOutputBuffer
];
475 p
->currentOutputIndex
= index
;
476 p
->time
+= (double) size
/(p
->sr
*p
->outchannels
);
480 //----------------------------------------------------------------------
482 // to ensure synchronisation between callbacks and processing code
483 void* createThreadLock(void)
486 p
= (threadLock
*) malloc(sizeof(threadLock
));
489 memset(p
, 0, sizeof(threadLock
));
490 if (pthread_mutex_init(&(p
->m
), (pthread_mutexattr_t
*) NULL
) != 0) {
494 if (pthread_cond_init(&(p
->c
), (pthread_condattr_t
*) NULL
) != 0) {
495 pthread_mutex_destroy(&(p
->m
));
499 p
->s
= (unsigned char) 1;
504 int waitThreadLock(void *lock
)
508 p
= (threadLock
*) lock
;
509 pthread_mutex_lock(&(p
->m
));
511 pthread_cond_wait(&(p
->c
), &(p
->m
));
513 p
->s
= (unsigned char) 0;
514 pthread_mutex_unlock(&(p
->m
));
518 void notifyThreadLock(void *lock
)
521 p
= (threadLock
*) lock
;
522 pthread_mutex_lock(&(p
->m
));
523 p
->s
= (unsigned char) 1;
524 pthread_cond_signal(&(p
->c
));
525 pthread_mutex_unlock(&(p
->m
));
529 void destroyThreadLock(void *lock
)
532 p
= (threadLock
*) lock
;
536 pthread_cond_destroy(&(p
->c
));
537 pthread_mutex_destroy(&(p
->m
));