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
;
76 #ifdef SL_DATAFORMAT_PCM_EX
77 static SLuint32
GetTypeRepresentation(enum DevFmtType type
)
84 return SL_PCM_REPRESENTATION_UNSIGNED_INT
;
88 return SL_PCM_REPRESENTATION_SIGNED_INT
;
90 return SL_PCM_REPRESENTATION_FLOAT
;
96 static const char *res_str(SLresult result
)
100 case SL_RESULT_SUCCESS
: return "Success";
101 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
102 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
103 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
104 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
105 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
106 case SL_RESULT_IO_ERROR
: return "I/O error";
107 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
108 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
109 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
110 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
111 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
112 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
113 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
114 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
115 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
116 case SL_RESULT_CONTROL_LOST
: return "Control lost";
117 #ifdef SL_RESULT_READONLY
118 case SL_RESULT_READONLY
: return "ReadOnly";
120 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
121 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
123 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
124 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
127 return "Unknown error code";
130 #define PRINTERR(x, s) do { \
131 if((x) != SL_RESULT_SUCCESS) \
132 ERR("%s: %s\n", (s), res_str((x))); \
136 typedef struct ALCopenslPlayback
{
137 DERIVE_FROM_TYPE(ALCbackend
);
139 /* engine interfaces */
140 SLObjectItf mEngineObj
;
143 /* output mix interfaces */
144 SLObjectItf mOutputMix
;
146 /* buffer queue player interfaces */
147 SLObjectItf mBufferQueueObj
;
149 ll_ringbuffer_t
*mRing
;
154 ATOMIC(ALboolean
) mKillNow
;
158 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
159 static int ALCopenslPlayback_mixerProc(void *arg
);
161 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
);
162 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
*self
);
163 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
);
164 static void ALCopenslPlayback_close(ALCopenslPlayback
*self
);
165 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
);
166 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
);
167 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
);
168 static DECLARE_FORWARD2(ALCopenslPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
169 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, ALCuint
, availableSamples
)
170 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
);
171 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, lock
)
172 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, unlock
)
173 DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback
)
175 DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback
);
178 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
)
180 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
181 SET_VTABLE2(ALCopenslPlayback
, ALCbackend
, self
);
183 self
->mEngineObj
= NULL
;
184 self
->mEngine
= NULL
;
185 self
->mOutputMix
= NULL
;
186 self
->mBufferQueueObj
= NULL
;
189 alcnd_init(&self
->mCond
);
191 self
->mFrameSize
= 0;
193 ATOMIC_INIT(&self
->mKillNow
, AL_FALSE
);
196 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
* self
)
198 if(self
->mBufferQueueObj
!= NULL
)
199 VCALL0(self
->mBufferQueueObj
,Destroy
)();
200 self
->mBufferQueueObj
= NULL
;
202 if(self
->mOutputMix
!= NULL
)
203 VCALL0(self
->mOutputMix
,Destroy
)();
204 self
->mOutputMix
= NULL
;
206 if(self
->mEngineObj
!= NULL
)
207 VCALL0(self
->mEngineObj
,Destroy
)();
208 self
->mEngineObj
= NULL
;
209 self
->mEngine
= NULL
;
211 ll_ringbuffer_free(self
->mRing
);
214 alcnd_destroy(&self
->mCond
);
216 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
220 /* this callback handler is called every time a buffer finishes playing */
221 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
223 ALCopenslPlayback
*self
= context
;
225 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
226 * pointer passed to the Enqueue method, rather than copying the audio.
227 * Consequently, the ringbuffer contains the audio that is currently queued
228 * and waiting to play. This process() callback is called when a buffer is
229 * finished, so we simply move the read pointer up to indicate the space is
230 * available for writing again, and wake up the mixer thread to mix and
233 ll_ringbuffer_read_advance(self
->mRing
, 1);
235 alcnd_signal(&self
->mCond
);
239 static int ALCopenslPlayback_mixerProc(void *arg
)
241 ALCopenslPlayback
*self
= arg
;
242 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
243 SLAndroidSimpleBufferQueueItf bufferQueue
;
244 ll_ringbuffer_data_t data
[2];
250 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
252 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
254 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
255 if(SL_RESULT_SUCCESS
== result
)
257 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
258 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
260 if(SL_RESULT_SUCCESS
!= result
)
262 ALCopenslPlayback_lock(self
);
263 aluHandleDisconnect(device
);
264 ALCopenslPlayback_unlock(self
);
268 /* NOTE: The ringbuffer will be larger than the desired buffer metrics.
269 * Calculate the amount of extra space so we know how much to keep unused.
271 padding
= ll_ringbuffer_write_space(self
->mRing
) - device
->NumUpdates
;
273 ALCopenslPlayback_lock(self
);
274 while(ATOMIC_LOAD_SEQ(&self
->mKillNow
) == AL_FALSE
&& device
->Connected
)
276 size_t todo
, len0
, len1
;
278 if(ll_ringbuffer_write_space(self
->mRing
) <= padding
)
282 result
= VCALL(player
,GetPlayState
)(&state
);
283 PRINTERR(result
, "player->GetPlayState");
284 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
286 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
287 PRINTERR(result
, "player->SetPlayState");
289 if(SL_RESULT_SUCCESS
!= result
)
291 aluHandleDisconnect(device
);
295 /* NOTE: Unfortunately, there is an unavoidable race condition
296 * here. It's possible for the process() method to run, updating
297 * the read pointer and signaling the condition variable, in
298 * between checking the write size and waiting for the condition
299 * variable here. This will cause alcnd_wait to wait until the
300 * *next* process() invocation signals the condition variable
303 * However, this should only happen if the mixer is running behind
304 * anyway (as ideally we'll be asleep in alcnd_wait by the time the
305 * process() method is invoked), so this behavior is not completely
306 * unwarranted. It's unfortunate since it'll be wasting time
307 * sleeping that could be used to catch up, but there's no way
308 * around it without blocking in the process() method.
310 if(ll_ringbuffer_write_space(self
->mRing
) <= padding
)
312 alcnd_wait(&self
->mCond
, &STATIC_CAST(ALCbackend
,self
)->mMutex
);
317 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
318 todo
= data
[0].len
+data
[1].len
- padding
;
320 len0
= minu(todo
, data
[0].len
);
321 len1
= minu(todo
-len0
, data
[1].len
);
323 aluMixData(device
, data
[0].buf
, len0
*device
->UpdateSize
);
324 for(size_t i
= 0;i
< len0
;i
++)
326 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
, device
->UpdateSize
*self
->mFrameSize
);
327 PRINTERR(result
, "bufferQueue->Enqueue");
328 if(SL_RESULT_SUCCESS
== result
)
329 ll_ringbuffer_write_advance(self
->mRing
, 1);
331 data
[0].buf
+= device
->UpdateSize
*self
->mFrameSize
;
336 aluMixData(device
, data
[1].buf
, len1
*device
->UpdateSize
);
337 for(size_t i
= 0;i
< len1
;i
++)
339 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
, device
->UpdateSize
*self
->mFrameSize
);
340 PRINTERR(result
, "bufferQueue->Enqueue");
341 if(SL_RESULT_SUCCESS
== result
)
342 ll_ringbuffer_write_advance(self
->mRing
, 1);
344 data
[1].buf
+= device
->UpdateSize
*self
->mFrameSize
;
348 ALCopenslPlayback_unlock(self
);
354 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
)
356 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
360 name
= opensl_device
;
361 else if(strcmp(name
, opensl_device
) != 0)
362 return ALC_INVALID_VALUE
;
365 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
366 PRINTERR(result
, "slCreateEngine");
367 if(SL_RESULT_SUCCESS
== result
)
369 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
370 PRINTERR(result
, "engine->Realize");
372 if(SL_RESULT_SUCCESS
== result
)
374 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
375 PRINTERR(result
, "engine->GetInterface");
377 if(SL_RESULT_SUCCESS
== result
)
379 result
= VCALL(self
->mEngine
,CreateOutputMix
)(&self
->mOutputMix
, 0, NULL
, NULL
);
380 PRINTERR(result
, "engine->CreateOutputMix");
382 if(SL_RESULT_SUCCESS
== result
)
384 result
= VCALL(self
->mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
385 PRINTERR(result
, "outputMix->Realize");
388 if(SL_RESULT_SUCCESS
!= result
)
390 if(self
->mOutputMix
!= NULL
)
391 VCALL0(self
->mOutputMix
,Destroy
)();
392 self
->mOutputMix
= NULL
;
394 if(self
->mEngineObj
!= NULL
)
395 VCALL0(self
->mEngineObj
,Destroy
)();
396 self
->mEngineObj
= NULL
;
397 self
->mEngine
= NULL
;
399 return ALC_INVALID_VALUE
;
402 al_string_copy_cstr(&device
->DeviceName
, name
);
407 static void ALCopenslPlayback_close(ALCopenslPlayback
*self
)
409 if(self
->mBufferQueueObj
!= NULL
)
410 VCALL0(self
->mBufferQueueObj
,Destroy
)();
411 self
->mBufferQueueObj
= NULL
;
413 VCALL0(self
->mOutputMix
,Destroy
)();
414 self
->mOutputMix
= NULL
;
416 VCALL0(self
->mEngineObj
,Destroy
)();
417 self
->mEngineObj
= NULL
;
418 self
->mEngine
= NULL
;
421 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
)
423 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
424 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
;
425 SLDataLocator_OutputMix loc_outmix
;
426 SLDataSource audioSrc
;
429 SLInterfaceID ids
[2];
434 if(self
->mBufferQueueObj
!= NULL
)
435 VCALL0(self
->mBufferQueueObj
,Destroy
)();
436 self
->mBufferQueueObj
= NULL
;
438 sampleRate
= device
->Frequency
;
439 if(!(device
->Flags
&DEVICE_FREQUENCY_REQUEST
) && (env
=Android_GetJNIEnv()) != NULL
)
441 /* FIXME: Disabled until I figure out how to get the Context needed for
442 * the getSystemService call.
445 /* Get necessary stuff for using java.lang.Integer,
446 * android.content.Context, and android.media.AudioManager.
448 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
449 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
450 "parseInt", "(Ljava/lang/String;)I"
452 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
454 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
455 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
456 "AUDIO_SERVICE", "Ljava/lang/String;"
458 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
459 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
461 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
462 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
464 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
465 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
466 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
468 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
469 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
471 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
472 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
474 const char *strchars
;
477 /* Now make the calls. */
478 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
479 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
480 jobject audMgr
= JCALL(env
,CallObjectMethod
)(ctx_cls
, ctx_getSysSvc
, strobj
);
481 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
482 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
483 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
485 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
486 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
487 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
488 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
489 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
490 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
492 //int sampleRate = Integer.parseInt(srateStr);
493 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
495 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, NULL
);
496 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
497 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
499 if(!sampleRate
) sampleRate
= device
->Frequency
;
500 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
504 if(sampleRate
!= device
->Frequency
)
506 device
->NumUpdates
= (device
->NumUpdates
*sampleRate
+ (device
->Frequency
>>1)) /
508 device
->NumUpdates
= maxu(device
->NumUpdates
, 2);
509 device
->Frequency
= sampleRate
;
512 device
->FmtChans
= DevFmtStereo
;
513 device
->FmtType
= DevFmtShort
;
515 SetDefaultWFXChannelOrder(device
);
516 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
519 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
520 loc_bufq
.numBuffers
= device
->NumUpdates
;
522 #ifdef SL_DATAFORMAT_PCM_EX
523 SLDataFormat_PCM_EX format_pcm
;
524 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
525 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
);
526 format_pcm
.sampleRate
= device
->Frequency
* 1000;
527 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
528 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
529 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
530 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
531 SL_BYTEORDER_BIGENDIAN
;
532 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
534 SLDataFormat_PCM format_pcm
;
535 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
536 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
);
537 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
538 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
539 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
540 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
541 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
542 SL_BYTEORDER_BIGENDIAN
;
545 audioSrc
.pLocator
= &loc_bufq
;
546 audioSrc
.pFormat
= &format_pcm
;
548 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
549 loc_outmix
.outputMix
= self
->mOutputMix
;
550 audioSnk
.pLocator
= &loc_outmix
;
551 audioSnk
.pFormat
= NULL
;
554 ids
[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE
;
555 reqs
[0] = SL_BOOLEAN_TRUE
;
556 ids
[1] = SL_IID_ANDROIDCONFIGURATION
;
557 reqs
[1] = SL_BOOLEAN_FALSE
;
559 result
= VCALL(self
->mEngine
,CreateAudioPlayer
)(&self
->mBufferQueueObj
,
560 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
562 PRINTERR(result
, "engine->CreateAudioPlayer");
563 if(SL_RESULT_SUCCESS
== result
)
565 /* Set the stream type to "media" (games, music, etc), if possible. */
566 SLAndroidConfigurationItf config
;
567 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
568 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
569 if(SL_RESULT_SUCCESS
== result
)
571 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
572 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
,
573 &streamType
, sizeof(streamType
)
575 PRINTERR(result
, "config->SetConfiguration");
578 /* Clear any error since this was optional. */
579 result
= SL_RESULT_SUCCESS
;
581 if(SL_RESULT_SUCCESS
== result
)
583 result
= VCALL(self
->mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
584 PRINTERR(result
, "bufferQueue->Realize");
587 if(SL_RESULT_SUCCESS
!= result
)
589 if(self
->mBufferQueueObj
!= NULL
)
590 VCALL0(self
->mBufferQueueObj
,Destroy
)();
591 self
->mBufferQueueObj
= NULL
;
599 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
)
601 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
602 SLAndroidSimpleBufferQueueItf bufferQueue
;
605 ll_ringbuffer_free(self
->mRing
);
606 /* NOTE: Add an extra update since one period's worth of audio in the ring
607 * buffer will always be left unfilled because one element of the ring
608 * buffer will not be writeable, and we only write in period-sized chunks.
610 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
+ 1,
611 self
->mFrameSize
*device
->UpdateSize
);
613 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
615 PRINTERR(result
, "bufferQueue->GetInterface");
616 if(SL_RESULT_SUCCESS
!= result
)
619 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslPlayback_process
, self
);
620 PRINTERR(result
, "bufferQueue->RegisterCallback");
621 if(SL_RESULT_SUCCESS
!= result
)
624 ATOMIC_STORE_SEQ(&self
->mKillNow
, AL_FALSE
);
625 if(althrd_create(&self
->mThread
, ALCopenslPlayback_mixerProc
, self
) != althrd_success
)
627 ERR("Failed to start mixer thread\n");
635 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
)
637 SLAndroidSimpleBufferQueueItf bufferQueue
;
642 if(ATOMIC_EXCHANGE_SEQ(ALboolean
, &self
->mKillNow
, AL_TRUE
))
645 /* Lock the backend to ensure we don't flag the mixer to die and signal the
646 * mixer to wake up in between it checking the flag and going to sleep and
647 * wait for a wakeup (potentially leading to it never waking back up to see
650 ALCopenslPlayback_lock(self
);
651 ALCopenslPlayback_unlock(self
);
652 alcnd_signal(&self
->mCond
);
653 althrd_join(self
->mThread
, &res
);
655 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
656 PRINTERR(result
, "bufferQueue->GetInterface");
657 if(SL_RESULT_SUCCESS
== result
)
659 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
660 PRINTERR(result
, "player->SetPlayState");
663 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
665 PRINTERR(result
, "bufferQueue->GetInterface");
666 if(SL_RESULT_SUCCESS
== result
)
668 result
= VCALL0(bufferQueue
,Clear
)();
669 PRINTERR(result
, "bufferQueue->Clear");
671 if(SL_RESULT_SUCCESS
== result
)
673 result
= VCALL(bufferQueue
,RegisterCallback
)(NULL
, NULL
);
674 PRINTERR(result
, "bufferQueue->RegisterCallback");
676 if(SL_RESULT_SUCCESS
== result
)
678 SLAndroidSimpleBufferQueueState state
;
681 result
= VCALL(bufferQueue
,GetState
)(&state
);
682 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
683 PRINTERR(result
, "bufferQueue->GetState");
686 ll_ringbuffer_free(self
->mRing
);
690 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
)
692 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
695 ALCopenslPlayback_lock(self
);
696 ret
.ClockTime
= GetDeviceClockTime(device
);
697 ret
.Latency
= ll_ringbuffer_read_space(self
->mRing
)*device
->UpdateSize
*
698 DEVICE_CLOCK_RES
/ device
->Frequency
;
699 ALCopenslPlayback_unlock(self
);
705 typedef struct ALCopenslBackendFactory
{
706 DERIVE_FROM_TYPE(ALCbackendFactory
);
707 } ALCopenslBackendFactory
;
708 #define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } }
710 static ALCboolean
ALCopenslBackendFactory_init(ALCopenslBackendFactory
* UNUSED(self
))
715 static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory
* UNUSED(self
))
719 static ALCboolean
ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
721 if(type
== ALCbackend_Playback
)
726 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory
* UNUSED(self
), enum DevProbe type
)
730 case ALL_DEVICE_PROBE
:
731 AppendAllDevicesList(opensl_device
);
734 case CAPTURE_DEVICE_PROBE
:
739 static ALCbackend
* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
741 if(type
== ALCbackend_Playback
)
743 ALCopenslPlayback
*backend
;
744 NEW_OBJ(backend
, ALCopenslPlayback
)(device
);
745 if(!backend
) return NULL
;
746 return STATIC_CAST(ALCbackend
, backend
);
752 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory
);
755 ALCbackendFactory
*ALCopenslBackendFactory_getFactory(void)
757 static ALCopenslBackendFactory factory
= ALCOPENSLBACKENDFACTORY_INITIALIZER
;
758 return STATIC_CAST(ALCbackendFactory
, &factory
);