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
36 #include "alnumeric.h"
37 #include "core/device.h"
38 #include "core/helpers.h"
39 #include "core/logging.h"
40 #include "opthelpers.h"
41 #include "ringbuffer.h"
44 #include <SLES/OpenSLES.h>
45 #include <SLES/OpenSLES_Android.h>
46 #include <SLES/OpenSLES_AndroidConfiguration.h>
52 #define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
53 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
54 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
57 constexpr char opensl_device[] = "OpenSL";
60 constexpr SLuint32 GetChannelMask(DevFmtChannels chans) noexcept
64 case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
65 case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
66 case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
67 SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
68 case DevFmtX51: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
69 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT |
70 SL_SPEAKER_SIDE_RIGHT;
71 case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
72 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER |
73 SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
75 case DevFmtX3D71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
76 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
77 SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
78 case DevFmtX714: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
79 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
80 SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT |
81 SL_SPEAKER_TOP_FRONT_LEFT | SL_SPEAKER_TOP_FRONT_RIGHT | SL_SPEAKER_TOP_BACK_LEFT |
82 SL_SPEAKER_TOP_BACK_RIGHT;
89 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
90 constexpr SLuint32 GetTypeRepresentation(DevFmtType type) noexcept
97 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
101 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
103 return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
109 constexpr SLuint32 GetByteOrderEndianness() noexcept
111 if(al::endian::native == al::endian::little)
112 return SL_BYTEORDER_LITTLEENDIAN;
113 return SL_BYTEORDER_BIGENDIAN;
116 constexpr const char *res_str(SLresult result) noexcept
120 case SL_RESULT_SUCCESS: return "Success";
121 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
122 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
123 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
124 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
125 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
126 case SL_RESULT_IO_ERROR: return "I/O error";
127 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
128 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
129 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
130 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
131 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
132 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
133 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
134 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
135 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
136 case SL_RESULT_CONTROL_LOST: return "Control lost";
137 #ifdef SL_RESULT_READONLY
138 case SL_RESULT_READONLY: return "ReadOnly";
140 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
141 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
143 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
144 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
147 return "Unknown error code";
150 inline void PrintErr(SLresult res, const char *str)
152 if(res != SL_RESULT_SUCCESS) UNLIKELY
153 ERR("%s: %s\n", str, res_str(res));
157 struct OpenSLPlayback final : public BackendBase {
158 OpenSLPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
159 ~OpenSLPlayback() override;
161 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
162 static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
163 { static_cast<OpenSLPlayback*>(context)->process(bq); }
167 void open(const char *name) override;
168 bool reset() override;
169 void start() override;
170 void stop() override;
171 ClockLatency getClockLatency() override;
173 /* engine interfaces */
174 SLObjectItf mEngineObj{nullptr};
175 SLEngineItf mEngine{nullptr};
177 /* output mix interfaces */
178 SLObjectItf mOutputMix{nullptr};
180 /* buffer queue player interfaces */
181 SLObjectItf mBufferQueueObj{nullptr};
183 RingBufferPtr mRing{nullptr};
190 std::atomic<bool> mKillNow{true};
193 DEF_NEWDEL(OpenSLPlayback)
196 OpenSLPlayback::~OpenSLPlayback()
199 VCALL0(mBufferQueueObj,Destroy)();
200 mBufferQueueObj = nullptr;
203 VCALL0(mOutputMix,Destroy)();
204 mOutputMix = nullptr;
207 VCALL0(mEngineObj,Destroy)();
208 mEngineObj = nullptr;
213 /* this callback handler is called every time a buffer finishes playing */
214 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) noexcept
216 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
217 * pointer passed to the Enqueue method, rather than copying the audio.
218 * Consequently, the ringbuffer contains the audio that is currently queued
219 * and waiting to play. This process() callback is called when a buffer is
220 * finished, so we simply move the read pointer up to indicate the space is
221 * available for writing again, and wake up the mixer thread to mix and
224 mRing->readAdvance(1);
229 int OpenSLPlayback::mixerProc()
232 althrd_setname(MIXER_THREAD_NAME);
235 SLAndroidSimpleBufferQueueItf bufferQueue;
236 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
238 PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
239 if(SL_RESULT_SUCCESS == result)
241 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
242 PrintErr(result, "bufferQueue->GetInterface SL_IID_PLAY");
245 const size_t frame_step{mDevice->channelsFromFmt()};
247 if(SL_RESULT_SUCCESS != result)
248 mDevice->handleDisconnect("Failed to get playback buffer: 0x%08x", result);
250 while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire)
251 && mDevice->Connected.load(std::memory_order_acquire))
253 if(mRing->writeSpace() == 0)
257 result = VCALL(player,GetPlayState)(&state);
258 PrintErr(result, "player->GetPlayState");
259 if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
261 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
262 PrintErr(result, "player->SetPlayState");
264 if(SL_RESULT_SUCCESS != result)
266 mDevice->handleDisconnect("Failed to start playback: 0x%08x", result);
270 if(mRing->writeSpace() == 0)
277 std::unique_lock<std::mutex> dlock{mMutex};
278 auto data = mRing->getWriteVector();
279 mDevice->renderSamples(data.first.buf,
280 static_cast<uint>(data.first.len)*mDevice->UpdateSize, frame_step);
281 if(data.second.len > 0)
282 mDevice->renderSamples(data.second.buf,
283 static_cast<uint>(data.second.len)*mDevice->UpdateSize, frame_step);
285 size_t todo{data.first.len + data.second.len};
286 mRing->writeAdvance(todo);
289 for(size_t i{0};i < todo;i++)
293 data.first = data.second;
294 data.second.buf = nullptr;
298 result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize);
299 PrintErr(result, "bufferQueue->Enqueue");
300 if(SL_RESULT_SUCCESS != result)
302 mDevice->handleDisconnect("Failed to queue audio: 0x%08x", result);
307 data.first.buf += mDevice->UpdateSize*mFrameSize;
315 void OpenSLPlayback::open(const char *name)
318 name = opensl_device;
319 else if(strcmp(name, opensl_device) != 0)
320 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
323 /* There's only one device, so if it's already open, there's nothing to do. */
324 if(mEngineObj) return;
327 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
328 PrintErr(result, "slCreateEngine");
329 if(SL_RESULT_SUCCESS == result)
331 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
332 PrintErr(result, "engine->Realize");
334 if(SL_RESULT_SUCCESS == result)
336 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
337 PrintErr(result, "engine->GetInterface");
339 if(SL_RESULT_SUCCESS == result)
341 result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr);
342 PrintErr(result, "engine->CreateOutputMix");
344 if(SL_RESULT_SUCCESS == result)
346 result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE);
347 PrintErr(result, "outputMix->Realize");
350 if(SL_RESULT_SUCCESS != result)
353 VCALL0(mOutputMix,Destroy)();
354 mOutputMix = nullptr;
357 VCALL0(mEngineObj,Destroy)();
358 mEngineObj = nullptr;
361 throw al::backend_exception{al::backend_error::DeviceError,
362 "Failed to initialize OpenSL device: 0x%08x", result};
365 mDevice->DeviceName = name;
368 bool OpenSLPlayback::reset()
373 VCALL0(mBufferQueueObj,Destroy)();
374 mBufferQueueObj = nullptr;
379 if(!mDevice->Flags.get<FrequencyRequest>())
381 /* FIXME: Disabled until I figure out how to get the Context needed for
382 * the getSystemService call.
384 JNIEnv *env = Android_GetJNIEnv();
385 jobject jctx = Android_GetContext();
387 /* Get necessary stuff for using java.lang.Integer,
388 * android.content.Context, and android.media.AudioManager.
390 jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
391 jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
392 "parseInt", "(Ljava/lang/String;)I"
394 TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
396 jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
397 jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
398 "AUDIO_SERVICE", "Ljava/lang/String;"
400 jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
401 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
403 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
404 ctx_cls, ctx_audsvc, ctx_getSysSvc);
406 jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
407 jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
408 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
410 jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
411 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
413 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
414 audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
416 const char *strchars;
419 /* Now make the calls. */
420 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
421 strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
422 jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj);
423 strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
424 TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
425 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
427 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
428 strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
429 jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
430 strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
431 TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
432 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
434 //int sampleRate = Integer.parseInt(srateStr);
435 sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
437 strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr);
438 TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
439 JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
441 if(!sampleRate) sampleRate = device->Frequency;
442 else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
446 mDevice->FmtChans = DevFmtStereo;
447 mDevice->FmtType = DevFmtShort;
449 setDefaultWFXChannelOrder();
450 mFrameSize = mDevice->frameSizeFromFmt();
453 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
454 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
456 SLDataLocator_OutputMix loc_outmix{};
457 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
458 loc_outmix.outputMix = mOutputMix;
460 SLDataSink audioSnk{};
461 audioSnk.pLocator = &loc_outmix;
462 audioSnk.pFormat = nullptr;
464 SLDataLocator_AndroidSimpleBufferQueue loc_bufq{};
465 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
466 loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
468 SLDataSource audioSrc{};
469 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
470 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
471 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
472 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
473 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
474 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
475 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
476 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
477 format_pcm_ex.endianness = GetByteOrderEndianness();
478 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
480 audioSrc.pLocator = &loc_bufq;
481 audioSrc.pFormat = &format_pcm_ex;
483 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
484 ids.data(), reqs.data());
485 if(SL_RESULT_SUCCESS != result)
488 /* Alter sample type according to what SLDataFormat_PCM can support. */
489 switch(mDevice->FmtType)
491 case DevFmtByte: mDevice->FmtType = DevFmtUByte; break;
492 case DevFmtUInt: mDevice->FmtType = DevFmtInt; break;
494 case DevFmtUShort: mDevice->FmtType = DevFmtShort; break;
501 SLDataFormat_PCM format_pcm{};
502 format_pcm.formatType = SL_DATAFORMAT_PCM;
503 format_pcm.numChannels = mDevice->channelsFromFmt();
504 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
505 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
506 format_pcm.containerSize = format_pcm.bitsPerSample;
507 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
508 format_pcm.endianness = GetByteOrderEndianness();
510 audioSrc.pLocator = &loc_bufq;
511 audioSrc.pFormat = &format_pcm;
513 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
514 ids.data(), reqs.data());
515 PrintErr(result, "engine->CreateAudioPlayer");
517 if(SL_RESULT_SUCCESS == result)
519 /* Set the stream type to "media" (games, music, etc), if possible. */
520 SLAndroidConfigurationItf config;
521 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
522 PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
523 if(SL_RESULT_SUCCESS == result)
525 SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
526 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType,
528 PrintErr(result, "config->SetConfiguration");
531 /* Clear any error since this was optional. */
532 result = SL_RESULT_SUCCESS;
534 if(SL_RESULT_SUCCESS == result)
536 result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
537 PrintErr(result, "bufferQueue->Realize");
539 if(SL_RESULT_SUCCESS == result)
541 const uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
542 mRing = RingBuffer::Create(num_updates, mFrameSize*mDevice->UpdateSize, true);
545 if(SL_RESULT_SUCCESS != result)
548 VCALL0(mBufferQueueObj,Destroy)();
549 mBufferQueueObj = nullptr;
557 void OpenSLPlayback::start()
561 SLAndroidSimpleBufferQueueItf bufferQueue;
562 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
564 PrintErr(result, "bufferQueue->GetInterface");
565 if(SL_RESULT_SUCCESS == result)
567 result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this);
568 PrintErr(result, "bufferQueue->RegisterCallback");
570 if(SL_RESULT_SUCCESS != result)
571 throw al::backend_exception{al::backend_error::DeviceError,
572 "Failed to register callback: 0x%08x", result};
575 mKillNow.store(false, std::memory_order_release);
576 mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this);
578 catch(std::exception& e) {
579 throw al::backend_exception{al::backend_error::DeviceError,
580 "Failed to start mixing thread: %s", e.what()};
584 void OpenSLPlayback::stop()
586 if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
593 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)};
594 PrintErr(result, "bufferQueue->GetInterface");
595 if(SL_RESULT_SUCCESS == result)
597 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
598 PrintErr(result, "player->SetPlayState");
601 SLAndroidSimpleBufferQueueItf bufferQueue;
602 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
603 PrintErr(result, "bufferQueue->GetInterface");
604 if(SL_RESULT_SUCCESS == result)
606 result = VCALL0(bufferQueue,Clear)();
607 PrintErr(result, "bufferQueue->Clear");
609 if(SL_RESULT_SUCCESS == result)
611 result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr);
612 PrintErr(result, "bufferQueue->RegisterCallback");
614 if(SL_RESULT_SUCCESS == result)
616 SLAndroidSimpleBufferQueueState state;
618 std::this_thread::yield();
619 result = VCALL(bufferQueue,GetState)(&state);
620 } while(SL_RESULT_SUCCESS == result && state.count > 0);
621 PrintErr(result, "bufferQueue->GetState");
627 ClockLatency OpenSLPlayback::getClockLatency()
631 std::lock_guard<std::mutex> _{mMutex};
632 ret.ClockTime = GetDeviceClockTime(mDevice);
633 ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize};
634 ret.Latency /= mDevice->Frequency;
640 struct OpenSLCapture final : public BackendBase {
641 OpenSLCapture(DeviceBase *device) noexcept : BackendBase{device} { }
642 ~OpenSLCapture() override;
644 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
645 static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
646 { static_cast<OpenSLCapture*>(context)->process(bq); }
648 void open(const char *name) override;
649 void start() override;
650 void stop() override;
651 void captureSamples(al::byte *buffer, uint samples) override;
652 uint availableSamples() override;
654 /* engine interfaces */
655 SLObjectItf mEngineObj{nullptr};
658 /* recording interfaces */
659 SLObjectItf mRecordObj{nullptr};
661 RingBufferPtr mRing{nullptr};
666 DEF_NEWDEL(OpenSLCapture)
669 OpenSLCapture::~OpenSLCapture()
672 VCALL0(mRecordObj,Destroy)();
673 mRecordObj = nullptr;
676 VCALL0(mEngineObj,Destroy)();
677 mEngineObj = nullptr;
682 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept
684 /* A new chunk has been written into the ring buffer, advance it. */
685 mRing->writeAdvance(1);
689 void OpenSLCapture::open(const char* name)
692 name = opensl_device;
693 else if(strcmp(name, opensl_device) != 0)
694 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
697 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
698 PrintErr(result, "slCreateEngine");
699 if(SL_RESULT_SUCCESS == result)
701 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
702 PrintErr(result, "engine->Realize");
704 if(SL_RESULT_SUCCESS == result)
706 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
707 PrintErr(result, "engine->GetInterface");
709 if(SL_RESULT_SUCCESS == result)
711 mFrameSize = mDevice->frameSizeFromFmt();
712 /* Ensure the total length is at least 100ms */
713 uint length{maxu(mDevice->BufferSize, mDevice->Frequency/10)};
714 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
715 uint update_len{clampu(mDevice->BufferSize/3, mDevice->Frequency/100,
716 mDevice->Frequency/100*5)};
717 uint num_updates{(length+update_len-1) / update_len};
719 mRing = RingBuffer::Create(num_updates, update_len*mFrameSize, false);
721 mDevice->UpdateSize = update_len;
722 mDevice->BufferSize = static_cast<uint>(mRing->writeSpace() * update_len);
724 if(SL_RESULT_SUCCESS == result)
726 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
727 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
729 SLDataLocator_IODevice loc_dev{};
730 loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
731 loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
732 loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
733 loc_dev.device = nullptr;
735 SLDataSource audioSrc{};
736 audioSrc.pLocator = &loc_dev;
737 audioSrc.pFormat = nullptr;
739 SLDataLocator_AndroidSimpleBufferQueue loc_bq{};
740 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
741 loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
743 SLDataSink audioSnk{};
744 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
745 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
746 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
747 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
748 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
749 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
750 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
751 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
752 format_pcm_ex.endianness = GetByteOrderEndianness();
753 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
755 audioSnk.pLocator = &loc_bq;
756 audioSnk.pFormat = &format_pcm_ex;
757 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
758 ids.size(), ids.data(), reqs.data());
759 if(SL_RESULT_SUCCESS != result)
762 /* Fallback to SLDataFormat_PCM only if it supports the desired
765 if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtShort
766 || mDevice->FmtType == DevFmtInt)
768 SLDataFormat_PCM format_pcm{};
769 format_pcm.formatType = SL_DATAFORMAT_PCM;
770 format_pcm.numChannels = mDevice->channelsFromFmt();
771 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
772 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
773 format_pcm.containerSize = format_pcm.bitsPerSample;
774 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
775 format_pcm.endianness = GetByteOrderEndianness();
777 audioSnk.pLocator = &loc_bq;
778 audioSnk.pFormat = &format_pcm;
779 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
780 ids.size(), ids.data(), reqs.data());
782 PrintErr(result, "engine->CreateAudioRecorder");
785 if(SL_RESULT_SUCCESS == result)
787 /* Set the record preset to "generic", if possible. */
788 SLAndroidConfigurationItf config;
789 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
790 PrintErr(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
791 if(SL_RESULT_SUCCESS == result)
793 SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
794 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset,
796 PrintErr(result, "config->SetConfiguration");
799 /* Clear any error since this was optional. */
800 result = SL_RESULT_SUCCESS;
802 if(SL_RESULT_SUCCESS == result)
804 result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE);
805 PrintErr(result, "recordObj->Realize");
808 SLAndroidSimpleBufferQueueItf bufferQueue;
809 if(SL_RESULT_SUCCESS == result)
811 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
812 PrintErr(result, "recordObj->GetInterface");
814 if(SL_RESULT_SUCCESS == result)
816 result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this);
817 PrintErr(result, "bufferQueue->RegisterCallback");
819 if(SL_RESULT_SUCCESS == result)
821 const uint chunk_size{mDevice->UpdateSize * mFrameSize};
822 const auto silence = (mDevice->FmtType == DevFmtUByte) ? al::byte{0x80} : al::byte{0};
824 auto data = mRing->getWriteVector();
825 std::fill_n(data.first.buf, data.first.len*chunk_size, silence);
826 std::fill_n(data.second.buf, data.second.len*chunk_size, silence);
827 for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++)
829 result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size);
830 PrintErr(result, "bufferQueue->Enqueue");
832 for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++)
834 result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size);
835 PrintErr(result, "bufferQueue->Enqueue");
839 if(SL_RESULT_SUCCESS != result)
842 VCALL0(mRecordObj,Destroy)();
843 mRecordObj = nullptr;
846 VCALL0(mEngineObj,Destroy)();
847 mEngineObj = nullptr;
850 throw al::backend_exception{al::backend_error::DeviceError,
851 "Failed to initialize OpenSL device: 0x%08x", result};
854 mDevice->DeviceName = name;
857 void OpenSLCapture::start()
860 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
861 PrintErr(result, "recordObj->GetInterface");
863 if(SL_RESULT_SUCCESS == result)
865 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
866 PrintErr(result, "record->SetRecordState");
868 if(SL_RESULT_SUCCESS != result)
869 throw al::backend_exception{al::backend_error::DeviceError,
870 "Failed to start capture: 0x%08x", result};
873 void OpenSLCapture::stop()
876 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
877 PrintErr(result, "recordObj->GetInterface");
879 if(SL_RESULT_SUCCESS == result)
881 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
882 PrintErr(result, "record->SetRecordState");
886 void OpenSLCapture::captureSamples(al::byte *buffer, uint samples)
888 const uint update_size{mDevice->UpdateSize};
889 const uint chunk_size{update_size * mFrameSize};
891 /* Read the desired samples from the ring buffer then advance its read
895 auto rdata = mRing->getReadVector();
896 for(uint i{0};i < samples;)
898 const uint rem{minu(samples - i, update_size - mSplOffset)};
899 std::copy_n(rdata.first.buf + mSplOffset*size_t{mFrameSize}, rem*size_t{mFrameSize},
900 buffer + i*size_t{mFrameSize});
903 if(mSplOffset == update_size)
905 /* Finished a chunk, reset the offset and advance the read pointer. */
909 rdata.first.len -= 1;
911 rdata.first = rdata.second;
913 rdata.first.buf += chunk_size;
919 SLAndroidSimpleBufferQueueItf bufferQueue{};
920 if(mDevice->Connected.load(std::memory_order_acquire)) LIKELY
922 const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
924 PrintErr(result, "recordObj->GetInterface");
925 if(SL_RESULT_SUCCESS != result) UNLIKELY
927 mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
928 bufferQueue = nullptr;
931 if(!bufferQueue || adv_count == 0)
934 /* For each buffer chunk that was fully read, queue another writable buffer
935 * chunk to keep the OpenSL queue full. This is rather convulated, as a
936 * result of the ring buffer holding more elements than are writable at a
937 * given time. The end of the write vector increments when the read pointer
938 * advances, which will "expose" a previously unwritable element. So for
939 * every element that we've finished reading, we queue that many elements
940 * from the end of the write vector.
942 mRing->readAdvance(adv_count);
944 SLresult result{SL_RESULT_SUCCESS};
945 auto wdata = mRing->getWriteVector();
946 if(adv_count > wdata.second.len) LIKELY
948 auto len1 = std::min(wdata.first.len, adv_count-wdata.second.len);
949 auto buf1 = wdata.first.buf + chunk_size*(wdata.first.len-len1);
950 for(size_t i{0u};i < len1 && SL_RESULT_SUCCESS == result;i++)
952 result = VCALL(bufferQueue,Enqueue)(buf1 + chunk_size*i, chunk_size);
953 PrintErr(result, "bufferQueue->Enqueue");
956 if(wdata.second.len > 0)
958 auto len2 = std::min(wdata.second.len, adv_count);
959 auto buf2 = wdata.second.buf + chunk_size*(wdata.second.len-len2);
960 for(size_t i{0u};i < len2 && SL_RESULT_SUCCESS == result;i++)
962 result = VCALL(bufferQueue,Enqueue)(buf2 + chunk_size*i, chunk_size);
963 PrintErr(result, "bufferQueue->Enqueue");
968 uint OpenSLCapture::availableSamples()
969 { return static_cast<uint>(mRing->readSpace()*mDevice->UpdateSize - mSplOffset); }
973 bool OSLBackendFactory::init() { return true; }
975 bool OSLBackendFactory::querySupport(BackendType type)
976 { return (type == BackendType::Playback || type == BackendType::Capture); }
978 std::string OSLBackendFactory::probe(BackendType type)
980 std::string outnames;
983 case BackendType::Playback:
984 case BackendType::Capture:
985 /* Includes null char. */
986 outnames.append(opensl_device, sizeof(opensl_device));
992 BackendPtr OSLBackendFactory::createBackend(DeviceBase *device, BackendType type)
994 if(type == BackendType::Playback)
995 return BackendPtr{new OpenSLPlayback{device}};
996 if(type == BackendType::Capture)
997 return BackendPtr{new OpenSLCapture{device}};
1001 BackendFactory &OSLBackendFactory::getFactory()
1003 static OSLBackendFactory factory{};