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
;
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
;
83 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
84 constexpr SLuint32
GetTypeRepresentation(DevFmtType type
) noexcept
91 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
;
95 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
;
97 return SL_ANDROID_PCM_REPRESENTATION_FLOAT
;
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
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";
134 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
135 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
137 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
138 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
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))); \
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
); }
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};
183 std::atomic
<bool> mKillNow
{true};
186 DEF_NEWDEL(OpenSLPlayback
)
189 OpenSLPlayback::~OpenSLPlayback()
192 VCALL0(mBufferQueueObj
,Destroy
)();
193 mBufferQueueObj
= nullptr;
196 VCALL0(mOutputMix
,Destroy
)();
197 mOutputMix
= nullptr;
200 VCALL0(mEngineObj
,Destroy
)();
201 mEngineObj
= 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
217 mRing
->readAdvance(1);
222 int OpenSLPlayback::mixerProc()
225 althrd_setname(MIXER_THREAD_NAME
);
228 SLAndroidSimpleBufferQueueItf bufferQueue
;
229 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
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)
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
);
263 if(mRing
->writeSpace() == 0)
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
);
282 for(size_t i
{0};i
< todo
;i
++)
286 data
.first
= data
.second
;
287 data
.second
.buf
= nullptr;
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
);
300 data
.first
.buf
+= mDevice
->UpdateSize
*mFrameSize
;
308 void OpenSLPlayback::open(const char *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",
316 /* There's only one device, so if it's already open, there's nothing to do. */
317 if(mEngineObj
) return;
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
)
346 VCALL0(mOutputMix
,Destroy
)();
347 mOutputMix
= nullptr;
350 VCALL0(mEngineObj
,Destroy
)();
351 mEngineObj
= 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()
366 VCALL0(mBufferQueueObj
,Destroy
)();
367 mBufferQueueObj
= nullptr;
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
;
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
);
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
)
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;
487 case DevFmtUShort
: mDevice
->FmtType
= DevFmtShort
; 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
,
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
)
541 VCALL0(mBufferQueueObj
,Destroy
)();
542 mBufferQueueObj
= nullptr;
550 void OpenSLPlayback::start()
554 SLAndroidSimpleBufferQueueItf bufferQueue
;
555 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
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
};
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())
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
;
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()
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
;
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};
649 /* recording interfaces */
650 SLObjectItf mRecordObj
{nullptr};
652 RingBufferPtr mRing
{nullptr};
657 DEF_NEWDEL(OpenSLCapture
)
660 OpenSLCapture::~OpenSLCapture()
663 VCALL0(mRecordObj
,Destroy
)();
664 mRecordObj
= nullptr;
667 VCALL0(mEngineObj
,Destroy
)();
668 mEngineObj
= 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
)
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",
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
)
753 /* Fallback to SLDataFormat_PCM only if it supports the desired
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
,
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
)
830 VCALL0(mRecordObj
,Destroy
)();
831 mRecordObj
= nullptr;
834 VCALL0(mEngineObj
,Destroy
)();
835 mEngineObj
= 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()
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()
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
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
});
891 if(mSplOffset
== update_size
)
893 /* Finished a chunk, reset the offset and advance the read pointer. */
897 rdata
.first
.len
-= 1;
899 rdata
.first
= rdata
.second
;
901 rdata
.first
.buf
+= chunk_size
;
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
,
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
); }
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
;
953 case BackendType::Playback
:
954 case BackendType::Capture
:
955 /* Includes null char. */
956 outnames
.append(opensl_device
, sizeof(opensl_device
));
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
}};
971 BackendFactory
&OSLBackendFactory::getFactory()
973 static OSLBackendFactory factory
{};