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"
33 #include "ringbuffer.h"
37 #include <SLES/OpenSLES.h>
38 #include <SLES/OpenSLES_Android.h>
39 #include <SLES/OpenSLES_AndroidConfiguration.h>
42 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
43 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
46 static const ALCchar opensl_device
[] = "OpenSL";
49 static SLuint32
GetChannelMask(enum DevFmtChannels chans
)
53 case DevFmtMono
: return SL_SPEAKER_FRONT_CENTER
;
54 case DevFmtStereo
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
;
55 case DevFmtQuad
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
56 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
57 case DevFmtX51
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
58 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
59 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
60 case DevFmtX51Rear
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
61 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
62 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
63 case DevFmtX61
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
64 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
65 SL_SPEAKER_BACK_CENTER
|
66 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
67 case DevFmtX71
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
68 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
69 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
|
70 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
77 #ifdef SL_DATAFORMAT_PCM_EX
78 static SLuint32
GetTypeRepresentation(enum DevFmtType type
)
85 return SL_PCM_REPRESENTATION_UNSIGNED_INT
;
89 return SL_PCM_REPRESENTATION_SIGNED_INT
;
91 return SL_PCM_REPRESENTATION_FLOAT
;
97 static const char *res_str(SLresult result
)
101 case SL_RESULT_SUCCESS
: return "Success";
102 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
103 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
104 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
105 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
106 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
107 case SL_RESULT_IO_ERROR
: return "I/O error";
108 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
109 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
110 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
111 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
112 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
113 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
114 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
115 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
116 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
117 case SL_RESULT_CONTROL_LOST
: return "Control lost";
118 #ifdef SL_RESULT_READONLY
119 case SL_RESULT_READONLY
: return "ReadOnly";
121 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
122 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
124 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
125 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
128 return "Unknown error code";
131 #define PRINTERR(x, s) do { \
132 if((x) != SL_RESULT_SUCCESS) \
133 ERR("%s: %s\n", (s), res_str((x))); \
137 struct ALCopenslPlayback final
: public ALCbackend
{
138 /* engine interfaces */
139 SLObjectItf mEngineObj
{nullptr};
140 SLEngineItf mEngine
{nullptr};
142 /* output mix interfaces */
143 SLObjectItf mOutputMix
{nullptr};
145 /* buffer queue player interfaces */
146 SLObjectItf mBufferQueueObj
{nullptr};
148 ll_ringbuffer_t
*mRing
{nullptr};
151 ALsizei mFrameSize
{0};
153 std::atomic
<ALenum
> mKillNow
{AL_TRUE
};
157 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
158 static int ALCopenslPlayback_mixerProc(ALCopenslPlayback
*self
);
160 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
);
161 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
*self
);
162 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
);
163 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
);
164 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
);
165 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
);
166 static DECLARE_FORWARD2(ALCopenslPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
167 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, ALCuint
, availableSamples
)
168 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
);
169 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, lock
)
170 static DECLARE_FORWARD(ALCopenslPlayback
, ALCbackend
, void, unlock
)
171 DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback
)
173 DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback
);
176 static void ALCopenslPlayback_Construct(ALCopenslPlayback
*self
, ALCdevice
*device
)
178 new (self
) ALCopenslPlayback
{};
179 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
180 SET_VTABLE2(ALCopenslPlayback
, ALCbackend
, self
);
182 alsem_init(&self
->mSem
, 0);
185 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
* self
)
187 if(self
->mBufferQueueObj
!= NULL
)
188 VCALL0(self
->mBufferQueueObj
,Destroy
)();
189 self
->mBufferQueueObj
= NULL
;
192 VCALL0(self
->mOutputMix
,Destroy
)();
193 self
->mOutputMix
= NULL
;
196 VCALL0(self
->mEngineObj
,Destroy
)();
197 self
->mEngineObj
= NULL
;
198 self
->mEngine
= NULL
;
200 ll_ringbuffer_free(self
->mRing
);
203 alsem_destroy(&self
->mSem
);
205 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
206 self
->~ALCopenslPlayback();
210 /* this callback handler is called every time a buffer finishes playing */
211 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
213 ALCopenslPlayback
*self
= static_cast<ALCopenslPlayback
*>(context
);
215 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
216 * pointer passed to the Enqueue method, rather than copying the audio.
217 * Consequently, the ringbuffer contains the audio that is currently queued
218 * and waiting to play. This process() callback is called when a buffer is
219 * finished, so we simply move the read pointer up to indicate the space is
220 * available for writing again, and wake up the mixer thread to mix and
223 ll_ringbuffer_read_advance(self
->mRing
, 1);
225 alsem_post(&self
->mSem
);
229 static int ALCopenslPlayback_mixerProc(ALCopenslPlayback
*self
)
231 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
232 SLAndroidSimpleBufferQueueItf bufferQueue
;
237 althrd_setname(MIXER_THREAD_NAME
);
239 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
241 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
242 if(SL_RESULT_SUCCESS
== result
)
244 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
245 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
248 ALCopenslPlayback_lock(self
);
249 if(SL_RESULT_SUCCESS
!= result
)
250 aluHandleDisconnect(device
, "Failed to get playback buffer: 0x%08x", result
);
252 while(SL_RESULT_SUCCESS
== result
&& !self
->mKillNow
.load(std::memory_order_acquire
) &&
253 device
->Connected
.load(std::memory_order_acquire
))
257 if(ll_ringbuffer_write_space(self
->mRing
) == 0)
261 result
= VCALL(player
,GetPlayState
)(&state
);
262 PRINTERR(result
, "player->GetPlayState");
263 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
265 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
266 PRINTERR(result
, "player->SetPlayState");
268 if(SL_RESULT_SUCCESS
!= result
)
270 aluHandleDisconnect(device
, "Failed to start platback: 0x%08x", result
);
274 if(ll_ringbuffer_write_space(self
->mRing
) == 0)
276 ALCopenslPlayback_unlock(self
);
277 alsem_wait(&self
->mSem
);
278 ALCopenslPlayback_lock(self
);
283 auto data
= ll_ringbuffer_get_write_vector(self
->mRing
);
284 aluMixData(device
, data
.first
.buf
, data
.first
.len
*device
->UpdateSize
);
285 if(data
.second
.len
> 0)
286 aluMixData(device
, data
.second
.buf
, data
.second
.len
*device
->UpdateSize
);
288 todo
= data
.first
.len
+data
.second
.len
;
289 ll_ringbuffer_write_advance(self
->mRing
, todo
);
291 for(size_t i
= 0;i
< todo
;i
++)
295 data
.first
= data
.second
;
296 data
.second
.buf
= nullptr;
300 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
,
301 device
->UpdateSize
*self
->mFrameSize
);
302 PRINTERR(result
, "bufferQueue->Enqueue");
303 if(SL_RESULT_SUCCESS
!= result
)
305 aluHandleDisconnect(device
, "Failed to queue audio: 0x%08x", result
);
310 data
.first
.buf
+= device
->UpdateSize
*self
->mFrameSize
;
313 ALCopenslPlayback_unlock(self
);
319 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
)
321 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
325 name
= opensl_device
;
326 else if(strcmp(name
, opensl_device
) != 0)
327 return ALC_INVALID_VALUE
;
330 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
331 PRINTERR(result
, "slCreateEngine");
332 if(SL_RESULT_SUCCESS
== result
)
334 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
335 PRINTERR(result
, "engine->Realize");
337 if(SL_RESULT_SUCCESS
== result
)
339 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
340 PRINTERR(result
, "engine->GetInterface");
342 if(SL_RESULT_SUCCESS
== result
)
344 result
= VCALL(self
->mEngine
,CreateOutputMix
)(&self
->mOutputMix
, 0, NULL
, NULL
);
345 PRINTERR(result
, "engine->CreateOutputMix");
347 if(SL_RESULT_SUCCESS
== result
)
349 result
= VCALL(self
->mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
350 PRINTERR(result
, "outputMix->Realize");
353 if(SL_RESULT_SUCCESS
!= result
)
355 if(self
->mOutputMix
!= NULL
)
356 VCALL0(self
->mOutputMix
,Destroy
)();
357 self
->mOutputMix
= NULL
;
359 if(self
->mEngineObj
!= NULL
)
360 VCALL0(self
->mEngineObj
,Destroy
)();
361 self
->mEngineObj
= NULL
;
362 self
->mEngine
= NULL
;
364 return ALC_INVALID_VALUE
;
367 device
->DeviceName
= name
;
371 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
)
373 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
374 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
;
375 SLDataLocator_OutputMix loc_outmix
;
376 SLDataSource audioSrc
;
379 SLInterfaceID ids
[2];
383 if(self
->mBufferQueueObj
!= NULL
)
384 VCALL0(self
->mBufferQueueObj
,Destroy
)();
385 self
->mBufferQueueObj
= NULL
;
387 ll_ringbuffer_free(self
->mRing
);
390 sampleRate
= device
->Frequency
;
392 if(!(device
->Flags
&DEVICE_FREQUENCY_REQUEST
))
394 /* FIXME: Disabled until I figure out how to get the Context needed for
395 * the getSystemService call.
397 JNIEnv
*env
= Android_GetJNIEnv();
398 jobject jctx
= Android_GetContext();
400 /* Get necessary stuff for using java.lang.Integer,
401 * android.content.Context, and android.media.AudioManager.
403 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
404 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
405 "parseInt", "(Ljava/lang/String;)I"
407 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
409 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
410 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
411 "AUDIO_SERVICE", "Ljava/lang/String;"
413 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
414 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
416 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
417 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
419 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
420 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
421 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
423 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
424 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
426 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
427 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
429 const char *strchars
;
432 /* Now make the calls. */
433 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
434 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
435 jobject audMgr
= JCALL(env
,CallObjectMethod
)(jctx
, ctx_getSysSvc
, strobj
);
436 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
437 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
438 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
440 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
441 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
442 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
443 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
444 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
445 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
447 //int sampleRate = Integer.parseInt(srateStr);
448 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
450 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, NULL
);
451 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
452 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
454 if(!sampleRate
) sampleRate
= device
->Frequency
;
455 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
459 if(sampleRate
!= device
->Frequency
)
461 device
->NumUpdates
= (device
->NumUpdates
*sampleRate
+ (device
->Frequency
>>1)) /
463 device
->NumUpdates
= maxu(device
->NumUpdates
, 2);
464 device
->Frequency
= sampleRate
;
467 device
->FmtChans
= DevFmtStereo
;
468 device
->FmtType
= DevFmtShort
;
470 SetDefaultWFXChannelOrder(device
);
471 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->mAmbiOrder
);
474 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
475 loc_bufq
.numBuffers
= device
->NumUpdates
;
477 #ifdef SL_DATAFORMAT_PCM_EX
478 SLDataFormat_PCM_EX format_pcm
;
479 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
480 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
481 format_pcm
.sampleRate
= device
->Frequency
* 1000;
482 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
483 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
484 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
485 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
486 SL_BYTEORDER_BIGENDIAN
;
487 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
489 SLDataFormat_PCM format_pcm
;
490 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
491 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
492 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
493 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
494 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
495 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
496 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
497 SL_BYTEORDER_BIGENDIAN
;
500 audioSrc
.pLocator
= &loc_bufq
;
501 audioSrc
.pFormat
= &format_pcm
;
503 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
504 loc_outmix
.outputMix
= self
->mOutputMix
;
505 audioSnk
.pLocator
= &loc_outmix
;
506 audioSnk
.pFormat
= NULL
;
509 ids
[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE
;
510 reqs
[0] = SL_BOOLEAN_TRUE
;
511 ids
[1] = SL_IID_ANDROIDCONFIGURATION
;
512 reqs
[1] = SL_BOOLEAN_FALSE
;
514 result
= VCALL(self
->mEngine
,CreateAudioPlayer
)(&self
->mBufferQueueObj
,
515 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
517 PRINTERR(result
, "engine->CreateAudioPlayer");
518 if(SL_RESULT_SUCCESS
== result
)
520 /* Set the stream type to "media" (games, music, etc), if possible. */
521 SLAndroidConfigurationItf config
;
522 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
523 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
524 if(SL_RESULT_SUCCESS
== result
)
526 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
527 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
,
528 &streamType
, sizeof(streamType
)
530 PRINTERR(result
, "config->SetConfiguration");
533 /* Clear any error since this was optional. */
534 result
= SL_RESULT_SUCCESS
;
536 if(SL_RESULT_SUCCESS
== result
)
538 result
= VCALL(self
->mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
539 PRINTERR(result
, "bufferQueue->Realize");
541 if(SL_RESULT_SUCCESS
== result
)
543 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
,
544 self
->mFrameSize
*device
->UpdateSize
, true
548 ERR("Out of memory allocating ring buffer %ux%u %u\n", device
->UpdateSize
,
549 device
->NumUpdates
, self
->mFrameSize
);
550 result
= SL_RESULT_MEMORY_FAILURE
;
554 if(SL_RESULT_SUCCESS
!= result
)
556 if(self
->mBufferQueueObj
!= NULL
)
557 VCALL0(self
->mBufferQueueObj
,Destroy
)();
558 self
->mBufferQueueObj
= NULL
;
566 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
)
568 SLAndroidSimpleBufferQueueItf bufferQueue
;
571 ll_ringbuffer_reset(self
->mRing
);
573 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
575 PRINTERR(result
, "bufferQueue->GetInterface");
576 if(SL_RESULT_SUCCESS
!= result
)
579 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslPlayback_process
, self
);
580 PRINTERR(result
, "bufferQueue->RegisterCallback");
581 if(SL_RESULT_SUCCESS
!= result
)
585 self
->mKillNow
.store(AL_FALSE
);
586 self
->mThread
= std::thread(ALCopenslPlayback_mixerProc
, self
);
589 catch(std::exception
& e
) {
590 ERR("Could not create playback thread: %s\n", e
.what());
598 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
)
600 SLAndroidSimpleBufferQueueItf bufferQueue
;
604 if(self
->mKillNow
.exchange(AL_TRUE
) || !self
->mThread
.joinable())
607 alsem_post(&self
->mSem
);
608 self
->mThread
.join();
610 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
611 PRINTERR(result
, "bufferQueue->GetInterface");
612 if(SL_RESULT_SUCCESS
== result
)
614 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
615 PRINTERR(result
, "player->SetPlayState");
618 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
620 PRINTERR(result
, "bufferQueue->GetInterface");
621 if(SL_RESULT_SUCCESS
== result
)
623 result
= VCALL0(bufferQueue
,Clear
)();
624 PRINTERR(result
, "bufferQueue->Clear");
626 if(SL_RESULT_SUCCESS
== result
)
628 result
= VCALL(bufferQueue
,RegisterCallback
)(NULL
, NULL
);
629 PRINTERR(result
, "bufferQueue->RegisterCallback");
631 if(SL_RESULT_SUCCESS
== result
)
633 SLAndroidSimpleBufferQueueState state
;
635 std::this_thread::yield();
636 result
= VCALL(bufferQueue
,GetState
)(&state
);
637 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
638 PRINTERR(result
, "bufferQueue->GetState");
642 static ClockLatency
ALCopenslPlayback_getClockLatency(ALCopenslPlayback
*self
)
644 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
647 ALCopenslPlayback_lock(self
);
648 ret
.ClockTime
= GetDeviceClockTime(device
);
649 ret
.Latency
= std::chrono::seconds
{ll_ringbuffer_read_space(self
->mRing
)*device
->UpdateSize
};
650 ret
.Latency
/= device
->Frequency
;
651 ALCopenslPlayback_unlock(self
);
657 struct ALCopenslCapture final
: public ALCbackend
{
658 /* engine interfaces */
659 SLObjectItf mEngineObj
{nullptr};
662 /* recording interfaces */
663 SLObjectItf mRecordObj
{nullptr};
665 ll_ringbuffer_t
*mRing
{nullptr};
666 ALCuint mSplOffset
{0u};
668 ALsizei mFrameSize
{0};
671 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
673 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
);
674 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
);
675 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
);
676 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ALCboolean
, reset
)
677 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
);
678 static void ALCopenslCapture_stop(ALCopenslCapture
*self
);
679 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
680 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
);
681 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
682 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, lock
)
683 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, unlock
)
684 DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture
)
685 DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture
);
688 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
)
690 new (self
) ALCopenslCapture
{};
691 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
692 SET_VTABLE2(ALCopenslCapture
, ALCbackend
, self
);
695 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
)
697 if(self
->mRecordObj
!= NULL
)
698 VCALL0(self
->mRecordObj
,Destroy
)();
699 self
->mRecordObj
= NULL
;
701 if(self
->mEngineObj
!= NULL
)
702 VCALL0(self
->mEngineObj
,Destroy
)();
703 self
->mEngineObj
= NULL
;
704 self
->mEngine
= NULL
;
706 ll_ringbuffer_free(self
->mRing
);
709 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
710 self
->~ALCopenslCapture();
714 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
716 ALCopenslCapture
*self
= static_cast<ALCopenslCapture
*>(context
);
717 /* A new chunk has been written into the ring buffer, advance it. */
718 ll_ringbuffer_write_advance(self
->mRing
, 1);
722 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
)
724 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
725 SLDataLocator_AndroidSimpleBufferQueue loc_bq
;
726 SLAndroidSimpleBufferQueueItf bufferQueue
;
727 SLDataLocator_IODevice loc_dev
;
728 SLDataSource audioSrc
;
733 name
= opensl_device
;
734 else if(strcmp(name
, opensl_device
) != 0)
735 return ALC_INVALID_VALUE
;
737 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
738 PRINTERR(result
, "slCreateEngine");
739 if(SL_RESULT_SUCCESS
== result
)
741 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
742 PRINTERR(result
, "engine->Realize");
744 if(SL_RESULT_SUCCESS
== result
)
746 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
747 PRINTERR(result
, "engine->GetInterface");
749 if(SL_RESULT_SUCCESS
== result
)
751 /* Ensure the total length is at least 100ms */
752 ALsizei length
= maxi(device
->NumUpdates
* device
->UpdateSize
,
753 device
->Frequency
/ 10);
754 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
755 ALsizei update_len
= clampi(device
->NumUpdates
*device
->UpdateSize
/ 3,
756 device
->Frequency
/ 100,
757 device
->Frequency
/ 100 * 5);
759 device
->UpdateSize
= update_len
;
760 device
->NumUpdates
= (length
+update_len
-1) / update_len
;
762 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->mAmbiOrder
);
764 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
765 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
766 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
767 loc_dev
.device
= NULL
;
769 audioSrc
.pLocator
= &loc_dev
;
770 audioSrc
.pFormat
= NULL
;
772 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
773 loc_bq
.numBuffers
= device
->NumUpdates
;
775 #ifdef SL_DATAFORMAT_PCM_EX
776 SLDataFormat_PCM_EX format_pcm
;
777 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
778 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
779 format_pcm
.sampleRate
= device
->Frequency
* 1000;
780 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
781 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
782 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
783 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
784 SL_BYTEORDER_BIGENDIAN
;
785 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
787 SLDataFormat_PCM format_pcm
;
788 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
789 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
790 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
791 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
792 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
793 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
794 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
795 SL_BYTEORDER_BIGENDIAN
;
798 audioSnk
.pLocator
= &loc_bq
;
799 audioSnk
.pFormat
= &format_pcm
;
801 if(SL_RESULT_SUCCESS
== result
)
803 const SLInterfaceID ids
[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
};
804 const SLboolean reqs
[2] = { SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
};
806 result
= VCALL(self
->mEngine
,CreateAudioRecorder
)(&self
->mRecordObj
,
807 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
809 PRINTERR(result
, "engine->CreateAudioRecorder");
811 if(SL_RESULT_SUCCESS
== result
)
813 /* Set the record preset to "generic", if possible. */
814 SLAndroidConfigurationItf config
;
815 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
816 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
817 if(SL_RESULT_SUCCESS
== result
)
819 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
820 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
,
821 &preset
, sizeof(preset
)
823 PRINTERR(result
, "config->SetConfiguration");
826 /* Clear any error since this was optional. */
827 result
= SL_RESULT_SUCCESS
;
829 if(SL_RESULT_SUCCESS
== result
)
831 result
= VCALL(self
->mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
832 PRINTERR(result
, "recordObj->Realize");
835 if(SL_RESULT_SUCCESS
== result
)
837 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
,
838 device
->UpdateSize
*self
->mFrameSize
, false
841 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
843 PRINTERR(result
, "recordObj->GetInterface");
845 if(SL_RESULT_SUCCESS
== result
)
847 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslCapture_process
, self
);
848 PRINTERR(result
, "bufferQueue->RegisterCallback");
850 if(SL_RESULT_SUCCESS
== result
)
852 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
855 auto data
= ll_ringbuffer_get_write_vector(self
->mRing
);
856 for(i
= 0;i
< data
.first
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
858 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
+ chunk_size
*i
, chunk_size
);
859 PRINTERR(result
, "bufferQueue->Enqueue");
861 for(i
= 0;i
< data
.second
.len
&& SL_RESULT_SUCCESS
== result
;i
++)
863 result
= VCALL(bufferQueue
,Enqueue
)(data
.second
.buf
+ chunk_size
*i
, chunk_size
);
864 PRINTERR(result
, "bufferQueue->Enqueue");
868 if(SL_RESULT_SUCCESS
!= result
)
870 if(self
->mRecordObj
!= NULL
)
871 VCALL0(self
->mRecordObj
,Destroy
)();
872 self
->mRecordObj
= NULL
;
874 if(self
->mEngineObj
!= NULL
)
875 VCALL0(self
->mEngineObj
,Destroy
)();
876 self
->mEngineObj
= NULL
;
877 self
->mEngine
= NULL
;
879 return ALC_INVALID_VALUE
;
882 device
->DeviceName
= name
;
886 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
)
891 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
892 PRINTERR(result
, "recordObj->GetInterface");
894 if(SL_RESULT_SUCCESS
== result
)
896 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_RECORDING
);
897 PRINTERR(result
, "record->SetRecordState");
900 if(SL_RESULT_SUCCESS
!= result
)
902 ALCopenslCapture_lock(self
);
903 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
,
904 "Failed to start capture: 0x%08x", result
);
905 ALCopenslCapture_unlock(self
);
912 static void ALCopenslCapture_stop(ALCopenslCapture
*self
)
917 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
918 PRINTERR(result
, "recordObj->GetInterface");
920 if(SL_RESULT_SUCCESS
== result
)
922 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
923 PRINTERR(result
, "record->SetRecordState");
927 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
929 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
930 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
931 SLAndroidSimpleBufferQueueItf bufferQueue
;
935 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
937 PRINTERR(result
, "recordObj->GetInterface");
939 /* Read the desired samples from the ring buffer then advance its read
942 auto data
= ll_ringbuffer_get_read_vector(self
->mRing
);
943 for(i
= 0;i
< samples
;)
945 ALCuint rem
= minu(samples
- i
, device
->UpdateSize
- self
->mSplOffset
);
946 memcpy((ALCbyte
*)buffer
+ i
*self
->mFrameSize
,
947 data
.first
.buf
+ self
->mSplOffset
*self
->mFrameSize
,
948 rem
* self
->mFrameSize
);
950 self
->mSplOffset
+= rem
;
951 if(self
->mSplOffset
== device
->UpdateSize
)
953 /* Finished a chunk, reset the offset and advance the read pointer. */
954 self
->mSplOffset
= 0;
956 ll_ringbuffer_read_advance(self
->mRing
, 1);
957 result
= VCALL(bufferQueue
,Enqueue
)(data
.first
.buf
, chunk_size
);
958 PRINTERR(result
, "bufferQueue->Enqueue");
959 if(SL_RESULT_SUCCESS
!= result
) break;
963 data
.first
= data
.second
;
965 data
.first
.buf
+= chunk_size
;
971 if(SL_RESULT_SUCCESS
!= result
)
973 ALCopenslCapture_lock(self
);
974 aluHandleDisconnect(device
, "Failed to update capture buffer: 0x%08x", result
);
975 ALCopenslCapture_unlock(self
);
976 return ALC_INVALID_DEVICE
;
982 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
)
984 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
985 return ll_ringbuffer_read_space(self
->mRing
) * device
->UpdateSize
;
989 bool OSLBackendFactory::init() { return true; }
991 bool OSLBackendFactory::querySupport(ALCbackend_Type type
)
992 { return (type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
); }
994 void OSLBackendFactory::probe(enum DevProbe type
, std::string
*outnames
)
998 case ALL_DEVICE_PROBE
:
999 case CAPTURE_DEVICE_PROBE
:
1000 /* Includes null char. */
1001 outnames
->append(opensl_device
, sizeof(opensl_device
));
1006 ALCbackend
*OSLBackendFactory::createBackend(ALCdevice
*device
, ALCbackend_Type type
)
1008 if(type
== ALCbackend_Playback
)
1010 ALCopenslPlayback
*backend
;
1011 NEW_OBJ(backend
, ALCopenslPlayback
)(device
);
1012 if(!backend
) return nullptr;
1013 return STATIC_CAST(ALCbackend
, backend
);
1015 if(type
== ALCbackend_Capture
)
1017 ALCopenslCapture
*backend
;
1018 NEW_OBJ(backend
, ALCopenslCapture
)(device
);
1019 if(!backend
) return nullptr;
1020 return STATIC_CAST(ALCbackend
, backend
);
1026 BackendFactory
&OSLBackendFactory::getFactory()
1028 static OSLBackendFactory factory
{};