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
;
84 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
85 constexpr SLuint32
GetTypeRepresentation(DevFmtType type
) noexcept
92 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
;
96 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
;
98 return SL_ANDROID_PCM_REPRESENTATION_FLOAT
;
104 constexpr SLuint32
GetByteOrderEndianness() noexcept
106 if(al::endian::native
== al::endian::little
)
107 return SL_BYTEORDER_LITTLEENDIAN
;
108 return SL_BYTEORDER_BIGENDIAN
;
111 const char *res_str(SLresult result
) noexcept
115 case SL_RESULT_SUCCESS
: return "Success";
116 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
117 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
118 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
119 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
120 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
121 case SL_RESULT_IO_ERROR
: return "I/O error";
122 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
123 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
124 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
125 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
126 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
127 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
128 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
129 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
130 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
131 case SL_RESULT_CONTROL_LOST
: return "Control lost";
132 #ifdef SL_RESULT_READONLY
133 case SL_RESULT_READONLY
: return "ReadOnly";
135 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
136 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
138 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
139 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
142 return "Unknown error code";
145 #define PRINTERR(x, s) do { \
146 if UNLIKELY((x) != SL_RESULT_SUCCESS) \
147 ERR("%s: %s\n", (s), res_str((x))); \
151 struct OpenSLPlayback final
: public BackendBase
{
152 OpenSLPlayback(DeviceBase
*device
) noexcept
: BackendBase
{device
} { }
153 ~OpenSLPlayback() override
;
155 void process(SLAndroidSimpleBufferQueueItf bq
) noexcept
;
156 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
) noexcept
157 { static_cast<OpenSLPlayback
*>(context
)->process(bq
); }
161 void open(const char *name
) override
;
162 bool reset() override
;
163 void start() override
;
164 void stop() override
;
165 ClockLatency
getClockLatency() override
;
167 /* engine interfaces */
168 SLObjectItf mEngineObj
{nullptr};
169 SLEngineItf mEngine
{nullptr};
171 /* output mix interfaces */
172 SLObjectItf mOutputMix
{nullptr};
174 /* buffer queue player interfaces */
175 SLObjectItf mBufferQueueObj
{nullptr};
177 RingBufferPtr mRing
{nullptr};
184 std::atomic
<bool> mKillNow
{true};
187 DEF_NEWDEL(OpenSLPlayback
)
190 OpenSLPlayback::~OpenSLPlayback()
193 VCALL0(mBufferQueueObj
,Destroy
)();
194 mBufferQueueObj
= nullptr;
197 VCALL0(mOutputMix
,Destroy
)();
198 mOutputMix
= nullptr;
201 VCALL0(mEngineObj
,Destroy
)();
202 mEngineObj
= nullptr;
207 /* this callback handler is called every time a buffer finishes playing */
208 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf
) noexcept
210 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
211 * pointer passed to the Enqueue method, rather than copying the audio.
212 * Consequently, the ringbuffer contains the audio that is currently queued
213 * and waiting to play. This process() callback is called when a buffer is
214 * finished, so we simply move the read pointer up to indicate the space is
215 * available for writing again, and wake up the mixer thread to mix and
218 mRing
->readAdvance(1);
223 int OpenSLPlayback::mixerProc()
226 althrd_setname(MIXER_THREAD_NAME
);
229 SLAndroidSimpleBufferQueueItf bufferQueue
;
230 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
232 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
233 if(SL_RESULT_SUCCESS
== result
)
235 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
236 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
239 const size_t frame_step
{mDevice
->channelsFromFmt()};
241 if(SL_RESULT_SUCCESS
!= result
)
242 mDevice
->handleDisconnect("Failed to get playback buffer: 0x%08x", result
);
244 while(SL_RESULT_SUCCESS
== result
&& !mKillNow
.load(std::memory_order_acquire
)
245 && mDevice
->Connected
.load(std::memory_order_acquire
))
247 if(mRing
->writeSpace() == 0)
251 result
= VCALL(player
,GetPlayState
)(&state
);
252 PRINTERR(result
, "player->GetPlayState");
253 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
255 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
256 PRINTERR(result
, "player->SetPlayState");
258 if(SL_RESULT_SUCCESS
!= result
)
260 mDevice
->handleDisconnect("Failed to start playback: 0x%08x", result
);
264 if(mRing
->writeSpace() == 0)
271 std::unique_lock
<std::mutex
> dlock
{mMutex
};
272 auto data
= mRing
->getWriteVector();
273 mDevice
->renderSamples(data
.first
.buf
,
274 static_cast<uint
>(data
.first
.len
)*mDevice
->UpdateSize
, frame_step
);
275 if(data
.second
.len
> 0)
276 mDevice
->renderSamples(data
.second
.buf
,
277 static_cast<uint
>(data
.second
.len
)*mDevice
->UpdateSize
, frame_step
);
279 size_t todo
{data
.first
.len
+ data
.second
.len
};
280 mRing
->writeAdvance(todo
);
283 for(size_t i
{0};i
< todo
;i
++)
287 data
.first
= data
.second
;
288 data
.second
.buf
= nullptr;
292 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
, mDevice
->UpdateSize
*mFrameSize
);
293 PRINTERR(result
, "bufferQueue->Enqueue");
294 if(SL_RESULT_SUCCESS
!= result
)
296 mDevice
->handleDisconnect("Failed to queue audio: 0x%08x", result
);
301 data
.first
.buf
+= mDevice
->UpdateSize
*mFrameSize
;
309 void OpenSLPlayback::open(const char *name
)
312 name
= opensl_device
;
313 else if(strcmp(name
, opensl_device
) != 0)
314 throw al::backend_exception
{al::backend_error::NoDevice
, "Device name \"%s\" not found",
317 /* There's only one device, so if it's already open, there's nothing to do. */
318 if(mEngineObj
) return;
321 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
322 PRINTERR(result
, "slCreateEngine");
323 if(SL_RESULT_SUCCESS
== result
)
325 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
326 PRINTERR(result
, "engine->Realize");
328 if(SL_RESULT_SUCCESS
== result
)
330 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
331 PRINTERR(result
, "engine->GetInterface");
333 if(SL_RESULT_SUCCESS
== result
)
335 result
= VCALL(mEngine
,CreateOutputMix
)(&mOutputMix
, 0, nullptr, nullptr);
336 PRINTERR(result
, "engine->CreateOutputMix");
338 if(SL_RESULT_SUCCESS
== result
)
340 result
= VCALL(mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
341 PRINTERR(result
, "outputMix->Realize");
344 if(SL_RESULT_SUCCESS
!= result
)
347 VCALL0(mOutputMix
,Destroy
)();
348 mOutputMix
= nullptr;
351 VCALL0(mEngineObj
,Destroy
)();
352 mEngineObj
= nullptr;
355 throw al::backend_exception
{al::backend_error::DeviceError
,
356 "Failed to initialize OpenSL device: 0x%08x", result
};
359 mDevice
->DeviceName
= name
;
362 bool OpenSLPlayback::reset()
367 VCALL0(mBufferQueueObj
,Destroy
)();
368 mBufferQueueObj
= nullptr;
373 if(!mDevice
->Flags
.get
<FrequencyRequest
>())
375 /* FIXME: Disabled until I figure out how to get the Context needed for
376 * the getSystemService call.
378 JNIEnv
*env
= Android_GetJNIEnv();
379 jobject jctx
= Android_GetContext();
381 /* Get necessary stuff for using java.lang.Integer,
382 * android.content.Context, and android.media.AudioManager.
384 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
385 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
386 "parseInt", "(Ljava/lang/String;)I"
388 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
390 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
391 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
392 "AUDIO_SERVICE", "Ljava/lang/String;"
394 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
395 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
397 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
398 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
400 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
401 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
402 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
404 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
405 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
407 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
408 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
410 const char *strchars
;
413 /* Now make the calls. */
414 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
415 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
416 jobject audMgr
= JCALL(env
,CallObjectMethod
)(jctx
, ctx_getSysSvc
, strobj
);
417 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
418 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
419 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
421 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
422 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
423 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
424 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
425 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
426 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
428 //int sampleRate = Integer.parseInt(srateStr);
429 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
431 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, nullptr);
432 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
433 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
435 if(!sampleRate
) sampleRate
= device
->Frequency
;
436 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
440 mDevice
->FmtChans
= DevFmtStereo
;
441 mDevice
->FmtType
= DevFmtShort
;
443 setDefaultWFXChannelOrder();
444 mFrameSize
= mDevice
->frameSizeFromFmt();
447 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
448 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
450 SLDataLocator_OutputMix loc_outmix
{};
451 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
452 loc_outmix
.outputMix
= mOutputMix
;
454 SLDataSink audioSnk
{};
455 audioSnk
.pLocator
= &loc_outmix
;
456 audioSnk
.pFormat
= nullptr;
458 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
{};
459 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
460 loc_bufq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
462 SLDataSource audioSrc
{};
463 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
464 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
465 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
466 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
467 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
468 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
469 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
470 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
471 format_pcm_ex
.endianness
= GetByteOrderEndianness();
472 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
474 audioSrc
.pLocator
= &loc_bufq
;
475 audioSrc
.pFormat
= &format_pcm_ex
;
477 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
478 ids
.data(), reqs
.data());
479 if(SL_RESULT_SUCCESS
!= result
)
482 /* Alter sample type according to what SLDataFormat_PCM can support. */
483 switch(mDevice
->FmtType
)
485 case DevFmtByte
: mDevice
->FmtType
= DevFmtUByte
; break;
486 case DevFmtUInt
: mDevice
->FmtType
= DevFmtInt
; break;
488 case DevFmtUShort
: mDevice
->FmtType
= DevFmtShort
; break;
495 SLDataFormat_PCM format_pcm
{};
496 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
497 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
498 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
499 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
500 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
501 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
502 format_pcm
.endianness
= GetByteOrderEndianness();
504 audioSrc
.pLocator
= &loc_bufq
;
505 audioSrc
.pFormat
= &format_pcm
;
507 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
508 ids
.data(), reqs
.data());
509 PRINTERR(result
, "engine->CreateAudioPlayer");
511 if(SL_RESULT_SUCCESS
== result
)
513 /* Set the stream type to "media" (games, music, etc), if possible. */
514 SLAndroidConfigurationItf config
;
515 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
516 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
517 if(SL_RESULT_SUCCESS
== result
)
519 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
520 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
, &streamType
,
522 PRINTERR(result
, "config->SetConfiguration");
525 /* Clear any error since this was optional. */
526 result
= SL_RESULT_SUCCESS
;
528 if(SL_RESULT_SUCCESS
== result
)
530 result
= VCALL(mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
531 PRINTERR(result
, "bufferQueue->Realize");
533 if(SL_RESULT_SUCCESS
== result
)
535 const uint num_updates
{mDevice
->BufferSize
/ mDevice
->UpdateSize
};
536 mRing
= RingBuffer::Create(num_updates
, mFrameSize
*mDevice
->UpdateSize
, true);
539 if(SL_RESULT_SUCCESS
!= result
)
542 VCALL0(mBufferQueueObj
,Destroy
)();
543 mBufferQueueObj
= nullptr;
551 void OpenSLPlayback::start()
555 SLAndroidSimpleBufferQueueItf bufferQueue
;
556 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
558 PRINTERR(result
, "bufferQueue->GetInterface");
559 if(SL_RESULT_SUCCESS
== result
)
561 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLPlayback::processC
, this);
562 PRINTERR(result
, "bufferQueue->RegisterCallback");
564 if(SL_RESULT_SUCCESS
!= result
)
565 throw al::backend_exception
{al::backend_error::DeviceError
,
566 "Failed to register callback: 0x%08x", result
};
569 mKillNow
.store(false, std::memory_order_release
);
570 mThread
= std::thread(std::mem_fn(&OpenSLPlayback::mixerProc
), this);
572 catch(std::exception
& e
) {
573 throw al::backend_exception
{al::backend_error::DeviceError
,
574 "Failed to start mixing thread: %s", e
.what()};
578 void OpenSLPlayback::stop()
580 if(mKillNow
.exchange(true, std::memory_order_acq_rel
) || !mThread
.joinable())
587 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
)};
588 PRINTERR(result
, "bufferQueue->GetInterface");
589 if(SL_RESULT_SUCCESS
== result
)
591 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
592 PRINTERR(result
, "player->SetPlayState");
595 SLAndroidSimpleBufferQueueItf bufferQueue
;
596 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
597 PRINTERR(result
, "bufferQueue->GetInterface");
598 if(SL_RESULT_SUCCESS
== result
)
600 result
= VCALL0(bufferQueue
,Clear
)();
601 PRINTERR(result
, "bufferQueue->Clear");
603 if(SL_RESULT_SUCCESS
== result
)
605 result
= VCALL(bufferQueue
,RegisterCallback
)(nullptr, nullptr);
606 PRINTERR(result
, "bufferQueue->RegisterCallback");
608 if(SL_RESULT_SUCCESS
== result
)
610 SLAndroidSimpleBufferQueueState state
;
612 std::this_thread::yield();
613 result
= VCALL(bufferQueue
,GetState
)(&state
);
614 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
615 PRINTERR(result
, "bufferQueue->GetState");
621 ClockLatency
OpenSLPlayback::getClockLatency()
625 std::lock_guard
<std::mutex
> _
{mMutex
};
626 ret
.ClockTime
= GetDeviceClockTime(mDevice
);
627 ret
.Latency
= std::chrono::seconds
{mRing
->readSpace() * mDevice
->UpdateSize
};
628 ret
.Latency
/= mDevice
->Frequency
;
634 struct OpenSLCapture final
: public BackendBase
{
635 OpenSLCapture(DeviceBase
*device
) noexcept
: BackendBase
{device
} { }
636 ~OpenSLCapture() override
;
638 void process(SLAndroidSimpleBufferQueueItf bq
) noexcept
;
639 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
) noexcept
640 { static_cast<OpenSLCapture
*>(context
)->process(bq
); }
642 void open(const char *name
) override
;
643 void start() override
;
644 void stop() override
;
645 void captureSamples(al::byte
*buffer
, uint samples
) override
;
646 uint
availableSamples() override
;
648 /* engine interfaces */
649 SLObjectItf mEngineObj
{nullptr};
652 /* recording interfaces */
653 SLObjectItf mRecordObj
{nullptr};
655 RingBufferPtr mRing
{nullptr};
660 DEF_NEWDEL(OpenSLCapture
)
663 OpenSLCapture::~OpenSLCapture()
666 VCALL0(mRecordObj
,Destroy
)();
667 mRecordObj
= nullptr;
670 VCALL0(mEngineObj
,Destroy
)();
671 mEngineObj
= nullptr;
676 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf
) noexcept
678 /* A new chunk has been written into the ring buffer, advance it. */
679 mRing
->writeAdvance(1);
683 void OpenSLCapture::open(const char* name
)
686 name
= opensl_device
;
687 else if(strcmp(name
, opensl_device
) != 0)
688 throw al::backend_exception
{al::backend_error::NoDevice
, "Device name \"%s\" not found",
691 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
692 PRINTERR(result
, "slCreateEngine");
693 if(SL_RESULT_SUCCESS
== result
)
695 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
696 PRINTERR(result
, "engine->Realize");
698 if(SL_RESULT_SUCCESS
== result
)
700 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
701 PRINTERR(result
, "engine->GetInterface");
703 if(SL_RESULT_SUCCESS
== result
)
705 mFrameSize
= mDevice
->frameSizeFromFmt();
706 /* Ensure the total length is at least 100ms */
707 uint length
{maxu(mDevice
->BufferSize
, mDevice
->Frequency
/10)};
708 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
709 uint update_len
{clampu(mDevice
->BufferSize
/3, mDevice
->Frequency
/100,
710 mDevice
->Frequency
/100*5)};
711 uint num_updates
{(length
+update_len
-1) / update_len
};
713 mRing
= RingBuffer::Create(num_updates
, update_len
*mFrameSize
, false);
715 mDevice
->UpdateSize
= update_len
;
716 mDevice
->BufferSize
= static_cast<uint
>(mRing
->writeSpace() * update_len
);
718 if(SL_RESULT_SUCCESS
== result
)
720 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
721 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
723 SLDataLocator_IODevice loc_dev
{};
724 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
725 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
726 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
727 loc_dev
.device
= nullptr;
729 SLDataSource audioSrc
{};
730 audioSrc
.pLocator
= &loc_dev
;
731 audioSrc
.pFormat
= nullptr;
733 SLDataLocator_AndroidSimpleBufferQueue loc_bq
{};
734 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
735 loc_bq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
737 SLDataSink audioSnk
{};
738 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
739 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
740 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
741 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
742 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
743 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
744 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
745 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
746 format_pcm_ex
.endianness
= GetByteOrderEndianness();
747 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
749 audioSnk
.pLocator
= &loc_bq
;
750 audioSnk
.pFormat
= &format_pcm_ex
;
751 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
752 ids
.size(), ids
.data(), reqs
.data());
753 if(SL_RESULT_SUCCESS
!= result
)
756 /* Fallback to SLDataFormat_PCM only if it supports the desired
759 if(mDevice
->FmtType
== DevFmtUByte
|| mDevice
->FmtType
== DevFmtShort
760 || mDevice
->FmtType
== DevFmtInt
)
762 SLDataFormat_PCM format_pcm
{};
763 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
764 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
765 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
766 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
767 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
768 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
769 format_pcm
.endianness
= GetByteOrderEndianness();
771 audioSnk
.pLocator
= &loc_bq
;
772 audioSnk
.pFormat
= &format_pcm
;
773 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
774 ids
.size(), ids
.data(), reqs
.data());
776 PRINTERR(result
, "engine->CreateAudioRecorder");
779 if(SL_RESULT_SUCCESS
== result
)
781 /* Set the record preset to "generic", if possible. */
782 SLAndroidConfigurationItf config
;
783 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
784 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
785 if(SL_RESULT_SUCCESS
== result
)
787 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
788 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
, &preset
,
790 PRINTERR(result
, "config->SetConfiguration");
793 /* Clear any error since this was optional. */
794 result
= SL_RESULT_SUCCESS
;
796 if(SL_RESULT_SUCCESS
== result
)
798 result
= VCALL(mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
799 PRINTERR(result
, "recordObj->Realize");
802 SLAndroidSimpleBufferQueueItf bufferQueue
;
803 if(SL_RESULT_SUCCESS
== result
)
805 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
806 PRINTERR(result
, "recordObj->GetInterface");
808 if(SL_RESULT_SUCCESS
== result
)
810 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLCapture::processC
, this);
811 PRINTERR(result
, "bufferQueue->RegisterCallback");
813 if(SL_RESULT_SUCCESS
== result
)
815 const uint chunk_size
{mDevice
->UpdateSize
* mFrameSize
};
816 const auto silence
= (mDevice
->FmtType
== DevFmtUByte
) ? al::byte
{0x80} : al::byte
{0};
818 auto data
= mRing
->getWriteVector();
819 std::fill_n(data
.first
.buf
, data
.first
.len
*chunk_size
, silence
);
820 std::fill_n(data
.second
.buf
, data
.second
.len
*chunk_size
, silence
);
821 for(size_t i
{0u};i
< data
.first
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
823 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
+ chunk_size
*i
, chunk_size
);
824 PRINTERR(result
, "bufferQueue->Enqueue");
826 for(size_t i
{0u};i
< data
.second
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
828 result
= VCALL(bufferQueue
,Enqueue
)(data
.second
.buf
+ chunk_size
*i
, chunk_size
);
829 PRINTERR(result
, "bufferQueue->Enqueue");
833 if(SL_RESULT_SUCCESS
!= result
)
836 VCALL0(mRecordObj
,Destroy
)();
837 mRecordObj
= nullptr;
840 VCALL0(mEngineObj
,Destroy
)();
841 mEngineObj
= nullptr;
844 throw al::backend_exception
{al::backend_error::DeviceError
,
845 "Failed to initialize OpenSL device: 0x%08x", result
};
848 mDevice
->DeviceName
= name
;
851 void OpenSLCapture::start()
854 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
)};
855 PRINTERR(result
, "recordObj->GetInterface");
857 if(SL_RESULT_SUCCESS
== result
)
859 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_RECORDING
);
860 PRINTERR(result
, "record->SetRecordState");
862 if(SL_RESULT_SUCCESS
!= result
)
863 throw al::backend_exception
{al::backend_error::DeviceError
,
864 "Failed to start capture: 0x%08x", result
};
867 void OpenSLCapture::stop()
870 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
)};
871 PRINTERR(result
, "recordObj->GetInterface");
873 if(SL_RESULT_SUCCESS
== result
)
875 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
876 PRINTERR(result
, "record->SetRecordState");
880 void OpenSLCapture::captureSamples(al::byte
*buffer
, uint samples
)
882 const uint update_size
{mDevice
->UpdateSize
};
883 const uint chunk_size
{update_size
* mFrameSize
};
884 const auto silence
= (mDevice
->FmtType
== DevFmtUByte
) ? al::byte
{0x80} : al::byte
{0};
886 /* Read the desired samples from the ring buffer then advance its read
890 auto rdata
= mRing
->getReadVector();
891 for(uint i
{0};i
< samples
;)
893 const uint rem
{minu(samples
- i
, update_size
- mSplOffset
)};
894 std::copy_n(rdata
.first
.buf
+ mSplOffset
*size_t{mFrameSize
}, rem
*size_t{mFrameSize
},
895 buffer
+ i
*size_t{mFrameSize
});
898 if(mSplOffset
== update_size
)
900 /* Finished a chunk, reset the offset and advance the read pointer. */
904 rdata
.first
.len
-= 1;
906 rdata
.first
= rdata
.second
;
908 rdata
.first
.buf
+= chunk_size
;
913 mRing
->readAdvance(adv_count
);
915 SLAndroidSimpleBufferQueueItf bufferQueue
{};
916 if LIKELY(mDevice
->Connected
.load(std::memory_order_acquire
))
918 const SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
920 PRINTERR(result
, "recordObj->GetInterface");
921 if UNLIKELY(SL_RESULT_SUCCESS
!= result
)
923 mDevice
->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result
);
924 bufferQueue
= nullptr;
928 if LIKELY(bufferQueue
)
930 SLresult result
{SL_RESULT_SUCCESS
};
931 auto wdata
= mRing
->getWriteVector();
932 std::fill_n(wdata
.first
.buf
, wdata
.first
.len
*chunk_size
, silence
);
933 for(size_t i
{0u};i
< wdata
.first
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
935 result
= VCALL(bufferQueue
,Enqueue
)(wdata
.first
.buf
+ chunk_size
*i
, chunk_size
);
936 PRINTERR(result
, "bufferQueue->Enqueue");
938 if(wdata
.second
.len
> 0)
940 std::fill_n(wdata
.second
.buf
, wdata
.second
.len
*chunk_size
, silence
);
941 for(size_t i
{0u};i
< wdata
.second
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
943 result
= VCALL(bufferQueue
,Enqueue
)(wdata
.second
.buf
+ chunk_size
*i
, chunk_size
);
944 PRINTERR(result
, "bufferQueue->Enqueue");
950 uint
OpenSLCapture::availableSamples()
951 { return static_cast<uint
>(mRing
->readSpace()*mDevice
->UpdateSize
- mSplOffset
); }
955 bool OSLBackendFactory::init() { return true; }
957 bool OSLBackendFactory::querySupport(BackendType type
)
958 { return (type
== BackendType::Playback
|| type
== BackendType::Capture
); }
960 std::string
OSLBackendFactory::probe(BackendType type
)
962 std::string outnames
;
965 case BackendType::Playback
:
966 case BackendType::Capture
:
967 /* Includes null char. */
968 outnames
.append(opensl_device
, sizeof(opensl_device
));
974 BackendPtr
OSLBackendFactory::createBackend(DeviceBase
*device
, BackendType type
)
976 if(type
== BackendType::Playback
)
977 return BackendPtr
{new OpenSLPlayback
{device
}};
978 if(type
== BackendType::Capture
)
979 return BackendPtr
{new OpenSLCapture
{device
}};
983 BackendFactory
&OSLBackendFactory::getFactory()
985 static OSLBackendFactory factory
{};