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 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
)
150 { static_cast<OpenSLPlayback
*>(context
)->process(bq
); }
151 void process(SLAndroidSimpleBufferQueueItf 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
)
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");
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
;
301 void OpenSLPlayback::open(const ALCchar
*name
)
304 name
= opensl_device
;
305 else if(strcmp(name
, opensl_device
) != 0)
306 throw al::backend_exception
{ALC_INVALID_VALUE
, "Device name \"%s\" not found", name
};
309 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
310 PRINTERR(result
, "slCreateEngine");
311 if(SL_RESULT_SUCCESS
== result
)
313 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
314 PRINTERR(result
, "engine->Realize");
316 if(SL_RESULT_SUCCESS
== result
)
318 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
319 PRINTERR(result
, "engine->GetInterface");
321 if(SL_RESULT_SUCCESS
== result
)
323 result
= VCALL(mEngine
,CreateOutputMix
)(&mOutputMix
, 0, nullptr, nullptr);
324 PRINTERR(result
, "engine->CreateOutputMix");
326 if(SL_RESULT_SUCCESS
== result
)
328 result
= VCALL(mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
329 PRINTERR(result
, "outputMix->Realize");
332 if(SL_RESULT_SUCCESS
!= result
)
335 VCALL0(mOutputMix
,Destroy
)();
336 mOutputMix
= nullptr;
339 VCALL0(mEngineObj
,Destroy
)();
340 mEngineObj
= nullptr;
343 throw al::backend_exception
{ALC_INVALID_VALUE
, "Failed to initialize OpenSL: 0x%08x",
347 mDevice
->DeviceName
= name
;
350 bool OpenSLPlayback::reset()
355 VCALL0(mBufferQueueObj
,Destroy
)();
356 mBufferQueueObj
= nullptr;
361 if(!mDevice
->Flags
.get
<FrequencyRequest
>())
363 /* FIXME: Disabled until I figure out how to get the Context needed for
364 * the getSystemService call.
366 JNIEnv
*env
= Android_GetJNIEnv();
367 jobject jctx
= Android_GetContext();
369 /* Get necessary stuff for using java.lang.Integer,
370 * android.content.Context, and android.media.AudioManager.
372 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
373 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
374 "parseInt", "(Ljava/lang/String;)I"
376 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
378 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
379 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
380 "AUDIO_SERVICE", "Ljava/lang/String;"
382 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
383 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
385 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
386 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
388 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
389 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
390 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
392 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
393 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
395 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
396 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
398 const char *strchars
;
401 /* Now make the calls. */
402 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
403 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
404 jobject audMgr
= JCALL(env
,CallObjectMethod
)(jctx
, ctx_getSysSvc
, strobj
);
405 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
406 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
407 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
409 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
410 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
411 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
412 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, nullptr);
413 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
414 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
416 //int sampleRate = Integer.parseInt(srateStr);
417 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
419 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, nullptr);
420 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
421 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
423 if(!sampleRate
) sampleRate
= device
->Frequency
;
424 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
428 mDevice
->FmtChans
= DevFmtStereo
;
429 mDevice
->FmtType
= DevFmtShort
;
431 SetDefaultWFXChannelOrder(mDevice
);
432 mFrameSize
= mDevice
->frameSizeFromFmt();
435 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
436 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
438 SLDataLocator_OutputMix loc_outmix
{};
439 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
440 loc_outmix
.outputMix
= mOutputMix
;
442 SLDataSink audioSnk
{};
443 audioSnk
.pLocator
= &loc_outmix
;
444 audioSnk
.pFormat
= nullptr;
446 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
{};
447 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
448 loc_bufq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
450 SLDataSource audioSrc
{};
451 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
452 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
453 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
454 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
455 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
456 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
457 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
458 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
459 format_pcm_ex
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
: SL_BYTEORDER_BIGENDIAN
;
460 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
462 audioSrc
.pLocator
= &loc_bufq
;
463 audioSrc
.pFormat
= &format_pcm_ex
;
465 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
466 ids
.data(), reqs
.data());
467 if(SL_RESULT_SUCCESS
!= result
)
470 /* Alter sample type according to what SLDataFormat_PCM can support. */
471 switch(mDevice
->FmtType
)
473 case DevFmtByte
: mDevice
->FmtType
= DevFmtUByte
; break;
474 case DevFmtUInt
: mDevice
->FmtType
= DevFmtInt
; break;
476 case DevFmtUShort
: mDevice
->FmtType
= DevFmtShort
; break;
483 SLDataFormat_PCM format_pcm
{};
484 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
485 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
486 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
487 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
488 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
489 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
490 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
491 SL_BYTEORDER_BIGENDIAN
;
493 audioSrc
.pLocator
= &loc_bufq
;
494 audioSrc
.pFormat
= &format_pcm
;
496 result
= VCALL(mEngine
,CreateAudioPlayer
)(&mBufferQueueObj
, &audioSrc
, &audioSnk
, ids
.size(),
497 ids
.data(), reqs
.data());
498 PRINTERR(result
, "engine->CreateAudioPlayer");
500 if(SL_RESULT_SUCCESS
== result
)
502 /* Set the stream type to "media" (games, music, etc), if possible. */
503 SLAndroidConfigurationItf config
;
504 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
505 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
506 if(SL_RESULT_SUCCESS
== result
)
508 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
509 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
, &streamType
,
511 PRINTERR(result
, "config->SetConfiguration");
514 /* Clear any error since this was optional. */
515 result
= SL_RESULT_SUCCESS
;
517 if(SL_RESULT_SUCCESS
== result
)
519 result
= VCALL(mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
520 PRINTERR(result
, "bufferQueue->Realize");
522 if(SL_RESULT_SUCCESS
== result
)
524 const ALuint num_updates
{mDevice
->BufferSize
/ mDevice
->UpdateSize
};
526 mRing
= CreateRingBuffer(num_updates
, mFrameSize
*mDevice
->UpdateSize
, true);
528 catch(std::exception
& e
) {
529 ERR("Failed allocating ring buffer %ux%ux%u: %s\n", mDevice
->UpdateSize
,
530 num_updates
, mFrameSize
, e
.what());
531 result
= SL_RESULT_MEMORY_FAILURE
;
535 if(SL_RESULT_SUCCESS
!= result
)
538 VCALL0(mBufferQueueObj
,Destroy
)();
539 mBufferQueueObj
= nullptr;
547 bool OpenSLPlayback::start()
551 SLAndroidSimpleBufferQueueItf bufferQueue
;
552 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
554 PRINTERR(result
, "bufferQueue->GetInterface");
555 if(SL_RESULT_SUCCESS
!= result
)
558 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLPlayback::processC
, this);
559 PRINTERR(result
, "bufferQueue->RegisterCallback");
560 if(SL_RESULT_SUCCESS
!= result
) return false;
563 mKillNow
.store(false, std::memory_order_release
);
564 mThread
= std::thread(std::mem_fn(&OpenSLPlayback::mixerProc
), this);
567 catch(std::exception
& e
) {
568 ERR("Could not create playback thread: %s\n", e
.what());
575 void OpenSLPlayback::stop()
577 if(mKillNow
.exchange(true, std::memory_order_acq_rel
) || !mThread
.joinable())
584 SLresult result
{VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
)};
585 PRINTERR(result
, "bufferQueue->GetInterface");
586 if(SL_RESULT_SUCCESS
== result
)
588 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
589 PRINTERR(result
, "player->SetPlayState");
592 SLAndroidSimpleBufferQueueItf bufferQueue
;
593 result
= VCALL(mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
594 PRINTERR(result
, "bufferQueue->GetInterface");
595 if(SL_RESULT_SUCCESS
== result
)
597 result
= VCALL0(bufferQueue
,Clear
)();
598 PRINTERR(result
, "bufferQueue->Clear");
600 if(SL_RESULT_SUCCESS
== result
)
602 result
= VCALL(bufferQueue
,RegisterCallback
)(nullptr, nullptr);
603 PRINTERR(result
, "bufferQueue->RegisterCallback");
605 if(SL_RESULT_SUCCESS
== result
)
607 SLAndroidSimpleBufferQueueState state
;
609 std::this_thread::yield();
610 result
= VCALL(bufferQueue
,GetState
)(&state
);
611 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
612 PRINTERR(result
, "bufferQueue->GetState");
616 ClockLatency
OpenSLPlayback::getClockLatency()
621 ret
.ClockTime
= GetDeviceClockTime(mDevice
);
622 ret
.Latency
= std::chrono::seconds
{mRing
->readSpace() * mDevice
->UpdateSize
};
623 ret
.Latency
/= mDevice
->Frequency
;
630 struct OpenSLCapture final
: public BackendBase
{
631 OpenSLCapture(ALCdevice
*device
) noexcept
: BackendBase
{device
} { }
632 ~OpenSLCapture() override
;
634 static void processC(SLAndroidSimpleBufferQueueItf bq
, void *context
)
635 { static_cast<OpenSLCapture
*>(context
)->process(bq
); }
636 void process(SLAndroidSimpleBufferQueueItf bq
);
638 void open(const ALCchar
*name
) override
;
639 bool start() override
;
640 void stop() override
;
641 ALCenum
captureSamples(al::byte
*buffer
, ALCuint samples
) override
;
642 ALCuint
availableSamples() override
;
644 /* engine interfaces */
645 SLObjectItf mEngineObj
{nullptr};
648 /* recording interfaces */
649 SLObjectItf mRecordObj
{nullptr};
651 RingBufferPtr mRing
{nullptr};
652 ALCuint mSplOffset
{0u};
654 ALuint mFrameSize
{0};
656 DEF_NEWDEL(OpenSLCapture
)
659 OpenSLCapture::~OpenSLCapture()
662 VCALL0(mRecordObj
,Destroy
)();
663 mRecordObj
= nullptr;
666 VCALL0(mEngineObj
,Destroy
)();
667 mEngineObj
= nullptr;
672 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf
)
674 /* A new chunk has been written into the ring buffer, advance it. */
675 mRing
->writeAdvance(1);
679 void OpenSLCapture::open(const ALCchar
* name
)
682 name
= opensl_device
;
683 else if(strcmp(name
, opensl_device
) != 0)
684 throw al::backend_exception
{ALC_INVALID_VALUE
, "Device name \"%s\" not found", name
};
686 SLresult result
{slCreateEngine(&mEngineObj
, 0, nullptr, 0, nullptr, nullptr)};
687 PRINTERR(result
, "slCreateEngine");
688 if(SL_RESULT_SUCCESS
== result
)
690 result
= VCALL(mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
691 PRINTERR(result
, "engine->Realize");
693 if(SL_RESULT_SUCCESS
== result
)
695 result
= VCALL(mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &mEngine
);
696 PRINTERR(result
, "engine->GetInterface");
698 if(SL_RESULT_SUCCESS
== result
)
700 mFrameSize
= mDevice
->frameSizeFromFmt();
701 /* Ensure the total length is at least 100ms */
702 ALuint length
{maxu(mDevice
->BufferSize
, mDevice
->Frequency
/10)};
703 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
704 ALuint update_len
{clampu(mDevice
->BufferSize
/3, mDevice
->Frequency
/100,
705 mDevice
->Frequency
/100*5)};
706 ALuint num_updates
{(length
+update_len
-1) / update_len
};
709 mRing
= CreateRingBuffer(num_updates
, update_len
*mFrameSize
, false);
711 mDevice
->UpdateSize
= update_len
;
712 mDevice
->BufferSize
= static_cast<ALuint
>(mRing
->writeSpace() * update_len
);
714 catch(std::exception
& e
) {
715 ERR("Failed to allocate ring buffer: %s\n", e
.what());
716 result
= SL_RESULT_MEMORY_FAILURE
;
719 if(SL_RESULT_SUCCESS
== result
)
721 const std::array
<SLInterfaceID
,2> ids
{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
}};
722 const std::array
<SLboolean
,2> reqs
{{ SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
}};
724 SLDataLocator_IODevice loc_dev
{};
725 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
726 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
727 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
728 loc_dev
.device
= nullptr;
730 SLDataSource audioSrc
{};
731 audioSrc
.pLocator
= &loc_dev
;
732 audioSrc
.pFormat
= nullptr;
734 SLDataLocator_AndroidSimpleBufferQueue loc_bq
{};
735 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
736 loc_bq
.numBuffers
= mDevice
->BufferSize
/ mDevice
->UpdateSize
;
738 SLDataSink audioSnk
{};
739 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
740 SLAndroidDataFormat_PCM_EX format_pcm_ex
{};
741 format_pcm_ex
.formatType
= SL_ANDROID_DATAFORMAT_PCM_EX
;
742 format_pcm_ex
.numChannels
= mDevice
->channelsFromFmt();
743 format_pcm_ex
.sampleRate
= mDevice
->Frequency
* 1000;
744 format_pcm_ex
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
745 format_pcm_ex
.containerSize
= format_pcm_ex
.bitsPerSample
;
746 format_pcm_ex
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
747 format_pcm_ex
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
748 SL_BYTEORDER_BIGENDIAN
;
749 format_pcm_ex
.representation
= GetTypeRepresentation(mDevice
->FmtType
);
751 audioSnk
.pLocator
= &loc_bq
;
752 audioSnk
.pFormat
= &format_pcm_ex
;
753 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
754 ids
.size(), ids
.data(), reqs
.data());
755 if(SL_RESULT_SUCCESS
!= result
)
758 /* Fallback to SLDataFormat_PCM only if it supports the desired
761 if(mDevice
->FmtType
== DevFmtUByte
|| mDevice
->FmtType
== DevFmtShort
762 || mDevice
->FmtType
== DevFmtInt
)
764 SLDataFormat_PCM format_pcm
{};
765 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
766 format_pcm
.numChannels
= mDevice
->channelsFromFmt();
767 format_pcm
.samplesPerSec
= mDevice
->Frequency
* 1000;
768 format_pcm
.bitsPerSample
= mDevice
->bytesFromFmt() * 8;
769 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
770 format_pcm
.channelMask
= GetChannelMask(mDevice
->FmtChans
);
771 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
772 SL_BYTEORDER_BIGENDIAN
;
774 audioSnk
.pLocator
= &loc_bq
;
775 audioSnk
.pFormat
= &format_pcm
;
776 result
= VCALL(mEngine
,CreateAudioRecorder
)(&mRecordObj
, &audioSrc
, &audioSnk
,
777 ids
.size(), ids
.data(), reqs
.data());
779 PRINTERR(result
, "engine->CreateAudioRecorder");
782 if(SL_RESULT_SUCCESS
== result
)
784 /* Set the record preset to "generic", if possible. */
785 SLAndroidConfigurationItf config
;
786 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
787 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
788 if(SL_RESULT_SUCCESS
== result
)
790 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
791 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
, &preset
,
793 PRINTERR(result
, "config->SetConfiguration");
796 /* Clear any error since this was optional. */
797 result
= SL_RESULT_SUCCESS
;
799 if(SL_RESULT_SUCCESS
== result
)
801 result
= VCALL(mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
802 PRINTERR(result
, "recordObj->Realize");
805 SLAndroidSimpleBufferQueueItf bufferQueue
;
806 if(SL_RESULT_SUCCESS
== result
)
808 result
= VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
);
809 PRINTERR(result
, "recordObj->GetInterface");
811 if(SL_RESULT_SUCCESS
== result
)
813 result
= VCALL(bufferQueue
,RegisterCallback
)(&OpenSLCapture::processC
, this);
814 PRINTERR(result
, "bufferQueue->RegisterCallback");
816 if(SL_RESULT_SUCCESS
== result
)
818 const ALuint chunk_size
{mDevice
->UpdateSize
* mFrameSize
};
820 auto data
= mRing
->getWriteVector();
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
{ALC_INVALID_VALUE
, "Failed to initialize OpenSL: 0x%08x",
848 mDevice
->DeviceName
= name
;
851 bool 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");
863 if(SL_RESULT_SUCCESS
!= result
)
865 aluHandleDisconnect(mDevice
, "Failed to start capture: 0x%08x", result
);
872 void OpenSLCapture::stop()
875 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
)};
876 PRINTERR(result
, "recordObj->GetInterface");
878 if(SL_RESULT_SUCCESS
== result
)
880 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
881 PRINTERR(result
, "record->SetRecordState");
885 ALCenum
OpenSLCapture::captureSamples(al::byte
*buffer
, ALCuint samples
)
887 SLAndroidSimpleBufferQueueItf bufferQueue
;
888 SLresult result
{VCALL(mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, &bufferQueue
)};
889 PRINTERR(result
, "recordObj->GetInterface");
891 const ALuint update_size
{mDevice
->UpdateSize
};
892 const ALuint chunk_size
{update_size
* mFrameSize
};
894 /* Read the desired samples from the ring buffer then advance its read
897 auto data
= mRing
->getReadVector();
898 for(ALCuint i
{0};i
< samples
;)
900 const ALCuint rem
{minu(samples
- i
, update_size
- mSplOffset
)};
901 std::copy_n(data
.first
.buf
+ mSplOffset
*mFrameSize
, rem
*mFrameSize
, buffer
+ i
*mFrameSize
);
904 if(mSplOffset
== update_size
)
906 /* Finished a chunk, reset the offset and advance the read pointer. */
909 mRing
->readAdvance(1);
910 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
, chunk_size
);
911 PRINTERR(result
, "bufferQueue->Enqueue");
912 if(SL_RESULT_SUCCESS
!= result
) break;
916 data
.first
= data
.second
;
918 data
.first
.buf
+= chunk_size
;
924 if UNLIKELY(SL_RESULT_SUCCESS
!= result
)
926 aluHandleDisconnect(mDevice
, "Failed to update capture buffer: 0x%08x", result
);
927 return ALC_INVALID_DEVICE
;
933 ALCuint
OpenSLCapture::availableSamples()
934 { return static_cast<ALuint
>(mRing
->readSpace()*mDevice
->UpdateSize
- mSplOffset
); }
938 bool OSLBackendFactory::init() { return true; }
940 bool OSLBackendFactory::querySupport(BackendType type
)
941 { return (type
== BackendType::Playback
|| type
== BackendType::Capture
); }
943 void OSLBackendFactory::probe(DevProbe type
, std::string
*outnames
)
947 case DevProbe::Playback
:
948 case DevProbe::Capture
:
949 /* Includes null char. */
950 outnames
->append(opensl_device
, sizeof(opensl_device
));
955 BackendPtr
OSLBackendFactory::createBackend(ALCdevice
*device
, BackendType type
)
957 if(type
== BackendType::Playback
)
958 return BackendPtr
{new OpenSLPlayback
{device
}};
959 if(type
== BackendType::Capture
)
960 return BackendPtr
{new OpenSLCapture
{device
}};
964 BackendFactory
&OSLBackendFactory::getFactory()
966 static OSLBackendFactory factory
{};