Release 1.18.1
[openal-soft.git] / Alc / backends / opensl.c
blobaa1ff991743d3d6df133a133d9ffd3a7be25e08e
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 DevFmtAmbi3D:
69 break;
71 return 0;
74 #ifdef SL_DATAFORMAT_PCM_EX
75 static SLuint32 GetTypeRepresentation(enum DevFmtType type)
77 switch(type)
79 case DevFmtUByte:
80 case DevFmtUShort:
81 case DevFmtUInt:
82 return SL_PCM_REPRESENTATION_UNSIGNED_INT;
83 case DevFmtByte:
84 case DevFmtShort:
85 case DevFmtInt:
86 return SL_PCM_REPRESENTATION_SIGNED_INT;
87 case DevFmtFloat:
88 return SL_PCM_REPRESENTATION_FLOAT;
90 return 0;
92 #endif
94 static const char *res_str(SLresult result)
96 switch(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";
117 #endif
118 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
119 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
120 #endif
121 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
122 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
123 #endif
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))); \
131 } while(0)
134 typedef struct ALCopenslPlayback {
135 DERIVE_FROM_TYPE(ALCbackend);
137 /* engine interfaces */
138 SLObjectItf mEngineObj;
139 SLEngineItf mEngine;
141 /* output mix interfaces */
142 SLObjectItf mOutputMix;
144 /* buffer queue player interfaces */
145 SLObjectItf mBufferQueueObj;
147 ll_ringbuffer_t *mRing;
148 alcnd_t mCond;
150 ALsizei mFrameSize;
152 ATOMIC(ALenum) mKillNow;
153 althrd_t mThread;
154 } ALCopenslPlayback;
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;
186 self->mRing = 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);
210 self->mRing = NULL;
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
229 * queue more audio.
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];
243 SLPlayItf player;
244 SLresult result;
245 size_t padding;
247 SetRTPriority();
248 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
250 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
251 &bufferQueue);
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);
263 return 1;
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)
278 SLuint32 state = 0;
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);
290 break;
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
299 * again.
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);
311 continue;
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;
332 if(len1 > 0)
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);
348 return 0;
352 static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name)
354 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
355 SLresult result;
357 if(!name)
358 name = opensl_device;
359 else if(strcmp(name, opensl_device) != 0)
360 return ALC_INVALID_VALUE;
362 // create engine
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);
402 return ALC_NO_ERROR;
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;
425 SLDataSink audioSnk;
426 ALuint sampleRate;
427 SLInterfaceID ids[2];
428 SLboolean reqs[2];
429 SLresult result;
430 JNIEnv *env;
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.
442 #if 0
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;
473 jstring strobj;
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);
499 #endif
502 if(sampleRate != device->Frequency)
504 device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) /
505 device->Frequency;
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);
531 #else
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;
541 #endif
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;
591 return ALC_FALSE;
594 return ALC_TRUE;
597 static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self)
599 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
600 SLAndroidSimpleBufferQueueItf bufferQueue;
601 SLresult result;
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,
612 &bufferQueue);
613 PRINTERR(result, "bufferQueue->GetInterface");
614 if(SL_RESULT_SUCCESS != result)
615 return ALC_FALSE;
617 result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self);
618 PRINTERR(result, "bufferQueue->RegisterCallback");
619 if(SL_RESULT_SUCCESS != result)
620 return ALC_FALSE;
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");
626 return ALC_FALSE;
629 return ALC_TRUE;
633 static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
635 SLAndroidSimpleBufferQueueItf bufferQueue;
636 SLPlayItf player;
637 SLresult result;
638 int res;
640 if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE))
641 return;
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
646 * the flag).
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,
662 &bufferQueue);
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;
677 do {
678 althrd_yield();
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);
685 self->mRing = NULL;
688 static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self)
690 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
691 ClockLatency ret;
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);
699 return ret;
703 typedef struct ALCopenslCapture {
704 DERIVE_FROM_TYPE(ALCbackend);
706 /* engine interfaces */
707 SLObjectItf mEngineObj;
708 SLEngineItf mEngine;
710 /* recording interfaces */
711 SLObjectItf mRecordObj;
713 ll_ringbuffer_t *mRing;
714 ALCuint mSplOffset;
716 ALsizei mFrameSize;
717 } ALCopenslCapture;
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;
755 self->mRing = NULL;
756 self->mSplOffset = 0;
758 self->mFrameSize = 0;
761 static void ALCopenslCapture_Destruct(ALCopenslCapture *self)
763 ll_ringbuffer_free(self->mRing);
764 self->mRing = NULL;
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;
785 SLDataSink audioSnk;
786 SLresult result;
788 if(!name)
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);
842 #else
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;
852 #endif
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,
897 &bufferQueue);
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];
909 size_t i;
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);
940 return ALC_NO_ERROR;
943 static void ALCopenslCapture_close(ALCopenslCapture *self)
945 ll_ringbuffer_free(self->mRing);
946 self->mRing = NULL;
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)
960 SLRecordItf record;
961 SLresult result;
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);
977 return ALC_FALSE;
980 return ALC_TRUE;
983 static void ALCopenslCapture_stop(ALCopenslCapture *self)
985 SLRecordItf record;
986 SLresult result;
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];
1004 SLresult result;
1005 size_t advance;
1006 ALCuint i;
1008 /* Read the desired samples from the ring buffer then advance its read
1009 * pointer.
1011 ll_ringbuffer_get_read_vector(self->mRing, data);
1012 advance = 0;
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;
1025 advance++;
1027 data[0].len--;
1028 if(!data[0].len)
1029 data[0] = data[1];
1030 else
1031 data[0].buf += chunk_size;
1034 i += rem;
1036 ll_ringbuffer_read_advance(self->mRing, advance);
1038 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
1039 &bufferQueue);
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))
1080 return ALC_TRUE;
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)
1090 return ALC_TRUE;
1091 return ALC_FALSE;
1094 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type)
1096 switch(type)
1098 case ALL_DEVICE_PROBE:
1099 AppendAllDevicesList(opensl_device);
1100 break;
1102 case CAPTURE_DEVICE_PROBE:
1103 AppendAllDevicesList(opensl_device);
1104 break;
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);
1125 return NULL;
1128 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory);
1131 ALCbackendFactory *ALCopenslBackendFactory_getFactory(void)
1133 static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER;
1134 return STATIC_CAST(ALCbackendFactory, &factory);