2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* This is an OpenAL backend for Android using the native audio APIs based on
18 * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app
32 #include "backends/base.h"
34 #include <SLES/OpenSLES.h>
35 #include <SLES/OpenSLES_Android.h>
36 #include <SLES/OpenSLES_AndroidConfiguration.h>
39 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
40 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
43 static const ALCchar opensl_device
[] = "OpenSL";
46 static SLuint32
GetChannelMask(enum DevFmtChannels chans
)
50 case DevFmtMono
: return SL_SPEAKER_FRONT_CENTER
;
51 case DevFmtStereo
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
;
52 case DevFmtQuad
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
53 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
54 case DevFmtX51
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
55 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
56 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
57 case DevFmtX51Rear
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
58 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
59 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
60 case DevFmtX61
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
61 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
62 SL_SPEAKER_BACK_CENTER
|
63 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
64 case DevFmtX71
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
65 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
66 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
|
67 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
74 #ifdef SL_DATAFORMAT_PCM_EX
75 static SLuint32
GetTypeRepresentation(enum DevFmtType type
)
82 return SL_PCM_REPRESENTATION_UNSIGNED_INT
;
86 return SL_PCM_REPRESENTATION_SIGNED_INT
;
88 return SL_PCM_REPRESENTATION_FLOAT
;
94 static const char *res_str(SLresult result
)
98 case SL_RESULT_SUCCESS
: return "Success";
99 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
100 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
101 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
102 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
103 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
104 case SL_RESULT_IO_ERROR
: return "I/O error";
105 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
106 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
107 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
108 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
109 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
110 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
111 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
112 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
113 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
114 case SL_RESULT_CONTROL_LOST
: return "Control lost";
115 #ifdef SL_RESULT_READONLY
116 case SL_RESULT_READONLY
: return "ReadOnly";
118 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
119 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
121 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
122 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
125 return "Unknown error code";
128 #define PRINTERR(x, s) do { \
129 if((x) != SL_RESULT_SUCCESS) \
130 ERR("%s: %s\n", (s), res_str((x))); \
134 typedef struct ALCopenslPlayback
{
135 DERIVE_FROM_TYPE(ALCbackend
);
137 /* engine interfaces */
138 SLObjectItf mEngineObj
;
141 /* output mix interfaces */
142 SLObjectItf mOutputMix
;
144 /* buffer queue player interfaces */
145 SLObjectItf mBufferQueueObj
;
147 ll_ringbuffer_t
*mRing
;
152 ATOMIC(ALenum
) mKillNow
;
156 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
157 static int ALCopenslPlayback_mixerProc(void *arg
);
159 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
);
160 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
*self
);
161 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
);
162 static void ALCopenslPlayback_close(ALCopenslPlayback
*self
);
163 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
);
164 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
);
165 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
);
166 static DECLARE_FORWARD2(ALCopenslPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
167 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, ALCuint
, availableSamples
)
168 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
);
169 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, lock
)
170 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, unlock
)
171 DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback
)
173 DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback
);
176 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
)
178 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
179 SET_VTABLE2(ALCopenslPlayback
, ALCbackend
, self
);
181 self
->mEngineObj
= NULL
;
182 self
->mEngine
= NULL
;
183 self
->mOutputMix
= NULL
;
184 self
->mBufferQueueObj
= NULL
;
187 alcnd_init(&self
->mCond
);
189 self
->mFrameSize
= 0;
191 ATOMIC_INIT(&self
->mKillNow
, AL_FALSE
);
194 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
* self
)
196 if(self
->mBufferQueueObj
!= NULL
)
197 VCALL0(self
->mBufferQueueObj
,Destroy
)();
198 self
->mBufferQueueObj
= NULL
;
200 if(self
->mOutputMix
!= NULL
)
201 VCALL0(self
->mOutputMix
,Destroy
)();
202 self
->mOutputMix
= NULL
;
204 if(self
->mEngineObj
!= NULL
)
205 VCALL0(self
->mEngineObj
,Destroy
)();
206 self
->mEngineObj
= NULL
;
207 self
->mEngine
= NULL
;
209 ll_ringbuffer_free(self
->mRing
);
212 alcnd_destroy(&self
->mCond
);
214 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
218 /* this callback handler is called every time a buffer finishes playing */
219 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
221 ALCopenslPlayback
*self
= context
;
223 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
224 * pointer passed to the Enqueue method, rather than copying the audio.
225 * Consequently, the ringbuffer contains the audio that is currently queued
226 * and waiting to play. This process() callback is called when a buffer is
227 * finished, so we simply move the read pointer up to indicate the space is
228 * available for writing again, and wake up the mixer thread to mix and
231 ll_ringbuffer_read_advance(self
->mRing
, 1);
233 alcnd_signal(&self
->mCond
);
237 static int ALCopenslPlayback_mixerProc(void *arg
)
239 ALCopenslPlayback
*self
= arg
;
240 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
241 SLAndroidSimpleBufferQueueItf bufferQueue
;
242 ll_ringbuffer_data_t data
[2];
248 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
250 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
252 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
253 if(SL_RESULT_SUCCESS
== result
)
255 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
256 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
258 if(SL_RESULT_SUCCESS
!= result
)
260 ALCopenslPlayback_lock(self
);
261 aluHandleDisconnect(device
);
262 ALCopenslPlayback_unlock(self
);
266 /* NOTE: The ringbuffer will be larger than the desired buffer metrics.
267 * Calculate the amount of extra space so we know how much to keep unused.
269 padding
= ll_ringbuffer_write_space(self
->mRing
) - device
->NumUpdates
;
271 ALCopenslPlayback_lock(self
);
272 while(ATOMIC_LOAD_SEQ(&self
->mKillNow
) == AL_FALSE
&& device
->Connected
)
274 size_t todo
, len0
, len1
;
276 if(ll_ringbuffer_write_space(self
->mRing
) <= padding
)
280 result
= VCALL(player
,GetPlayState
)(&state
);
281 PRINTERR(result
, "player->GetPlayState");
282 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
284 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
285 PRINTERR(result
, "player->SetPlayState");
287 if(SL_RESULT_SUCCESS
!= result
)
289 aluHandleDisconnect(device
);
293 /* NOTE: Unfortunately, there is an unavoidable race condition
294 * here. It's possible for the process() method to run, updating
295 * the read pointer and signaling the condition variable, in
296 * between checking the write size and waiting for the condition
297 * variable here. This will cause alcnd_wait to wait until the
298 * *next* process() invocation signals the condition variable
301 * However, this should only happen if the mixer is running behind
302 * anyway (as ideally we'll be asleep in alcnd_wait by the time the
303 * process() method is invoked), so this behavior is not completely
304 * unwarranted. It's unfortunate since it'll be wasting time
305 * sleeping that could be used to catch up, but there's no way
306 * around it without blocking in the process() method.
308 if(ll_ringbuffer_write_space(self
->mRing
) <= padding
)
310 alcnd_wait(&self
->mCond
, &STATIC_CAST(ALCbackend
,self
)->mMutex
);
315 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
316 todo
= data
[0].len
+data
[1].len
- padding
;
318 len0
= minu(todo
, data
[0].len
);
319 len1
= minu(todo
-len0
, data
[1].len
);
321 aluMixData(device
, data
[0].buf
, len0
*device
->UpdateSize
);
322 for(size_t i
= 0;i
< len0
;i
++)
324 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
, device
->UpdateSize
*self
->mFrameSize
);
325 PRINTERR(result
, "bufferQueue->Enqueue");
326 if(SL_RESULT_SUCCESS
== result
)
327 ll_ringbuffer_write_advance(self
->mRing
, 1);
329 data
[0].buf
+= device
->UpdateSize
*self
->mFrameSize
;
334 aluMixData(device
, data
[1].buf
, len1
*device
->UpdateSize
);
335 for(size_t i
= 0;i
< len1
;i
++)
337 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
, device
->UpdateSize
*self
->mFrameSize
);
338 PRINTERR(result
, "bufferQueue->Enqueue");
339 if(SL_RESULT_SUCCESS
== result
)
340 ll_ringbuffer_write_advance(self
->mRing
, 1);
342 data
[1].buf
+= device
->UpdateSize
*self
->mFrameSize
;
346 ALCopenslPlayback_unlock(self
);
352 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
)
354 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
358 name
= opensl_device
;
359 else if(strcmp(name
, opensl_device
) != 0)
360 return ALC_INVALID_VALUE
;
363 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
364 PRINTERR(result
, "slCreateEngine");
365 if(SL_RESULT_SUCCESS
== result
)
367 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
368 PRINTERR(result
, "engine->Realize");
370 if(SL_RESULT_SUCCESS
== result
)
372 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
373 PRINTERR(result
, "engine->GetInterface");
375 if(SL_RESULT_SUCCESS
== result
)
377 result
= VCALL(self
->mEngine
,CreateOutputMix
)(&self
->mOutputMix
, 0, NULL
, NULL
);
378 PRINTERR(result
, "engine->CreateOutputMix");
380 if(SL_RESULT_SUCCESS
== result
)
382 result
= VCALL(self
->mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
383 PRINTERR(result
, "outputMix->Realize");
386 if(SL_RESULT_SUCCESS
!= result
)
388 if(self
->mOutputMix
!= NULL
)
389 VCALL0(self
->mOutputMix
,Destroy
)();
390 self
->mOutputMix
= NULL
;
392 if(self
->mEngineObj
!= NULL
)
393 VCALL0(self
->mEngineObj
,Destroy
)();
394 self
->mEngineObj
= NULL
;
395 self
->mEngine
= NULL
;
397 return ALC_INVALID_VALUE
;
400 alstr_copy_cstr(&device
->DeviceName
, name
);
405 static void ALCopenslPlayback_close(ALCopenslPlayback
*self
)
407 if(self
->mBufferQueueObj
!= NULL
)
408 VCALL0(self
->mBufferQueueObj
,Destroy
)();
409 self
->mBufferQueueObj
= NULL
;
411 VCALL0(self
->mOutputMix
,Destroy
)();
412 self
->mOutputMix
= NULL
;
414 VCALL0(self
->mEngineObj
,Destroy
)();
415 self
->mEngineObj
= NULL
;
416 self
->mEngine
= NULL
;
419 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
)
421 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
422 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
;
423 SLDataLocator_OutputMix loc_outmix
;
424 SLDataSource audioSrc
;
427 SLInterfaceID ids
[2];
432 if(self
->mBufferQueueObj
!= NULL
)
433 VCALL0(self
->mBufferQueueObj
,Destroy
)();
434 self
->mBufferQueueObj
= NULL
;
436 sampleRate
= device
->Frequency
;
437 if(!(device
->Flags
&DEVICE_FREQUENCY_REQUEST
) && (env
=Android_GetJNIEnv()) != NULL
)
439 /* FIXME: Disabled until I figure out how to get the Context needed for
440 * the getSystemService call.
443 /* Get necessary stuff for using java.lang.Integer,
444 * android.content.Context, and android.media.AudioManager.
446 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
447 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
448 "parseInt", "(Ljava/lang/String;)I"
450 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
452 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
453 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
454 "AUDIO_SERVICE", "Ljava/lang/String;"
456 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
457 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
459 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
460 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
462 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
463 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
464 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
466 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
467 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
469 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
470 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
472 const char *strchars
;
475 /* Now make the calls. */
476 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
477 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
478 jobject audMgr
= JCALL(env
,CallObjectMethod
)(ctx_cls
, ctx_getSysSvc
, strobj
);
479 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
480 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
481 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
483 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
484 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
485 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
486 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
487 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
488 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
490 //int sampleRate = Integer.parseInt(srateStr);
491 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
493 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, NULL
);
494 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
495 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
497 if(!sampleRate
) sampleRate
= device
->Frequency
;
498 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
502 if(sampleRate
!= device
->Frequency
)
504 device
->NumUpdates
= (device
->NumUpdates
*sampleRate
+ (device
->Frequency
>>1)) /
506 device
->NumUpdates
= maxu(device
->NumUpdates
, 2);
507 device
->Frequency
= sampleRate
;
510 device
->FmtChans
= DevFmtStereo
;
511 device
->FmtType
= DevFmtShort
;
513 SetDefaultWFXChannelOrder(device
);
514 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
517 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
518 loc_bufq
.numBuffers
= device
->NumUpdates
;
520 #ifdef SL_DATAFORMAT_PCM_EX
521 SLDataFormat_PCM_EX format_pcm
;
522 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
523 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
524 format_pcm
.sampleRate
= device
->Frequency
* 1000;
525 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
526 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
527 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
528 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
529 SL_BYTEORDER_BIGENDIAN
;
530 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
532 SLDataFormat_PCM format_pcm
;
533 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
534 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
535 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
536 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
537 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
538 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
539 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
540 SL_BYTEORDER_BIGENDIAN
;
543 audioSrc
.pLocator
= &loc_bufq
;
544 audioSrc
.pFormat
= &format_pcm
;
546 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
547 loc_outmix
.outputMix
= self
->mOutputMix
;
548 audioSnk
.pLocator
= &loc_outmix
;
549 audioSnk
.pFormat
= NULL
;
552 ids
[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE
;
553 reqs
[0] = SL_BOOLEAN_TRUE
;
554 ids
[1] = SL_IID_ANDROIDCONFIGURATION
;
555 reqs
[1] = SL_BOOLEAN_FALSE
;
557 result
= VCALL(self
->mEngine
,CreateAudioPlayer
)(&self
->mBufferQueueObj
,
558 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
560 PRINTERR(result
, "engine->CreateAudioPlayer");
561 if(SL_RESULT_SUCCESS
== result
)
563 /* Set the stream type to "media" (games, music, etc), if possible. */
564 SLAndroidConfigurationItf config
;
565 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
566 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
567 if(SL_RESULT_SUCCESS
== result
)
569 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
570 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
,
571 &streamType
, sizeof(streamType
)
573 PRINTERR(result
, "config->SetConfiguration");
576 /* Clear any error since this was optional. */
577 result
= SL_RESULT_SUCCESS
;
579 if(SL_RESULT_SUCCESS
== result
)
581 result
= VCALL(self
->mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
582 PRINTERR(result
, "bufferQueue->Realize");
585 if(SL_RESULT_SUCCESS
!= result
)
587 if(self
->mBufferQueueObj
!= NULL
)
588 VCALL0(self
->mBufferQueueObj
,Destroy
)();
589 self
->mBufferQueueObj
= NULL
;
597 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
)
599 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
600 SLAndroidSimpleBufferQueueItf bufferQueue
;
603 ll_ringbuffer_free(self
->mRing
);
604 /* NOTE: Add an extra update since one period's worth of audio in the ring
605 * buffer will always be left unfilled because one element of the ring
606 * buffer will not be writeable, and we only write in period-sized chunks.
608 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
+ 1,
609 self
->mFrameSize
*device
->UpdateSize
);
611 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
613 PRINTERR(result
, "bufferQueue->GetInterface");
614 if(SL_RESULT_SUCCESS
!= result
)
617 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslPlayback_process
, self
);
618 PRINTERR(result
, "bufferQueue->RegisterCallback");
619 if(SL_RESULT_SUCCESS
!= result
)
622 ATOMIC_STORE_SEQ(&self
->mKillNow
, AL_FALSE
);
623 if(althrd_create(&self
->mThread
, ALCopenslPlayback_mixerProc
, self
) != althrd_success
)
625 ERR("Failed to start mixer thread\n");
633 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
)
635 SLAndroidSimpleBufferQueueItf bufferQueue
;
640 if(ATOMIC_EXCHANGE_SEQ(&self
->mKillNow
, AL_TRUE
))
643 /* Lock the backend to ensure we don't flag the mixer to die and signal the
644 * mixer to wake up in between it checking the flag and going to sleep and
645 * wait for a wakeup (potentially leading to it never waking back up to see
648 ALCopenslPlayback_lock(self
);
649 ALCopenslPlayback_unlock(self
);
650 alcnd_signal(&self
->mCond
);
651 althrd_join(self
->mThread
, &res
);
653 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
654 PRINTERR(result
, "bufferQueue->GetInterface");
655 if(SL_RESULT_SUCCESS
== result
)
657 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
658 PRINTERR(result
, "player->SetPlayState");
661 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
663 PRINTERR(result
, "bufferQueue->GetInterface");
664 if(SL_RESULT_SUCCESS
== result
)
666 result
= VCALL0(bufferQueue
,Clear
)();
667 PRINTERR(result
, "bufferQueue->Clear");
669 if(SL_RESULT_SUCCESS
== result
)
671 result
= VCALL(bufferQueue
,RegisterCallback
)(NULL
, NULL
);
672 PRINTERR(result
, "bufferQueue->RegisterCallback");
674 if(SL_RESULT_SUCCESS
== result
)
676 SLAndroidSimpleBufferQueueState state
;
679 result
= VCALL(bufferQueue
,GetState
)(&state
);
680 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
681 PRINTERR(result
, "bufferQueue->GetState");
684 ll_ringbuffer_free(self
->mRing
);
688 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
)
690 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
693 ALCopenslPlayback_lock(self
);
694 ret
.ClockTime
= GetDeviceClockTime(device
);
695 ret
.Latency
= ll_ringbuffer_read_space(self
->mRing
)*device
->UpdateSize
*
696 DEVICE_CLOCK_RES
/ device
->Frequency
;
697 ALCopenslPlayback_unlock(self
);
703 typedef struct ALCopenslCapture
{
704 DERIVE_FROM_TYPE(ALCbackend
);
706 /* engine interfaces */
707 SLObjectItf mEngineObj
;
710 /* recording interfaces */
711 SLObjectItf mRecordObj
;
713 ll_ringbuffer_t
*mRing
;
719 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
721 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
);
722 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
);
723 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
);
724 static void ALCopenslCapture_close(ALCopenslCapture
*self
);
725 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ALCboolean
, reset
)
726 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
);
727 static void ALCopenslCapture_stop(ALCopenslCapture
*self
);
728 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
729 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
);
730 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
731 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, lock
)
732 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, unlock
)
733 DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture
)
734 DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture
);
737 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
739 ALCopenslCapture
*self
= context
;
740 /* A new chunk has been written into the ring buffer, advance it. */
741 ll_ringbuffer_write_advance(self
->mRing
, 1);
745 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
)
747 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
748 SET_VTABLE2(ALCopenslCapture
, ALCbackend
, self
);
750 self
->mEngineObj
= NULL
;
751 self
->mEngine
= NULL
;
753 self
->mRecordObj
= NULL
;
756 self
->mSplOffset
= 0;
758 self
->mFrameSize
= 0;
761 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
)
763 ll_ringbuffer_free(self
->mRing
);
766 if(self
->mRecordObj
!= NULL
)
767 VCALL0(self
->mRecordObj
,Destroy
)();
768 self
->mRecordObj
= NULL
;
770 if(self
->mEngineObj
!= NULL
)
771 VCALL0(self
->mEngineObj
,Destroy
)();
772 self
->mEngineObj
= NULL
;
773 self
->mEngine
= NULL
;
775 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
778 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
)
780 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
781 SLDataLocator_AndroidSimpleBufferQueue loc_bq
;
782 SLAndroidSimpleBufferQueueItf bufferQueue
;
783 SLDataLocator_IODevice loc_dev
;
784 SLDataSource audioSrc
;
789 name
= opensl_device
;
790 else if(strcmp(name
, opensl_device
) != 0)
791 return ALC_INVALID_VALUE
;
793 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
794 PRINTERR(result
, "slCreateEngine");
795 if(SL_RESULT_SUCCESS
== result
)
797 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
798 PRINTERR(result
, "engine->Realize");
800 if(SL_RESULT_SUCCESS
== result
)
802 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
803 PRINTERR(result
, "engine->GetInterface");
805 if(SL_RESULT_SUCCESS
== result
)
807 /* Ensure the total length is at least 100ms */
808 ALsizei length
= maxi(device
->NumUpdates
* device
->UpdateSize
,
809 device
->Frequency
/ 10);
810 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
811 ALsizei update_len
= clampi(device
->NumUpdates
*device
->UpdateSize
/ 3,
812 device
->Frequency
/ 100,
813 device
->Frequency
/ 100 * 5);
815 device
->UpdateSize
= update_len
;
816 device
->NumUpdates
= (length
+update_len
-1) / update_len
;
818 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
820 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
821 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
822 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
823 loc_dev
.device
= NULL
;
825 audioSrc
.pLocator
= &loc_dev
;
826 audioSrc
.pFormat
= NULL
;
828 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
829 loc_bq
.numBuffers
= device
->NumUpdates
;
831 #ifdef SL_DATAFORMAT_PCM_EX
832 SLDataFormat_PCM_EX format_pcm
;
833 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
834 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
835 format_pcm
.sampleRate
= device
->Frequency
* 1000;
836 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
837 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
838 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
839 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
840 SL_BYTEORDER_BIGENDIAN
;
841 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
843 SLDataFormat_PCM format_pcm
;
844 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
845 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
846 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
847 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
848 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
849 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
850 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
851 SL_BYTEORDER_BIGENDIAN
;
854 audioSnk
.pLocator
= &loc_bq
;
855 audioSnk
.pFormat
= &format_pcm
;
857 if(SL_RESULT_SUCCESS
== result
)
859 const SLInterfaceID ids
[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
};
860 const SLboolean reqs
[2] = { SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
};
862 result
= VCALL(self
->mEngine
,CreateAudioRecorder
)(&self
->mRecordObj
,
863 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
865 PRINTERR(result
, "engine->CreateAudioRecorder");
867 if(SL_RESULT_SUCCESS
== result
)
869 /* Set the record preset to "generic", if possible. */
870 SLAndroidConfigurationItf config
;
871 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
872 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
873 if(SL_RESULT_SUCCESS
== result
)
875 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
876 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
,
877 &preset
, sizeof(preset
)
879 PRINTERR(result
, "config->SetConfiguration");
882 /* Clear any error since this was optional. */
883 result
= SL_RESULT_SUCCESS
;
885 if(SL_RESULT_SUCCESS
== result
)
887 result
= VCALL(self
->mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
888 PRINTERR(result
, "recordObj->Realize");
891 if(SL_RESULT_SUCCESS
== result
)
893 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
+ 1,
894 device
->UpdateSize
* self
->mFrameSize
);
896 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
898 PRINTERR(result
, "recordObj->GetInterface");
900 if(SL_RESULT_SUCCESS
== result
)
902 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslCapture_process
, self
);
903 PRINTERR(result
, "bufferQueue->RegisterCallback");
905 if(SL_RESULT_SUCCESS
== result
)
907 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
908 ll_ringbuffer_data_t data
[2];
911 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
912 for(i
= 0;i
< data
[0].len
&& SL_RESULT_SUCCESS
== result
;i
++)
914 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
+ chunk_size
*i
, chunk_size
);
915 PRINTERR(result
, "bufferQueue->Enqueue");
917 for(i
= 0;i
< data
[1].len
&& SL_RESULT_SUCCESS
== result
;i
++)
919 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
+ chunk_size
*i
, chunk_size
);
920 PRINTERR(result
, "bufferQueue->Enqueue");
924 if(SL_RESULT_SUCCESS
!= result
)
926 if(self
->mRecordObj
!= NULL
)
927 VCALL0(self
->mRecordObj
,Destroy
)();
928 self
->mRecordObj
= NULL
;
930 if(self
->mEngineObj
!= NULL
)
931 VCALL0(self
->mEngineObj
,Destroy
)();
932 self
->mEngineObj
= NULL
;
933 self
->mEngine
= NULL
;
935 return ALC_INVALID_VALUE
;
938 alstr_copy_cstr(&device
->DeviceName
, name
);
943 static void ALCopenslCapture_close(ALCopenslCapture
*self
)
945 ll_ringbuffer_free(self
->mRing
);
948 if(self
->mRecordObj
!= NULL
)
949 VCALL0(self
->mRecordObj
,Destroy
)();
950 self
->mRecordObj
= NULL
;
952 if(self
->mEngineObj
!= NULL
)
953 VCALL0(self
->mEngineObj
,Destroy
)();
954 self
->mEngineObj
= NULL
;
955 self
->mEngine
= NULL
;
958 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
)
963 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
964 PRINTERR(result
, "recordObj->GetInterface");
966 if(SL_RESULT_SUCCESS
== result
)
968 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_RECORDING
);
969 PRINTERR(result
, "record->SetRecordState");
972 if(SL_RESULT_SUCCESS
!= result
)
974 ALCopenslCapture_lock(self
);
975 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
);
976 ALCopenslCapture_unlock(self
);
983 static void ALCopenslCapture_stop(ALCopenslCapture
*self
)
988 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
989 PRINTERR(result
, "recordObj->GetInterface");
991 if(SL_RESULT_SUCCESS
== result
)
993 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
994 PRINTERR(result
, "record->SetRecordState");
998 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
1000 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
1001 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
1002 SLAndroidSimpleBufferQueueItf bufferQueue
;
1003 ll_ringbuffer_data_t data
[2];
1008 /* Read the desired samples from the ring buffer then advance its read
1011 ll_ringbuffer_get_read_vector(self
->mRing
, data
);
1013 for(i
= 0;i
< samples
;)
1015 ALCuint rem
= minu(samples
- i
, device
->UpdateSize
- self
->mSplOffset
);
1016 memcpy((ALCbyte
*)buffer
+ i
*self
->mFrameSize
,
1017 data
[0].buf
+ self
->mSplOffset
*self
->mFrameSize
,
1018 rem
* self
->mFrameSize
);
1020 self
->mSplOffset
+= rem
;
1021 if(self
->mSplOffset
== device
->UpdateSize
)
1023 /* Finished a chunk, reset the offset and advance the read pointer. */
1024 self
->mSplOffset
= 0;
1031 data
[0].buf
+= chunk_size
;
1036 ll_ringbuffer_read_advance(self
->mRing
, advance
);
1038 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
1040 PRINTERR(result
, "recordObj->GetInterface");
1042 /* Enqueue any newly-writable chunks in the ring buffer. */
1043 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
1044 for(i
= 0;i
< data
[0].len
&& SL_RESULT_SUCCESS
== result
;i
++)
1046 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
+ chunk_size
*i
, chunk_size
);
1047 PRINTERR(result
, "bufferQueue->Enqueue");
1049 for(i
= 0;i
< data
[1].len
&& SL_RESULT_SUCCESS
== result
;i
++)
1051 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
+ chunk_size
*i
, chunk_size
);
1052 PRINTERR(result
, "bufferQueue->Enqueue");
1055 if(SL_RESULT_SUCCESS
!= result
)
1057 ALCopenslCapture_lock(self
);
1058 aluHandleDisconnect(device
);
1059 ALCopenslCapture_unlock(self
);
1060 return ALC_INVALID_DEVICE
;
1063 return ALC_NO_ERROR
;
1066 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
)
1068 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
1069 return ll_ringbuffer_read_space(self
->mRing
) * device
->UpdateSize
;
1073 typedef struct ALCopenslBackendFactory
{
1074 DERIVE_FROM_TYPE(ALCbackendFactory
);
1075 } ALCopenslBackendFactory
;
1076 #define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } }
1078 static ALCboolean
ALCopenslBackendFactory_init(ALCopenslBackendFactory
* UNUSED(self
))
1083 static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory
* UNUSED(self
))
1087 static ALCboolean
ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
1089 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
1094 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory
* UNUSED(self
), enum DevProbe type
)
1098 case ALL_DEVICE_PROBE
:
1099 AppendAllDevicesList(opensl_device
);
1102 case CAPTURE_DEVICE_PROBE
:
1103 AppendAllDevicesList(opensl_device
);
1108 static ALCbackend
* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
1110 if(type
== ALCbackend_Playback
)
1112 ALCopenslPlayback
*backend
;
1113 NEW_OBJ(backend
, ALCopenslPlayback
)(device
);
1114 if(!backend
) return NULL
;
1115 return STATIC_CAST(ALCbackend
, backend
);
1117 if(type
== ALCbackend_Capture
)
1119 ALCopenslCapture
*backend
;
1120 NEW_OBJ(backend
, ALCopenslCapture
)(device
);
1121 if(!backend
) return NULL
;
1122 return STATIC_CAST(ALCbackend
, backend
);
1128 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory
);
1131 ALCbackendFactory
*ALCopenslBackendFactory_getFactory(void)
1133 static ALCopenslBackendFactory factory
= ALCOPENSLBACKENDFACTORY_INITIALIZER
;
1134 return STATIC_CAST(ALCbackendFactory
, &factory
);