Remove althrd_yield
[openal-soft.git] / Alc / backends / opensl.cpp
blobe8d4a862c9ca9e911209d7896428a919f55b306a
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 "backends/opensl.h"
26 #include <stdlib.h>
27 #include <jni.h>
29 #include <thread>
31 #include "alMain.h"
32 #include "alu.h"
33 #include "ringbuffer.h"
34 #include "threads.h"
35 #include "compat.h"
37 #include <SLES/OpenSLES.h>
38 #include <SLES/OpenSLES_Android.h>
39 #include <SLES/OpenSLES_AndroidConfiguration.h>
41 /* Helper macros */
42 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
43 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
46 static const ALCchar opensl_device[] = "OpenSL";
49 static SLuint32 GetChannelMask(enum DevFmtChannels chans)
51 switch(chans)
53 case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
54 case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
55 case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
56 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
57 case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
58 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
59 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
60 case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
61 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
62 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
63 case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
64 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
65 SL_SPEAKER_BACK_CENTER|
66 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
67 case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
68 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
69 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
70 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
71 case DevFmtAmbi3D:
72 break;
74 return 0;
77 #ifdef SL_DATAFORMAT_PCM_EX
78 static SLuint32 GetTypeRepresentation(enum DevFmtType type)
80 switch(type)
82 case DevFmtUByte:
83 case DevFmtUShort:
84 case DevFmtUInt:
85 return SL_PCM_REPRESENTATION_UNSIGNED_INT;
86 case DevFmtByte:
87 case DevFmtShort:
88 case DevFmtInt:
89 return SL_PCM_REPRESENTATION_SIGNED_INT;
90 case DevFmtFloat:
91 return SL_PCM_REPRESENTATION_FLOAT;
93 return 0;
95 #endif
97 static const char *res_str(SLresult result)
99 switch(result)
101 case SL_RESULT_SUCCESS: return "Success";
102 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
103 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
104 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
105 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
106 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
107 case SL_RESULT_IO_ERROR: return "I/O error";
108 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
109 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
110 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
111 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
112 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
113 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
114 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
115 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
116 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
117 case SL_RESULT_CONTROL_LOST: return "Control lost";
118 #ifdef SL_RESULT_READONLY
119 case SL_RESULT_READONLY: return "ReadOnly";
120 #endif
121 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
122 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
123 #endif
124 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
125 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
126 #endif
128 return "Unknown error code";
131 #define PRINTERR(x, s) do { \
132 if((x) != SL_RESULT_SUCCESS) \
133 ERR("%s: %s\n", (s), res_str((x))); \
134 } while(0)
137 struct ALCopenslPlayback final : public ALCbackend {
138 /* engine interfaces */
139 SLObjectItf mEngineObj{nullptr};
140 SLEngineItf mEngine{nullptr};
142 /* output mix interfaces */
143 SLObjectItf mOutputMix{nullptr};
145 /* buffer queue player interfaces */
146 SLObjectItf mBufferQueueObj{nullptr};
148 ll_ringbuffer_t *mRing{nullptr};
149 alsem_t mSem;
151 ALsizei mFrameSize{0};
153 std::atomic<ALenum> mKillNow{AL_TRUE};
154 std::thread mThread;
157 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context);
158 static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self);
160 static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device);
161 static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self);
162 static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name);
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 new (self) ALCopenslPlayback{};
179 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
180 SET_VTABLE2(ALCopenslPlayback, ALCbackend, self);
182 alsem_init(&self->mSem, 0);
185 static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self)
187 if(self->mBufferQueueObj != NULL)
188 VCALL0(self->mBufferQueueObj,Destroy)();
189 self->mBufferQueueObj = NULL;
191 if(self->mOutputMix)
192 VCALL0(self->mOutputMix,Destroy)();
193 self->mOutputMix = NULL;
195 if(self->mEngineObj)
196 VCALL0(self->mEngineObj,Destroy)();
197 self->mEngineObj = NULL;
198 self->mEngine = NULL;
200 ll_ringbuffer_free(self->mRing);
201 self->mRing = NULL;
203 alsem_destroy(&self->mSem);
205 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
206 self->~ALCopenslPlayback();
210 /* this callback handler is called every time a buffer finishes playing */
211 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context)
213 ALCopenslPlayback *self = static_cast<ALCopenslPlayback*>(context);
215 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
216 * pointer passed to the Enqueue method, rather than copying the audio.
217 * Consequently, the ringbuffer contains the audio that is currently queued
218 * and waiting to play. This process() callback is called when a buffer is
219 * finished, so we simply move the read pointer up to indicate the space is
220 * available for writing again, and wake up the mixer thread to mix and
221 * queue more audio.
223 ll_ringbuffer_read_advance(self->mRing, 1);
225 alsem_post(&self->mSem);
229 static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self)
231 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
232 SLAndroidSimpleBufferQueueItf bufferQueue;
233 SLPlayItf player;
234 SLresult result;
236 SetRTPriority();
237 althrd_setname(MIXER_THREAD_NAME);
239 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
240 &bufferQueue);
241 PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
242 if(SL_RESULT_SUCCESS == result)
244 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
245 PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY");
248 ALCopenslPlayback_lock(self);
249 if(SL_RESULT_SUCCESS != result)
250 aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result);
252 while(SL_RESULT_SUCCESS == result && !self->mKillNow.load(std::memory_order_acquire) &&
253 device->Connected.load(std::memory_order_acquire))
255 size_t todo;
257 if(ll_ringbuffer_write_space(self->mRing) == 0)
259 SLuint32 state = 0;
261 result = VCALL(player,GetPlayState)(&state);
262 PRINTERR(result, "player->GetPlayState");
263 if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
265 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
266 PRINTERR(result, "player->SetPlayState");
268 if(SL_RESULT_SUCCESS != result)
270 aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result);
271 break;
274 if(ll_ringbuffer_write_space(self->mRing) == 0)
276 ALCopenslPlayback_unlock(self);
277 alsem_wait(&self->mSem);
278 ALCopenslPlayback_lock(self);
279 continue;
283 auto data = ll_ringbuffer_get_write_vector(self->mRing);
284 aluMixData(device, data.first.buf, data.first.len*device->UpdateSize);
285 if(data.second.len > 0)
286 aluMixData(device, data.second.buf, data.second.len*device->UpdateSize);
288 todo = data.first.len+data.second.len;
289 ll_ringbuffer_write_advance(self->mRing, todo);
291 for(size_t i = 0;i < todo;i++)
293 if(!data.first.len)
295 data.first = data.second;
296 data.second.buf = nullptr;
297 data.second.len = 0;
300 result = VCALL(bufferQueue,Enqueue)(data.first.buf,
301 device->UpdateSize*self->mFrameSize);
302 PRINTERR(result, "bufferQueue->Enqueue");
303 if(SL_RESULT_SUCCESS != result)
305 aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result);
306 break;
309 data.first.len--;
310 data.first.buf += device->UpdateSize*self->mFrameSize;
313 ALCopenslPlayback_unlock(self);
315 return 0;
319 static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name)
321 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
322 SLresult result;
324 if(!name)
325 name = opensl_device;
326 else if(strcmp(name, opensl_device) != 0)
327 return ALC_INVALID_VALUE;
329 // create engine
330 result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL);
331 PRINTERR(result, "slCreateEngine");
332 if(SL_RESULT_SUCCESS == result)
334 result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE);
335 PRINTERR(result, "engine->Realize");
337 if(SL_RESULT_SUCCESS == result)
339 result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine);
340 PRINTERR(result, "engine->GetInterface");
342 if(SL_RESULT_SUCCESS == result)
344 result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL);
345 PRINTERR(result, "engine->CreateOutputMix");
347 if(SL_RESULT_SUCCESS == result)
349 result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE);
350 PRINTERR(result, "outputMix->Realize");
353 if(SL_RESULT_SUCCESS != result)
355 if(self->mOutputMix != NULL)
356 VCALL0(self->mOutputMix,Destroy)();
357 self->mOutputMix = NULL;
359 if(self->mEngineObj != NULL)
360 VCALL0(self->mEngineObj,Destroy)();
361 self->mEngineObj = NULL;
362 self->mEngine = NULL;
364 return ALC_INVALID_VALUE;
367 device->DeviceName = name;
368 return ALC_NO_ERROR;
371 static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self)
373 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
374 SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
375 SLDataLocator_OutputMix loc_outmix;
376 SLDataSource audioSrc;
377 SLDataSink audioSnk;
378 ALuint sampleRate;
379 SLInterfaceID ids[2];
380 SLboolean reqs[2];
381 SLresult result;
383 if(self->mBufferQueueObj != NULL)
384 VCALL0(self->mBufferQueueObj,Destroy)();
385 self->mBufferQueueObj = NULL;
387 ll_ringbuffer_free(self->mRing);
388 self->mRing = NULL;
390 sampleRate = device->Frequency;
391 #if 0
392 if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
394 /* FIXME: Disabled until I figure out how to get the Context needed for
395 * the getSystemService call.
397 JNIEnv *env = Android_GetJNIEnv();
398 jobject jctx = Android_GetContext();
400 /* Get necessary stuff for using java.lang.Integer,
401 * android.content.Context, and android.media.AudioManager.
403 jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
404 jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
405 "parseInt", "(Ljava/lang/String;)I"
407 TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
409 jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
410 jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
411 "AUDIO_SERVICE", "Ljava/lang/String;"
413 jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
414 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
416 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
417 ctx_cls, ctx_audsvc, ctx_getSysSvc);
419 jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
420 jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
421 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
423 jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
424 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
426 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
427 audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
429 const char *strchars;
430 jstring strobj;
432 /* Now make the calls. */
433 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
434 strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
435 jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj);
436 strchars = JCALL(env,GetStringUTFChars)(strobj, NULL);
437 TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
438 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
440 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
441 strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
442 jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
443 strchars = JCALL(env,GetStringUTFChars)(strobj, NULL);
444 TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
445 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
447 //int sampleRate = Integer.parseInt(srateStr);
448 sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
450 strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL);
451 TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
452 JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
454 if(!sampleRate) sampleRate = device->Frequency;
455 else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
457 #endif
459 if(sampleRate != device->Frequency)
461 device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) /
462 device->Frequency;
463 device->NumUpdates = maxu(device->NumUpdates, 2);
464 device->Frequency = sampleRate;
467 device->FmtChans = DevFmtStereo;
468 device->FmtType = DevFmtShort;
470 SetDefaultWFXChannelOrder(device);
471 self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder);
474 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
475 loc_bufq.numBuffers = device->NumUpdates;
477 #ifdef SL_DATAFORMAT_PCM_EX
478 SLDataFormat_PCM_EX format_pcm;
479 format_pcm.formatType = SL_DATAFORMAT_PCM_EX;
480 format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder);
481 format_pcm.sampleRate = device->Frequency * 1000;
482 format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
483 format_pcm.containerSize = format_pcm.bitsPerSample;
484 format_pcm.channelMask = GetChannelMask(device->FmtChans);
485 format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
486 SL_BYTEORDER_BIGENDIAN;
487 format_pcm.representation = GetTypeRepresentation(device->FmtType);
488 #else
489 SLDataFormat_PCM format_pcm;
490 format_pcm.formatType = SL_DATAFORMAT_PCM;
491 format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder);
492 format_pcm.samplesPerSec = device->Frequency * 1000;
493 format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
494 format_pcm.containerSize = format_pcm.bitsPerSample;
495 format_pcm.channelMask = GetChannelMask(device->FmtChans);
496 format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
497 SL_BYTEORDER_BIGENDIAN;
498 #endif
500 audioSrc.pLocator = &loc_bufq;
501 audioSrc.pFormat = &format_pcm;
503 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
504 loc_outmix.outputMix = self->mOutputMix;
505 audioSnk.pLocator = &loc_outmix;
506 audioSnk.pFormat = NULL;
509 ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
510 reqs[0] = SL_BOOLEAN_TRUE;
511 ids[1] = SL_IID_ANDROIDCONFIGURATION;
512 reqs[1] = SL_BOOLEAN_FALSE;
514 result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj,
515 &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs
517 PRINTERR(result, "engine->CreateAudioPlayer");
518 if(SL_RESULT_SUCCESS == result)
520 /* Set the stream type to "media" (games, music, etc), if possible. */
521 SLAndroidConfigurationItf config;
522 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
523 PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
524 if(SL_RESULT_SUCCESS == result)
526 SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
527 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE,
528 &streamType, sizeof(streamType)
530 PRINTERR(result, "config->SetConfiguration");
533 /* Clear any error since this was optional. */
534 result = SL_RESULT_SUCCESS;
536 if(SL_RESULT_SUCCESS == result)
538 result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
539 PRINTERR(result, "bufferQueue->Realize");
541 if(SL_RESULT_SUCCESS == result)
543 self->mRing = ll_ringbuffer_create(device->NumUpdates,
544 self->mFrameSize*device->UpdateSize, true
546 if(!self->mRing)
548 ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize,
549 device->NumUpdates, self->mFrameSize);
550 result = SL_RESULT_MEMORY_FAILURE;
554 if(SL_RESULT_SUCCESS != result)
556 if(self->mBufferQueueObj != NULL)
557 VCALL0(self->mBufferQueueObj,Destroy)();
558 self->mBufferQueueObj = NULL;
560 return ALC_FALSE;
563 return ALC_TRUE;
566 static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self)
568 SLAndroidSimpleBufferQueueItf bufferQueue;
569 SLresult result;
571 ll_ringbuffer_reset(self->mRing);
573 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
574 &bufferQueue);
575 PRINTERR(result, "bufferQueue->GetInterface");
576 if(SL_RESULT_SUCCESS != result)
577 return ALC_FALSE;
579 result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self);
580 PRINTERR(result, "bufferQueue->RegisterCallback");
581 if(SL_RESULT_SUCCESS != result)
582 return ALC_FALSE;
584 try {
585 self->mKillNow.store(AL_FALSE);
586 self->mThread = std::thread(ALCopenslPlayback_mixerProc, self);
587 return ALC_TRUE;
589 catch(std::exception& e) {
590 ERR("Could not create playback thread: %s\n", e.what());
592 catch(...) {
594 return ALC_FALSE;
598 static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
600 SLAndroidSimpleBufferQueueItf bufferQueue;
601 SLPlayItf player;
602 SLresult result;
604 if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable())
605 return;
607 alsem_post(&self->mSem);
608 self->mThread.join();
610 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
611 PRINTERR(result, "bufferQueue->GetInterface");
612 if(SL_RESULT_SUCCESS == result)
614 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
615 PRINTERR(result, "player->SetPlayState");
618 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
619 &bufferQueue);
620 PRINTERR(result, "bufferQueue->GetInterface");
621 if(SL_RESULT_SUCCESS == result)
623 result = VCALL0(bufferQueue,Clear)();
624 PRINTERR(result, "bufferQueue->Clear");
626 if(SL_RESULT_SUCCESS == result)
628 result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL);
629 PRINTERR(result, "bufferQueue->RegisterCallback");
631 if(SL_RESULT_SUCCESS == result)
633 SLAndroidSimpleBufferQueueState state;
634 do {
635 std::this_thread::yield();
636 result = VCALL(bufferQueue,GetState)(&state);
637 } while(SL_RESULT_SUCCESS == result && state.count > 0);
638 PRINTERR(result, "bufferQueue->GetState");
642 static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self)
644 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
645 ClockLatency ret;
647 ALCopenslPlayback_lock(self);
648 ret.ClockTime = GetDeviceClockTime(device);
649 ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing)*device->UpdateSize};
650 ret.Latency /= device->Frequency;
651 ALCopenslPlayback_unlock(self);
653 return ret;
657 struct ALCopenslCapture final : public ALCbackend {
658 /* engine interfaces */
659 SLObjectItf mEngineObj{nullptr};
660 SLEngineItf mEngine;
662 /* recording interfaces */
663 SLObjectItf mRecordObj{nullptr};
665 ll_ringbuffer_t *mRing{nullptr};
666 ALCuint mSplOffset{0u};
668 ALsizei mFrameSize{0};
671 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context);
673 static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device);
674 static void ALCopenslCapture_Destruct(ALCopenslCapture *self);
675 static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name);
676 static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset)
677 static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self);
678 static void ALCopenslCapture_stop(ALCopenslCapture *self);
679 static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples);
680 static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self);
681 static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency)
682 static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock)
683 static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock)
684 DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture)
685 DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture);
688 static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device)
690 new (self) ALCopenslCapture{};
691 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
692 SET_VTABLE2(ALCopenslCapture, ALCbackend, self);
695 static void ALCopenslCapture_Destruct(ALCopenslCapture *self)
697 if(self->mRecordObj != NULL)
698 VCALL0(self->mRecordObj,Destroy)();
699 self->mRecordObj = NULL;
701 if(self->mEngineObj != NULL)
702 VCALL0(self->mEngineObj,Destroy)();
703 self->mEngineObj = NULL;
704 self->mEngine = NULL;
706 ll_ringbuffer_free(self->mRing);
707 self->mRing = NULL;
709 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
710 self->~ALCopenslCapture();
714 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context)
716 ALCopenslCapture *self = static_cast<ALCopenslCapture*>(context);
717 /* A new chunk has been written into the ring buffer, advance it. */
718 ll_ringbuffer_write_advance(self->mRing, 1);
722 static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name)
724 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
725 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
726 SLAndroidSimpleBufferQueueItf bufferQueue;
727 SLDataLocator_IODevice loc_dev;
728 SLDataSource audioSrc;
729 SLDataSink audioSnk;
730 SLresult result;
732 if(!name)
733 name = opensl_device;
734 else if(strcmp(name, opensl_device) != 0)
735 return ALC_INVALID_VALUE;
737 result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL);
738 PRINTERR(result, "slCreateEngine");
739 if(SL_RESULT_SUCCESS == result)
741 result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE);
742 PRINTERR(result, "engine->Realize");
744 if(SL_RESULT_SUCCESS == result)
746 result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine);
747 PRINTERR(result, "engine->GetInterface");
749 if(SL_RESULT_SUCCESS == result)
751 /* Ensure the total length is at least 100ms */
752 ALsizei length = maxi(device->NumUpdates * device->UpdateSize,
753 device->Frequency / 10);
754 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
755 ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3,
756 device->Frequency / 100,
757 device->Frequency / 100 * 5);
759 device->UpdateSize = update_len;
760 device->NumUpdates = (length+update_len-1) / update_len;
762 self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder);
764 loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
765 loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
766 loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
767 loc_dev.device = NULL;
769 audioSrc.pLocator = &loc_dev;
770 audioSrc.pFormat = NULL;
772 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
773 loc_bq.numBuffers = device->NumUpdates;
775 #ifdef SL_DATAFORMAT_PCM_EX
776 SLDataFormat_PCM_EX format_pcm;
777 format_pcm.formatType = SL_DATAFORMAT_PCM_EX;
778 format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder);
779 format_pcm.sampleRate = device->Frequency * 1000;
780 format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
781 format_pcm.containerSize = format_pcm.bitsPerSample;
782 format_pcm.channelMask = GetChannelMask(device->FmtChans);
783 format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
784 SL_BYTEORDER_BIGENDIAN;
785 format_pcm.representation = GetTypeRepresentation(device->FmtType);
786 #else
787 SLDataFormat_PCM format_pcm;
788 format_pcm.formatType = SL_DATAFORMAT_PCM;
789 format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder);
790 format_pcm.samplesPerSec = device->Frequency * 1000;
791 format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
792 format_pcm.containerSize = format_pcm.bitsPerSample;
793 format_pcm.channelMask = GetChannelMask(device->FmtChans);
794 format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
795 SL_BYTEORDER_BIGENDIAN;
796 #endif
798 audioSnk.pLocator = &loc_bq;
799 audioSnk.pFormat = &format_pcm;
801 if(SL_RESULT_SUCCESS == result)
803 const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
804 const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };
806 result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj,
807 &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs
809 PRINTERR(result, "engine->CreateAudioRecorder");
811 if(SL_RESULT_SUCCESS == result)
813 /* Set the record preset to "generic", if possible. */
814 SLAndroidConfigurationItf config;
815 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
816 PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
817 if(SL_RESULT_SUCCESS == result)
819 SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
820 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET,
821 &preset, sizeof(preset)
823 PRINTERR(result, "config->SetConfiguration");
826 /* Clear any error since this was optional. */
827 result = SL_RESULT_SUCCESS;
829 if(SL_RESULT_SUCCESS == result)
831 result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE);
832 PRINTERR(result, "recordObj->Realize");
835 if(SL_RESULT_SUCCESS == result)
837 self->mRing = ll_ringbuffer_create(device->NumUpdates,
838 device->UpdateSize*self->mFrameSize, false
841 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
842 &bufferQueue);
843 PRINTERR(result, "recordObj->GetInterface");
845 if(SL_RESULT_SUCCESS == result)
847 result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self);
848 PRINTERR(result, "bufferQueue->RegisterCallback");
850 if(SL_RESULT_SUCCESS == result)
852 ALsizei chunk_size = device->UpdateSize * self->mFrameSize;
853 size_t i;
855 auto data = ll_ringbuffer_get_write_vector(self->mRing);
856 for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++)
858 result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size);
859 PRINTERR(result, "bufferQueue->Enqueue");
861 for(i = 0;i < data.second.len && SL_RESULT_SUCCESS == result;i++)
863 result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size);
864 PRINTERR(result, "bufferQueue->Enqueue");
868 if(SL_RESULT_SUCCESS != result)
870 if(self->mRecordObj != NULL)
871 VCALL0(self->mRecordObj,Destroy)();
872 self->mRecordObj = NULL;
874 if(self->mEngineObj != NULL)
875 VCALL0(self->mEngineObj,Destroy)();
876 self->mEngineObj = NULL;
877 self->mEngine = NULL;
879 return ALC_INVALID_VALUE;
882 device->DeviceName = name;
883 return ALC_NO_ERROR;
886 static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self)
888 SLRecordItf record;
889 SLresult result;
891 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record);
892 PRINTERR(result, "recordObj->GetInterface");
894 if(SL_RESULT_SUCCESS == result)
896 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
897 PRINTERR(result, "record->SetRecordState");
900 if(SL_RESULT_SUCCESS != result)
902 ALCopenslCapture_lock(self);
903 aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
904 "Failed to start capture: 0x%08x", result);
905 ALCopenslCapture_unlock(self);
906 return ALC_FALSE;
909 return ALC_TRUE;
912 static void ALCopenslCapture_stop(ALCopenslCapture *self)
914 SLRecordItf record;
915 SLresult result;
917 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record);
918 PRINTERR(result, "recordObj->GetInterface");
920 if(SL_RESULT_SUCCESS == result)
922 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
923 PRINTERR(result, "record->SetRecordState");
927 static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples)
929 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
930 ALsizei chunk_size = device->UpdateSize * self->mFrameSize;
931 SLAndroidSimpleBufferQueueItf bufferQueue;
932 SLresult result;
933 ALCuint i;
935 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
936 &bufferQueue);
937 PRINTERR(result, "recordObj->GetInterface");
939 /* Read the desired samples from the ring buffer then advance its read
940 * pointer.
942 auto data = ll_ringbuffer_get_read_vector(self->mRing);
943 for(i = 0;i < samples;)
945 ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset);
946 memcpy((ALCbyte*)buffer + i*self->mFrameSize,
947 data.first.buf + self->mSplOffset*self->mFrameSize,
948 rem * self->mFrameSize);
950 self->mSplOffset += rem;
951 if(self->mSplOffset == device->UpdateSize)
953 /* Finished a chunk, reset the offset and advance the read pointer. */
954 self->mSplOffset = 0;
956 ll_ringbuffer_read_advance(self->mRing, 1);
957 result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size);
958 PRINTERR(result, "bufferQueue->Enqueue");
959 if(SL_RESULT_SUCCESS != result) break;
961 data.first.len--;
962 if(!data.first.len)
963 data.first = data.second;
964 else
965 data.first.buf += chunk_size;
968 i += rem;
971 if(SL_RESULT_SUCCESS != result)
973 ALCopenslCapture_lock(self);
974 aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result);
975 ALCopenslCapture_unlock(self);
976 return ALC_INVALID_DEVICE;
979 return ALC_NO_ERROR;
982 static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self)
984 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
985 return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize;
989 bool OSLBackendFactory::init() { return true; }
991 bool OSLBackendFactory::querySupport(ALCbackend_Type type)
992 { return (type == ALCbackend_Playback || type == ALCbackend_Capture); }
994 void OSLBackendFactory::probe(enum DevProbe type, std::string *outnames)
996 switch(type)
998 case ALL_DEVICE_PROBE:
999 case CAPTURE_DEVICE_PROBE:
1000 /* Includes null char. */
1001 outnames->append(opensl_device, sizeof(opensl_device));
1002 break;
1006 ALCbackend *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type)
1008 if(type == ALCbackend_Playback)
1010 ALCopenslPlayback *backend;
1011 NEW_OBJ(backend, ALCopenslPlayback)(device);
1012 if(!backend) return nullptr;
1013 return STATIC_CAST(ALCbackend, backend);
1015 if(type == ALCbackend_Capture)
1017 ALCopenslCapture *backend;
1018 NEW_OBJ(backend, ALCopenslCapture)(device);
1019 if(!backend) return nullptr;
1020 return STATIC_CAST(ALCbackend, backend);
1023 return nullptr;
1026 BackendFactory &OSLBackendFactory::getFactory()
1028 static OSLBackendFactory factory{};
1029 return factory;