Add some some experimental code for a new backend architecture.

This commit is contained in:
David Reid
2025-07-06 10:19:21 +10:00
parent 636fe28d86
commit 9bce75d858
+44 -3
View File
@@ -7114,6 +7114,25 @@ typedef union
MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB); MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB);
/*
This data structure is used to bridge the backend with the device's data callback. When a backend needs to
invoke the data callback, it should call `ma_device_data_callback_invoke()`. When the backend needs data for
for playback, the backend should pass in a value for `pFramesOutInBackendFormat` which will be in the
backend's native format. Likewise for capture, when the backend is ready to push data to the application from
the microphone, it should pass in a value for `pFramesInInBackendFormat`, which again is in the backend's
native format.
The `ma_device_data_callback` structure should be considered opaque. It is declared here in the header section
so it can be stored directly in the `ma_device` object without needing a heap allocation.
*/
typedef struct ma_device_data_callback
{
void* pInternal;
} ma_device_data_callback;
MA_API void ma_device_data_callback_invoke(ma_device_data_callback* pDeviceDataCallback, void* pFramesOutInBackendFormat, const void* pFramesInInBackendFormat, ma_uint32 frameCount);
typedef struct ma_context_config ma_context_config; typedef struct ma_context_config ma_context_config;
typedef struct ma_device_config ma_device_config; typedef struct ma_device_config ma_device_config;
typedef struct ma_device_backend_vtable ma_device_backend_vtable; typedef struct ma_device_backend_vtable ma_device_backend_vtable;
@@ -7458,6 +7477,7 @@ struct ma_context
const ma_device_backend_vtable* pVTable; /* New system. */ const ma_device_backend_vtable* pVTable; /* New system. */
void* pVTableUserData; 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. */ 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. */
void* pBackendState;
ma_backend backend; /* DirectSound, ALSA, etc. */ ma_backend backend; /* DirectSound, ALSA, etc. */
ma_log* pLog; 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. */ ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
@@ -7867,12 +7887,14 @@ struct ma_device
{ {
ma_context* pContext; ma_context* pContext;
ma_device_type type; ma_device_type type;
ma_device_data_callback dataCallback; /* The data callback object for bridging the backend to the device. */
ma_uint32 sampleRate; ma_uint32 sampleRate;
ma_atomic_device_state state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ ma_atomic_device_state state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */ 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. */ ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */ void* pUserData; /* Application defined data. */
void* pBackendData; /* This is not used by miniaudio, but is a way for custom backends to associate some backend-specific data with the device. Custom backends are free to use this pointer however they like. */ void* pBackendData; /* This is not used by miniaudio, but is a way for custom backends to associate some backend-specific data with the device. Custom backends are free to use this pointer however they like. */
void* pBackendState;
ma_mutex startStopLock; ma_mutex startStopLock;
ma_event wakeupEvent; ma_event wakeupEvent;
ma_event startEvent; ma_event startEvent;
@@ -43185,6 +43207,24 @@ MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id*
} }
MA_API void ma_device_data_callback_invoke(ma_device_data_callback* pDeviceDataCallback, void* pFramesOutInBackendFormat, const void* pFramesInInBackendFormat, ma_uint32 frameCount)
{
if (pDeviceDataCallback == NULL) {
return;
}
MA_ASSERT(pDeviceDataCallback->pInternal != NULL);
/*
For now `ma_device_data_callback` is just a wrapper around `ma_device`, but later on I want to update
this so that it's entirely decoupled from `ma_device`.
*/
ma_device_handle_backend_data_callback((ma_device*)pDeviceDataCallback->pInternal, pFramesOutInBackendFormat, pFramesInInBackendFormat, frameCount);
}
static const void* ma_find_device_backend_config(const ma_device_backend_spec* pBackends, size_t count, const ma_device_backend_vtable* pVTable) static const void* ma_find_device_backend_config(const ma_device_backend_spec* pBackends, size_t count, const ma_device_backend_vtable* pVTable)
{ {
size_t iBackend; size_t iBackend;
@@ -43754,9 +43794,10 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
} }
} }
pDevice->pContext = pContext; /* The data callback object is for bridging the data callback between the backend and the device. */
pDevice->dataCallback.pInternal = pDevice;
/* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */ pDevice->pContext = pContext;
pDevice->pUserData = pConfig->pUserData; pDevice->pUserData = pConfig->pUserData;
pDevice->onData = pConfig->dataCallback; pDevice->onData = pConfig->dataCallback;
pDevice->onNotification = pConfig->notificationCallback; pDevice->onNotification = pConfig->notificationCallback;
@@ -43962,7 +44003,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
} else { } else {
/* /*
If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done
after ma_device__post_init_setup(). after ma_device_post_init().
*/ */
if (ma_context_is_backend_asynchronous(pContext)) { if (ma_context_is_backend_asynchronous(pContext)) {
if (pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_duplex) {