mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 00:34:03 +02:00
API CHANGE: Updates to custom backends.
Custom backends must now use the `ma_device_backend_vtable` object to define their callbacks. All of these functions are largely the same, except they all now take a `void*` as their first parameter which represents the user data pointer. The ma_backend_callbacks parameter has been removed from onContextInit which means you must now statically define your callbacks in the ma_device_backend_vtable object that you pass into the context config. The `custom` member of the context config has been replaced with a new set of members to support the ability to plug in multiple vtables.
This commit is contained in:
+62
-73
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
This example show how a custom backend can be implemented.
|
||||
This example shows how a custom backend can be implemented.
|
||||
|
||||
This implements a full-featured SDL2 backend. It's intentionally built using the same paradigms as the built-in backends in order to make
|
||||
it suitable as a solid basis for a custom implementation. The SDL2 backend can be disabled with MA_NO_SDL, exactly like the build-in
|
||||
it suitable as a solid basis for a custom implementation. The SDL2 backend can be disabled with MA_NO_SDL, exactly like the built-in
|
||||
backends. It supports both runtime and compile-time linking and respects the MA_NO_RUNTIME_LINKING option. It also works on Emscripten
|
||||
which requires the `-s USE_SDL=2` option.
|
||||
|
||||
@@ -11,17 +11,21 @@ custom backends without needing to modify any of the base miniaudio initializati
|
||||
`ma_context_ex`. The first member of this structure is a `ma_context` object which allows it to be cast between the two. The same is done
|
||||
for devices, which is called `ma_device_ex`. In these structures there is a section for each custom backend, which in this example is just
|
||||
SDL. These are only enabled at compile time if `MA_SUPPORT_SDL` is defined, which it always is in this example (you may want to have some
|
||||
logic which more intelligently enables or disables SDL support).
|
||||
logic which more intelligently enables or disables SDL support). This is not the only way to associate backend-specific data with the
|
||||
context and/or device. In both the `ma_context` and `ma_device` structures there is a member named `pBackendData` which is a `void*` and
|
||||
can be used to reference any data you like. It is not used by miniaudio and exists purely for the purpose of allowing you to associate
|
||||
backend-specific data with the context and/or device.
|
||||
|
||||
To use a custom backend, at a minimum you must set the `custom.onContextInit()` callback in the context config. You do not need to set the
|
||||
other callbacks, but if you don't, you must set them in the implementation of the `onContextInit()` callback which is done via an output
|
||||
parameter. This is the approach taken by this example because it's the simplest way to support multiple custom backends. The idea is that
|
||||
the `onContextInit()` callback is set to a generic "loader", which then calls out to a backend-specific implementation which then sets the
|
||||
remaining callbacks if it is successfully initialized.
|
||||
To use a custom backend, you must implement a `ma_device_backend_vtable`. You pass a pointer to this into the context config along with
|
||||
an optional user data pointer. In this example we just declare our `ma_device_backend_vtable` statically and pass in NULL for the user
|
||||
data. The device config accepts an array of vtable pointers which is how you can plug in multiple custom backends. In this example we just
|
||||
have the one vtable pointer, but it's designed to easily allow you to plug in other custom backends. Any functions that you don't need
|
||||
can be defined as NULL in the vtable.
|
||||
|
||||
Custom backends are identified with the `ma_backend_custom` backend type. For the purpose of demonstration, this example only uses the
|
||||
`ma_backend_custom` backend type because otherwise the built-in backends would always get chosen first and none of the code for the custom
|
||||
backends would actually get hit. By default, the `ma_backend_custom` backend is the lowest priority backend, except for `ma_backend_null`.
|
||||
backends would actually get hit. By default, the `ma_backend_custom` backend is the second-lowest priority backend, sitting just above
|
||||
`ma_backend_null`.
|
||||
*/
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "../miniaudio.h"
|
||||
@@ -173,7 +177,7 @@ ma_format ma_format_from_sdl(MA_SDL_AudioFormat format)
|
||||
}
|
||||
}
|
||||
|
||||
static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
static ma_result ma_context_enumerate_devices__sdl(void* pUserData, ma_context* pContext, ma_enum_devices_callback_proc callback, void* pCallbackUserData)
|
||||
{
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pContext;
|
||||
ma_bool32 isTerminated = MA_FALSE;
|
||||
@@ -182,6 +186,7 @@ static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
MA_ASSERT(callback != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
/* Playback */
|
||||
if (!isTerminated) {
|
||||
@@ -197,7 +202,7 @@ static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum
|
||||
deviceInfo.isDefault = MA_TRUE;
|
||||
}
|
||||
|
||||
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
|
||||
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pCallbackUserData);
|
||||
if (cbResult == MA_FALSE) {
|
||||
isTerminated = MA_TRUE;
|
||||
break;
|
||||
@@ -219,7 +224,7 @@ static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum
|
||||
deviceInfo.isDefault = MA_TRUE;
|
||||
}
|
||||
|
||||
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
|
||||
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pCallbackUserData);
|
||||
if (cbResult == MA_FALSE) {
|
||||
isTerminated = MA_TRUE;
|
||||
break;
|
||||
@@ -230,7 +235,7 @@ static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_get_device_info__sdl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
|
||||
static ma_result ma_context_get_device_info__sdl(void* pUserData, ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
|
||||
{
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pContext;
|
||||
|
||||
@@ -242,6 +247,7 @@ static ma_result ma_context_get_device_info__sdl(ma_context* pContext, ma_device
|
||||
#endif
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
if (pDeviceID == NULL) {
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
@@ -424,13 +430,14 @@ static ma_result ma_device_init_internal__sdl(ma_device_ex* pDeviceEx, const ma_
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_init__sdl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||
static ma_result ma_device_init__sdl(void* pUserData, ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||
{
|
||||
ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice;
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext;
|
||||
ma_result result;
|
||||
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
/* SDL does not support loopback mode, so must return MA_DEVICE_TYPE_NOT_SUPPORTED if it's requested. */
|
||||
if (pConfig->deviceType == ma_device_type_loopback) {
|
||||
@@ -458,12 +465,13 @@ static ma_result ma_device_init__sdl(ma_device* pDevice, const ma_device_config*
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_uninit__sdl(ma_device* pDevice)
|
||||
static ma_result ma_device_uninit__sdl(void* pUserData, ma_device* pDevice)
|
||||
{
|
||||
ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice;
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext;
|
||||
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||
((MA_PFN_SDL_CloseAudioDevice)pContextEx->sdl.SDL_CloseAudioDevice)(pDeviceEx->sdl.deviceIDCapture);
|
||||
@@ -476,12 +484,13 @@ static ma_result ma_device_uninit__sdl(ma_device* pDevice)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_start__sdl(ma_device* pDevice)
|
||||
static ma_result ma_device_start__sdl(void* pUserData, ma_device* pDevice)
|
||||
{
|
||||
ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice;
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext;
|
||||
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||
((MA_PFN_SDL_PauseAudioDevice)pContextEx->sdl.SDL_PauseAudioDevice)(pDeviceEx->sdl.deviceIDCapture, 0);
|
||||
@@ -494,12 +503,13 @@ static ma_result ma_device_start__sdl(ma_device* pDevice)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_stop__sdl(ma_device* pDevice)
|
||||
static ma_result ma_device_stop__sdl(void* pUserData, ma_device* pDevice)
|
||||
{
|
||||
ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice;
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext;
|
||||
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||
((MA_PFN_SDL_PauseAudioDevice)pContextEx->sdl.SDL_PauseAudioDevice)(pDeviceEx->sdl.deviceIDCapture, 1);
|
||||
@@ -512,11 +522,12 @@ static ma_result ma_device_stop__sdl(ma_device* pDevice)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_uninit__sdl(ma_context* pContext)
|
||||
static ma_result ma_context_uninit__sdl(void* pUserData, ma_context* pContext)
|
||||
{
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pContext;
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
(void)pUserData;
|
||||
|
||||
((MA_PFN_SDL_QuitSubSystem)pContextEx->sdl.SDL_QuitSubSystem)(MA_SDL_INIT_AUDIO);
|
||||
|
||||
@@ -527,7 +538,7 @@ static ma_result ma_context_uninit__sdl(ma_context* pContext)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||
static ma_result ma_context_init__sdl(void* pUserData, ma_context* pContext, const ma_context_config* pConfig)
|
||||
{
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pContext;
|
||||
int resultSDL;
|
||||
@@ -547,6 +558,7 @@ static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_con
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
|
||||
(void)pUserData;
|
||||
(void)pConfig;
|
||||
|
||||
/* Check if we have SDL2 installed somewhere. If not it's not usable and we need to abort. */
|
||||
@@ -585,51 +597,26 @@ static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_con
|
||||
return MA_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
The last step is to make sure the callbacks are set properly in `pCallbacks`. Internally, miniaudio will copy these callbacks into the
|
||||
context object and then use them for then on for calling into our custom backend.
|
||||
*/
|
||||
pCallbacks->onContextInit = ma_context_init__sdl;
|
||||
pCallbacks->onContextUninit = ma_context_uninit__sdl;
|
||||
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__sdl;
|
||||
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__sdl;
|
||||
pCallbacks->onDeviceInit = ma_device_init__sdl;
|
||||
pCallbacks->onDeviceUninit = ma_device_uninit__sdl;
|
||||
pCallbacks->onDeviceStart = ma_device_start__sdl;
|
||||
pCallbacks->onDeviceStop = ma_device_stop__sdl;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
#endif /* MA_HAS_SDL */
|
||||
|
||||
|
||||
/*
|
||||
This is our custom backend "loader". All this does is attempts to initialize our custom backends in the order they are listed. The first
|
||||
one to successfully initialize is the one that's chosen. In this example we're just listing them statically, but you can use whatever logic
|
||||
you want to handle backend selection.
|
||||
|
||||
This is used as the onContextInit() callback in the context config.
|
||||
*/
|
||||
static ma_result ma_context_init__custom_loader(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||
static ma_device_backend_vtable ma_gDeviceBackendVTable_SDL =
|
||||
{
|
||||
ma_result result = MA_NO_BACKEND;
|
||||
|
||||
/* Silence some unused parameter warnings just in case no custom backends are enabled. */
|
||||
(void)pContext;
|
||||
(void)pCallbacks;
|
||||
|
||||
/* SDL. */
|
||||
#if !defined(MA_NO_SDL)
|
||||
if (result != MA_SUCCESS) {
|
||||
result = ma_context_init__sdl(pContext, pConfig, pCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ... plug in any other custom backends here ... */
|
||||
|
||||
/* If we have a success result we have initialized a backend. Otherwise we need to tell miniaudio about the error so it can skip over our custom backends. */
|
||||
return result;
|
||||
}
|
||||
ma_context_init__sdl,
|
||||
ma_context_uninit__sdl,
|
||||
ma_context_enumerate_devices__sdl,
|
||||
ma_context_get_device_info__sdl,
|
||||
ma_device_init__sdl,
|
||||
ma_device_uninit__sdl,
|
||||
ma_device_start__sdl,
|
||||
ma_device_stop__sdl,
|
||||
NULL, /* onDeviceRead */
|
||||
NULL, /* onDeviceWrite */
|
||||
NULL, /* onDeviceDataLoop */
|
||||
NULL, /* onDeviceDataLoopWakeup */
|
||||
NULL /* onDeviceGetInfo */
|
||||
};
|
||||
#endif /* MA_HAS_SDL */
|
||||
|
||||
|
||||
/*
|
||||
@@ -666,6 +653,7 @@ int main(int argc, char** argv)
|
||||
ma_device_ex device;
|
||||
ma_waveform_config sineWaveConfig;
|
||||
ma_waveform sineWave;
|
||||
char name[256];
|
||||
|
||||
/*
|
||||
We're just using ma_backend_custom in this example for demonstration purposes, but a more realistic use case would probably want to include
|
||||
@@ -675,20 +663,20 @@ int main(int argc, char** argv)
|
||||
ma_backend_custom
|
||||
};
|
||||
|
||||
/*
|
||||
To implement a custom backend you need to implement the callbacks in the "custom" member of the context config. The only mandatory
|
||||
callback required at this point is the onContextInit() callback. If you do not set the other callbacks, you must set them in
|
||||
onContextInit() by setting them on the `pCallbacks` parameter.
|
||||
/* Plug in our vtable pointers. Add any custom backends to this list. */
|
||||
ma_device_backend_vtable* pBackendVTables[] =
|
||||
{
|
||||
#if !defined(MA_NO_SDL)
|
||||
&ma_gDeviceBackendVTable_SDL,
|
||||
#endif
|
||||
NULL, /* Just so we don't end up with an empty array. */
|
||||
};
|
||||
|
||||
The way we're doing it in this example enables us to easily plug in multiple custom backends. What we do is set the onContextInit()
|
||||
callback to a generic "loader" function (ma_context_init__custom_loader() in this example), which then calls out to backend-specific
|
||||
context initialization routines, one of which will be for SDL. That way, if for example we wanted to add support for another backend,
|
||||
we don't need to touch this part of the code. Instead we add logic to ma_context_init__custom_loader() to choose the most appropriate
|
||||
custom backend. That will then fill out the other callbacks appropriately.
|
||||
*/
|
||||
contextConfig = ma_context_config_init();
|
||||
contextConfig.custom.onContextInit = ma_context_init__custom_loader;
|
||||
|
||||
contextConfig.custom.ppVTables = pBackendVTables;
|
||||
contextConfig.custom.ppUserDatas = NULL; /* We're not using user data in this example so can set this to NULL, but if you need it, declare an array here, one for each item in ppVTables. */
|
||||
contextConfig.custom.count = (sizeof(pBackendVTables) / sizeof(pBackendVTables[0])) - 1;
|
||||
|
||||
result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &contextConfig, (ma_context*)&context);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
@@ -715,7 +703,8 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
|
||||
printf("Device Name: %s\n", ((ma_device*)&device)->playback.name);
|
||||
ma_device_get_name((ma_device*)&device, ma_device_type_playback, name, sizeof(name), NULL);
|
||||
printf("Device Name: %s\n", name);
|
||||
|
||||
if (ma_device_start((ma_device*)&device) != MA_SUCCESS) {
|
||||
ma_device_uninit((ma_device*)&device);
|
||||
|
||||
+49
-29
@@ -7185,7 +7185,7 @@ struct ma_backend_callbacks
|
||||
|
||||
struct ma_device_backend_vtable
|
||||
{
|
||||
ma_result (* onContextInit )(void* pUserData, ma_context* pContext, const ma_context_config* pConfig, ma_device_backend_vtable** ppBackendVTable, void** ppBackendUserData);
|
||||
ma_result (* onContextInit )(void* pUserData, ma_context* pContext, const ma_context_config* pConfig);
|
||||
ma_result (* onContextUninit )(void* pUserData, ma_context* pContext);
|
||||
ma_result (* onContextEnumerateDevices)(void* pUserData, ma_context* pContext, ma_enum_devices_callback_proc callback, void* pCallbackUserData);
|
||||
ma_result (* onContextGetDeviceInfo )(void* pUserData, ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
|
||||
@@ -7242,10 +7242,8 @@ struct ma_context_config
|
||||
{
|
||||
ma_device_backend_vtable** ppVTables;
|
||||
void** ppUserDatas;
|
||||
ma_uint32 count;
|
||||
} custom2;
|
||||
|
||||
ma_backend_callbacks custom;
|
||||
size_t count;
|
||||
} custom;
|
||||
};
|
||||
|
||||
/* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */
|
||||
@@ -7279,6 +7277,7 @@ struct ma_context
|
||||
ma_backend_callbacks callbacks; /* Old system. Will be removed when all stock backends have been converted over to the new system. */
|
||||
ma_device_backend_vtable* pVTable; /* New system. */
|
||||
void* pVTableUserData;
|
||||
void* pBackendData; /* This is not used by miniaudio, but is a way for custom backends to store associate some backend-specific data with the device. Custom backends are free to use this pointer however they like. */
|
||||
ma_backend backend; /* DirectSound, ALSA, etc. */
|
||||
ma_log* pLog;
|
||||
ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
|
||||
@@ -7690,6 +7689,7 @@ struct ma_device
|
||||
ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */
|
||||
ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */
|
||||
void* pUserData; /* Application defined data. */
|
||||
void* pBackendData; /* This is not used by miniaudio, but is a way for custom backends to store associate some backend-specific data with the device. Custom backends are free to use this pointer however they like. */
|
||||
ma_mutex startStopLock;
|
||||
ma_event wakeupEvent;
|
||||
ma_event startEvent;
|
||||
@@ -17769,11 +17769,9 @@ DEVICE I/O
|
||||
|
||||
|
||||
|
||||
static ma_result ma_context_init__compat(void* pUserData, ma_context* pContext, const ma_context_config* pConfig, ma_device_backend_vtable** ppBackendVTable, void** ppBackendUserData)
|
||||
static ma_result ma_context_init__compat(void* pUserData, ma_context* pContext, const ma_context_config* pConfig)
|
||||
{
|
||||
(void)pUserData;
|
||||
(void)ppBackendVTable;
|
||||
(void)ppBackendUserData;
|
||||
return pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks);
|
||||
}
|
||||
|
||||
@@ -41316,6 +41314,8 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
|
||||
/* Make sure all callbacks are reset so we don't accidentally drag in any from previously failed initialization attempts. */
|
||||
MA_ZERO_OBJECT(&pContext->callbacks);
|
||||
pContext->pVTable = NULL;
|
||||
pContext->pVTableUserData = NULL;
|
||||
|
||||
/* For stock backends we can just map the backend enum to the appropriate vtable. */
|
||||
|
||||
@@ -41419,15 +41419,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
#ifdef MA_HAS_CUSTOM
|
||||
case ma_backend_custom:
|
||||
{
|
||||
/* Slightly different logic for custom backends. Custom backends can optionally set all of their callbacks in the config. */
|
||||
pContext->callbacks = pConfig->custom;
|
||||
pContext->pVTable = &ma_gDeviceVTable_Compat;
|
||||
|
||||
/*
|
||||
TODO: We'll need to handle custom backends differently so we can iterate over each of the vtables in
|
||||
order and choose the first one that works. When we do this, this branch here will be empty and we'll
|
||||
just do the logic after this switch.
|
||||
*/
|
||||
/* Custom backends are handled differently. */
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_NULL
|
||||
@@ -41441,24 +41433,52 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (pContext->pVTable != NULL) {
|
||||
MA_ASSERT(pContext->pVTable->onContextInit != NULL); /* onContextInit() must always be specified. */
|
||||
/* Special case for custom backends. */
|
||||
if (backend == ma_backend_custom) {
|
||||
/* It's a custom backend. We need to iterate over each vtable and use the first one that works. */
|
||||
if (pConfig->custom.ppVTables != NULL && pConfig->custom.count > 0) {
|
||||
size_t iVTable;
|
||||
for (iVTable = 0; iVTable < pConfig->custom.count; iVTable += 1) {
|
||||
void* pUserData = NULL;
|
||||
if (pConfig->custom.ppUserDatas != NULL) {
|
||||
pUserData = pConfig->custom.ppUserDatas[iVTable];
|
||||
}
|
||||
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend));
|
||||
result = pContext->pVTable->onContextInit(pContext->pVTableUserData, pContext, pConfig, &pContext->pVTable, &pContext->pVTableUserData);
|
||||
} else {
|
||||
/* Getting here means the vtable is not set which means the backend is not enabled. Special case for the custom backend. */
|
||||
if (backend != ma_backend_custom) {
|
||||
result = MA_BACKEND_NOT_ENABLED;
|
||||
pContext->pVTable = pConfig->custom.ppVTables[iVTable];
|
||||
pContext->pVTableUserData = pUserData;
|
||||
|
||||
if (pContext->pVTable != NULL) {
|
||||
MA_ASSERT(pContext->pVTable->onContextInit != NULL); /* onContextInit() must always be specified. */
|
||||
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize custom backend %d...\n", (int)iVTable);
|
||||
|
||||
result = pContext->pVTable->onContextInit(pContext->pVTableUserData, pContext, pConfig);
|
||||
if (result == MA_SUCCESS) {
|
||||
break;
|
||||
} else {
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Failed to initialize custom backend %d.\n", (int)iVTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if !defined(MA_HAS_CUSTOM)
|
||||
result = MA_BACKEND_NOT_ENABLED;
|
||||
#else
|
||||
/* No custom backend vtables defined. */
|
||||
result = MA_NO_BACKEND;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* It's not a custom backend. */
|
||||
if (pContext->pVTable != NULL) {
|
||||
MA_ASSERT(pContext->pVTable->onContextInit != NULL); /* onContextInit() must always be specified. */
|
||||
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend));
|
||||
result = pContext->pVTable->onContextInit(pContext->pVTableUserData, pContext, pConfig);
|
||||
} else {
|
||||
/* Getting here means the vtable is not set which means the backend is not enabled. */
|
||||
result = MA_BACKEND_NOT_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* If this iteration was successful, return. */
|
||||
if (result == MA_SUCCESS) {
|
||||
result = ma_mutex_init(&pContext->deviceEnumLock);
|
||||
|
||||
Reference in New Issue
Block a user