Check some float property values for being finite
[openal-soft.git] / alc / backends / opensl.cpp
bloba6678d9a2ea264c794928f3f9939d1430d53b22b
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 <jni.h>
28 #include <array>
29 #include <cstdlib>
30 #include <cstring>
31 #include <mutex>
32 #include <new>
33 #include <thread>
34 #include <functional>
36 #include "albit.h"
37 #include "alnumeric.h"
38 #include "alsem.h"
39 #include "alstring.h"
40 #include "althrd_setname.h"
41 #include "core/device.h"
42 #include "core/helpers.h"
43 #include "core/logging.h"
44 #include "opthelpers.h"
45 #include "ringbuffer.h"
47 #include <SLES/OpenSLES.h>
48 #include <SLES/OpenSLES_Android.h>
49 #include <SLES/OpenSLES_AndroidConfiguration.h>
52 namespace {
54 using namespace std::string_view_literals;
56 /* Helper macros */
57 #define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
58 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
59 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
62 [[nodiscard]] constexpr auto GetDeviceName() noexcept { return "OpenSL"sv; }
64 [[nodiscard]]
65 constexpr SLuint32 GetChannelMask(DevFmtChannels chans) noexcept
67 switch(chans)
69 case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
70 case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
71 case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
72 SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
73 case DevFmtX51: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
74 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT |
75 SL_SPEAKER_SIDE_RIGHT;
76 case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
77 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER |
78 SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
79 case DevFmtX71:
80 case DevFmtX3D71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
81 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
82 SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
83 case DevFmtX714: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
84 SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
85 SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT |
86 SL_SPEAKER_TOP_FRONT_LEFT | SL_SPEAKER_TOP_FRONT_RIGHT | SL_SPEAKER_TOP_BACK_LEFT |
87 SL_SPEAKER_TOP_BACK_RIGHT;
88 case DevFmtX7144:
89 case DevFmtAmbi3D:
90 break;
92 return 0;
95 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
96 constexpr SLuint32 GetTypeRepresentation(DevFmtType type) noexcept
98 switch(type)
100 case DevFmtUByte:
101 case DevFmtUShort:
102 case DevFmtUInt:
103 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
104 case DevFmtByte:
105 case DevFmtShort:
106 case DevFmtInt:
107 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
108 case DevFmtFloat:
109 return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
111 return 0;
113 #endif
115 constexpr SLuint32 GetByteOrderEndianness() noexcept
117 if(al::endian::native == al::endian::little)
118 return SL_BYTEORDER_LITTLEENDIAN;
119 return SL_BYTEORDER_BIGENDIAN;
122 constexpr const char *res_str(SLresult result) noexcept
124 switch(result)
126 case SL_RESULT_SUCCESS: return "Success";
127 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
128 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
129 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
130 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
131 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
132 case SL_RESULT_IO_ERROR: return "I/O error";
133 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
134 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
135 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
136 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
137 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
138 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
139 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
140 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
141 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
142 case SL_RESULT_CONTROL_LOST: return "Control lost";
143 #ifdef SL_RESULT_READONLY
144 case SL_RESULT_READONLY: return "ReadOnly";
145 #endif
146 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
147 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
148 #endif
149 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
150 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
151 #endif
153 return "Unknown error code";
156 inline void PrintErr(SLresult res, const char *str)
158 if(res != SL_RESULT_SUCCESS) UNLIKELY
159 ERR("%s: %s\n", str, res_str(res));
163 struct OpenSLPlayback final : public BackendBase {
164 OpenSLPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
165 ~OpenSLPlayback() override;
167 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
169 int mixerProc();
171 void open(std::string_view name) override;
172 bool reset() override;
173 void start() override;
174 void stop() override;
175 ClockLatency getClockLatency() override;
177 /* engine interfaces */
178 SLObjectItf mEngineObj{nullptr};
179 SLEngineItf mEngine{nullptr};
181 /* output mix interfaces */
182 SLObjectItf mOutputMix{nullptr};
184 /* buffer queue player interfaces */
185 SLObjectItf mBufferQueueObj{nullptr};
187 RingBufferPtr mRing{nullptr};
188 al::semaphore mSem;
190 std::mutex mMutex;
192 uint mFrameSize{0};
194 std::atomic<bool> mKillNow{true};
195 std::thread mThread;
198 OpenSLPlayback::~OpenSLPlayback()
200 if(mBufferQueueObj)
201 VCALL0(mBufferQueueObj,Destroy)();
202 mBufferQueueObj = nullptr;
204 if(mOutputMix)
205 VCALL0(mOutputMix,Destroy)();
206 mOutputMix = nullptr;
208 if(mEngineObj)
209 VCALL0(mEngineObj,Destroy)();
210 mEngineObj = nullptr;
211 mEngine = nullptr;
215 /* this callback handler is called every time a buffer finishes playing */
216 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) noexcept
218 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
219 * pointer passed to the Enqueue method, rather than copying the audio.
220 * Consequently, the ringbuffer contains the audio that is currently queued
221 * and waiting to play. This process() callback is called when a buffer is
222 * finished, so we simply move the read pointer up to indicate the space is
223 * available for writing again, and wake up the mixer thread to mix and
224 * queue more audio.
226 mRing->readAdvance(1);
228 mSem.post();
231 int OpenSLPlayback::mixerProc()
233 SetRTPriority();
234 althrd_setname(GetMixerThreadName());
236 SLPlayItf player;
237 SLAndroidSimpleBufferQueueItf bufferQueue;
238 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
239 &bufferQueue)};
240 PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
241 if(SL_RESULT_SUCCESS == result)
243 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
244 PrintErr(result, "bufferQueue->GetInterface SL_IID_PLAY");
247 const size_t frame_step{mDevice->channelsFromFmt()};
249 if(SL_RESULT_SUCCESS != result)
250 mDevice->handleDisconnect("Failed to get playback buffer: 0x%08x", result);
252 while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire)
253 && mDevice->Connected.load(std::memory_order_acquire))
255 if(mRing->writeSpace() == 0)
257 SLuint32 state{0};
259 result = VCALL(player,GetPlayState)(&state);
260 PrintErr(result, "player->GetPlayState");
261 if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
263 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
264 PrintErr(result, "player->SetPlayState");
266 if(SL_RESULT_SUCCESS != result)
268 mDevice->handleDisconnect("Failed to start playback: 0x%08x", result);
269 break;
272 if(mRing->writeSpace() == 0)
274 mSem.wait();
275 continue;
279 std::unique_lock<std::mutex> dlock{mMutex};
280 auto data = mRing->getWriteVector();
281 mDevice->renderSamples(data.first.buf,
282 static_cast<uint>(data.first.len)*mDevice->UpdateSize, frame_step);
283 if(data.second.len > 0)
284 mDevice->renderSamples(data.second.buf,
285 static_cast<uint>(data.second.len)*mDevice->UpdateSize, frame_step);
287 size_t todo{data.first.len + data.second.len};
288 mRing->writeAdvance(todo);
289 dlock.unlock();
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, mDevice->UpdateSize*mFrameSize);
301 PrintErr(result, "bufferQueue->Enqueue");
302 if(SL_RESULT_SUCCESS != result)
304 mDevice->handleDisconnect("Failed to queue audio: 0x%08x", result);
305 break;
308 data.first.len--;
309 data.first.buf += mDevice->UpdateSize*mFrameSize;
313 return 0;
317 void OpenSLPlayback::open(std::string_view name)
319 if(name.empty())
320 name = GetDeviceName();
321 else if(name != GetDeviceName())
322 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
323 al::sizei(name), name.data()};
325 /* There's only one device, so if it's already open, there's nothing to do. */
326 if(mEngineObj) return;
328 // create engine
329 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
330 PrintErr(result, "slCreateEngine");
331 if(SL_RESULT_SUCCESS == result)
333 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
334 PrintErr(result, "engine->Realize");
336 if(SL_RESULT_SUCCESS == result)
338 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
339 PrintErr(result, "engine->GetInterface");
341 if(SL_RESULT_SUCCESS == result)
343 result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr);
344 PrintErr(result, "engine->CreateOutputMix");
346 if(SL_RESULT_SUCCESS == result)
348 result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE);
349 PrintErr(result, "outputMix->Realize");
352 if(SL_RESULT_SUCCESS != result)
354 if(mOutputMix)
355 VCALL0(mOutputMix,Destroy)();
356 mOutputMix = nullptr;
358 if(mEngineObj)
359 VCALL0(mEngineObj,Destroy)();
360 mEngineObj = nullptr;
361 mEngine = nullptr;
363 throw al::backend_exception{al::backend_error::DeviceError,
364 "Failed to initialize OpenSL device: 0x%08x", result};
367 mDeviceName = name;
370 bool OpenSLPlayback::reset()
372 SLresult result;
374 if(mBufferQueueObj)
375 VCALL0(mBufferQueueObj,Destroy)();
376 mBufferQueueObj = nullptr;
378 mRing = nullptr;
380 mDevice->FmtChans = DevFmtStereo;
381 mDevice->FmtType = DevFmtShort;
383 setDefaultWFXChannelOrder();
384 mFrameSize = mDevice->frameSizeFromFmt();
387 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
388 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
390 SLDataLocator_OutputMix loc_outmix{};
391 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
392 loc_outmix.outputMix = mOutputMix;
394 SLDataSink audioSnk{};
395 audioSnk.pLocator = &loc_outmix;
396 audioSnk.pFormat = nullptr;
398 SLDataLocator_AndroidSimpleBufferQueue loc_bufq{};
399 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
400 loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
402 SLDataSource audioSrc{};
403 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
404 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
405 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
406 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
407 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
408 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
409 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
410 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
411 format_pcm_ex.endianness = GetByteOrderEndianness();
412 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
414 audioSrc.pLocator = &loc_bufq;
415 audioSrc.pFormat = &format_pcm_ex;
417 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
418 ids.data(), reqs.data());
419 if(SL_RESULT_SUCCESS != result)
420 #endif
422 /* Alter sample type according to what SLDataFormat_PCM can support. */
423 switch(mDevice->FmtType)
425 case DevFmtByte: mDevice->FmtType = DevFmtUByte; break;
426 case DevFmtUInt: mDevice->FmtType = DevFmtInt; break;
427 case DevFmtFloat:
428 case DevFmtUShort: mDevice->FmtType = DevFmtShort; break;
429 case DevFmtUByte:
430 case DevFmtShort:
431 case DevFmtInt:
432 break;
435 SLDataFormat_PCM format_pcm{};
436 format_pcm.formatType = SL_DATAFORMAT_PCM;
437 format_pcm.numChannels = mDevice->channelsFromFmt();
438 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
439 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
440 format_pcm.containerSize = format_pcm.bitsPerSample;
441 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
442 format_pcm.endianness = GetByteOrderEndianness();
444 audioSrc.pLocator = &loc_bufq;
445 audioSrc.pFormat = &format_pcm;
447 result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
448 ids.data(), reqs.data());
449 PrintErr(result, "engine->CreateAudioPlayer");
451 if(SL_RESULT_SUCCESS == result)
453 /* Set the stream type to "media" (games, music, etc), if possible. */
454 SLAndroidConfigurationItf config;
455 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
456 PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
457 if(SL_RESULT_SUCCESS == result)
459 SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
460 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType,
461 sizeof(streamType));
462 PrintErr(result, "config->SetConfiguration");
465 /* Clear any error since this was optional. */
466 result = SL_RESULT_SUCCESS;
468 if(SL_RESULT_SUCCESS == result)
470 result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
471 PrintErr(result, "bufferQueue->Realize");
473 if(SL_RESULT_SUCCESS == result)
475 const uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
476 mRing = RingBuffer::Create(num_updates, mFrameSize*mDevice->UpdateSize, true);
479 if(SL_RESULT_SUCCESS != result)
481 if(mBufferQueueObj)
482 VCALL0(mBufferQueueObj,Destroy)();
483 mBufferQueueObj = nullptr;
485 return false;
488 return true;
491 void OpenSLPlayback::start()
493 mRing->reset();
495 SLAndroidSimpleBufferQueueItf bufferQueue;
496 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
497 &bufferQueue)};
498 PrintErr(result, "bufferQueue->GetInterface");
499 if(SL_RESULT_SUCCESS == result)
501 result = VCALL(bufferQueue,RegisterCallback)(
502 [](SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
503 { static_cast<OpenSLPlayback*>(context)->process(bq); }, this);
504 PrintErr(result, "bufferQueue->RegisterCallback");
506 if(SL_RESULT_SUCCESS != result)
507 throw al::backend_exception{al::backend_error::DeviceError,
508 "Failed to register callback: 0x%08x", result};
510 try {
511 mKillNow.store(false, std::memory_order_release);
512 mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this);
514 catch(std::exception& e) {
515 throw al::backend_exception{al::backend_error::DeviceError,
516 "Failed to start mixing thread: %s", e.what()};
520 void OpenSLPlayback::stop()
522 if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
523 return;
525 mSem.post();
526 mThread.join();
528 SLPlayItf player;
529 SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)};
530 PrintErr(result, "bufferQueue->GetInterface");
531 if(SL_RESULT_SUCCESS == result)
533 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
534 PrintErr(result, "player->SetPlayState");
537 SLAndroidSimpleBufferQueueItf bufferQueue;
538 result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
539 PrintErr(result, "bufferQueue->GetInterface");
540 if(SL_RESULT_SUCCESS == result)
542 result = VCALL0(bufferQueue,Clear)();
543 PrintErr(result, "bufferQueue->Clear");
545 if(SL_RESULT_SUCCESS == result)
547 result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr);
548 PrintErr(result, "bufferQueue->RegisterCallback");
550 if(SL_RESULT_SUCCESS == result)
552 SLAndroidSimpleBufferQueueState state;
553 do {
554 std::this_thread::yield();
555 result = VCALL(bufferQueue,GetState)(&state);
556 } while(SL_RESULT_SUCCESS == result && state.count > 0);
557 PrintErr(result, "bufferQueue->GetState");
559 mRing->reset();
563 ClockLatency OpenSLPlayback::getClockLatency()
565 ClockLatency ret;
567 std::lock_guard<std::mutex> dlock{mMutex};
568 ret.ClockTime = mDevice->getClockTime();
569 ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize};
570 ret.Latency /= mDevice->Frequency;
572 return ret;
576 struct OpenSLCapture final : public BackendBase {
577 OpenSLCapture(DeviceBase *device) noexcept : BackendBase{device} { }
578 ~OpenSLCapture() override;
580 void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
582 void open(std::string_view name) override;
583 void start() override;
584 void stop() override;
585 void captureSamples(std::byte *buffer, uint samples) override;
586 uint availableSamples() override;
588 /* engine interfaces */
589 SLObjectItf mEngineObj{nullptr};
590 SLEngineItf mEngine;
592 /* recording interfaces */
593 SLObjectItf mRecordObj{nullptr};
595 RingBufferPtr mRing{nullptr};
596 uint mSplOffset{0u};
598 uint mFrameSize{0};
601 OpenSLCapture::~OpenSLCapture()
603 if(mRecordObj)
604 VCALL0(mRecordObj,Destroy)();
605 mRecordObj = nullptr;
607 if(mEngineObj)
608 VCALL0(mEngineObj,Destroy)();
609 mEngineObj = nullptr;
610 mEngine = nullptr;
614 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept
616 /* A new chunk has been written into the ring buffer, advance it. */
617 mRing->writeAdvance(1);
621 void OpenSLCapture::open(std::string_view name)
623 if(name.empty())
624 name = GetDeviceName();
625 else if(name != GetDeviceName())
626 throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
627 al::sizei(name), name.data()};
629 SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
630 PrintErr(result, "slCreateEngine");
631 if(SL_RESULT_SUCCESS == result)
633 result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
634 PrintErr(result, "engine->Realize");
636 if(SL_RESULT_SUCCESS == result)
638 result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
639 PrintErr(result, "engine->GetInterface");
641 if(SL_RESULT_SUCCESS == result)
643 mFrameSize = mDevice->frameSizeFromFmt();
644 /* Ensure the total length is at least 100ms */
645 uint length{std::max(mDevice->BufferSize, mDevice->Frequency/10u)};
646 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
647 uint update_len{std::clamp(mDevice->BufferSize/3u, mDevice->Frequency/100u,
648 mDevice->Frequency/100u*5u)};
649 uint num_updates{(length+update_len-1) / update_len};
651 mRing = RingBuffer::Create(num_updates, update_len*mFrameSize, false);
653 mDevice->UpdateSize = update_len;
654 mDevice->BufferSize = static_cast<uint>(mRing->writeSpace() * update_len);
656 if(SL_RESULT_SUCCESS == result)
658 const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
659 const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
661 SLDataLocator_IODevice loc_dev{};
662 loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
663 loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
664 loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
665 loc_dev.device = nullptr;
667 SLDataSource audioSrc{};
668 audioSrc.pLocator = &loc_dev;
669 audioSrc.pFormat = nullptr;
671 SLDataLocator_AndroidSimpleBufferQueue loc_bq{};
672 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
673 loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
675 SLDataSink audioSnk{};
676 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
677 SLAndroidDataFormat_PCM_EX format_pcm_ex{};
678 format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
679 format_pcm_ex.numChannels = mDevice->channelsFromFmt();
680 format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
681 format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
682 format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
683 format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
684 format_pcm_ex.endianness = GetByteOrderEndianness();
685 format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
687 audioSnk.pLocator = &loc_bq;
688 audioSnk.pFormat = &format_pcm_ex;
689 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
690 ids.size(), ids.data(), reqs.data());
691 if(SL_RESULT_SUCCESS != result)
692 #endif
694 /* Fallback to SLDataFormat_PCM only if it supports the desired
695 * sample type.
697 if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtShort
698 || mDevice->FmtType == DevFmtInt)
700 SLDataFormat_PCM format_pcm{};
701 format_pcm.formatType = SL_DATAFORMAT_PCM;
702 format_pcm.numChannels = mDevice->channelsFromFmt();
703 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
704 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
705 format_pcm.containerSize = format_pcm.bitsPerSample;
706 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
707 format_pcm.endianness = GetByteOrderEndianness();
709 audioSnk.pLocator = &loc_bq;
710 audioSnk.pFormat = &format_pcm;
711 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
712 ids.size(), ids.data(), reqs.data());
714 PrintErr(result, "engine->CreateAudioRecorder");
717 if(SL_RESULT_SUCCESS == result)
719 /* Set the record preset to "generic", if possible. */
720 SLAndroidConfigurationItf config;
721 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
722 PrintErr(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
723 if(SL_RESULT_SUCCESS == result)
725 SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
726 result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset,
727 sizeof(preset));
728 PrintErr(result, "config->SetConfiguration");
731 /* Clear any error since this was optional. */
732 result = SL_RESULT_SUCCESS;
734 if(SL_RESULT_SUCCESS == result)
736 result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE);
737 PrintErr(result, "recordObj->Realize");
740 SLAndroidSimpleBufferQueueItf bufferQueue;
741 if(SL_RESULT_SUCCESS == result)
743 result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
744 PrintErr(result, "recordObj->GetInterface");
746 if(SL_RESULT_SUCCESS == result)
748 result = VCALL(bufferQueue,RegisterCallback)(
749 [](SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
750 { static_cast<OpenSLCapture*>(context)->process(bq); }, this);
751 PrintErr(result, "bufferQueue->RegisterCallback");
753 if(SL_RESULT_SUCCESS == result)
755 const uint chunk_size{mDevice->UpdateSize * mFrameSize};
756 const auto silence = (mDevice->FmtType == DevFmtUByte) ? std::byte{0x80} : std::byte{0};
758 auto data = mRing->getWriteVector();
759 std::fill_n(data.first.buf, data.first.len*chunk_size, silence);
760 std::fill_n(data.second.buf, data.second.len*chunk_size, silence);
761 for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++)
763 result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size);
764 PrintErr(result, "bufferQueue->Enqueue");
766 for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++)
768 result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size);
769 PrintErr(result, "bufferQueue->Enqueue");
773 if(SL_RESULT_SUCCESS != result)
775 if(mRecordObj)
776 VCALL0(mRecordObj,Destroy)();
777 mRecordObj = nullptr;
779 if(mEngineObj)
780 VCALL0(mEngineObj,Destroy)();
781 mEngineObj = nullptr;
782 mEngine = nullptr;
784 throw al::backend_exception{al::backend_error::DeviceError,
785 "Failed to initialize OpenSL device: 0x%08x", result};
788 mDeviceName = name;
791 void OpenSLCapture::start()
793 SLRecordItf record;
794 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
795 PrintErr(result, "recordObj->GetInterface");
797 if(SL_RESULT_SUCCESS == result)
799 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
800 PrintErr(result, "record->SetRecordState");
802 if(SL_RESULT_SUCCESS != result)
803 throw al::backend_exception{al::backend_error::DeviceError,
804 "Failed to start capture: 0x%08x", result};
807 void OpenSLCapture::stop()
809 SLRecordItf record;
810 SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
811 PrintErr(result, "recordObj->GetInterface");
813 if(SL_RESULT_SUCCESS == result)
815 result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
816 PrintErr(result, "record->SetRecordState");
820 void OpenSLCapture::captureSamples(std::byte *buffer, uint samples)
822 const uint update_size{mDevice->UpdateSize};
823 const uint chunk_size{update_size * mFrameSize};
825 /* Read the desired samples from the ring buffer then advance its read
826 * pointer.
828 size_t adv_count{0};
829 auto rdata = mRing->getReadVector();
830 for(uint i{0};i < samples;)
832 const uint rem{std::min(samples - i, update_size - mSplOffset)};
833 std::copy_n(rdata.first.buf + mSplOffset*size_t{mFrameSize}, rem*size_t{mFrameSize},
834 buffer + i*size_t{mFrameSize});
836 mSplOffset += rem;
837 if(mSplOffset == update_size)
839 /* Finished a chunk, reset the offset and advance the read pointer. */
840 mSplOffset = 0;
842 ++adv_count;
843 rdata.first.len -= 1;
844 if(!rdata.first.len)
845 rdata.first = rdata.second;
846 else
847 rdata.first.buf += chunk_size;
850 i += rem;
853 SLAndroidSimpleBufferQueueItf bufferQueue{};
854 if(mDevice->Connected.load(std::memory_order_acquire)) LIKELY
856 const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
857 &bufferQueue)};
858 PrintErr(result, "recordObj->GetInterface");
859 if(SL_RESULT_SUCCESS != result) UNLIKELY
861 mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
862 bufferQueue = nullptr;
865 if(!bufferQueue || adv_count == 0)
866 return;
868 /* For each buffer chunk that was fully read, queue another writable buffer
869 * chunk to keep the OpenSL queue full. This is rather convoluted, as a
870 * result of the ring buffer holding more elements than are writable at a
871 * given time. The end of the write vector increments when the read pointer
872 * advances, which will "expose" a previously unwritable element. So for
873 * every element that we've finished reading, we queue that many elements
874 * from the end of the write vector.
876 mRing->readAdvance(adv_count);
878 SLresult result{SL_RESULT_SUCCESS};
879 auto wdata = mRing->getWriteVector();
880 if(adv_count > wdata.second.len) LIKELY
882 auto len1 = std::min(wdata.first.len, adv_count-wdata.second.len);
883 auto buf1 = wdata.first.buf + chunk_size*(wdata.first.len-len1);
884 for(size_t i{0u};i < len1 && SL_RESULT_SUCCESS == result;i++)
886 result = VCALL(bufferQueue,Enqueue)(buf1 + chunk_size*i, chunk_size);
887 PrintErr(result, "bufferQueue->Enqueue");
890 if(wdata.second.len > 0)
892 auto len2 = std::min(wdata.second.len, adv_count);
893 auto buf2 = wdata.second.buf + chunk_size*(wdata.second.len-len2);
894 for(size_t i{0u};i < len2 && SL_RESULT_SUCCESS == result;i++)
896 result = VCALL(bufferQueue,Enqueue)(buf2 + chunk_size*i, chunk_size);
897 PrintErr(result, "bufferQueue->Enqueue");
902 uint OpenSLCapture::availableSamples()
903 { return static_cast<uint>(mRing->readSpace()*mDevice->UpdateSize - mSplOffset); }
905 } // namespace
907 bool OSLBackendFactory::init() { return true; }
909 bool OSLBackendFactory::querySupport(BackendType type)
910 { return (type == BackendType::Playback || type == BackendType::Capture); }
912 auto OSLBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
914 switch(type)
916 case BackendType::Playback:
917 case BackendType::Capture:
918 return std::vector{std::string{GetDeviceName()}};
920 return {};
923 BackendPtr OSLBackendFactory::createBackend(DeviceBase *device, BackendType type)
925 if(type == BackendType::Playback)
926 return BackendPtr{new OpenSLPlayback{device}};
927 if(type == BackendType::Capture)
928 return BackendPtr{new OpenSLCapture{device}};
929 return nullptr;
932 BackendFactory &OSLBackendFactory::getFactory()
934 static OSLBackendFactory factory{};
935 return factory;