Avoid a stateful unique_ptr deleter
[openal-soft.git] / alc / backends / opensl.cpp
blob5ba95e4c9bde2d2f8269831bb2ade966ff47e1fa
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 "opensl.h"
26 #include <stdlib.h>
27 #include <jni.h>
29 #include <new>
30 #include <array>
31 #include <cstring>
32 #include <thread>
33 #include <functional>
35 #include "albit.h"
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"
42 #include "threads.h"
44 #include <SLES/OpenSLES.h>
45 #include <SLES/OpenSLES_Android.h>
46 #include <SLES/OpenSLES_AndroidConfiguration.h>
49 namespace {
51 /* Helper macros */
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
62 switch(chans)
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;
74 case DevFmtX71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
75 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
76 SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
77 case DevFmtAmbi3D:
78 break;
80 return 0;
83 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
84 constexpr SLuint32 GetTypeRepresentation(DevFmtType type) noexcept
86 switch(type)
88 case DevFmtUByte:
89 case DevFmtUShort:
90 case DevFmtUInt:
91 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
92 case DevFmtByte:
93 case DevFmtShort:
94 case DevFmtInt:
95 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
96 case DevFmtFloat:
97 return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
99 return 0;
101 #endif
103 constexpr SLuint32 GetByteOrderEndianness() noexcept
105 if(al::endian::native == al::endian::little)
106 return SL_BYTEORDER_LITTLEENDIAN;
107 return SL_BYTEORDER_BIGENDIAN;
110 const char *res_str(SLresult result) noexcept
112 switch(result)
114 case SL_RESULT_SUCCESS: return "Success";
115 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
116 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
117 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
118 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
119 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
120 case SL_RESULT_IO_ERROR: return "I/O error";
121 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
122 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
123 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
124 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
125 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
126 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
127 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
128 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
129 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
130 case SL_RESULT_CONTROL_LOST: return "Control lost";
131 #ifdef SL_RESULT_READONLY
132 case SL_RESULT_READONLY: return "ReadOnly";
133 #endif
134 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
135 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
136 #endif
137 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
138 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
139 #endif
141 return "Unknown error code";
144 #define PRINTERR(x, s) do { \
145 if UNLIKELY((x) != SL_RESULT_SUCCESS) \
146 ERR("%s: %s\n", (s), res_str((x))); \
147 } while(0)
150 struct OpenSLPlayback final : public BackendBase {
151 OpenSLPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
152 ~OpenSLPlayback() override;
154 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
155 static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
156 { static_cast<OpenSLPlayback*>(context)->process(bq); }
158 int mixerProc();
160 void open(const char *name) override;
161 bool reset() override;
162 void start() override;
163 void stop() override;
164 ClockLatency getClockLatency() override;
166 /* engine interfaces */
167 SLObjectItf mEngineObj{nullptr};
168 SLEngineItf mEngine{nullptr};
170 /* output mix interfaces */
171 SLObjectItf mOutputMix{nullptr};
173 /* buffer queue player interfaces */
174 SLObjectItf mBufferQueueObj{nullptr};
176 RingBufferPtr mRing{nullptr};
177 al::semaphore mSem;
179 std::mutex mMutex;
181 uint mFrameSize{0};
183 std::atomic<bool> mKillNow{true};
184 std::thread mThread;
186 DEF_NEWDEL(OpenSLPlayback)
189 OpenSLPlayback::~OpenSLPlayback()
191 if(mBufferQueueObj)
192 VCALL0(mBufferQueueObj,Destroy)();
193 mBufferQueueObj = nullptr;
195 if(mOutputMix)
196 VCALL0(mOutputMix,Destroy)();
197 mOutputMix = nullptr;
199 if(mEngineObj)
200 VCALL0(mEngineObj,Destroy)();
201 mEngineObj = nullptr;
202 mEngine = nullptr;
206 /* this callback handler is called every time a buffer finishes playing */
207 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) noexcept
209 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
210 * pointer passed to the Enqueue method, rather than copying the audio.
211 * Consequently, the ringbuffer contains the audio that is currently queued
212 * and waiting to play. This process() callback is called when a buffer is
213 * finished, so we simply move the read pointer up to indicate the space is
214 * available for writing again, and wake up the mixer thread to mix and
215 * queue more audio.
217 mRing->readAdvance(1);
219 mSem.post();
222 int OpenSLPlayback::mixerProc()
224 SetRTPriority();
225 althrd_setname(MIXER_THREAD_NAME);
227 SLPlayItf player;
228 SLAndroidSimpleBufferQueueItf bufferQueue;
229 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
230 &bufferQueue)};
231 PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
232 if(SL_RESULT_SUCCESS == result)
234 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
235 PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY");
238 const size_t frame_step{mDevice->channelsFromFmt()};
240 if(SL_RESULT_SUCCESS != result)
241 mDevice->handleDisconnect("Failed to get playback buffer: 0x%08x", result);
243 while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire)
244 && mDevice->Connected.load(std::memory_order_acquire))
246 if(mRing->writeSpace() == 0)
248 SLuint32 state{0};
250 result = VCALL(player,GetPlayState)(&state);
251 PRINTERR(result, "player->GetPlayState");
252 if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
254 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
255 PRINTERR(result, "player->SetPlayState");
257 if(SL_RESULT_SUCCESS != result)
259 mDevice->handleDisconnect("Failed to start playback: 0x%08x", result);
260 break;
263 if(mRing->writeSpace() == 0)
265 mSem.wait();
266 continue;
270 std::unique_lock<std::mutex> dlock{mMutex};
271 auto data = mRing->getWriteVector();
272 mDevice->renderSamples(data.first.buf,
273 static_cast<uint>(data.first.len)*mDevice->UpdateSize, frame_step);
274 if(data.second.len > 0)
275 mDevice->renderSamples(data.second.buf,
276 static_cast<uint>(data.second.len)*mDevice->UpdateSize, frame_step);
278 size_t todo{data.first.len + data.second.len};
279 mRing->writeAdvance(todo);
280 dlock.unlock();
282 for(size_t i{0};i < todo;i++)
284 if(!data.first.len)
286 data.first = data.second;
287 data.second.buf = nullptr;
288 data.second.len = 0;
291 result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize);
292 PRINTERR(result, "bufferQueue->Enqueue");
293 if(SL_RESULT_SUCCESS != result)
295 mDevice->handleDisconnect("Failed to queue audio: 0x%08x", result);
296 break;
299 data.first.len--;
300 data.first.buf += mDevice->UpdateSize*mFrameSize;
304 return 0;
308 void OpenSLPlayback::open(const char *name)
310 if(!name)
311 name = opensl_device;
312 else if(strcmp(name, opensl_device) != 0)
313 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
314 name};
316 /* There's only one device, so if it's already open, there's nothing to do. */
317 if(mEngineObj) return;
319 // create engine
320 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
321 PRINTERR(result, "slCreateEngine");
322 if(SL_RESULT_SUCCESS == result)
324 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
325 PRINTERR(result, "engine->Realize");
327 if(SL_RESULT_SUCCESS == result)
329 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
330 PRINTERR(result, "engine->GetInterface");
332 if(SL_RESULT_SUCCESS == result)
334 result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr);
335 PRINTERR(result, "engine->CreateOutputMix");
337 if(SL_RESULT_SUCCESS == result)
339 result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE);
340 PRINTERR(result, "outputMix->Realize");
343 if(SL_RESULT_SUCCESS != result)
345 if(mOutputMix)
346 VCALL0(mOutputMix,Destroy)();
347 mOutputMix = nullptr;
349 if(mEngineObj)
350 VCALL0(mEngineObj,Destroy)();
351 mEngineObj = nullptr;
352 mEngine = nullptr;
354 throw al::backend_exception{al::backend_error::DeviceError,
355 "Failed to initialize OpenSL device: 0x%08x", result};
358 mDevice->DeviceName = name;
361 bool OpenSLPlayback::reset()
363 SLresult result;
365 if(mBufferQueueObj)
366 VCALL0(mBufferQueueObj,Destroy)();
367 mBufferQueueObj = nullptr;
369 mRing = nullptr;
371 #if 0
372 if(!mDevice->Flags.get<FrequencyRequest>())
374 /* FIXME: Disabled until I figure out how to get the Context needed for
375 * the getSystemService call.
377 JNIEnv *env = Android_GetJNIEnv();
378 jobject jctx = Android_GetContext();
380 /* Get necessary stuff for using java.lang.Integer,
381 * android.content.Context, and android.media.AudioManager.
383 jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
384 jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
385 "parseInt", "(Ljava/lang/String;)I"
387 TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
389 jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
390 jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
391 "AUDIO_SERVICE", "Ljava/lang/String;"
393 jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
394 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
396 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
397 ctx_cls, ctx_audsvc, ctx_getSysSvc);
399 jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
400 jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
401 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
403 jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
404 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
406 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
407 audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
409 const char *strchars;
410 jstring strobj;
412 /* Now make the calls. */
413 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
414 strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
415 jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj);
416 strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
417 TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
418 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
420 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
421 strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
422 jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
423 strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
424 TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
425 JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
427 //int sampleRate = Integer.parseInt(srateStr);
428 sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
430 strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr);
431 TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
432 JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
434 if(!sampleRate) sampleRate = device->Frequency;
435 else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
437 #endif
439 mDevice->FmtChans = DevFmtStereo;
440 mDevice->FmtType = DevFmtShort;
442 setDefaultWFXChannelOrder();
443 mFrameSize = mDevice->frameSizeFromFmt();
446 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
447 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
449 SLDataLocator_OutputMix loc_outmix{};
450 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
451 loc_outmix.outputMix = mOutputMix;
453 SLDataSink audioSnk{};
454 audioSnk.pLocator = &loc_outmix;
455 audioSnk.pFormat = nullptr;
457 SLDataLocator_AndroidSimpleBufferQueue loc_bufq{};
458 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
459 loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
461 SLDataSource audioSrc{};
462 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
463 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
464 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
465 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
466 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
467 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
468 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
469 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
470 format_pcm_ex.endianness = GetByteOrderEndianness();
471 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
473 audioSrc.pLocator = &loc_bufq;
474 audioSrc.pFormat = &format_pcm_ex;
476 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
477 ids.data(), reqs.data());
478 if(SL_RESULT_SUCCESS != result)
479 #endif
481 /* Alter sample type according to what SLDataFormat_PCM can support. */
482 switch(mDevice->FmtType)
484 case DevFmtByte: mDevice->FmtType = DevFmtUByte; break;
485 case DevFmtUInt: mDevice->FmtType = DevFmtInt; break;
486 case DevFmtFloat:
487 case DevFmtUShort: mDevice->FmtType = DevFmtShort; break;
488 case DevFmtUByte:
489 case DevFmtShort:
490 case DevFmtInt:
491 break;
494 SLDataFormat_PCM format_pcm{};
495 format_pcm.formatType = SL_DATAFORMAT_PCM;
496 format_pcm.numChannels = mDevice->channelsFromFmt();
497 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
498 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
499 format_pcm.containerSize = format_pcm.bitsPerSample;
500 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
501 format_pcm.endianness = GetByteOrderEndianness();
503 audioSrc.pLocator = &loc_bufq;
504 audioSrc.pFormat = &format_pcm;
506 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
507 ids.data(), reqs.data());
508 PRINTERR(result, "engine->CreateAudioPlayer");
510 if(SL_RESULT_SUCCESS == result)
512 /* Set the stream type to "media" (games, music, etc), if possible. */
513 SLAndroidConfigurationItf config;
514 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
515 PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
516 if(SL_RESULT_SUCCESS == result)
518 SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
519 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType,
520 sizeof(streamType));
521 PRINTERR(result, "config->SetConfiguration");
524 /* Clear any error since this was optional. */
525 result = SL_RESULT_SUCCESS;
527 if(SL_RESULT_SUCCESS == result)
529 result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
530 PRINTERR(result, "bufferQueue->Realize");
532 if(SL_RESULT_SUCCESS == result)
534 const uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
535 mRing = RingBuffer::Create(num_updates, mFrameSize*mDevice->UpdateSize, true);
538 if(SL_RESULT_SUCCESS != result)
540 if(mBufferQueueObj)
541 VCALL0(mBufferQueueObj,Destroy)();
542 mBufferQueueObj = nullptr;
544 return false;
547 return true;
550 void OpenSLPlayback::start()
552 mRing->reset();
554 SLAndroidSimpleBufferQueueItf bufferQueue;
555 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
556 &bufferQueue)};
557 PRINTERR(result, "bufferQueue->GetInterface");
558 if(SL_RESULT_SUCCESS == result)
560 result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this);
561 PRINTERR(result, "bufferQueue->RegisterCallback");
563 if(SL_RESULT_SUCCESS != result)
564 throw al::backend_exception{al::backend_error::DeviceError,
565 "Failed to register callback: 0x%08x", result};
567 try {
568 mKillNow.store(false, std::memory_order_release);
569 mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this);
571 catch(std::exception& e) {
572 throw al::backend_exception{al::backend_error::DeviceError,
573 "Failed to start mixing thread: %s", e.what()};
577 void OpenSLPlayback::stop()
579 if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
580 return;
582 mSem.post();
583 mThread.join();
585 SLPlayItf player;
586 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)};
587 PRINTERR(result, "bufferQueue->GetInterface");
588 if(SL_RESULT_SUCCESS == result)
590 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
591 PRINTERR(result, "player->SetPlayState");
594 SLAndroidSimpleBufferQueueItf bufferQueue;
595 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
596 PRINTERR(result, "bufferQueue->GetInterface");
597 if(SL_RESULT_SUCCESS == result)
599 result = VCALL0(bufferQueue,Clear)();
600 PRINTERR(result, "bufferQueue->Clear");
602 if(SL_RESULT_SUCCESS == result)
604 result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr);
605 PRINTERR(result, "bufferQueue->RegisterCallback");
607 if(SL_RESULT_SUCCESS == result)
609 SLAndroidSimpleBufferQueueState state;
610 do {
611 std::this_thread::yield();
612 result = VCALL(bufferQueue,GetState)(&state);
613 } while(SL_RESULT_SUCCESS == result && state.count > 0);
614 PRINTERR(result, "bufferQueue->GetState");
618 ClockLatency OpenSLPlayback::getClockLatency()
620 ClockLatency ret;
622 std::lock_guard<std::mutex> _{mMutex};
623 ret.ClockTime = GetDeviceClockTime(mDevice);
624 ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize};
625 ret.Latency /= mDevice->Frequency;
627 return ret;
631 struct OpenSLCapture final : public BackendBase {
632 OpenSLCapture(DeviceBase *device) noexcept : BackendBase{device} { }
633 ~OpenSLCapture() override;
635 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
636 static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
637 { static_cast<OpenSLCapture*>(context)->process(bq); }
639 void open(const char *name) override;
640 void start() override;
641 void stop() override;
642 void captureSamples(al::byte *buffer, uint samples) override;
643 uint availableSamples() override;
645 /* engine interfaces */
646 SLObjectItf mEngineObj{nullptr};
647 SLEngineItf mEngine;
649 /* recording interfaces */
650 SLObjectItf mRecordObj{nullptr};
652 RingBufferPtr mRing{nullptr};
653 uint mSplOffset{0u};
655 uint mFrameSize{0};
657 DEF_NEWDEL(OpenSLCapture)
660 OpenSLCapture::~OpenSLCapture()
662 if(mRecordObj)
663 VCALL0(mRecordObj,Destroy)();
664 mRecordObj = nullptr;
666 if(mEngineObj)
667 VCALL0(mEngineObj,Destroy)();
668 mEngineObj = nullptr;
669 mEngine = nullptr;
673 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept
675 /* A new chunk has been written into the ring buffer, advance it. */
676 mRing->writeAdvance(1);
680 void OpenSLCapture::open(const char* name)
682 if(!name)
683 name = opensl_device;
684 else if(strcmp(name, opensl_device) != 0)
685 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
686 name};
688 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
689 PRINTERR(result, "slCreateEngine");
690 if(SL_RESULT_SUCCESS == result)
692 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
693 PRINTERR(result, "engine->Realize");
695 if(SL_RESULT_SUCCESS == result)
697 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
698 PRINTERR(result, "engine->GetInterface");
700 if(SL_RESULT_SUCCESS == result)
702 mFrameSize = mDevice->frameSizeFromFmt();
703 /* Ensure the total length is at least 100ms */
704 uint length{maxu(mDevice->BufferSize, mDevice->Frequency/10)};
705 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
706 uint update_len{clampu(mDevice->BufferSize/3, mDevice->Frequency/100,
707 mDevice->Frequency/100*5)};
708 uint num_updates{(length+update_len-1) / update_len};
710 mRing = RingBuffer::Create(num_updates, update_len*mFrameSize, false);
712 mDevice->UpdateSize = update_len;
713 mDevice->BufferSize = static_cast<uint>(mRing->writeSpace() * update_len);
715 if(SL_RESULT_SUCCESS == result)
717 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
718 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
720 SLDataLocator_IODevice loc_dev{};
721 loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
722 loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
723 loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
724 loc_dev.device = nullptr;
726 SLDataSource audioSrc{};
727 audioSrc.pLocator = &loc_dev;
728 audioSrc.pFormat = nullptr;
730 SLDataLocator_AndroidSimpleBufferQueue loc_bq{};
731 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
732 loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
734 SLDataSink audioSnk{};
735 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
736 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
737 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
738 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
739 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
740 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
741 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
742 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
743 format_pcm_ex.endianness = GetByteOrderEndianness();
744 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
746 audioSnk.pLocator = &loc_bq;
747 audioSnk.pFormat = &format_pcm_ex;
748 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
749 ids.size(), ids.data(), reqs.data());
750 if(SL_RESULT_SUCCESS != result)
751 #endif
753 /* Fallback to SLDataFormat_PCM only if it supports the desired
754 * sample type.
756 if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtShort
757 || mDevice->FmtType == DevFmtInt)
759 SLDataFormat_PCM format_pcm{};
760 format_pcm.formatType = SL_DATAFORMAT_PCM;
761 format_pcm.numChannels = mDevice->channelsFromFmt();
762 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
763 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
764 format_pcm.containerSize = format_pcm.bitsPerSample;
765 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
766 format_pcm.endianness = GetByteOrderEndianness();
768 audioSnk.pLocator = &loc_bq;
769 audioSnk.pFormat = &format_pcm;
770 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
771 ids.size(), ids.data(), reqs.data());
773 PRINTERR(result, "engine->CreateAudioRecorder");
776 if(SL_RESULT_SUCCESS == result)
778 /* Set the record preset to "generic", if possible. */
779 SLAndroidConfigurationItf config;
780 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
781 PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
782 if(SL_RESULT_SUCCESS == result)
784 SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
785 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset,
786 sizeof(preset));
787 PRINTERR(result, "config->SetConfiguration");
790 /* Clear any error since this was optional. */
791 result = SL_RESULT_SUCCESS;
793 if(SL_RESULT_SUCCESS == result)
795 result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE);
796 PRINTERR(result, "recordObj->Realize");
799 SLAndroidSimpleBufferQueueItf bufferQueue;
800 if(SL_RESULT_SUCCESS == result)
802 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
803 PRINTERR(result, "recordObj->GetInterface");
805 if(SL_RESULT_SUCCESS == result)
807 result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this);
808 PRINTERR(result, "bufferQueue->RegisterCallback");
810 if(SL_RESULT_SUCCESS == result)
812 const uint chunk_size{mDevice->UpdateSize * mFrameSize};
814 auto data = mRing->getWriteVector();
815 for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++)
817 result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size);
818 PRINTERR(result, "bufferQueue->Enqueue");
820 for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++)
822 result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size);
823 PRINTERR(result, "bufferQueue->Enqueue");
827 if(SL_RESULT_SUCCESS != result)
829 if(mRecordObj)
830 VCALL0(mRecordObj,Destroy)();
831 mRecordObj = nullptr;
833 if(mEngineObj)
834 VCALL0(mEngineObj,Destroy)();
835 mEngineObj = nullptr;
836 mEngine = nullptr;
838 throw al::backend_exception{al::backend_error::DeviceError,
839 "Failed to initialize OpenSL device: 0x%08x", result};
842 mDevice->DeviceName = name;
845 void OpenSLCapture::start()
847 SLRecordItf record;
848 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
849 PRINTERR(result, "recordObj->GetInterface");
851 if(SL_RESULT_SUCCESS == result)
853 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
854 PRINTERR(result, "record->SetRecordState");
856 if(SL_RESULT_SUCCESS != result)
857 throw al::backend_exception{al::backend_error::DeviceError,
858 "Failed to start capture: 0x%08x", result};
861 void OpenSLCapture::stop()
863 SLRecordItf record;
864 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
865 PRINTERR(result, "recordObj->GetInterface");
867 if(SL_RESULT_SUCCESS == result)
869 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
870 PRINTERR(result, "record->SetRecordState");
874 void OpenSLCapture::captureSamples(al::byte *buffer, uint samples)
876 const uint update_size{mDevice->UpdateSize};
877 const uint chunk_size{update_size * mFrameSize};
879 /* Read the desired samples from the ring buffer then advance its read
880 * pointer.
882 size_t adv_count{0};
883 auto rdata = mRing->getReadVector();
884 for(uint i{0};i < samples;)
886 const uint rem{minu(samples - i, update_size - mSplOffset)};
887 std::copy_n(rdata.first.buf + mSplOffset*size_t{mFrameSize}, rem*size_t{mFrameSize},
888 buffer + i*size_t{mFrameSize});
890 mSplOffset += rem;
891 if(mSplOffset == update_size)
893 /* Finished a chunk, reset the offset and advance the read pointer. */
894 mSplOffset = 0;
896 ++adv_count;
897 rdata.first.len -= 1;
898 if(!rdata.first.len)
899 rdata.first = rdata.second;
900 else
901 rdata.first.buf += chunk_size;
904 i += rem;
906 mRing->readAdvance(adv_count);
908 SLAndroidSimpleBufferQueueItf bufferQueue{};
909 if LIKELY(mDevice->Connected.load(std::memory_order_acquire))
911 const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
912 &bufferQueue)};
913 PRINTERR(result, "recordObj->GetInterface");
914 if UNLIKELY(SL_RESULT_SUCCESS != result)
916 mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
917 bufferQueue = nullptr;
921 if LIKELY(bufferQueue)
923 SLresult result{SL_RESULT_SUCCESS};
924 auto wdata = mRing->getWriteVector();
925 for(size_t i{0u};i < wdata.first.len && SL_RESULT_SUCCESS == result;i++)
927 result = VCALL(bufferQueue,Enqueue)(wdata.first.buf + chunk_size*i, chunk_size);
928 PRINTERR(result, "bufferQueue->Enqueue");
930 for(size_t i{0u};i < wdata.second.len && SL_RESULT_SUCCESS == result;i++)
932 result = VCALL(bufferQueue,Enqueue)(wdata.second.buf + chunk_size*i, chunk_size);
933 PRINTERR(result, "bufferQueue->Enqueue");
938 uint OpenSLCapture::availableSamples()
939 { return static_cast<uint>(mRing->readSpace()*mDevice->UpdateSize - mSplOffset); }
941 } // namespace
943 bool OSLBackendFactory::init() { return true; }
945 bool OSLBackendFactory::querySupport(BackendType type)
946 { return (type == BackendType::Playback || type == BackendType::Capture); }
948 std::string OSLBackendFactory::probe(BackendType type)
950 std::string outnames;
951 switch(type)
953 case BackendType::Playback:
954 case BackendType::Capture:
955 /* Includes null char. */
956 outnames.append(opensl_device, sizeof(opensl_device));
957 break;
959 return outnames;
962 BackendPtr OSLBackendFactory::createBackend(DeviceBase *device, BackendType type)
964 if(type == BackendType::Playback)
965 return BackendPtr{new OpenSLPlayback{device}};
966 if(type == BackendType::Capture)
967 return BackendPtr{new OpenSLCapture{device}};
968 return nullptr;
971 BackendFactory &OSLBackendFactory::getFactory()
973 static OSLBackendFactory factory{};
974 return factory;