Merge pull request #204 from jhasse/android-byte-order
[openal-soft.git] / Alc / backends / opensl.c
bloba5ad3b098728f28f8199c31590a44d83f08d0c2d
1 /*
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
19 * bundled with NDK.
22 #include "config.h"
24 #include <stdlib.h>
25 #include <jni.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "ringbuffer.h"
30 #include "threads.h"
31 #include "compat.h"
33 #include "backends/base.h"
35 #include <SLES/OpenSLES.h>
36 #include <SLES/OpenSLES_Android.h>
37 #include <SLES/OpenSLES_AndroidConfiguration.h>
39 /* Helper macros */
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)
49 switch(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;
69 case DevFmtAmbi3D:
70 break;
72 return 0;
75 #ifdef SL_DATAFORMAT_PCM_EX
76 static SLuint32 GetTypeRepresentation(enum DevFmtType type)
78 switch(type)
80 case DevFmtUByte:
81 case DevFmtUShort:
82 case DevFmtUInt:
83 return SL_PCM_REPRESENTATION_UNSIGNED_INT;
84 case DevFmtByte:
85 case DevFmtShort:
86 case DevFmtInt:
87 return SL_PCM_REPRESENTATION_SIGNED_INT;
88 case DevFmtFloat:
89 return SL_PCM_REPRESENTATION_FLOAT;
91 return 0;
93 #endif
95 static const char *res_str(SLresult result)
97 switch(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";
118 #endif
119 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
120 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
121 #endif
122 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
123 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
124 #endif
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))); \
132 } while(0)
135 typedef struct ALCopenslPlayback {
136 DERIVE_FROM_TYPE(ALCbackend);
138 /* engine interfaces */
139 SLObjectItf mEngineObj;
140 SLEngineItf mEngine;
142 /* output mix interfaces */
143 SLObjectItf mOutputMix;
145 /* buffer queue player interfaces */
146 SLObjectItf mBufferQueueObj;
148 ll_ringbuffer_t *mRing;
149 alsem_t mSem;
151 ALsizei mFrameSize;
153 ATOMIC(ALenum) mKillNow;
154 althrd_t mThread;
155 } ALCopenslPlayback;
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;
186 self->mRing = 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;
200 if(self->mOutputMix)
201 VCALL0(self->mOutputMix,Destroy)();
202 self->mOutputMix = NULL;
204 if(self->mEngineObj)
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
226 * queue more audio.
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];
240 SLPlayItf player;
241 SLresult result;
243 SetRTPriority();
244 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
246 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
247 &bufferQueue);
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);
259 return 1;
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)
270 SLuint32 state = 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);
282 break;
285 if(ll_ringbuffer_write_space(self->mRing) == 0)
287 ALCopenslPlayback_unlock(self);
288 alsem_wait(&self->mSem);
289 ALCopenslPlayback_lock(self);
290 continue;
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;
311 if(len1 > 0)
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);
327 return 0;
331 static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name)
333 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
334 SLresult result;
336 if(!name)
337 name = opensl_device;
338 else if(strcmp(name, opensl_device) != 0)
339 return ALC_INVALID_VALUE;
341 // create engine
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);
381 return ALC_NO_ERROR;
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;
390 SLDataSink audioSnk;
391 ALuint sampleRate;
392 SLInterfaceID ids[2];
393 SLboolean reqs[2];
394 SLresult result;
395 JNIEnv *env;
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.
407 #if 0
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;
438 jstring strobj;
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);
464 #endif
467 if(sampleRate != device->Frequency)
469 device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) /
470 device->Frequency;
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);
496 #else
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;
506 #endif
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;
556 return ALC_FALSE;
559 return ALC_TRUE;
562 static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self)
564 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
565 SLAndroidSimpleBufferQueueItf bufferQueue;
566 SLresult result;
568 ll_ringbuffer_free(self->mRing);
569 self->mRing = ll_ringbuffer_create(device->NumUpdates, self->mFrameSize*device->UpdateSize,
570 true);
572 result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
573 &bufferQueue);
574 PRINTERR(result, "bufferQueue->GetInterface");
575 if(SL_RESULT_SUCCESS != result)
576 return ALC_FALSE;
578 result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self);
579 PRINTERR(result, "bufferQueue->RegisterCallback");
580 if(SL_RESULT_SUCCESS != result)
581 return ALC_FALSE;
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");
587 return ALC_FALSE;
590 return ALC_TRUE;
594 static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
596 SLAndroidSimpleBufferQueueItf bufferQueue;
597 SLPlayItf player;
598 SLresult result;
599 int res;
601 if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE))
602 return;
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,
616 &bufferQueue);
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;
631 do {
632 althrd_yield();
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);
639 self->mRing = NULL;
642 static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self)
644 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
645 ClockLatency ret;
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);
653 return ret;
657 typedef struct ALCopenslCapture {
658 DERIVE_FROM_TYPE(ALCbackend);
660 /* engine interfaces */
661 SLObjectItf mEngineObj;
662 SLEngineItf mEngine;
664 /* recording interfaces */
665 SLObjectItf mRecordObj;
667 ll_ringbuffer_t *mRing;
668 ALCuint mSplOffset;
670 ALsizei mFrameSize;
671 } ALCopenslCapture;
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;
708 self->mRing = NULL;
709 self->mSplOffset = 0;
711 self->mFrameSize = 0;
714 static void ALCopenslCapture_Destruct(ALCopenslCapture *self)
716 ll_ringbuffer_free(self->mRing);
717 self->mRing = NULL;
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;
738 SLDataSink audioSnk;
739 SLresult result;
741 if(!name)
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);
795 #else
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;
805 #endif
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,
847 false);
849 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
850 &bufferQueue);
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];
862 size_t i;
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);
893 return ALC_NO_ERROR;
896 static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self)
898 SLRecordItf record;
899 SLresult result;
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);
916 return ALC_FALSE;
919 return ALC_TRUE;
922 static void ALCopenslCapture_stop(ALCopenslCapture *self)
924 SLRecordItf record;
925 SLresult result;
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];
943 SLresult result;
944 size_t advance;
945 ALCuint i;
947 /* Read the desired samples from the ring buffer then advance its read
948 * pointer.
950 ll_ringbuffer_get_read_vector(self->mRing, data);
951 advance = 0;
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;
964 advance++;
966 data[0].len--;
967 if(!data[0].len)
968 data[0] = data[1];
969 else
970 data[0].buf += chunk_size;
973 i += rem;
975 ll_ringbuffer_read_advance(self->mRing, advance);
977 result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
978 &bufferQueue);
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))
1019 return ALC_TRUE;
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)
1029 return ALC_TRUE;
1030 return ALC_FALSE;
1033 static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type)
1035 switch(type)
1037 case ALL_DEVICE_PROBE:
1038 AppendAllDevicesList(opensl_device);
1039 break;
1041 case CAPTURE_DEVICE_PROBE:
1042 AppendAllDevicesList(opensl_device);
1043 break;
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);
1064 return NULL;
1067 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory);
1070 ALCbackendFactory *ALCopenslBackendFactory_getFactory(void)
1072 static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER;
1073 return STATIC_CAST(ALCbackendFactory, &factory);