Commit d2582f26 authored by David Reid's avatar David Reid

OpenSL: Use runtime linking for libOpenSLES.

Public issues:

  * https://github.com/dr-soft/miniaudio/issues/163
  * https://github.com/dr-soft/miniaudio/issues/183
parent 3e0ad8dd
...@@ -3555,7 +3555,14 @@ struct ma_context ...@@ -3555,7 +3555,14 @@ struct ma_context
#ifdef MA_SUPPORT_OPENSL #ifdef MA_SUPPORT_OPENSL
struct struct
{ {
int _unused; ma_handle libOpenSLES;
ma_handle SL_IID_ENGINE;
ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
ma_handle SL_IID_RECORD;
ma_handle SL_IID_PLAY;
ma_handle SL_IID_OUTPUTMIX;
ma_proc slCreateEngine;
} opensl; } opensl;
#endif #endif
#ifdef MA_SUPPORT_WEBAUDIO #ifdef MA_SUPPORT_WEBAUDIO
...@@ -28878,6 +28885,8 @@ OpenSL|ES Backend ...@@ -28878,6 +28885,8 @@ OpenSL|ES Backend
#include <SLES/OpenSLES_Android.h> #include <SLES/OpenSLES_Android.h>
#endif #endif
typedef SLresult (SLAPIENTRY * ma_slCreateEngine_proc)(SLObjectItf* pEngine, SLuint32 numOptions, SLEngineOption* pEngineOptions, SLuint32 numInterfaces, SLInterfaceID* pInterfaceIds, SLboolean* pInterfaceRequired);
/* OpenSL|ES has one-per-application objects :( */ /* OpenSL|ES has one-per-application objects :( */
SLObjectItf g_maEngineObjectSL = NULL; SLObjectItf g_maEngineObjectSL = NULL;
SLEngineItf g_maEngineSL = NULL; SLEngineItf g_maEngineSL = NULL;
...@@ -29097,7 +29106,7 @@ static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_e ...@@ -29097,7 +29106,7 @@ static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_e
SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]); SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]);
SLAudioIODeviceCapabilitiesItf deviceCaps; SLAudioIODeviceCapabilitiesItf deviceCaps;
SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
/* The interface may not be supported so just report a default device. */ /* The interface may not be supported so just report a default device. */
goto return_default_device; goto return_default_device;
...@@ -29203,7 +29212,7 @@ static ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_dev ...@@ -29203,7 +29212,7 @@ static ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_dev
*/ */
#if 0 && !defined(MA_ANDROID) #if 0 && !defined(MA_ANDROID)
SLAudioIODeviceCapabilitiesItf deviceCaps; SLAudioIODeviceCapabilitiesItf deviceCaps;
SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
/* The interface may not be supported so just report a default device. */ /* The interface may not be supported so just report a default device. */
goto return_default_device; goto return_default_device;
...@@ -29492,7 +29501,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29492,7 +29501,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
SLresult resultSL; SLresult resultSL;
ma_uint32 periodSizeInFrames; ma_uint32 periodSizeInFrames;
size_t bufferSizeInBytes; size_t bufferSizeInBytes;
const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; SLInterfaceID itfIDs1[0];
const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE};
#endif #endif
...@@ -29513,6 +29522,8 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29513,6 +29522,8 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
queues). queues).
*/ */
#ifdef MA_ANDROID #ifdef MA_ANDROID
itfIDs1[0] = (SLInterfaceID)pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
/* No exclusive mode with OpenSL|ES. */ /* No exclusive mode with OpenSL|ES. */
if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) {
...@@ -29569,13 +29580,13 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29569,13 +29580,13 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL));
} }
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_RECORD, &pDevice->opensl.pAudioRecorder); resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice); ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL));
} }
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture); resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice); ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
...@@ -29628,7 +29639,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29628,7 +29639,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL));
} }
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix); resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice); ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL));
...@@ -29672,13 +29683,13 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29672,13 +29683,13 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL));
} }
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_PLAY, &pDevice->opensl.pAudioPlayer); resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice); ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL));
} }
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback); resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice); ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
...@@ -29886,15 +29897,90 @@ static ma_result ma_context_uninit__opensl(ma_context* pContext) ...@@ -29886,15 +29897,90 @@ static ma_result ma_context_uninit__opensl(ma_context* pContext)
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_dlsym_SLInterfaceID__opensl(ma_context* pContext, const char* pName, ma_handle* pHandle)
{
/* We need to return an error if the symbol cannot be found. This is important because there have been reports that some symbols do not exist. */
ma_handle* p = (ma_handle*)ma_dlsym(pContext, pContext->opensl.libOpenSLES, pName);
if (p == NULL) {
ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol %s", pName);
return MA_NO_BACKEND;
}
*pHandle = *p;
return MA_SUCCESS;
}
static ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_context* pContext) static ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_context* pContext)
{ {
ma_result result;
size_t i;
const char* libOpenSLESNames[] = {
"libOpenSLES.so"
};
MA_ASSERT(pContext != NULL); MA_ASSERT(pContext != NULL);
(void)pConfig; (void)pConfig;
/*
Dynamically link against libOpenSLES.so. I have now had multiple reports that SL_IID_ANDROIDSIMPLEBUFFERQUEUE cannot be found. One
report was happening at compile time and another at runtime. To try working around this, I'm going to link to libOpenSLES at runtime
and extract the symbols rather than reference them directly. This should, hopefully, fix these issues as the compiler won't see any
references to the symbols and will hopefully skip the checks.
*/
for (i = 0; i < ma_countof(libOpenSLESNames); i += 1) {
pContext->opensl.libOpenSLES = ma_dlopen(pContext, libOpenSLESNames[i]);
if (pContext->opensl.libOpenSLES != NULL) {
break;
}
}
if (pContext->opensl.libOpenSLES == NULL) {
return MA_NO_BACKEND; /* Couldn't find libOpenSLES.so */
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ENGINE", &pContext->opensl.SL_IID_ENGINE);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_AUDIOIODEVICECAPABILITIES", &pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_RECORD", &pContext->opensl.SL_IID_RECORD);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_PLAY", &pContext->opensl.SL_IID_PLAY);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_OUTPUTMIX", &pContext->opensl.SL_IID_OUTPUTMIX);
if (result != MA_SUCCESS) {
return result;
}
pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine");
if (pContext->opensl.slCreateEngine == NULL) {
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol slCreateEngine.");
return MA_NO_BACKEND;
}
/* Initialize global data first if applicable. */ /* Initialize global data first if applicable. */
if (c89atomic_fetch_add_32(&g_maOpenSLInitCounter, 1) == 0) { if (c89atomic_fetch_add_32(&g_maOpenSLInitCounter, 1) == 0) { /* TODO: Use a spinlock here and remove the atomic increment (can be done with a normal increment inside the critical section). */
SLresult resultSL = slCreateEngine(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL); SLresult resultSL;
resultSL = ((ma_slCreateEngine_proc)pContext->opensl.slCreateEngine)(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
c89atomic_fetch_sub_32(&g_maOpenSLInitCounter, 1); c89atomic_fetch_sub_32(&g_maOpenSLInitCounter, 1);
return ma_result_from_OpenSL(resultSL); return ma_result_from_OpenSL(resultSL);
...@@ -29902,7 +29988,7 @@ static ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_co ...@@ -29902,7 +29988,7 @@ static ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_co
(*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE); (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE);
resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_ENGINE, &g_maEngineSL); resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_ENGINE, &g_maEngineSL);
if (resultSL != SL_RESULT_SUCCESS) { if (resultSL != SL_RESULT_SUCCESS) {
(*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL); (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
c89atomic_fetch_sub_32(&g_maOpenSLInitCounter, 1); c89atomic_fetch_sub_32(&g_maOpenSLInitCounter, 1);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment