Update the backend template.

This commit is contained in:
David Reid
2026-02-27 20:18:25 +10:00
parent bc69c86868
commit e35c1fd64b
@@ -14,76 +14,307 @@
#endif #endif
#if defined(MA_HAS_TEMPLATE) #if defined(MA_HAS_TEMPLATE)
typedef struct ma_context_state_template
{
int _unused;
} ma_context_state_template;
typedef struct ma_device_state_template
{
int _unused;
} ma_device_state_template;
static ma_context_state_template* ma_context_get_backend_state__template(ma_context* pContext)
{
return (ma_context_state_template*)ma_context_get_backend_state(pContext);
}
static ma_device_state_template* ma_device_get_backend_state__template(ma_device* pDevice)
{
return (ma_device_state_template*)ma_device_get_backend_state(pDevice);
}
static void ma_backend_info__template(ma_device_backend_info* pBackendInfo) static void ma_backend_info__template(ma_device_backend_info* pBackendInfo)
{ {
(void)pBackendInfo; pBackendInfo->pName = "Template";
} }
static ma_result ma_context_init__template(ma_context* pContext, const void* pContextBackendConfig, void** ppContextState) static ma_result ma_context_init__template(ma_context* pContext, const void* pContextBackendConfig, void** ppContextState)
{ {
(void)pContext; ma_context_state_template* pContextStateTemplate;
(void)pContextBackendConfig; const ma_context_config_template* pContextConfigTemplate = (ma_context_config_template*)pContextBackendConfig;
(void)ppContextState;
return MA_NOT_IMPLEMENTED; pContextStateTemplate = (ma_context_state_template*)ma_calloc(sizeof(*pContextStateTemplate), ma_context_get_allocation_callbacks(pContext));
if (pContextStateTemplate == NULL) {
return MA_OUT_OF_MEMORY;
}
/* Do any context-level initialization here. */
(void)pContextConfigTemplate;
(void)pContext;
*ppContextState = pContextStateTemplate;
return MA_SUCCESS;
} }
static void ma_context_uninit__template(ma_context* pContext) static void ma_context_uninit__template(ma_context* pContext)
{ {
(void)pContext; ma_context_state_template* pContextStateTemplate = ma_context_get_backend_state__template(pContext);
/* Do any context-level uninitialization here. */
ma_free(pContextStateTemplate, ma_context_get_allocation_callbacks(pContext));
} }
static ma_result ma_context_enumerate_devices__template(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pCallbackUserData) static ma_result ma_context_enumerate_devices__template(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pCallbackUserData)
{ {
(void)pContext; ma_context_state_template* pContextStateTemplate = ma_context_get_backend_state__template(pContext);
(void)callback; ma_device_info deviceInfo;
(void)pCallbackUserData; ma_device_enumeration_result enumerationResult;
return MA_NOT_IMPLEMENTED; /* This example is only outputting a default playback and capture device. Modify this as required. */
(void)pContextStateTemplate;
/* Playback. */
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.isDefault = MA_TRUE;
deviceInfo.id.custom.i = 0;
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "Default Playback Device", (size_t)-1);
/* Add a native format for each natively supported sample format. The channel count and sample rates are ranges. The format is the key. */
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s16, 1, 2, 44100, 48000);
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, 1, 2, 44100, 48000);
/* If the callback has requested that we abort enumeration we need to respect it. */
enumerationResult = callback(ma_device_type_playback, &deviceInfo, pCallbackUserData);
if (enumerationResult == MA_DEVICE_ENUMERATION_ABORT) {
return MA_SUCCESS;
}
/* Capture. */
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.isDefault = MA_TRUE;
deviceInfo.id.custom.i = 0;
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "Default Capture Device", (size_t)-1);
/* Add a native format for each natively supported sample format. The channel count and sample rates are ranges. The format is the key. */
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s16, 1, 2, 44100, 48000);
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, 1, 2, 44100, 48000);
/* If the callback has requested that we abort enumeration we need to respect it. */
enumerationResult = callback(ma_device_type_capture, &deviceInfo, pCallbackUserData);
if (enumerationResult == MA_DEVICE_ENUMERATION_ABORT) {
return MA_SUCCESS;
}
/* Enumeration done. */
return MA_SUCCESS;
} }
static ma_result ma_device_init__template(ma_device* pDevice, const void* pDeviceBackendConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture, void** ppDeviceState) static ma_result ma_device_init__template(ma_device* pDevice, const void* pDeviceBackendConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture, void** ppDeviceState)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate;
(void)pDeviceBackendConfig; ma_device_config_template* pDeviceConfigTemplate = (ma_device_config_template*)pDeviceBackendConfig;
(void)pDescriptorPlayback; ma_context_state_template* pContextStateTemplate = ma_context_get_backend_state__template(ma_device_get_context(pDevice));
(void)pDescriptorCapture; ma_device_config_template defaultConfig;
(void)ppDeviceState; ma_device_type deviceType = ma_device_get_type(pDevice);
return MA_NOT_IMPLEMENTED; /* Use a default config if one was not provided. This is not mandated by miniaudio, but it's good practice. */
if (pDeviceConfigTemplate == NULL) {
defaultConfig = ma_device_config_template_init();
pDeviceConfigTemplate = &defaultConfig;
}
/* Return an error for any unsupported device types. */
if (deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
pDeviceStateTemplate = (ma_device_state_template*)ma_calloc(sizeof(*pDeviceStateTemplate), ma_device_get_allocation_callbacks(pDevice));
if (pDeviceStateTemplate == NULL) {
return MA_OUT_OF_MEMORY;
}
/* Not using the context state for this example. */
(void)pContextStateTemplate;
/* No backend-specific config for this example. */
(void)pDeviceConfigTemplate;
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
/* Do any backend initialization for the capture side here. Update pDescriptorCapture with the actual internal format, channels, rate and period size. */
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_uint32 periodSizeInFrames;
/*
On input pDescriptorCapture contains what miniaudio would like, if possible. On output, you set
it to what the backend actually supports. You would typically try to make it as close as possible,
but it's ultimately up to the backend to choose what it gives you.
*/
/* Negotiate the format. */
format = pDescriptorCapture->format;
if (format != ma_format_f32) {
format = ma_format_f32;
}
/* Negotiate the channel count. */
channels = pDescriptorCapture->channels;
if (channels != 1 && channels != 2) {
channels = 2;
}
/* Negotiate the sample rate. */
sampleRate = pDescriptorCapture->sampleRate;
if (sampleRate != 44100 && sampleRate != 48000) {
sampleRate = 48000;
}
/*
Negotiate the period size. You will want to use ma_calculate_buffer_size_in_frames_from_descriptor() to
calculate an appropriate period size based on standardized miniaudio conventions as a base point, and then
massage it based on the requirements of the backend. This example is just clamping it between 1024 and
16384 just for demonstration purposes.
*/
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, sampleRate);
if (periodSizeInFrames < 1024) {
periodSizeInFrames = 1024;
}
/* Initialize any backend-specific stuff here. */
/* Update the descriptor with the actual internal settings. */
pDescriptorCapture->format = format;
pDescriptorCapture->channels = channels;
pDescriptorCapture->sampleRate = sampleRate;
pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
pDescriptorCapture->periodCount = 1; /* Just set this 1 if you're unsure. Set it to 2 if you are using a double-buffering technique. */
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
/* This works exactly the same as capture, but for playback. */
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_uint32 periodSizeInFrames;
format = pDescriptorPlayback->format;
if (format != ma_format_f32) {
format = ma_format_f32;
}
channels = pDescriptorPlayback->channels;
if (channels != 1 && channels != 2) {
channels = 2;
}
sampleRate = pDescriptorPlayback->sampleRate;
if (sampleRate != 44100 && sampleRate != 48000) {
sampleRate = 48000;
}
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, sampleRate);
if (periodSizeInFrames < 1024) {
periodSizeInFrames = 1024;
}
/* Initialize any backend-specific stuff here. */
/* Update the descriptor with the actual internal settings. */
pDescriptorPlayback->format = format;
pDescriptorPlayback->channels = channels;
pDescriptorPlayback->sampleRate = sampleRate;
pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
pDescriptorPlayback->periodCount = 1;
}
*ppDeviceState = pDeviceStateTemplate;
return MA_SUCCESS;
} }
static void ma_device_uninit__template(ma_device* pDevice) static void ma_device_uninit__template(ma_device* pDevice)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate = ma_device_get_backend_state__template(pDevice);
/* Do any device-level uninitialization here. */
ma_free(pDeviceStateTemplate, ma_device_get_allocation_callbacks(pDevice));
} }
static ma_result ma_device_start__template(ma_device* pDevice) static ma_result ma_device_start__template(ma_device* pDevice)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate = ma_device_get_backend_state__template(pDevice);
ma_device_type deviceType = ma_device_get_type(pDevice);
return MA_NOT_IMPLEMENTED; if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
/* Start the capture side. */
(void)pDeviceStateTemplate;
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
/* Start the playback side. */
(void)pDeviceStateTemplate;
}
return MA_SUCCESS;
} }
static ma_result ma_device_stop__template(ma_device* pDevice) static ma_result ma_device_stop__template(ma_device* pDevice)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate = ma_device_get_backend_state__template(pDevice);
ma_device_type deviceType = ma_device_get_type(pDevice);
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
/* Stop the capture side. */
(void)pDeviceStateTemplate;
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
/* Stop the playback side. */
(void)pDeviceStateTemplate;
}
return MA_NOT_IMPLEMENTED; return MA_NOT_IMPLEMENTED;
} }
static ma_result ma_device_step__template(ma_device* pDevice, ma_blocking_mode blockingMode) static ma_result ma_device_step__template(ma_device* pDevice, ma_blocking_mode blockingMode)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate = ma_device_get_backend_state__template(pDevice);
(void)blockingMode;
return MA_NOT_IMPLEMENTED; /*
When blockingMode is MA_BLOCKING_MODE_BLOCKING, this function should block until data has been processed. Otherwise
if it's set to MA_BLOCKING_MODE_NON_BLOCKING it should try processing any data if ready and then immediately return,
regardless of whether or not any data was processed. Use ma_device_handle_backend_data_callback() to process data.
The code below is an example of the general idea. You don't have to follow this exact design.
*/
if (blockingMode == MA_BLOCKING_MODE_BLOCKING) {
/* Wait here. */
(void)pDeviceStateTemplate;
}
/* If after waiting the device has been stopped don't process any audio data. */
if (!ma_device_is_started(pDevice)) {
return MA_DEVICE_NOT_STARTED;
}
/* Call ma_device_handle_backend_data_callback() at some point. */
return MA_SUCCESS;
} }
static void ma_device_wakeup__template(ma_device* pDevice) static void ma_device_wakeup__template(ma_device* pDevice)
{ {
(void)pDevice; ma_device_state_template* pDeviceStateTemplate = ma_device_get_backend_state__template(pDevice);
/* Do whatever needs to be done to wakeup the step function. It's OK to just do nothing here so long as your backend will return from a blocking step in a reasonable amount of time. */
(void)pDeviceStateTemplate;
} }
static ma_device_backend_vtable ma_gDeviceBackendVTable_Template = static ma_device_backend_vtable ma_gDeviceBackendVTable_Template =