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
37 #include "alnumeric.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>
54 using namespace std::string_view_literals
;
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
; }
65 constexpr SLuint32
GetChannelMask(DevFmtChannels chans
) noexcept
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
;
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
;
95 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
96 constexpr SLuint32
GetTypeRepresentation(DevFmtType type
) noexcept
103 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
;
107 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
;
109 return SL_ANDROID_PCM_REPRESENTATION_FLOAT
;
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
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";
146 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
147 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
149 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
150 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
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
;
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};
194 std::atomic
<bool> mKillNow
{true};
198 OpenSLPlayback::~OpenSLPlayback()
201 VCALL0(mBufferQueueObj
,Destroy
)();
202 mBufferQueueObj
= nullptr;
205 VCALL0(mOutputMix
,Destroy
)();
206 mOutputMix
= nullptr;
209 VCALL0(mEngineObj
,Destroy
)();
210 mEngineObj
= 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
226 mRing
->readAdvance(1);
231 int OpenSLPlayback::mixerProc()
234 althrd_setname(GetMixerThreadName());
237 SLAndroidSimpleBufferQueueItf bufferQueue
;
238 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
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)
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
);
272 if(mRing
->writeSpace() == 0)
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
);
291 for(size_t i
{0};i
< todo
;i
++)
295 data
.first
= data
.second
;
296 data
.second
.buf
= nullptr;
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
);
309 data
.first
.buf
+= mDevice
->UpdateSize
*mFrameSize
;
317 void OpenSLPlayback::open(std::string_view name
)
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;
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
)
355 VCALL0(mOutputMix
,Destroy
)();
356 mOutputMix
= nullptr;
359 VCALL0(mEngineObj
,Destroy
)();
360 mEngineObj
= nullptr;
363 throw al::backend_exception
{al::backend_error::DeviceError
,
364 "Failed to initialize OpenSL device: 0x%08x", result
};
367 mDevice
->DeviceName
= name
;
370 bool OpenSLPlayback::reset()
375 VCALL0(mBufferQueueObj
,Destroy
)();
376 mBufferQueueObj
= 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
)
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;
428 case DevFmtUShort
: mDevice
->FmtType
= DevFmtShort
; 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
,
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
)
482 VCALL0(mBufferQueueObj
,Destroy
)();
483 mBufferQueueObj
= nullptr;
491 void OpenSLPlayback::start()
495 SLAndroidSimpleBufferQueueItf bufferQueue
;
496 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
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
};
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())
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
;
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");
563 ClockLatency
OpenSLPlayback::getClockLatency()
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
;
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};
592 /* recording interfaces */
593 SLObjectItf mRecordObj
{nullptr};
595 RingBufferPtr mRing
{nullptr};
601 OpenSLCapture::~OpenSLCapture()
604 VCALL0(mRecordObj
,Destroy
)();
605 mRecordObj
= nullptr;
608 VCALL0(mEngineObj
,Destroy
)();
609 mEngineObj
= 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
)
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
)
694 /* Fallback to SLDataFormat_PCM only if it supports the desired
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
,
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
)
776 VCALL0(mRecordObj
,Destroy
)();
777 mRecordObj
= nullptr;
780 VCALL0(mEngineObj
,Destroy
)();
781 mEngineObj
= nullptr;
784 throw al::backend_exception
{al::backend_error::DeviceError
,
785 "Failed to initialize OpenSL device: 0x%08x", result
};
788 mDevice
->DeviceName
= name
;
791 void OpenSLCapture::start()
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()
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
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
});
837 if(mSplOffset
== update_size
)
839 /* Finished a chunk, reset the offset and advance the read pointer. */
843 rdata
.first
.len
-= 1;
845 rdata
.first
= rdata
.second
;
847 rdata
.first
.buf
+= chunk_size
;
853 SLAndroidSimpleBufferQueueItf bufferQueue
{};
854 if(mDevice
->Connected
.load(std::memory_order_acquire
)) LIKELY
856 const SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
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)
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
); }
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
>
916 case BackendType::Playback
:
917 case BackendType::Capture
:
918 return std::vector
{std::string
{GetDeviceName()}};
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
}};
932 BackendFactory
&OSLBackendFactory::getFactory()
934 static OSLBackendFactory factory
{};