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
24 #include "backends/opensl.h"
39 #include "endiantest.h"
40 #include "ringbuffer.h"
43 #include <SLES/OpenSLES.h>
44 #include <SLES/OpenSLES_Android.h>
45 #include <SLES/OpenSLES_AndroidConfiguration.h>
51 #define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
52 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
53 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
56 constexpr ALCchar opensl_device
[] = "OpenSL";
59 SLuint32
GetChannelMask(DevFmtChannels chans
)
63 case DevFmtMono
: return SL_SPEAKER_FRONT_CENTER
;
64 case DevFmtStereo
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
;
65 case DevFmtQuad
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
|
66 SL_SPEAKER_BACK_LEFT
| SL_SPEAKER_BACK_RIGHT
;
67 case DevFmtX51
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
|
68 SL_SPEAKER_FRONT_CENTER
| SL_SPEAKER_LOW_FREQUENCY
| SL_SPEAKER_SIDE_LEFT
|
69 SL_SPEAKER_SIDE_RIGHT
;
70 case DevFmtX51Rear
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
|
71 SL_SPEAKER_FRONT_CENTER
| SL_SPEAKER_LOW_FREQUENCY
| SL_SPEAKER_BACK_LEFT
|
72 SL_SPEAKER_BACK_RIGHT
;
73 case DevFmtX61
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
|
74 SL_SPEAKER_FRONT_CENTER
| SL_SPEAKER_LOW_FREQUENCY
| SL_SPEAKER_BACK_CENTER
|
75 SL_SPEAKER_SIDE_LEFT
| SL_SPEAKER_SIDE_RIGHT
;
76 case DevFmtX71
: return SL_SPEAKER_FRONT_LEFT
| SL_SPEAKER_FRONT_RIGHT
|
77 SL_SPEAKER_FRONT_CENTER
| SL_SPEAKER_LOW_FREQUENCY
| SL_SPEAKER_BACK_LEFT
|
78 SL_SPEAKER_BACK_RIGHT
| SL_SPEAKER_SIDE_LEFT
| SL_SPEAKER_SIDE_RIGHT
;
85 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
86 SLuint32
GetTypeRepresentation(DevFmtType type
)
93 return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
;
97 return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
;
99 return SL_ANDROID_PCM_REPRESENTATION_FLOAT
;
105 const char *res_str(SLresult result
)
109 case SL_RESULT_SUCCESS
: return "Success";
110 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
111 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
112 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
113 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
114 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
115 case SL_RESULT_IO_ERROR
: return "I/O error";
116 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
117 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
118 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
119 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
120 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
121 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
122 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
123 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
124 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
125 case SL_RESULT_CONTROL_LOST
: return "Control lost";
126 #ifdef SL_RESULT_READONLY
127 case SL_RESULT_READONLY
: return "ReadOnly";
129 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
130 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
132 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
133 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
136 return "Unknown error code";
139 #define PRINTERR(x, s) do { \
140 if UNLIKELY((x) != SL_RESULT_SUCCESS) \
141 ERR("%s: %s\n", (s), res_str((x))); \
145 struct OpenSLPlayback final
: public BackendBase
{
146 OpenSLPlayback(ALCdevice
*device
) noexcept
: BackendBase
{device
} { }
147 ~OpenSLPlayback() override
;
149 void process(SLAndroidSimpleBufferQueueItf bq
) noexcept
;
150 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
) noexcept
151 { static_cast<OpenSLPlayback
*>(context
)->process(bq
); }
155 void open(const ALCchar
*name
) override
;
156 bool reset() override
;
157 bool start() override
;
158 void stop() override
;
159 ClockLatency
getClockLatency() override
;
161 /* engine interfaces */
162 SLObjectItf mEngineObj
{nullptr};
163 SLEngineItf mEngine
{nullptr};
165 /* output mix interfaces */
166 SLObjectItf mOutputMix
{nullptr};
168 /* buffer queue player interfaces */
169 SLObjectItf mBufferQueueObj
{nullptr};
171 RingBufferPtr mRing
{nullptr};
174 ALuint mFrameSize
{0};
176 std::atomic
<bool> mKillNow
{true};
179 DEF_NEWDEL(OpenSLPlayback
)
182 OpenSLPlayback::~OpenSLPlayback()
185 VCALL0(mBufferQueueObj
,Destroy
)();
186 mBufferQueueObj
= nullptr;
189 VCALL0(mOutputMix
,Destroy
)();
190 mOutputMix
= nullptr;
193 VCALL0(mEngineObj
,Destroy
)();
194 mEngineObj
= nullptr;
199 /* this callback handler is called every time a buffer finishes playing */
200 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf
) noexcept
202 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
203 * pointer passed to the Enqueue method, rather than copying the audio.
204 * Consequently, the ringbuffer contains the audio that is currently queued
205 * and waiting to play. This process() callback is called when a buffer is
206 * finished, so we simply move the read pointer up to indicate the space is
207 * available for writing again, and wake up the mixer thread to mix and
210 mRing
->readAdvance(1);
215 int OpenSLPlayback::mixerProc()
218 althrd_setname(MIXER_THREAD_NAME
);
221 SLAndroidSimpleBufferQueueItf bufferQueue
;
222 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
224 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
225 if(SL_RESULT_SUCCESS
== result
)
227 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
228 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
231 std::unique_lock
<OpenSLPlayback
> dlock
{*this};
232 if(SL_RESULT_SUCCESS
!= result
)
233 aluHandleDisconnect(mDevice
, "Failed to get playback buffer: 0x%08x", result
);
235 while(SL_RESULT_SUCCESS
== result
&& !mKillNow
.load(std::memory_order_acquire
) &&
236 mDevice
->Connected
.load(std::memory_order_acquire
))
238 if(mRing
->writeSpace() == 0)
242 result
= VCALL(player
,GetPlayState
)(&state
);
243 PRINTERR(result
, "player->GetPlayState");
244 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
246 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
247 PRINTERR(result
, "player->SetPlayState");
249 if(SL_RESULT_SUCCESS
!= result
)
251 aluHandleDisconnect(mDevice
, "Failed to start platback: 0x%08x", result
);
255 if(mRing
->writeSpace() == 0)
264 auto data
= mRing
->getWriteVector();
265 aluMixData(mDevice
, data
.first
.buf
,
266 static_cast<ALuint
>(data
.first
.len
*mDevice
->UpdateSize
));
267 if(data
.second
.len
> 0)
268 aluMixData(mDevice
, data
.second
.buf
,
269 static_cast<ALuint
>(data
.second
.len
*mDevice
->UpdateSize
));
271 size_t todo
{data
.first
.len
+ data
.second
.len
};
272 mRing
->writeAdvance(todo
);
274 for(size_t i
{0};i
< todo
;i
++)
278 data
.first
= data
.second
;
279 data
.second
.buf
= nullptr;
283 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
, mDevice
->UpdateSize
*mFrameSize
);
284 PRINTERR(result
, "bufferQueue->Enqueue");
285 if(SL_RESULT_SUCCESS
!= result
)
287 aluHandleDisconnect(mDevice
, "Failed to queue audio: 0x%08x", result
);
292 data
.first
.buf
+= mDevice
->UpdateSize
*mFrameSize
;
300 void OpenSLPlayback::open(const ALCchar
*name
)
303 name
= opensl_device
;
304 else if(strcmp(name
, opensl_device
) != 0)
305 throw al::backend_exception
{ALC_INVALID_VALUE
, "Device name \"%s\" not found", name
};
308 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
309 PRINTERR(result
, "slCreateEngine");
310 if(SL_RESULT_SUCCESS
== result
)
312 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
313 PRINTERR(result
, "engine->Realize");
315 if(SL_RESULT_SUCCESS
== result
)
317 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
318 PRINTERR(result
, "engine->GetInterface");
320 if(SL_RESULT_SUCCESS
== result
)
322 result
= VCALL(mEngine
,CreateOutputMix
)(&mOutputMix
, 0, nullptr, nullptr);
323 PRINTERR(result
, "engine->CreateOutputMix");
325 if(SL_RESULT_SUCCESS
== result
)
327 result
= VCALL(mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
328 PRINTERR(result
, "outputMix->Realize");
331 if(SL_RESULT_SUCCESS
!= result
)
334 VCALL0(mOutputMix
,Destroy
)();
335 mOutputMix
= nullptr;
338 VCALL0(mEngineObj
,Destroy
)();
339 mEngineObj
= nullptr;
342 throw al::backend_exception
{ALC_INVALID_VALUE
,
343 "Failed to initialize OpenSL device: 0x%08x", result
};
346 mDevice
->DeviceName
= name
;
349 bool OpenSLPlayback::reset()
354 VCALL0(mBufferQueueObj
,Destroy
)();
355 mBufferQueueObj
= nullptr;
360 if(!mDevice
->Flags
.get
<FrequencyRequest
>())
362 /* FIXME: Disabled until I figure out how to get the Context needed for
363 * the getSystemService call.
365 JNIEnv
*env
= Android_GetJNIEnv();
366 jobject jctx
= Android_GetContext();
368 /* Get necessary stuff for using java.lang.Integer,
369 * android.content.Context, and android.media.AudioManager.
371 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
372 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
373 "parseInt", "(Ljava/lang/String;)I"
375 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
377 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
378 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
379 "AUDIO_SERVICE", "Ljava/lang/String;"
381 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
382 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
384 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
385 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
387 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
388 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
389 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
391 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
392 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
394 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
395 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
397 const char *strchars
;
400 /* Now make the calls. */
401 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
402 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
403 jobject audMgr
= JCALL(env
,CallObjectMethod
)(jctx
, ctx_getSysSvc
, strobj
);
404 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
405 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
406 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
408 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
409 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
410 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
411 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
412 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
413 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
415 //int sampleRate = Integer.parseInt(srateStr);
416 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
418 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, nullptr);
419 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
420 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
422 if(!sampleRate
) sampleRate
= device
->Frequency
;
423 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
427 mDevice
->FmtChans
= DevFmtStereo
;
428 mDevice
->FmtType
= DevFmtShort
;
430 SetDefaultWFXChannelOrder(mDevice
);
431 mFrameSize
= mDevice
->frameSizeFromFmt();
434 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
435 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
437 SLDataLocator_OutputMix loc_outmix
{};
438 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
439 loc_outmix
.outputMix
= mOutputMix
;
441 SLDataSink audioSnk
{};
442 audioSnk
.pLocator
= &loc_outmix
;
443 audioSnk
.pFormat
= nullptr;
445 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
{};
446 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
447 loc_bufq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
449 SLDataSource audioSrc
{};
450 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
451 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
452 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
453 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
454 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
455 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
456 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
457 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
458 format_pcm_ex
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
: SL_BYTEORDER_BIGENDIAN
;
459 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
461 audioSrc
.pLocator
= &loc_bufq
;
462 audioSrc
.pFormat
= &format_pcm_ex
;
464 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
465 ids
.data(), reqs
.data());
466 if(SL_RESULT_SUCCESS
!= result
)
469 /* Alter sample type according to what SLDataFormat_PCM can support. */
470 switch(mDevice
->FmtType
)
472 case DevFmtByte
: mDevice
->FmtType
= DevFmtUByte
; break;
473 case DevFmtUInt
: mDevice
->FmtType
= DevFmtInt
; break;
475 case DevFmtUShort
: mDevice
->FmtType
= DevFmtShort
; break;
482 SLDataFormat_PCM format_pcm
{};
483 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
484 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
485 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
486 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
487 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
488 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
489 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
490 SL_BYTEORDER_BIGENDIAN
;
492 audioSrc
.pLocator
= &loc_bufq
;
493 audioSrc
.pFormat
= &format_pcm
;
495 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
496 ids
.data(), reqs
.data());
497 PRINTERR(result
, "engine->CreateAudioPlayer");
499 if(SL_RESULT_SUCCESS
== result
)
501 /* Set the stream type to "media" (games, music, etc), if possible. */
502 SLAndroidConfigurationItf config
;
503 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
504 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
505 if(SL_RESULT_SUCCESS
== result
)
507 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
508 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
, &streamType
,
510 PRINTERR(result
, "config->SetConfiguration");
513 /* Clear any error since this was optional. */
514 result
= SL_RESULT_SUCCESS
;
516 if(SL_RESULT_SUCCESS
== result
)
518 result
= VCALL(mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
519 PRINTERR(result
, "bufferQueue->Realize");
521 if(SL_RESULT_SUCCESS
== result
)
523 const ALuint num_updates
{mDevice
->BufferSize
/ mDevice
->UpdateSize
};
524 mRing
= CreateRingBuffer(num_updates
, mFrameSize
*mDevice
->UpdateSize
, true);
527 if(SL_RESULT_SUCCESS
!= result
)
530 VCALL0(mBufferQueueObj
,Destroy
)();
531 mBufferQueueObj
= nullptr;
539 bool OpenSLPlayback::start()
543 SLAndroidSimpleBufferQueueItf bufferQueue
;
544 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
546 PRINTERR(result
, "bufferQueue->GetInterface");
547 if(SL_RESULT_SUCCESS
!= result
)
550 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLPlayback::processC
, this);
551 PRINTERR(result
, "bufferQueue->RegisterCallback");
552 if(SL_RESULT_SUCCESS
!= result
) return false;
555 mKillNow
.store(false, std::memory_order_release
);
556 mThread
= std::thread(std::mem_fn(&OpenSLPlayback::mixerProc
), this);
559 catch(std::exception
& e
) {
560 ERR("Could not create playback thread: %s\n", e
.what());
567 void OpenSLPlayback::stop()
569 if(mKillNow
.exchange(true, std::memory_order_acq_rel
) || !mThread
.joinable())
576 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
)};
577 PRINTERR(result
, "bufferQueue->GetInterface");
578 if(SL_RESULT_SUCCESS
== result
)
580 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
581 PRINTERR(result
, "player->SetPlayState");
584 SLAndroidSimpleBufferQueueItf bufferQueue
;
585 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
586 PRINTERR(result
, "bufferQueue->GetInterface");
587 if(SL_RESULT_SUCCESS
== result
)
589 result
= VCALL0(bufferQueue
,Clear
)();
590 PRINTERR(result
, "bufferQueue->Clear");
592 if(SL_RESULT_SUCCESS
== result
)
594 result
= VCALL(bufferQueue
,RegisterCallback
)(nullptr, nullptr);
595 PRINTERR(result
, "bufferQueue->RegisterCallback");
597 if(SL_RESULT_SUCCESS
== result
)
599 SLAndroidSimpleBufferQueueState state
;
601 std::this_thread::yield();
602 result
= VCALL(bufferQueue
,GetState
)(&state
);
603 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
604 PRINTERR(result
, "bufferQueue->GetState");
608 ClockLatency
OpenSLPlayback::getClockLatency()
612 std::lock_guard
<OpenSLPlayback
> _
{*this};
613 ret
.ClockTime
= GetDeviceClockTime(mDevice
);
614 ret
.Latency
= std::chrono::seconds
{mRing
->readSpace() * mDevice
->UpdateSize
};
615 ret
.Latency
/= mDevice
->Frequency
;
621 struct OpenSLCapture final
: public BackendBase
{
622 OpenSLCapture(ALCdevice
*device
) noexcept
: BackendBase
{device
} { }
623 ~OpenSLCapture() override
;
625 void process(SLAndroidSimpleBufferQueueItf bq
) noexcept
;
626 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
) noexcept
627 { static_cast<OpenSLCapture
*>(context
)->process(bq
); }
629 void open(const ALCchar
*name
) override
;
630 bool start() override
;
631 void stop() override
;
632 ALCenum
captureSamples(al::byte
*buffer
, ALCuint samples
) override
;
633 ALCuint
availableSamples() override
;
635 /* engine interfaces */
636 SLObjectItf mEngineObj
{nullptr};
639 /* recording interfaces */
640 SLObjectItf mRecordObj
{nullptr};
642 RingBufferPtr mRing
{nullptr};
643 ALCuint mSplOffset
{0u};
645 ALuint mFrameSize
{0};
647 DEF_NEWDEL(OpenSLCapture
)
650 OpenSLCapture::~OpenSLCapture()
653 VCALL0(mRecordObj
,Destroy
)();
654 mRecordObj
= nullptr;
657 VCALL0(mEngineObj
,Destroy
)();
658 mEngineObj
= nullptr;
663 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf
) noexcept
665 /* A new chunk has been written into the ring buffer, advance it. */
666 mRing
->writeAdvance(1);
670 void OpenSLCapture::open(const ALCchar
* name
)
673 name
= opensl_device
;
674 else if(strcmp(name
, opensl_device
) != 0)
675 throw al::backend_exception
{ALC_INVALID_VALUE
, "Device name \"%s\" not found", name
};
677 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
678 PRINTERR(result
, "slCreateEngine");
679 if(SL_RESULT_SUCCESS
== result
)
681 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
682 PRINTERR(result
, "engine->Realize");
684 if(SL_RESULT_SUCCESS
== result
)
686 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
687 PRINTERR(result
, "engine->GetInterface");
689 if(SL_RESULT_SUCCESS
== result
)
691 mFrameSize
= mDevice
->frameSizeFromFmt();
692 /* Ensure the total length is at least 100ms */
693 ALuint length
{maxu(mDevice
->BufferSize
, mDevice
->Frequency
/10)};
694 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
695 ALuint update_len
{clampu(mDevice
->BufferSize
/3, mDevice
->Frequency
/100,
696 mDevice
->Frequency
/100*5)};
697 ALuint num_updates
{(length
+update_len
-1) / update_len
};
699 mRing
= CreateRingBuffer(num_updates
, update_len
*mFrameSize
, false);
701 mDevice
->UpdateSize
= update_len
;
702 mDevice
->BufferSize
= static_cast<ALuint
>(mRing
->writeSpace() * update_len
);
704 if(SL_RESULT_SUCCESS
== result
)
706 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
707 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
709 SLDataLocator_IODevice loc_dev
{};
710 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
711 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
712 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
713 loc_dev
.device
= nullptr;
715 SLDataSource audioSrc
{};
716 audioSrc
.pLocator
= &loc_dev
;
717 audioSrc
.pFormat
= nullptr;
719 SLDataLocator_AndroidSimpleBufferQueue loc_bq
{};
720 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
721 loc_bq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
723 SLDataSink audioSnk
{};
724 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
725 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
726 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
727 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
728 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
729 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
730 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
731 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
732 format_pcm_ex
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
733 SL_BYTEORDER_BIGENDIAN
;
734 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
736 audioSnk
.pLocator
= &loc_bq
;
737 audioSnk
.pFormat
= &format_pcm_ex
;
738 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
739 ids
.size(), ids
.data(), reqs
.data());
740 if(SL_RESULT_SUCCESS
!= result
)
743 /* Fallback to SLDataFormat_PCM only if it supports the desired
746 if(mDevice
->FmtType
== DevFmtUByte
|| mDevice
->FmtType
== DevFmtShort
747 || mDevice
->FmtType
== DevFmtInt
)
749 SLDataFormat_PCM format_pcm
{};
750 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
751 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
752 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
753 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
754 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
755 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
756 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
757 SL_BYTEORDER_BIGENDIAN
;
759 audioSnk
.pLocator
= &loc_bq
;
760 audioSnk
.pFormat
= &format_pcm
;
761 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
762 ids
.size(), ids
.data(), reqs
.data());
764 PRINTERR(result
, "engine->CreateAudioRecorder");
767 if(SL_RESULT_SUCCESS
== result
)
769 /* Set the record preset to "generic", if possible. */
770 SLAndroidConfigurationItf config
;
771 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
772 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
773 if(SL_RESULT_SUCCESS
== result
)
775 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
776 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
, &preset
,
778 PRINTERR(result
, "config->SetConfiguration");
781 /* Clear any error since this was optional. */
782 result
= SL_RESULT_SUCCESS
;
784 if(SL_RESULT_SUCCESS
== result
)
786 result
= VCALL(mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
787 PRINTERR(result
, "recordObj->Realize");
790 SLAndroidSimpleBufferQueueItf bufferQueue
;
791 if(SL_RESULT_SUCCESS
== result
)
793 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
794 PRINTERR(result
, "recordObj->GetInterface");
796 if(SL_RESULT_SUCCESS
== result
)
798 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLCapture::processC
, this);
799 PRINTERR(result
, "bufferQueue->RegisterCallback");
801 if(SL_RESULT_SUCCESS
== result
)
803 const ALuint chunk_size
{mDevice
->UpdateSize
* mFrameSize
};
805 auto data
= mRing
->getWriteVector();
806 for(size_t i
{0u};i
< data
.first
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
808 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
+ chunk_size
*i
, chunk_size
);
809 PRINTERR(result
, "bufferQueue->Enqueue");
811 for(size_t i
{0u};i
< data
.second
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
813 result
= VCALL(bufferQueue
,Enqueue
)(data
.second
.buf
+ chunk_size
*i
, chunk_size
);
814 PRINTERR(result
, "bufferQueue->Enqueue");
818 if(SL_RESULT_SUCCESS
!= result
)
821 VCALL0(mRecordObj
,Destroy
)();
822 mRecordObj
= nullptr;
825 VCALL0(mEngineObj
,Destroy
)();
826 mEngineObj
= nullptr;
829 throw al::backend_exception
{ALC_INVALID_VALUE
,
830 "Failed to initialize OpenSL device: 0x%08x", result
};
833 mDevice
->DeviceName
= name
;
836 bool OpenSLCapture::start()
839 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
)};
840 PRINTERR(result
, "recordObj->GetInterface");
842 if(SL_RESULT_SUCCESS
== result
)
844 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_RECORDING
);
845 PRINTERR(result
, "record->SetRecordState");
848 if(SL_RESULT_SUCCESS
!= result
)
850 aluHandleDisconnect(mDevice
, "Failed to start capture: 0x%08x", result
);
857 void OpenSLCapture::stop()
860 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
)};
861 PRINTERR(result
, "recordObj->GetInterface");
863 if(SL_RESULT_SUCCESS
== result
)
865 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
866 PRINTERR(result
, "record->SetRecordState");
870 ALCenum
OpenSLCapture::captureSamples(al::byte
*buffer
, ALCuint samples
)
872 SLAndroidSimpleBufferQueueItf bufferQueue
;
873 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
)};
874 PRINTERR(result
, "recordObj->GetInterface");
876 const ALuint update_size
{mDevice
->UpdateSize
};
877 const ALuint chunk_size
{update_size
* mFrameSize
};
879 /* Read the desired samples from the ring buffer then advance its read
882 auto data
= mRing
->getReadVector();
883 for(ALCuint i
{0};i
< samples
;)
885 const ALCuint rem
{minu(samples
- i
, update_size
- mSplOffset
)};
886 std::copy_n(data
.first
.buf
+ mSplOffset
*mFrameSize
, rem
*mFrameSize
, buffer
+ i
*mFrameSize
);
889 if(mSplOffset
== update_size
)
891 /* Finished a chunk, reset the offset and advance the read pointer. */
894 mRing
->readAdvance(1);
895 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
, chunk_size
);
896 PRINTERR(result
, "bufferQueue->Enqueue");
897 if(SL_RESULT_SUCCESS
!= result
) break;
901 data
.first
= data
.second
;
903 data
.first
.buf
+= chunk_size
;
909 if UNLIKELY(SL_RESULT_SUCCESS
!= result
)
911 aluHandleDisconnect(mDevice
, "Failed to update capture buffer: 0x%08x", result
);
912 return ALC_INVALID_DEVICE
;
918 ALCuint
OpenSLCapture::availableSamples()
919 { return static_cast<ALuint
>(mRing
->readSpace()*mDevice
->UpdateSize
- mSplOffset
); }
923 bool OSLBackendFactory::init() { return true; }
925 bool OSLBackendFactory::querySupport(BackendType type
)
926 { return (type
== BackendType::Playback
|| type
== BackendType::Capture
); }
928 void OSLBackendFactory::probe(DevProbe type
, std::string
*outnames
)
932 case DevProbe::Playback
:
933 case DevProbe::Capture
:
934 /* Includes null char. */
935 outnames
->append(opensl_device
, sizeof(opensl_device
));
940 BackendPtr
OSLBackendFactory::createBackend(ALCdevice
*device
, BackendType type
)
942 if(type
== BackendType::Playback
)
943 return BackendPtr
{new OpenSLPlayback
{device
}};
944 if(type
== BackendType::Capture
)
945 return BackendPtr
{new OpenSLCapture
{device
}};
949 BackendFactory
&OSLBackendFactory::getFactory()
951 static OSLBackendFactory factory
{};