diff options
author | Chris Robinson <[email protected]> | 2018-11-13 00:33:25 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2018-11-13 00:33:25 -0800 |
commit | 51a1310902d45220cc89f498403d91ee57905c90 (patch) | |
tree | 1f7d58c9cab1e9250d30142895e2b0ba3c7048f5 /Alc/backends/opensl.c | |
parent | c93b7ca0daf453b963f27d8d44dbb94cc8d581dd (diff) |
Convert the OpenSL backend to C++
Diffstat (limited to 'Alc/backends/opensl.c')
-rw-r--r-- | Alc/backends/opensl.c | 1070 |
1 files changed, 0 insertions, 1070 deletions
diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c deleted file mode 100644 index d8ae001b..00000000 --- a/Alc/backends/opensl.c +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This is an OpenAL backend for Android using the native audio APIs based on - * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app - * bundled with NDK. - */ - -#include "config.h" - -#include <stdlib.h> -#include <jni.h> - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include <SLES/OpenSLES.h> -#include <SLES/OpenSLES_Android.h> -#include <SLES/OpenSLES_AndroidConfiguration.h> - -/* Helper macros */ -#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS -#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS - - -static const ALCchar opensl_device[] = "OpenSL"; - - -static SLuint32 GetChannelMask(enum DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; - case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; - case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_CENTER| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtAmbi3D: - break; - } - return 0; -} - -#ifdef SL_DATAFORMAT_PCM_EX -static SLuint32 GetTypeRepresentation(enum DevFmtType type) -{ - switch(type) - { - case DevFmtUByte: - case DevFmtUShort: - case DevFmtUInt: - return SL_PCM_REPRESENTATION_UNSIGNED_INT; - case DevFmtByte: - case DevFmtShort: - case DevFmtInt: - return SL_PCM_REPRESENTATION_SIGNED_INT; - case DevFmtFloat: - return SL_PCM_REPRESENTATION_FLOAT; - } - return 0; -} -#endif - -static const char *res_str(SLresult result) -{ - switch(result) - { - case SL_RESULT_SUCCESS: return "Success"; - case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; - case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; - case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; - case SL_RESULT_RESOURCE_ERROR: return "Resource error"; - case SL_RESULT_RESOURCE_LOST: return "Resource lost"; - case SL_RESULT_IO_ERROR: return "I/O error"; - case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; - case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; - case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; - case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; - case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; - case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; - case SL_RESULT_INTERNAL_ERROR: return "Internal error"; - case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; - case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; - case SL_RESULT_CONTROL_LOST: return "Control lost"; -#ifdef SL_RESULT_READONLY - case SL_RESULT_READONLY: return "ReadOnly"; -#endif -#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED - case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; -#endif -#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE - case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; -#endif - } - return "Unknown error code"; -} - -#define PRINTERR(x, s) do { \ - if((x) != SL_RESULT_SUCCESS) \ - ERR("%s: %s\n", (s), res_str((x))); \ -} while(0) - - -typedef struct ALCopenslPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - /* engine interfaces */ - SLObjectItf mEngineObj; - SLEngineItf mEngine; - - /* output mix interfaces */ - SLObjectItf mOutputMix; - - /* buffer queue player interfaces */ - SLObjectItf mBufferQueueObj; - - ll_ringbuffer_t *mRing; - alsem_t mSem; - - ALsizei mFrameSize; - - ATOMIC(ALenum) mKillNow; - althrd_t mThread; -} ALCopenslPlayback; - -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); -static int ALCopenslPlayback_mixerProc(void *arg); - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); -static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); -static void ALCopenslPlayback_stop(ALCopenslPlayback *self); -static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); - - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); - - self->mEngineObj = NULL; - self->mEngine = NULL; - self->mOutputMix = NULL; - self->mBufferQueueObj = NULL; - - self->mRing = NULL; - alsem_init(&self->mSem, 0); - - self->mFrameSize = 0; - - ATOMIC_INIT(&self->mKillNow, AL_FALSE); -} - -static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) -{ - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - if(self->mOutputMix) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - alsem_destroy(&self->mSem); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -/* this callback handler is called every time a buffer finishes playing */ -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) -{ - ALCopenslPlayback *self = context; - - /* A note on the ringbuffer usage: The buffer queue seems to hold on to the - * pointer passed to the Enqueue method, rather than copying the audio. - * Consequently, the ringbuffer contains the audio that is currently queued - * and waiting to play. This process() callback is called when a buffer is - * finished, so we simply move the read pointer up to indicate the space is - * available for writing again, and wake up the mixer thread to mix and - * queue more audio. - */ - ll_ringbuffer_read_advance(self->mRing, 1); - - alsem_post(&self->mSem); -} - - -static int ALCopenslPlayback_mixerProc(void *arg) -{ - ALCopenslPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; - SLPlayItf player; - SLresult result; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); - } - - ALCopenslPlayback_lock(self); - if(SL_RESULT_SUCCESS != result) - aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); - - while(SL_RESULT_SUCCESS == result && - !ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - size_t todo; - - if(ll_ringbuffer_write_space(self->mRing) == 0) - { - SLuint32 state = 0; - - result = VCALL(player,GetPlayState)(&state); - PRINTERR(result, "player->GetPlayState"); - if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); - PRINTERR(result, "player->SetPlayState"); - } - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result); - break; - } - - if(ll_ringbuffer_write_space(self->mRing) == 0) - { - ALCopenslPlayback_unlock(self); - alsem_wait(&self->mSem); - ALCopenslPlayback_lock(self); - continue; - } - } - - ll_ringbuffer_get_write_vector(self->mRing, data); - - aluMixData(device, data[0].buf, data[0].len*device->UpdateSize); - if(data[1].len > 0) - aluMixData(device, data[1].buf, data[1].len*device->UpdateSize); - - todo = data[0].len+data[1].len; - ll_ringbuffer_write_advance(self->mRing, todo); - - for(size_t i = 0;i < todo;i++) - { - if(!data[0].len) - { - data[0] = data[1]; - data[1].buf = NULL; - data[1].len = 0; - } - - result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result); - break; - } - - data[0].len--; - data[0].buf += device->UpdateSize*self->mFrameSize; - } - } - ALCopenslPlayback_unlock(self); - - return 0; -} - - -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLresult result; - - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - // create engine - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); - PRINTERR(result, "engine->CreateOutputMix"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "outputMix->Realize"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mOutputMix != NULL) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataLocator_OutputMix loc_outmix; - SLDataSource audioSrc; - SLDataSink audioSnk; - ALuint sampleRate; - SLInterfaceID ids[2]; - SLboolean reqs[2]; - SLresult result; - - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - sampleRate = device->Frequency; -#if 0 - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - { - /* FIXME: Disabled until I figure out how to get the Context needed for - * the getSystemService call. - */ - JNIEnv *env = Android_GetJNIEnv(); - jobject jctx = Android_GetContext(); - - /* Get necessary stuff for using java.lang.Integer, - * android.content.Context, and android.media.AudioManager. - */ - jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); - jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, - "parseInt", "(Ljava/lang/String;)I" - ); - TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); - - jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); - jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, - "AUDIO_SERVICE", "Ljava/lang/String;" - ); - jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, - "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" - ); - TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", - ctx_cls, ctx_audsvc, ctx_getSysSvc); - - jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); - jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, - "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" - ); - jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, - "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" - ); - TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", - audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); - - const char *strchars; - jstring strobj; - - /* Now make the calls. */ - //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); - TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); - jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); - TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //int sampleRate = Integer.parseInt(srateStr); - sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); - - strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL); - TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); - JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); - - if(!sampleRate) sampleRate = device->Frequency; - else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); - } -#endif - - if(sampleRate != device->Frequency) - { - device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / - device->Frequency; - device->NumUpdates = maxu(device->NumUpdates, 2); - device->Frequency = sampleRate; - } - - device->FmtChans = DevFmtStereo; - device->FmtType = DevFmtShort; - - SetDefaultWFXChannelOrder(device); - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - - loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = device->NumUpdates; - -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); -#else - SLDataFormat_PCM format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif - - audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = &format_pcm; - - loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = self->mOutputMix; - audioSnk.pLocator = &loc_outmix; - audioSnk.pFormat = NULL; - - - ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - reqs[0] = SL_BOOLEAN_TRUE; - ids[1] = SL_IID_ANDROIDCONFIGURATION; - reqs[1] = SL_BOOLEAN_FALSE; - - result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); - PRINTERR(result, "engine->CreateAudioPlayer"); - if(SL_RESULT_SUCCESS == result) - { - /* Set the stream type to "media" (games, music, etc), if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLint32 streamType = SL_ANDROID_STREAM_MEDIA; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, - &streamType, sizeof(streamType) - ); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "bufferQueue->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true - ); - if(!self->mRing) - { - ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, - device->NumUpdates, self->mFrameSize); - result = SL_RESULT_MEMORY_FAILURE; - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) -{ - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; - - ll_ringbuffer_reset(self->mRing); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; - - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self); - PRINTERR(result, "bufferQueue->RegisterCallback"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; - - ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE); - if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) - { - ERR("Failed to start mixer thread\n"); - return ALC_FALSE; - } - - return ALC_TRUE; -} - - -static void ALCopenslPlayback_stop(ALCopenslPlayback *self) -{ - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) - return; - - alsem_post(&self->mSem); - althrd_join(self->mThread, &res); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); - PRINTERR(result, "player->SetPlayState"); - } - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL0(bufferQueue,Clear)(); - PRINTERR(result, "bufferQueue->Clear"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - SLAndroidSimpleBufferQueueState state; - do { - althrd_yield(); - result = VCALL(bufferQueue,GetState)(&state); - } while(SL_RESULT_SUCCESS == result && state.count > 0); - PRINTERR(result, "bufferQueue->GetState"); - } -} - -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCopenslPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize * - DEVICE_CLOCK_RES / device->Frequency; - ALCopenslPlayback_unlock(self); - - return ret; -} - - -typedef struct ALCopenslCapture { - DERIVE_FROM_TYPE(ALCbackend); - - /* engine interfaces */ - SLObjectItf mEngineObj; - SLEngineItf mEngine; - - /* recording interfaces */ - SLObjectItf mRecordObj; - - ll_ringbuffer_t *mRing; - ALCuint mSplOffset; - - ALsizei mFrameSize; -} ALCopenslCapture; - -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); -static void ALCopenslCapture_Destruct(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); -static void ALCopenslCapture_stop(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) -DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); - - -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) -{ - ALCopenslCapture *self = context; - /* A new chunk has been written into the ring buffer, advance it. */ - ll_ringbuffer_write_advance(self->mRing, 1); -} - - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCopenslCapture, ALCbackend, self); - - self->mEngineObj = NULL; - self->mEngine = NULL; - - self->mRecordObj = NULL; - - self->mRing = NULL; - self->mSplOffset = 0; - - self->mFrameSize = 0; -} - -static void ALCopenslCapture_Destruct(ALCopenslCapture *self) -{ - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - SLDataLocator_AndroidSimpleBufferQueue loc_bq; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLDataLocator_IODevice loc_dev; - SLDataSource audioSrc; - SLDataSink audioSnk; - SLresult result; - - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - /* Ensure the total length is at least 100ms */ - ALsizei length = maxi(device->NumUpdates * device->UpdateSize, - device->Frequency / 10); - /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, - device->Frequency / 100, - device->Frequency / 100 * 5); - - device->UpdateSize = update_len; - device->NumUpdates = (length+update_len-1) / update_len; - - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - } - loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; - loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; - loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; - loc_dev.device = NULL; - - audioSrc.pLocator = &loc_dev; - audioSrc.pFormat = NULL; - - loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bq.numBuffers = device->NumUpdates; - -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); -#else - SLDataFormat_PCM format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif - - audioSnk.pLocator = &loc_bq; - audioSnk.pFormat = &format_pcm; - - if(SL_RESULT_SUCCESS == result) - { - const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; - - result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); - PRINTERR(result, "engine->CreateAudioRecorder"); - } - if(SL_RESULT_SUCCESS == result) - { - /* Set the record preset to "generic", if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, - &preset, sizeof(preset) - ); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "recordObj->Realize"); - } - - if(SL_RESULT_SUCCESS == result) - { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false - ); - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; - ll_ringbuffer_data_t data[2]; - size_t i; - - ll_ringbuffer_get_write_vector(self->mRing, data); - for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) -{ - SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); - PRINTERR(result, "record->SetRecordState"); - } - - if(SL_RESULT_SUCCESS != result) - { - ALCopenslCapture_lock(self); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failed to start capture: 0x%08x", result); - ALCopenslCapture_unlock(self); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCopenslCapture_stop(ALCopenslCapture *self) -{ - SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); - PRINTERR(result, "record->SetRecordState"); - } -} - -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; - SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; - SLresult result; - ALCuint i; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - - /* Read the desired samples from the ring buffer then advance its read - * pointer. - */ - ll_ringbuffer_get_read_vector(self->mRing, data); - for(i = 0;i < samples;) - { - ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); - memcpy((ALCbyte*)buffer + i*self->mFrameSize, - data[0].buf + self->mSplOffset*self->mFrameSize, - rem * self->mFrameSize); - - self->mSplOffset += rem; - if(self->mSplOffset == device->UpdateSize) - { - /* Finished a chunk, reset the offset and advance the read pointer. */ - self->mSplOffset = 0; - - ll_ringbuffer_read_advance(self->mRing, 1); - result = VCALL(bufferQueue,Enqueue)(data[0].buf, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) break; - - data[0].len--; - if(!data[0].len) - data[0] = data[1]; - else - data[0].buf += chunk_size; - } - - i += rem; - } - - if(SL_RESULT_SUCCESS != result) - { - ALCopenslCapture_lock(self); - aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); - ALCopenslCapture_unlock(self); - return ALC_INVALID_DEVICE; - } - - return ALC_NO_ERROR; -} - -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize; -} - - -typedef struct ALCopenslBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCopenslBackendFactory; -#define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self)) -{ -} - -static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device)); - break; - } -} - -static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCopenslPlayback *backend; - NEW_OBJ(backend, ALCopenslPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCopenslCapture *backend; - NEW_OBJ(backend, ALCopenslCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory); - - -ALCbackendFactory *ALCopenslBackendFactory_getFactory(void) -{ - static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} |