Fix OpenSL latency calculation
[openal-soft.git] / Alc / backends / opensl.c
blobb8d6d29acd8bd17773e0c8c6bfd28fd3586ef3f5
1 /*
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
19 * bundled with NDK.
22 #include "config.h"
24 #include <stdlib.h>
25 #include <jni.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "compat.h"
30 #include "threads.h"
32 #include "backends/base.h"
34 #include <SLES/OpenSLES.h>
35 #include <SLES/OpenSLES_Android.h>
36 #include <SLES/OpenSLES_AndroidConfiguration.h>
38 /* Helper macros */
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)
48 switch(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;
68 case DevFmtAmbi1:
69 case DevFmtAmbi2:
70 case DevFmtAmbi3:
71 break;
73 return 0;
76 #ifdef SL_DATAFORMAT_PCM_EX
77 static SLuint32 GetTypeRepresentation(enum DevFmtType type)
79 switch(type)
81 case DevFmtUByte:
82 case DevFmtUShort:
83 case DevFmtUInt:
84 return SL_PCM_REPRESENTATION_UNSIGNED_INT;
85 case DevFmtByte:
86 case DevFmtShort:
87 case DevFmtInt:
88 return SL_PCM_REPRESENTATION_SIGNED_INT;
89 case DevFmtFloat:
90 return SL_PCM_REPRESENTATION_FLOAT;
92 return 0;
94 #endif
96 static const char *res_str(SLresult result)
98 switch(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";
119 #endif
120 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
121 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
122 #endif
123 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
124 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
125 #endif
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))); \
133 } while(0)
136 typedef struct ALCopenslPlayback {
137 DERIVE_FROM_TYPE(ALCbackend);
139 /* engine interfaces */
140 SLObjectItf mEngineObj;
141 SLEngineItf mEngine;
143 /* output mix interfaces */
144 SLObjectItf mOutputMix;
146 /* buffer queue player interfaces */
147 SLObjectItf mBufferQueueObj;
149 ll_ringbuffer_t *mRing;
150 alcnd_t mCond;
152 ALsizei mFrameSize;
154 ATOMIC(ALboolean) mKillNow;
155 althrd_t mThread;
156 } ALCopenslPlayback;
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;
188 self->mRing = 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);
212 self->mRing = NULL;
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
231 * queue more audio.
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];
245 SLPlayItf player;
246 SLresult result;
247 size_t padding;
249 SetRTPriority();
250 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
252 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
253 &bufferQueue);
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);
265 return 1;
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)
280 SLuint32 state = 0;
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);
292 break;
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
301 * again.
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);
313 continue;
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;
334 if(len1 > 0)
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);
350 return 0;
354 static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name)
356 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
357 SLresult result;
359 if(!name)
360 name = opensl_device;
361 else if(strcmp(name, opensl_device) != 0)
362 return ALC_INVALID_VALUE;
364 // create engine
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);
404 return ALC_NO_ERROR;
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;
427 SLDataSink audioSnk;
428 ALuint sampleRate;
429 SLInterfaceID ids[2];
430 SLboolean reqs[2];
431 SLresult result;
432 JNIEnv *env;
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.
444 #if 0
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;
475 jstring strobj;
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);
501 #endif
504 if(sampleRate != device->Frequency)
506 device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) /
507 device->Frequency;
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);
533 #else
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;
543 #endif
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;
593 return ALC_FALSE;
596 return ALC_TRUE;
599 static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self)
601 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
602 SLAndroidSimpleBufferQueueItf bufferQueue;
603 SLresult result;
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,
614 &bufferQueue);
615 PRINTERR(result, "bufferQueue->GetInterface");
616 if(SL_RESULT_SUCCESS != result)
617 return ALC_FALSE;
619 result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self);
620 PRINTERR(result, "bufferQueue->RegisterCallback");
621 if(SL_RESULT_SUCCESS != result)
622 return ALC_FALSE;
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");
628 return ALC_FALSE;
631 return ALC_TRUE;
635 static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
637 SLAndroidSimpleBufferQueueItf bufferQueue;
638 SLPlayItf player;
639 SLresult result;
640 int res;
642 if(ATOMIC_EXCHANGE_SEQ(ALboolean, &self->mKillNow, AL_TRUE))
643 return;
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
648 * the flag).
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,
664 &bufferQueue);
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;
679 do {
680 althrd_yield();
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);
687 self->mRing = NULL;
690 static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self)
692 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
693 ClockLatency ret;
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);
701 return ret;
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))
712 return ALC_TRUE;
715 static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self))
719 static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type)
721 if(type == ALCbackend_Playback)
722 return ALC_TRUE;
723 return ALC_FALSE;
726 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type)
728 switch(type)
730 case ALL_DEVICE_PROBE:
731 AppendAllDevicesList(opensl_device);
732 break;
734 case CAPTURE_DEVICE_PROBE:
735 break;
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);
749 return NULL;
752 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory);
755 ALCbackendFactory *ALCopenslBackendFactory_getFactory(void)
757 static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER;
758 return STATIC_CAST(ALCbackendFactory, &factory);