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
29 #include "ringbuffer.h"
33 #include "backends/base.h"
35 #include <SLES/OpenSLES.h>
36 #include <SLES/OpenSLES_Android.h>
37 #include <SLES/OpenSLES_AndroidConfiguration.h>
40 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
41 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
44 static const ALCchar opensl_device
[] = "OpenSL";
47 static SLuint32
GetChannelMask(enum DevFmtChannels chans
)
51 case DevFmtMono
: return SL_SPEAKER_FRONT_CENTER
;
52 case DevFmtStereo
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
;
53 case DevFmtQuad
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
54 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
55 case DevFmtX51
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
56 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
57 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
58 case DevFmtX51Rear
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
59 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
60 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
;
61 case DevFmtX61
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
62 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
63 SL_SPEAKER_BACK_CENTER
|
64 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
65 case DevFmtX71
: return SL_SPEAKER_FRONT_LEFT
|SL_SPEAKER_FRONT_RIGHT
|
66 SL_SPEAKER_FRONT_CENTER
|SL_SPEAKER_LOW_FREQUENCY
|
67 SL_SPEAKER_BACK_LEFT
|SL_SPEAKER_BACK_RIGHT
|
68 SL_SPEAKER_SIDE_LEFT
|SL_SPEAKER_SIDE_RIGHT
;
75 #ifdef SL_DATAFORMAT_PCM_EX
76 static SLuint32
GetTypeRepresentation(enum DevFmtType type
)
83 return SL_PCM_REPRESENTATION_UNSIGNED_INT
;
87 return SL_PCM_REPRESENTATION_SIGNED_INT
;
89 return SL_PCM_REPRESENTATION_FLOAT
;
95 static const char *res_str(SLresult result
)
99 case SL_RESULT_SUCCESS
: return "Success";
100 case SL_RESULT_PRECONDITIONS_VIOLATED
: return "Preconditions violated";
101 case SL_RESULT_PARAMETER_INVALID
: return "Parameter invalid";
102 case SL_RESULT_MEMORY_FAILURE
: return "Memory failure";
103 case SL_RESULT_RESOURCE_ERROR
: return "Resource error";
104 case SL_RESULT_RESOURCE_LOST
: return "Resource lost";
105 case SL_RESULT_IO_ERROR
: return "I/O error";
106 case SL_RESULT_BUFFER_INSUFFICIENT
: return "Buffer insufficient";
107 case SL_RESULT_CONTENT_CORRUPTED
: return "Content corrupted";
108 case SL_RESULT_CONTENT_UNSUPPORTED
: return "Content unsupported";
109 case SL_RESULT_CONTENT_NOT_FOUND
: return "Content not found";
110 case SL_RESULT_PERMISSION_DENIED
: return "Permission denied";
111 case SL_RESULT_FEATURE_UNSUPPORTED
: return "Feature unsupported";
112 case SL_RESULT_INTERNAL_ERROR
: return "Internal error";
113 case SL_RESULT_UNKNOWN_ERROR
: return "Unknown error";
114 case SL_RESULT_OPERATION_ABORTED
: return "Operation aborted";
115 case SL_RESULT_CONTROL_LOST
: return "Control lost";
116 #ifdef SL_RESULT_READONLY
117 case SL_RESULT_READONLY
: return "ReadOnly";
119 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
120 case SL_RESULT_ENGINEOPTION_UNSUPPORTED
: return "Engine option unsupported";
122 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
123 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE
: return "Source/Sink incompatible";
126 return "Unknown error code";
129 #define PRINTERR(x, s) do { \
130 if((x) != SL_RESULT_SUCCESS) \
131 ERR("%s: %s\n", (s), res_str((x))); \
135 typedef struct ALCopenslPlayback
{
136 DERIVE_FROM_TYPE(ALCbackend
);
138 /* engine interfaces */
139 SLObjectItf mEngineObj
;
142 /* output mix interfaces */
143 SLObjectItf mOutputMix
;
145 /* buffer queue player interfaces */
146 SLObjectItf mBufferQueueObj
;
148 ll_ringbuffer_t
*mRing
;
153 ATOMIC(ALenum
) mKillNow
;
157 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
158 static int ALCopenslPlayback_mixerProc(void *arg
);
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 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
179 SET_VTABLE2(ALCopenslPlayback
, ALCbackend
, self
);
181 self
->mEngineObj
= NULL
;
182 self
->mEngine
= NULL
;
183 self
->mOutputMix
= NULL
;
184 self
->mBufferQueueObj
= NULL
;
187 alsem_init(&self
->mSem
, 0);
189 self
->mFrameSize
= 0;
191 ATOMIC_INIT(&self
->mKillNow
, AL_FALSE
);
194 static void ALCopenslPlayback_Destruct(ALCopenslPlayback
* self
)
196 if(self
->mBufferQueueObj
!= NULL
)
197 VCALL0(self
->mBufferQueueObj
,Destroy
)();
198 self
->mBufferQueueObj
= NULL
;
201 VCALL0(self
->mOutputMix
,Destroy
)();
202 self
->mOutputMix
= NULL
;
205 VCALL0(self
->mEngineObj
,Destroy
)();
206 self
->mEngineObj
= NULL
;
207 self
->mEngine
= NULL
;
209 alsem_destroy(&self
->mSem
);
211 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
215 /* this callback handler is called every time a buffer finishes playing */
216 static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
218 ALCopenslPlayback
*self
= context
;
220 /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
221 * pointer passed to the Enqueue method, rather than copying the audio.
222 * Consequently, the ringbuffer contains the audio that is currently queued
223 * and waiting to play. This process() callback is called when a buffer is
224 * finished, so we simply move the read pointer up to indicate the space is
225 * available for writing again, and wake up the mixer thread to mix and
228 ll_ringbuffer_read_advance(self
->mRing
, 1);
230 alsem_post(&self
->mSem
);
234 static int ALCopenslPlayback_mixerProc(void *arg
)
236 ALCopenslPlayback
*self
= arg
;
237 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
238 SLAndroidSimpleBufferQueueItf bufferQueue
;
239 ll_ringbuffer_data_t data
[2];
244 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
246 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
248 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
249 if(SL_RESULT_SUCCESS
== result
)
251 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
252 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_PLAY");
254 if(SL_RESULT_SUCCESS
!= result
)
256 ALCopenslPlayback_lock(self
);
257 aluHandleDisconnect(device
, "Failed to get playback buffer: 0x%08x", result
);
258 ALCopenslPlayback_unlock(self
);
262 ALCopenslPlayback_lock(self
);
263 while(!ATOMIC_LOAD(&self
->mKillNow
, almemory_order_acquire
) &&
264 ATOMIC_LOAD(&device
->Connected
, almemory_order_acquire
))
266 size_t todo
, len0
, len1
;
268 if(ll_ringbuffer_write_space(self
->mRing
) == 0)
272 result
= VCALL(player
,GetPlayState
)(&state
);
273 PRINTERR(result
, "player->GetPlayState");
274 if(SL_RESULT_SUCCESS
== result
&& state
!= SL_PLAYSTATE_PLAYING
)
276 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_PLAYING
);
277 PRINTERR(result
, "player->SetPlayState");
279 if(SL_RESULT_SUCCESS
!= result
)
281 aluHandleDisconnect(device
, "Failed to start platback: 0x%08x", result
);
285 if(ll_ringbuffer_write_space(self
->mRing
) == 0)
287 ALCopenslPlayback_unlock(self
);
288 alsem_wait(&self
->mSem
);
289 ALCopenslPlayback_lock(self
);
294 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
295 todo
= data
[0].len
+data
[1].len
;
297 len0
= minu(todo
, data
[0].len
);
298 len1
= minu(todo
-len0
, data
[1].len
);
300 aluMixData(device
, data
[0].buf
, len0
*device
->UpdateSize
);
301 for(size_t i
= 0;i
< len0
;i
++)
303 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
, device
->UpdateSize
*self
->mFrameSize
);
304 PRINTERR(result
, "bufferQueue->Enqueue");
305 if(SL_RESULT_SUCCESS
== result
)
306 ll_ringbuffer_write_advance(self
->mRing
, 1);
308 data
[0].buf
+= device
->UpdateSize
*self
->mFrameSize
;
313 aluMixData(device
, data
[1].buf
, len1
*device
->UpdateSize
);
314 for(size_t i
= 0;i
< len1
;i
++)
316 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
, device
->UpdateSize
*self
->mFrameSize
);
317 PRINTERR(result
, "bufferQueue->Enqueue");
318 if(SL_RESULT_SUCCESS
== result
)
319 ll_ringbuffer_write_advance(self
->mRing
, 1);
321 data
[1].buf
+= device
->UpdateSize
*self
->mFrameSize
;
325 ALCopenslPlayback_unlock(self
);
331 static ALCenum
ALCopenslPlayback_open(ALCopenslPlayback
*self
, const ALCchar
*name
)
333 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
337 name
= opensl_device
;
338 else if(strcmp(name
, opensl_device
) != 0)
339 return ALC_INVALID_VALUE
;
342 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
343 PRINTERR(result
, "slCreateEngine");
344 if(SL_RESULT_SUCCESS
== result
)
346 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
347 PRINTERR(result
, "engine->Realize");
349 if(SL_RESULT_SUCCESS
== result
)
351 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
352 PRINTERR(result
, "engine->GetInterface");
354 if(SL_RESULT_SUCCESS
== result
)
356 result
= VCALL(self
->mEngine
,CreateOutputMix
)(&self
->mOutputMix
, 0, NULL
, NULL
);
357 PRINTERR(result
, "engine->CreateOutputMix");
359 if(SL_RESULT_SUCCESS
== result
)
361 result
= VCALL(self
->mOutputMix
,Realize
)(SL_BOOLEAN_FALSE
);
362 PRINTERR(result
, "outputMix->Realize");
365 if(SL_RESULT_SUCCESS
!= result
)
367 if(self
->mOutputMix
!= NULL
)
368 VCALL0(self
->mOutputMix
,Destroy
)();
369 self
->mOutputMix
= NULL
;
371 if(self
->mEngineObj
!= NULL
)
372 VCALL0(self
->mEngineObj
,Destroy
)();
373 self
->mEngineObj
= NULL
;
374 self
->mEngine
= NULL
;
376 return ALC_INVALID_VALUE
;
379 alstr_copy_cstr(&device
->DeviceName
, name
);
384 static ALCboolean
ALCopenslPlayback_reset(ALCopenslPlayback
*self
)
386 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
387 SLDataLocator_AndroidSimpleBufferQueue loc_bufq
;
388 SLDataLocator_OutputMix loc_outmix
;
389 SLDataSource audioSrc
;
392 SLInterfaceID ids
[2];
397 if(self
->mBufferQueueObj
!= NULL
)
398 VCALL0(self
->mBufferQueueObj
,Destroy
)();
399 self
->mBufferQueueObj
= NULL
;
401 sampleRate
= device
->Frequency
;
402 if(!(device
->Flags
&DEVICE_FREQUENCY_REQUEST
) && (env
=Android_GetJNIEnv()) != NULL
)
404 /* FIXME: Disabled until I figure out how to get the Context needed for
405 * the getSystemService call.
408 /* Get necessary stuff for using java.lang.Integer,
409 * android.content.Context, and android.media.AudioManager.
411 jclass int_cls
= JCALL(env
,FindClass
)("java/lang/Integer");
412 jmethodID int_parseint
= JCALL(env
,GetStaticMethodID
)(int_cls
,
413 "parseInt", "(Ljava/lang/String;)I"
415 TRACE("Integer: %p, parseInt: %p\n", int_cls
, int_parseint
);
417 jclass ctx_cls
= JCALL(env
,FindClass
)("android/content/Context");
418 jfieldID ctx_audsvc
= JCALL(env
,GetStaticFieldID
)(ctx_cls
,
419 "AUDIO_SERVICE", "Ljava/lang/String;"
421 jmethodID ctx_getSysSvc
= JCALL(env
,GetMethodID
)(ctx_cls
,
422 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
424 TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
425 ctx_cls
, ctx_audsvc
, ctx_getSysSvc
);
427 jclass audmgr_cls
= JCALL(env
,FindClass
)("android/media/AudioManager");
428 jfieldID audmgr_prop_out_srate
= JCALL(env
,GetStaticFieldID
)(audmgr_cls
,
429 "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
431 jmethodID audmgr_getproperty
= JCALL(env
,GetMethodID
)(audmgr_cls
,
432 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
434 TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
435 audmgr_cls
, audmgr_prop_out_srate
, audmgr_getproperty
);
437 const char *strchars
;
440 /* Now make the calls. */
441 //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
442 strobj
= JCALL(env
,GetStaticObjectField
)(ctx_cls
, ctx_audsvc
);
443 jobject audMgr
= JCALL(env
,CallObjectMethod
)(ctx_cls
, ctx_getSysSvc
, strobj
);
444 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
445 TRACE("Context.getSystemService(%s) = %p\n", strchars
, audMgr
);
446 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
448 //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
449 strobj
= JCALL(env
,GetStaticObjectField
)(audmgr_cls
, audmgr_prop_out_srate
);
450 jstring srateStr
= JCALL(env
,CallObjectMethod
)(audMgr
, audmgr_getproperty
, strobj
);
451 strchars
= JCALL(env
,GetStringUTFChars
)(strobj
, NULL
);
452 TRACE("audMgr.getProperty(%s) = %p\n", strchars
, srateStr
);
453 JCALL(env
,ReleaseStringUTFChars
)(strobj
, strchars
);
455 //int sampleRate = Integer.parseInt(srateStr);
456 sampleRate
= JCALL(env
,CallStaticIntMethod
)(int_cls
, int_parseint
, srateStr
);
458 strchars
= JCALL(env
,GetStringUTFChars
)(srateStr
, NULL
);
459 TRACE("Got system sample rate %uhz (%s)\n", sampleRate
, strchars
);
460 JCALL(env
,ReleaseStringUTFChars
)(srateStr
, strchars
);
462 if(!sampleRate
) sampleRate
= device
->Frequency
;
463 else sampleRate
= maxu(sampleRate
, MIN_OUTPUT_RATE
);
467 if(sampleRate
!= device
->Frequency
)
469 device
->NumUpdates
= (device
->NumUpdates
*sampleRate
+ (device
->Frequency
>>1)) /
471 device
->NumUpdates
= maxu(device
->NumUpdates
, 2);
472 device
->Frequency
= sampleRate
;
475 device
->FmtChans
= DevFmtStereo
;
476 device
->FmtType
= DevFmtShort
;
478 SetDefaultWFXChannelOrder(device
);
479 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
482 loc_bufq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
483 loc_bufq
.numBuffers
= device
->NumUpdates
;
485 #ifdef SL_DATAFORMAT_PCM_EX
486 SLDataFormat_PCM_EX format_pcm
;
487 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
488 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
489 format_pcm
.sampleRate
= device
->Frequency
* 1000;
490 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
491 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
492 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
493 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
494 SL_BYTEORDER_BIGENDIAN
;
495 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
497 SLDataFormat_PCM format_pcm
;
498 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
499 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
500 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
501 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
502 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
503 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
504 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
505 SL_BYTEORDER_BIGENDIAN
;
508 audioSrc
.pLocator
= &loc_bufq
;
509 audioSrc
.pFormat
= &format_pcm
;
511 loc_outmix
.locatorType
= SL_DATALOCATOR_OUTPUTMIX
;
512 loc_outmix
.outputMix
= self
->mOutputMix
;
513 audioSnk
.pLocator
= &loc_outmix
;
514 audioSnk
.pFormat
= NULL
;
517 ids
[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE
;
518 reqs
[0] = SL_BOOLEAN_TRUE
;
519 ids
[1] = SL_IID_ANDROIDCONFIGURATION
;
520 reqs
[1] = SL_BOOLEAN_FALSE
;
522 result
= VCALL(self
->mEngine
,CreateAudioPlayer
)(&self
->mBufferQueueObj
,
523 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
525 PRINTERR(result
, "engine->CreateAudioPlayer");
526 if(SL_RESULT_SUCCESS
== result
)
528 /* Set the stream type to "media" (games, music, etc), if possible. */
529 SLAndroidConfigurationItf config
;
530 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
531 PRINTERR(result
, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
532 if(SL_RESULT_SUCCESS
== result
)
534 SLint32 streamType
= SL_ANDROID_STREAM_MEDIA
;
535 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_STREAM_TYPE
,
536 &streamType
, sizeof(streamType
)
538 PRINTERR(result
, "config->SetConfiguration");
541 /* Clear any error since this was optional. */
542 result
= SL_RESULT_SUCCESS
;
544 if(SL_RESULT_SUCCESS
== result
)
546 result
= VCALL(self
->mBufferQueueObj
,Realize
)(SL_BOOLEAN_FALSE
);
547 PRINTERR(result
, "bufferQueue->Realize");
550 if(SL_RESULT_SUCCESS
!= result
)
552 if(self
->mBufferQueueObj
!= NULL
)
553 VCALL0(self
->mBufferQueueObj
,Destroy
)();
554 self
->mBufferQueueObj
= NULL
;
562 static ALCboolean
ALCopenslPlayback_start(ALCopenslPlayback
*self
)
564 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
565 SLAndroidSimpleBufferQueueItf bufferQueue
;
568 ll_ringbuffer_free(self
->mRing
);
569 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
, self
->mFrameSize
*device
->UpdateSize
,
572 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
574 PRINTERR(result
, "bufferQueue->GetInterface");
575 if(SL_RESULT_SUCCESS
!= result
)
578 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslPlayback_process
, self
);
579 PRINTERR(result
, "bufferQueue->RegisterCallback");
580 if(SL_RESULT_SUCCESS
!= result
)
583 ATOMIC_STORE_SEQ(&self
->mKillNow
, AL_FALSE
);
584 if(althrd_create(&self
->mThread
, ALCopenslPlayback_mixerProc
, self
) != althrd_success
)
586 ERR("Failed to start mixer thread\n");
594 static void ALCopenslPlayback_stop(ALCopenslPlayback
*self
)
596 SLAndroidSimpleBufferQueueItf bufferQueue
;
601 if(ATOMIC_EXCHANGE_SEQ(&self
->mKillNow
, AL_TRUE
))
604 alsem_post(&self
->mSem
);
605 althrd_join(self
->mThread
, &res
);
607 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_PLAY
, &player
);
608 PRINTERR(result
, "bufferQueue->GetInterface");
609 if(SL_RESULT_SUCCESS
== result
)
611 result
= VCALL(player
,SetPlayState
)(SL_PLAYSTATE_STOPPED
);
612 PRINTERR(result
, "player->SetPlayState");
615 result
= VCALL(self
->mBufferQueueObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
617 PRINTERR(result
, "bufferQueue->GetInterface");
618 if(SL_RESULT_SUCCESS
== result
)
620 result
= VCALL0(bufferQueue
,Clear
)();
621 PRINTERR(result
, "bufferQueue->Clear");
623 if(SL_RESULT_SUCCESS
== result
)
625 result
= VCALL(bufferQueue
,RegisterCallback
)(NULL
, NULL
);
626 PRINTERR(result
, "bufferQueue->RegisterCallback");
628 if(SL_RESULT_SUCCESS
== result
)
630 SLAndroidSimpleBufferQueueState state
;
633 result
= VCALL(bufferQueue
,GetState
)(&state
);
634 } while(SL_RESULT_SUCCESS
== result
&& state
.count
> 0);
635 PRINTERR(result
, "bufferQueue->GetState");
638 ll_ringbuffer_free(self
->mRing
);
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
= ll_ringbuffer_read_space(self
->mRing
)*device
->UpdateSize
*
650 DEVICE_CLOCK_RES
/ device
->Frequency
;
651 ALCopenslPlayback_unlock(self
);
657 typedef struct ALCopenslCapture
{
658 DERIVE_FROM_TYPE(ALCbackend
);
660 /* engine interfaces */
661 SLObjectItf mEngineObj
;
664 /* recording interfaces */
665 SLObjectItf mRecordObj
;
667 ll_ringbuffer_t
*mRing
;
673 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq
, void *context
);
675 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
);
676 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
);
677 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
);
678 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ALCboolean
, reset
)
679 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
);
680 static void ALCopenslCapture_stop(ALCopenslCapture
*self
);
681 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
682 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
);
683 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
684 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, lock
)
685 static DECLARE_FORWARD(ALCopenslCapture
, ALCbackend
, void, unlock
)
686 DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture
)
687 DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture
);
690 static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf
UNUSED(bq
), void *context
)
692 ALCopenslCapture
*self
= context
;
693 /* A new chunk has been written into the ring buffer, advance it. */
694 ll_ringbuffer_write_advance(self
->mRing
, 1);
698 static void ALCopenslCapture_Construct(ALCopenslCapture
*self
, ALCdevice
*device
)
700 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
701 SET_VTABLE2(ALCopenslCapture
, ALCbackend
, self
);
703 self
->mEngineObj
= NULL
;
704 self
->mEngine
= NULL
;
706 self
->mRecordObj
= NULL
;
709 self
->mSplOffset
= 0;
711 self
->mFrameSize
= 0;
714 static void ALCopenslCapture_Destruct(ALCopenslCapture
*self
)
716 ll_ringbuffer_free(self
->mRing
);
719 if(self
->mRecordObj
!= NULL
)
720 VCALL0(self
->mRecordObj
,Destroy
)();
721 self
->mRecordObj
= NULL
;
723 if(self
->mEngineObj
!= NULL
)
724 VCALL0(self
->mEngineObj
,Destroy
)();
725 self
->mEngineObj
= NULL
;
726 self
->mEngine
= NULL
;
728 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
731 static ALCenum
ALCopenslCapture_open(ALCopenslCapture
*self
, const ALCchar
*name
)
733 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
734 SLDataLocator_AndroidSimpleBufferQueue loc_bq
;
735 SLAndroidSimpleBufferQueueItf bufferQueue
;
736 SLDataLocator_IODevice loc_dev
;
737 SLDataSource audioSrc
;
742 name
= opensl_device
;
743 else if(strcmp(name
, opensl_device
) != 0)
744 return ALC_INVALID_VALUE
;
746 result
= slCreateEngine(&self
->mEngineObj
, 0, NULL
, 0, NULL
, NULL
);
747 PRINTERR(result
, "slCreateEngine");
748 if(SL_RESULT_SUCCESS
== result
)
750 result
= VCALL(self
->mEngineObj
,Realize
)(SL_BOOLEAN_FALSE
);
751 PRINTERR(result
, "engine->Realize");
753 if(SL_RESULT_SUCCESS
== result
)
755 result
= VCALL(self
->mEngineObj
,GetInterface
)(SL_IID_ENGINE
, &self
->mEngine
);
756 PRINTERR(result
, "engine->GetInterface");
758 if(SL_RESULT_SUCCESS
== result
)
760 /* Ensure the total length is at least 100ms */
761 ALsizei length
= maxi(device
->NumUpdates
* device
->UpdateSize
,
762 device
->Frequency
/ 10);
763 /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
764 ALsizei update_len
= clampi(device
->NumUpdates
*device
->UpdateSize
/ 3,
765 device
->Frequency
/ 100,
766 device
->Frequency
/ 100 * 5);
768 device
->UpdateSize
= update_len
;
769 device
->NumUpdates
= (length
+update_len
-1) / update_len
;
771 self
->mFrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
773 loc_dev
.locatorType
= SL_DATALOCATOR_IODEVICE
;
774 loc_dev
.deviceType
= SL_IODEVICE_AUDIOINPUT
;
775 loc_dev
.deviceID
= SL_DEFAULTDEVICEID_AUDIOINPUT
;
776 loc_dev
.device
= NULL
;
778 audioSrc
.pLocator
= &loc_dev
;
779 audioSrc
.pFormat
= NULL
;
781 loc_bq
.locatorType
= SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
;
782 loc_bq
.numBuffers
= device
->NumUpdates
;
784 #ifdef SL_DATAFORMAT_PCM_EX
785 SLDataFormat_PCM_EX format_pcm
;
786 format_pcm
.formatType
= SL_DATAFORMAT_PCM_EX
;
787 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
788 format_pcm
.sampleRate
= device
->Frequency
* 1000;
789 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
790 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
791 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
792 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
793 SL_BYTEORDER_BIGENDIAN
;
794 format_pcm
.representation
= GetTypeRepresentation(device
->FmtType
);
796 SLDataFormat_PCM format_pcm
;
797 format_pcm
.formatType
= SL_DATAFORMAT_PCM
;
798 format_pcm
.numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
799 format_pcm
.samplesPerSec
= device
->Frequency
* 1000;
800 format_pcm
.bitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
801 format_pcm
.containerSize
= format_pcm
.bitsPerSample
;
802 format_pcm
.channelMask
= GetChannelMask(device
->FmtChans
);
803 format_pcm
.endianness
= IS_LITTLE_ENDIAN
? SL_BYTEORDER_LITTLEENDIAN
:
804 SL_BYTEORDER_BIGENDIAN
;
807 audioSnk
.pLocator
= &loc_bq
;
808 audioSnk
.pFormat
= &format_pcm
;
810 if(SL_RESULT_SUCCESS
== result
)
812 const SLInterfaceID ids
[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE
, SL_IID_ANDROIDCONFIGURATION
};
813 const SLboolean reqs
[2] = { SL_BOOLEAN_TRUE
, SL_BOOLEAN_FALSE
};
815 result
= VCALL(self
->mEngine
,CreateAudioRecorder
)(&self
->mRecordObj
,
816 &audioSrc
, &audioSnk
, COUNTOF(ids
), ids
, reqs
818 PRINTERR(result
, "engine->CreateAudioRecorder");
820 if(SL_RESULT_SUCCESS
== result
)
822 /* Set the record preset to "generic", if possible. */
823 SLAndroidConfigurationItf config
;
824 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDCONFIGURATION
, &config
);
825 PRINTERR(result
, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
826 if(SL_RESULT_SUCCESS
== result
)
828 SLuint32 preset
= SL_ANDROID_RECORDING_PRESET_GENERIC
;
829 result
= VCALL(config
,SetConfiguration
)(SL_ANDROID_KEY_RECORDING_PRESET
,
830 &preset
, sizeof(preset
)
832 PRINTERR(result
, "config->SetConfiguration");
835 /* Clear any error since this was optional. */
836 result
= SL_RESULT_SUCCESS
;
838 if(SL_RESULT_SUCCESS
== result
)
840 result
= VCALL(self
->mRecordObj
,Realize
)(SL_BOOLEAN_FALSE
);
841 PRINTERR(result
, "recordObj->Realize");
844 if(SL_RESULT_SUCCESS
== result
)
846 self
->mRing
= ll_ringbuffer_create(device
->NumUpdates
, device
->UpdateSize
*self
->mFrameSize
,
849 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
851 PRINTERR(result
, "recordObj->GetInterface");
853 if(SL_RESULT_SUCCESS
== result
)
855 result
= VCALL(bufferQueue
,RegisterCallback
)(ALCopenslCapture_process
, self
);
856 PRINTERR(result
, "bufferQueue->RegisterCallback");
858 if(SL_RESULT_SUCCESS
== result
)
860 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
861 ll_ringbuffer_data_t data
[2];
864 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
865 for(i
= 0;i
< data
[0].len
&& SL_RESULT_SUCCESS
== result
;i
++)
867 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
+ chunk_size
*i
, chunk_size
);
868 PRINTERR(result
, "bufferQueue->Enqueue");
870 for(i
= 0;i
< data
[1].len
&& SL_RESULT_SUCCESS
== result
;i
++)
872 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
+ chunk_size
*i
, chunk_size
);
873 PRINTERR(result
, "bufferQueue->Enqueue");
877 if(SL_RESULT_SUCCESS
!= result
)
879 if(self
->mRecordObj
!= NULL
)
880 VCALL0(self
->mRecordObj
,Destroy
)();
881 self
->mRecordObj
= NULL
;
883 if(self
->mEngineObj
!= NULL
)
884 VCALL0(self
->mEngineObj
,Destroy
)();
885 self
->mEngineObj
= NULL
;
886 self
->mEngine
= NULL
;
888 return ALC_INVALID_VALUE
;
891 alstr_copy_cstr(&device
->DeviceName
, name
);
896 static ALCboolean
ALCopenslCapture_start(ALCopenslCapture
*self
)
901 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
902 PRINTERR(result
, "recordObj->GetInterface");
904 if(SL_RESULT_SUCCESS
== result
)
906 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_RECORDING
);
907 PRINTERR(result
, "record->SetRecordState");
910 if(SL_RESULT_SUCCESS
!= result
)
912 ALCopenslCapture_lock(self
);
913 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
,
914 "Failed to start capture: 0x%08x", result
);
915 ALCopenslCapture_unlock(self
);
922 static void ALCopenslCapture_stop(ALCopenslCapture
*self
)
927 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_RECORD
, &record
);
928 PRINTERR(result
, "recordObj->GetInterface");
930 if(SL_RESULT_SUCCESS
== result
)
932 result
= VCALL(record
,SetRecordState
)(SL_RECORDSTATE_PAUSED
);
933 PRINTERR(result
, "record->SetRecordState");
937 static ALCenum
ALCopenslCapture_captureSamples(ALCopenslCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
939 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
940 ALsizei chunk_size
= device
->UpdateSize
* self
->mFrameSize
;
941 SLAndroidSimpleBufferQueueItf bufferQueue
;
942 ll_ringbuffer_data_t data
[2];
947 /* Read the desired samples from the ring buffer then advance its read
950 ll_ringbuffer_get_read_vector(self
->mRing
, data
);
952 for(i
= 0;i
< samples
;)
954 ALCuint rem
= minu(samples
- i
, device
->UpdateSize
- self
->mSplOffset
);
955 memcpy((ALCbyte
*)buffer
+ i
*self
->mFrameSize
,
956 data
[0].buf
+ self
->mSplOffset
*self
->mFrameSize
,
957 rem
* self
->mFrameSize
);
959 self
->mSplOffset
+= rem
;
960 if(self
->mSplOffset
== device
->UpdateSize
)
962 /* Finished a chunk, reset the offset and advance the read pointer. */
963 self
->mSplOffset
= 0;
970 data
[0].buf
+= chunk_size
;
975 ll_ringbuffer_read_advance(self
->mRing
, advance
);
977 result
= VCALL(self
->mRecordObj
,GetInterface
)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE
,
979 PRINTERR(result
, "recordObj->GetInterface");
981 /* Enqueue any newly-writable chunks in the ring buffer. */
982 ll_ringbuffer_get_write_vector(self
->mRing
, data
);
983 for(i
= 0;i
< data
[0].len
&& SL_RESULT_SUCCESS
== result
;i
++)
985 result
= VCALL(bufferQueue
,Enqueue
)(data
[0].buf
+ chunk_size
*i
, chunk_size
);
986 PRINTERR(result
, "bufferQueue->Enqueue");
988 for(i
= 0;i
< data
[1].len
&& SL_RESULT_SUCCESS
== result
;i
++)
990 result
= VCALL(bufferQueue
,Enqueue
)(data
[1].buf
+ chunk_size
*i
, chunk_size
);
991 PRINTERR(result
, "bufferQueue->Enqueue");
994 if(SL_RESULT_SUCCESS
!= result
)
996 ALCopenslCapture_lock(self
);
997 aluHandleDisconnect(device
, "Failed to update capture buffer: 0x%08x", result
);
998 ALCopenslCapture_unlock(self
);
999 return ALC_INVALID_DEVICE
;
1002 return ALC_NO_ERROR
;
1005 static ALCuint
ALCopenslCapture_availableSamples(ALCopenslCapture
*self
)
1007 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
1008 return ll_ringbuffer_read_space(self
->mRing
) * device
->UpdateSize
;
1012 typedef struct ALCopenslBackendFactory
{
1013 DERIVE_FROM_TYPE(ALCbackendFactory
);
1014 } ALCopenslBackendFactory
;
1015 #define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } }
1017 static ALCboolean
ALCopenslBackendFactory_init(ALCopenslBackendFactory
* UNUSED(self
))
1022 static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory
* UNUSED(self
))
1026 static ALCboolean
ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
1028 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
1033 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory
* UNUSED(self
), enum DevProbe type
)
1037 case ALL_DEVICE_PROBE
:
1038 AppendAllDevicesList(opensl_device
);
1041 case CAPTURE_DEVICE_PROBE
:
1042 AppendAllDevicesList(opensl_device
);
1047 static ALCbackend
* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
1049 if(type
== ALCbackend_Playback
)
1051 ALCopenslPlayback
*backend
;
1052 NEW_OBJ(backend
, ALCopenslPlayback
)(device
);
1053 if(!backend
) return NULL
;
1054 return STATIC_CAST(ALCbackend
, backend
);
1056 if(type
== ALCbackend_Capture
)
1058 ALCopenslCapture
*backend
;
1059 NEW_OBJ(backend
, ALCopenslCapture
)(device
);
1060 if(!backend
) return NULL
;
1061 return STATIC_CAST(ALCbackend
, backend
);
1067 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory
);
1070 ALCbackendFactory
*ALCopenslBackendFactory_getFactory(void)
1072 static ALCopenslBackendFactory factory
= ALCOPENSLBACKENDFACTORY_INITIALIZER
;
1073 return STATIC_CAST(ALCbackendFactory
, &factory
);