Set up some infrastructure for some future optimizations.

This changes the way backends update the internal data format in
response to a device reroute. With this change we'll be able to remove
the `channelMap` and `internalChannel` map members from the `ma_device`
struct which should reduce its size by ~1KB.
This commit is contained in:
David Reid
2026-02-04 11:46:05 +10:00
parent dc72a5683b
commit 02f8a6b952
+330 -191
View File
@@ -9605,6 +9605,46 @@ the two. Use `ma_device_type_playback` for the playback side, or `ma_device_type
MA_API void ma_device_get_internal_channel_map(const ma_device* pDevice, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap); MA_API void ma_device_get_internal_channel_map(const ma_device* pDevice, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap);
/*
Updates the public and internal device descriptors.
A normal application should never be calling this directly. It would only be called by device backends in response to a device reroute.
Information describing a device, such as its ID, data format and period size is specified in a structure referred to as a "descriptor".
Where this function matters is with the data format. With the sample format, channel count, sample rate and channel map, there is the
public facing data format which the application requests, and then there is the actual data format that is used by the backend internally.
Sitting between these two is a data converter. The public descriptor will never change after initialization, but sometimes the backend
will change the internal descriptor. When this happens, the data converter needs to be reinitialized, and that is when a backend would
want to call this function.
Parameters
----------
pDevice (in)
A pointer to the device whose descriptor is being updated.
deviceType (in)
Either `ma_device_type_playback` or `ma_device_type_capture` specifying which side of the device whose descriptor is being updated.
pPublicDescriptor (in, optional)
A pointer to the public facing descriptor. This should always be NULL.
pInternalDescriptor (in)
A pointer to the new internal descriptor. This cannot be NULL.
Return Value
------------
`MA_SUCCESS` if successful; any other result code if an error occurs.
Remarks
-------
If you are a normal consumer of miniaudio, do not ever call this function. It should only be called by device backends.
*/
MA_API ma_result ma_device_update_descriptor(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptor, const ma_device_descriptor* pInternalDescriptor);
/* /*
Performs post backend initialization routines for setting up internal data conversion. Performs post backend initialization routines for setting up internal data conversion.
@@ -9651,7 +9691,7 @@ is specified as a parameter rather than deriving it from the device.
You do not need to call this manually unless you are doing a custom backend, in which case you need You do not need to call this manually unless you are doing a custom backend, in which case you need
only do it if you're manually performing rerouting or reinitialization. only do it if you're manually performing rerouting or reinitialization.
*/ */
MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPlaybackDescriptor, const ma_device_descriptor* pCaptureDescriptor); MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptorPlayback, const ma_device_descriptor* pPublicDescriptorCapture, const ma_device_descriptor* pInternalPlaybackDescriptor, const ma_device_descriptor* pInternalCaptureDescriptor);
/* /*
@@ -21115,7 +21155,7 @@ MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = bette
return (ma_uint32)-1; return (ma_uint32)-1;
} }
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType); static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptorPlayback, const ma_device_descriptor* pPublicDescriptorCapture, const ma_device_descriptor* pInternalDescriptorPlayback, const ma_device_descriptor* pInternalDescriptorCapture);
static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor) static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor)
{ {
@@ -24227,6 +24267,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
ma_device_state_wasapi* pDeviceStateWASAPI = ma_device_get_backend_state__wasapi(pDevice); ma_device_state_wasapi* pDeviceStateWASAPI = ma_device_get_backend_state__wasapi(pDevice);
ma_device_init_internal_data__wasapi data; ma_device_init_internal_data__wasapi data;
ma_result result; ma_result result;
ma_device_descriptor internalDescriptor;
const ma_device_id* pDeviceID = NULL; const ma_device_id* pDeviceID = NULL;
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
@@ -24264,20 +24305,17 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
pDeviceID = pDevice->playback.pID; pDeviceID = pDevice->playback.pID;
data.formatIn = pDevice->playback.format; data.shareMode = pDevice->playback.shareMode;
data.channelsIn = pDevice->playback.channels;
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
data.shareMode = pDevice->playback.shareMode;
} else { } else {
pDeviceID = pDevice->playback.pID; pDeviceID = pDevice->playback.pID;
data.formatIn = pDevice->capture.format; data.shareMode = pDevice->capture.shareMode;
data.channelsIn = pDevice->capture.channels;
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
data.shareMode = pDevice->capture.shareMode;
} }
data.sampleRateIn = pDevice->sampleRate; data.formatIn = ma_device_get_format(pDevice, deviceType);
data.channelsIn = ma_device_get_channels(pDevice, deviceType);
data.sampleRateIn = ma_device_get_sample_rate(pDevice);
ma_device_get_channel_map(pDevice, deviceType, data.channelMapIn, ma_countof(data.channelMapIn));
data.periodSizeInFramesIn = pDeviceStateWASAPI->originalPeriodSizeInFrames; data.periodSizeInFramesIn = pDeviceStateWASAPI->originalPeriodSizeInFrames;
data.periodSizeInMillisecondsIn = pDeviceStateWASAPI->originalPeriodSizeInMilliseconds; data.periodSizeInMillisecondsIn = pDeviceStateWASAPI->originalPeriodSizeInMilliseconds;
data.periodsIn = pDeviceStateWASAPI->originalPeriods; data.periodsIn = pDeviceStateWASAPI->originalPeriods;
@@ -24293,15 +24331,8 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
/* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */ /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient; pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient;
pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient; pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient;
pDevice->capture.internalFormat = data.formatOut;
pDevice->capture.internalChannels = data.channelsOut;
pDevice->capture.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->capture.internalPeriods = data.periodsOut;
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDeviceStateWASAPI->pAudioClientCapture, (HANDLE)pDeviceStateWASAPI->hEventCapture); ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDeviceStateWASAPI->pAudioClientCapture, (HANDLE)pDeviceStateWASAPI->hEventCapture);
@@ -24313,15 +24344,8 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
} }
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient; pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient;
pDeviceStateWASAPI->pRenderClient = data.pRenderClient; pDeviceStateWASAPI->pRenderClient = data.pRenderClient;
pDevice->playback.internalFormat = data.formatOut;
pDevice->playback.internalChannels = data.channelsOut;
pDevice->playback.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->playback.internalPeriods = data.periodsOut;
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDeviceStateWASAPI->pAudioClientPlayback, (HANDLE)pDeviceStateWASAPI->hEventPlayback); ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDeviceStateWASAPI->pAudioClientPlayback, (HANDLE)pDeviceStateWASAPI->hEventPlayback);
@@ -24332,6 +24356,20 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
ma_strcpy_s_WCHAR(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi); ma_strcpy_s_WCHAR(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
} }
/* The internal data converter needs to be reinitialized. */
MA_ZERO_OBJECT(&internalDescriptor);
internalDescriptor.format = data.formatOut;
internalDescriptor.channels = data.channelsOut;
internalDescriptor.sampleRate = data.sampleRateOut;
MA_COPY_MEMORY(internalDescriptor.channelMap, data.channelMapOut, sizeof(data.channelMapOut));
internalDescriptor.periodSizeInFrames = data.periodSizeInFramesOut;
internalDescriptor.periodCount = data.periodsOut;
result = ma_device_update_descriptor(pDevice, deviceType, NULL, &internalDescriptor);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS; return MA_SUCCESS;
} }
@@ -24706,7 +24744,6 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de
return result; return result;
} }
ma_device__post_init_setup(pDevice, deviceType);
ma_device_post_notification_rerouted(pDevice); ma_device_post_notification_rerouted(pDevice);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== DEVICE CHANGED ==="); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== DEVICE CHANGED ===");
@@ -39741,6 +39778,7 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
ma_device_state_coreaudio* pDeviceStateCoreAudio = ma_device_get_backend_state__coreaudio(pDevice); ma_device_state_coreaudio* pDeviceStateCoreAudio = ma_device_get_backend_state__coreaudio(pDevice);
ma_context_state_coreaudio* pContextStateCoreAudio = ma_context_get_backend_state__coreaudio(ma_device_get_context(pDevice)); ma_context_state_coreaudio* pContextStateCoreAudio = ma_context_get_backend_state__coreaudio(ma_device_get_context(pDevice));
ma_device_init_internal_data__coreaudio data; ma_device_init_internal_data__coreaudio data;
ma_device_descriptor internalDescriptor;
ma_result result; ma_result result;
/* This should only be called for playback or capture, not duplex. */ /* This should only be called for playback or capture, not duplex. */
@@ -39751,12 +39789,8 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
data.allowNominalSampleRateChange = MA_FALSE; /* Don't change the nominal sample rate when switching devices. */ data.allowNominalSampleRateChange = MA_FALSE; /* Don't change the nominal sample rate when switching devices. */
if (deviceType == ma_device_type_capture) { if (deviceType == ma_device_type_capture) {
data.formatIn = pDevice->capture.format; data.shareMode = pDevice->capture.shareMode;
data.channelsIn = pDevice->capture.channels; data.registerStopEvent = MA_TRUE;
data.sampleRateIn = pDevice->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
data.shareMode = pDevice->capture.shareMode;
data.registerStopEvent = MA_TRUE;
if (disposePreviousAudioUnit) { if (disposePreviousAudioUnit) {
pContextStateCoreAudio->AudioOutputUnitStop(pDeviceStateCoreAudio->audioUnitCapture); pContextStateCoreAudio->AudioOutputUnitStop(pDeviceStateCoreAudio->audioUnitCapture);
@@ -39766,18 +39800,19 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
ma_free(pDeviceStateCoreAudio->pAudioBufferList, ma_device_get_allocation_callbacks(pDevice)); ma_free(pDeviceStateCoreAudio->pAudioBufferList, ma_device_get_allocation_callbacks(pDevice));
} }
} else if (deviceType == ma_device_type_playback) { } else if (deviceType == ma_device_type_playback) {
data.formatIn = pDevice->playback.format; data.shareMode = pDevice->playback.shareMode;
data.channelsIn = pDevice->playback.channels; data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
data.sampleRateIn = pDevice->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
data.shareMode = pDevice->playback.shareMode;
data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
if (disposePreviousAudioUnit) { if (disposePreviousAudioUnit) {
pContextStateCoreAudio->AudioOutputUnitStop(pDeviceStateCoreAudio->audioUnitPlayback); pContextStateCoreAudio->AudioOutputUnitStop(pDeviceStateCoreAudio->audioUnitPlayback);
pContextStateCoreAudio->AudioComponentInstanceDispose(pDeviceStateCoreAudio->audioUnitPlayback); pContextStateCoreAudio->AudioComponentInstanceDispose(pDeviceStateCoreAudio->audioUnitPlayback);
} }
} }
data.formatIn = ma_device_get_format(pDevice, deviceType);
data.channelsIn = ma_device_get_channels(pDevice, deviceType);
data.sampleRateIn = ma_device_get_sample_rate(pDevice);
ma_device_get_channel_map(pDevice, deviceType, data.channelMapIn, ma_countof(data.channelMapIn));
data.periodSizeInFramesIn = pDeviceStateCoreAudio->originalPeriodSizeInFrames; data.periodSizeInFramesIn = pDeviceStateCoreAudio->originalPeriodSizeInFrames;
data.periodSizeInMillisecondsIn = pDeviceStateCoreAudio->originalPeriodSizeInMilliseconds; data.periodSizeInMillisecondsIn = pDeviceStateCoreAudio->originalPeriodSizeInMilliseconds;
data.periodsIn = pDeviceStateCoreAudio->originalPeriods; data.periodsIn = pDeviceStateCoreAudio->originalPeriods;
@@ -39792,6 +39827,22 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
return result; return result;
} }
/* The device's internal descriptor needs to be updated. */
MA_ZERO_OBJECT(&internalDescriptor);
internalDescriptor.format = data.formatOut;
internalDescriptor.channels = data.channelsOut;
internalDescriptor.sampleRate = data.sampleRateOut;
MA_COPY_MEMORY(internalDescriptor.channelMap, data.channelMapOut, sizeof(data.channelMapOut));
internalDescriptor.periodSizeInFrames = data.periodSizeInFramesOut;
internalDescriptor.periodCount = data.periodsOut;
result = ma_device_update_descriptor(pDevice, deviceType, NULL, &internalDescriptor);
if (result != MA_SUCCESS) {
ma_device_uninit__coreaudio(pDevice);
return result;
}
/* /*
We need to reinitialize our async state object to account for the new internal format and We need to reinitialize our async state object to account for the new internal format and
buffer configuration. To do this we'll need to set up a dummy descriptor. buffer configuration. To do this we'll need to set up a dummy descriptor.
@@ -39806,26 +39857,12 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
pDeviceStateCoreAudio->audioUnitCapture = data.audioUnit; pDeviceStateCoreAudio->audioUnitCapture = data.audioUnit;
pDeviceStateCoreAudio->pAudioBufferList = data.pAudioBufferList; pDeviceStateCoreAudio->pAudioBufferList = data.pAudioBufferList;
pDeviceStateCoreAudio->audioBufferCapInFrames = data.periodSizeInFramesOut; pDeviceStateCoreAudio->audioBufferCapInFrames = data.periodSizeInFramesOut;
pDevice->capture.internalFormat = data.formatOut;
pDevice->capture.internalChannels = data.channelsOut;
pDevice->capture.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->capture.internalPeriods = data.periodsOut;
} else if (deviceType == ma_device_type_playback) { } else if (deviceType == ma_device_type_playback) {
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
pDeviceStateCoreAudio->deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; pDeviceStateCoreAudio->deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
ma_get_AudioObject_uid(pDevice->pContext, pDeviceStateCoreAudio->deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); ma_get_AudioObject_uid(pDevice->pContext, pDeviceStateCoreAudio->deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio);
#endif #endif
pDeviceStateCoreAudio->audioUnitPlayback = data.audioUnit; pDeviceStateCoreAudio->audioUnitPlayback = data.audioUnit;
pDevice->playback.internalFormat = data.formatOut;
pDevice->playback.internalChannels = data.channelsOut;
pDevice->playback.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->playback.internalPeriods = data.periodsOut;
} }
{ {
@@ -39833,18 +39870,18 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
ma_device_descriptor descriptorCapture; ma_device_descriptor descriptorCapture;
MA_ZERO_OBJECT(&descriptorPlayback); MA_ZERO_OBJECT(&descriptorPlayback);
descriptorPlayback.format = pDevice->playback.internalFormat; descriptorPlayback.format = ma_device_get_internal_format(pDevice, ma_device_type_playback);
descriptorPlayback.channels = pDevice->playback.internalChannels; descriptorPlayback.channels = ma_device_get_internal_channels(pDevice, ma_device_type_playback);
descriptorPlayback.sampleRate = pDevice->playback.internalSampleRate; descriptorPlayback.sampleRate = ma_device_get_internal_sample_rate(pDevice, ma_device_type_playback);
descriptorPlayback.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames; descriptorPlayback.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
descriptorPlayback.periodCount = pDevice->playback.internalPeriods; descriptorPlayback.periodCount = pDevice->playback.internalPeriods;
MA_ZERO_OBJECT(&descriptorCapture); MA_ZERO_OBJECT(&descriptorCapture);
descriptorCapture.format = pDevice->capture.internalFormat; descriptorCapture.format = ma_device_get_internal_format(pDevice, ma_device_type_capture);
descriptorCapture.channels = pDevice->capture.internalChannels; descriptorCapture.channels = ma_device_get_internal_channels(pDevice, ma_device_type_capture);
descriptorCapture.sampleRate = pDevice->capture.internalSampleRate; descriptorCapture.sampleRate = ma_device_get_internal_sample_rate(pDevice, ma_device_type_capture);
descriptorCapture.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames; descriptorCapture.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
descriptorCapture.periodCount = pDevice->capture.internalPeriods; descriptorCapture.periodCount = pDevice->capture.internalPeriods;
result = ma_device_state_async_init(ma_device_get_type(pDevice), &descriptorPlayback, &descriptorCapture, ma_device_get_allocation_callbacks(pDevice), &pDeviceStateCoreAudio->async); result = ma_device_state_async_init(ma_device_get_type(pDevice), &descriptorPlayback, &descriptorCapture, ma_device_get_allocation_callbacks(pDevice), &pDeviceStateCoreAudio->async);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
@@ -40120,8 +40157,6 @@ static ma_result ma_device_step_extra__coreaudio(ma_device* pDevice)
} }
if (wasReinitialized && result == MA_SUCCESS) { if (wasReinitialized && result == MA_SUCCESS) {
ma_device__post_init_setup(pDevice, deviceType);
/* Restart the device if required. If this fails we need to stop the device entirely. */ /* Restart the device if required. If this fails we need to stop the device entirely. */
if (ma_device_get_status(pDevice) == ma_device_status_started) { if (ma_device_get_status(pDevice) == ma_device_status_started) {
OSStatus status; OSStatus status;
@@ -44620,7 +44655,7 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev
/* The first thing to do is close the streams. */ /* The first thing to do is close the streams. */
ma_close_streams__aaudio(pDevice); ma_close_streams__aaudio(pDevice);
/* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ /* Now we need to reinitialize each streams. The hardest part with this is just filling out the config and descriptors. */
deviceConfigAAudio = ma_device_config_aaudio_init(); deviceConfigAAudio = ma_device_config_aaudio_init();
deviceConfigAAudio.usage = pDeviceStateAAudio->usage; deviceConfigAAudio.usage = pDeviceStateAAudio->usage;
deviceConfigAAudio.contentType = pDeviceStateAAudio->contentType; deviceConfigAAudio.contentType = pDeviceStateAAudio->contentType;
@@ -44631,9 +44666,9 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
descriptorCapture.pDeviceID = NULL; /* Only doing rerouting with default devices. */ descriptorCapture.pDeviceID = NULL; /* Only doing rerouting with default devices. */
descriptorCapture.shareMode = pDevice->capture.shareMode; descriptorCapture.shareMode = pDevice->capture.shareMode;
descriptorCapture.format = pDevice->capture.format; descriptorCapture.format = ma_device_get_format(pDevice, ma_device_type_capture);
descriptorCapture.channels = pDevice->capture.channels; descriptorCapture.channels = ma_device_get_channels(pDevice, ma_device_type_capture);
descriptorCapture.sampleRate = pDevice->sampleRate; descriptorCapture.sampleRate = ma_device_get_sample_rate(pDevice);
descriptorCapture.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames; descriptorCapture.periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
descriptorCapture.periodCount = 1; descriptorCapture.periodCount = 1;
} }
@@ -44641,9 +44676,9 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
descriptorPlayback.pDeviceID = NULL; /* Only doing rerouting with default devices. */ descriptorPlayback.pDeviceID = NULL; /* Only doing rerouting with default devices. */
descriptorPlayback.shareMode = pDevice->playback.shareMode; descriptorPlayback.shareMode = pDevice->playback.shareMode;
descriptorPlayback.format = pDevice->playback.format; descriptorPlayback.format = ma_device_get_format(pDevice, ma_device_type_playback);
descriptorPlayback.channels = pDevice->playback.channels; descriptorPlayback.channels = ma_device_get_channels(pDevice, ma_device_type_playback);
descriptorPlayback.sampleRate = pDevice->sampleRate; descriptorPlayback.sampleRate = ma_device_get_sample_rate(pDevice);
descriptorPlayback.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames; descriptorPlayback.periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
descriptorPlayback.periodCount = 1; descriptorPlayback.periodCount = 1;
} }
@@ -44651,16 +44686,26 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev
result = ma_device_init_streams__aaudio(pDevice, pDeviceStateAAudio, &deviceConfigAAudio, &descriptorPlayback, &descriptorCapture); result = ma_device_init_streams__aaudio(pDevice, pDeviceStateAAudio, &deviceConfigAAudio, &descriptorPlayback, &descriptorCapture);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change.");
/* Reroute failed! */
break; break;
} }
result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); /* The internal data converters need to be updated. */
if (result != MA_SUCCESS) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); result = ma_device_update_descriptor(pDevice, ma_device_type_capture, NULL, &descriptorCapture);
ma_close_streams__aaudio(pDevice); if (result != MA_SUCCESS) {
/* Reroute failed! */ ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
break; ma_close_streams__aaudio(pDevice);
break;
}
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
result = ma_device_update_descriptor(pDevice, ma_device_type_playback, NULL, &descriptorPlayback);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
ma_close_streams__aaudio(pDevice);
break;
}
} }
/* We'll only ever do this in response to a reroute. */ /* We'll only ever do this in response to a reroute. */
@@ -47387,81 +47432,101 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint
} }
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType) MA_API ma_result ma_device_update_descriptor(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptor, const ma_device_descriptor* pInternalDescriptor)
{ {
ma_result result; ma_result result;
ma_device_descriptor publicDescriptor;
ma_device_descriptor internalDescriptor;
ma_data_converter_config converterConfig;
MA_ASSERT(pDevice != NULL); if (pDevice == NULL || pInternalDescriptor == NULL) {
return MA_INVALID_ARGS;
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
if (pDevice->capture.format == ma_format_unknown) {
pDevice->capture.format = pDevice->capture.internalFormat;
}
if (pDevice->capture.channels == 0) {
pDevice->capture.channels = pDevice->capture.internalChannels;
}
if (pDevice->capture.channelMap[0] == MA_CHANNEL_NONE) {
MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS);
if (pDevice->capture.internalChannels == pDevice->capture.channels) {
ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels);
} else {
if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) {
ma_channel_map_init_blank(pDevice->capture.channelMap, pDevice->capture.channels);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pDevice->capture.channels);
}
}
}
} }
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { /* This function should never be called with ma_device_type_duplex. It should be called once for each side. */
if (pDevice->playback.format == ma_format_unknown) { if (deviceType == ma_device_type_duplex) {
pDevice->playback.format = pDevice->playback.internalFormat; return MA_INVALID_ARGS;
}
if (pDevice->playback.channels == 0) {
pDevice->playback.channels = pDevice->playback.internalChannels;
}
if (pDevice->playback.channelMap[0] == MA_CHANNEL_NONE) {
MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS);
if (pDevice->playback.internalChannels == pDevice->playback.channels) {
ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels);
} else {
if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) {
ma_channel_map_init_blank(pDevice->playback.channelMap, pDevice->playback.channels);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pDevice->playback.channels);
}
}
}
} }
if (pDevice->sampleRate == 0) { /* The public descriptor can be null only if the device has already been initialized, in which case we can synthesise it from existing info. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { if (pPublicDescriptor == NULL) {
pDevice->sampleRate = pDevice->capture.internalSampleRate; if (ma_device_get_status(pDevice) == ma_device_status_uninitialized) {
return MA_INVALID_ARGS; /* Can't know what the public format it. */
}
publicDescriptor.format = ma_device_get_format(pDevice, deviceType);
publicDescriptor.channels = ma_device_get_channels(pDevice, deviceType);
publicDescriptor.sampleRate = ma_device_get_sample_rate(pDevice);
ma_device_get_channel_map(pDevice, deviceType, publicDescriptor.channelMap, ma_countof(publicDescriptor.channelMap));
} else {
publicDescriptor = *pPublicDescriptor;
}
if (pInternalDescriptor == NULL) {
return MA_INVALID_ARGS; /* Internal format must always be provided. */
} else {
internalDescriptor = *pInternalDescriptor;
}
/* At this point we should not be needing to access `pPublic/InternalDescriptor`. We should be accessing `public/internalDescriptor` instead. We'll clear this to null so we can catch any errors. */
pPublicDescriptor = NULL;
pInternalDescriptor = NULL;
/* Make sure we have valid values for everything on the public side. */
if (publicDescriptor.format == ma_format_unknown) {
publicDescriptor.format = internalDescriptor.format;
}
if (publicDescriptor.channels == 0) {
publicDescriptor.channels = internalDescriptor.channels;
}
if (publicDescriptor.sampleRate == 0) {
publicDescriptor.sampleRate = internalDescriptor.sampleRate;
}
if (publicDescriptor.channelMap[0] == MA_CHANNEL_NONE) {
MA_ASSERT(publicDescriptor.channels <= MA_MAX_CHANNELS);
if (publicDescriptor.channels == internalDescriptor.channels) {
ma_channel_map_copy(publicDescriptor.channelMap, internalDescriptor.channelMap, internalDescriptor.channels);
} else { } else {
pDevice->sampleRate = pDevice->playback.internalSampleRate; ma_channel_mix_mode channelMixMode;
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
channelMixMode = pDevice->capture.channelMixMode;
} else {
channelMixMode = pDevice->playback.channelMixMode;
}
if (channelMixMode == ma_channel_mix_mode_simple) {
ma_channel_map_init_blank(publicDescriptor.channelMap, publicDescriptor.channels);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default, publicDescriptor.channelMap, ma_countof(publicDescriptor.channelMap), publicDescriptor.channels);
}
} }
} }
/* Data converters. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { /* The data converter can now be initialized. */
/* Converting from internal device format to client format. */ converterConfig = ma_data_converter_config_init_default();
ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); converterConfig.allowDynamicSampleRate = MA_FALSE;
converterConfig.formatIn = pDevice->capture.internalFormat; converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.channelsIn = pDevice->capture.internalChannels; converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable;
converterConfig.pChannelMapIn = pDevice->capture.internalChannelMap; converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData;
converterConfig.formatOut = pDevice->capture.format;
converterConfig.channelsOut = pDevice->capture.channels; if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
converterConfig.sampleRateOut = pDevice->sampleRate; converterConfig.formatIn = internalDescriptor.format;
converterConfig.pChannelMapOut = pDevice->capture.channelMap; converterConfig.channelsIn = internalDescriptor.channels;
converterConfig.sampleRateIn = internalDescriptor.sampleRate;
converterConfig.pChannelMapIn = internalDescriptor.channelMap;
converterConfig.formatOut = publicDescriptor.format;
converterConfig.channelsOut = publicDescriptor.channels;
converterConfig.sampleRateOut = publicDescriptor.sampleRate;
converterConfig.pChannelMapOut = publicDescriptor.channelMap;
converterConfig.channelMixMode = pDevice->capture.channelMixMode; converterConfig.channelMixMode = pDevice->capture.channelMixMode;
converterConfig.calculateLFEFromSpatialChannels = pDevice->capture.calculateLFEFromSpatialChannels; converterConfig.calculateLFEFromSpatialChannels = pDevice->capture.calculateLFEFromSpatialChannels;
converterConfig.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable;
converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData;
/* Make sure the old converter is uninitialized first. */ /* Make sure the old converter is uninitialized first. */
if (ma_device_get_status(pDevice) != ma_device_status_uninitialized) { if (ma_device_get_status(pDevice) != ma_device_status_uninitialized) {
@@ -47472,26 +47537,17 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
} } else {
converterConfig.formatIn = publicDescriptor.format;
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { converterConfig.channelsIn = publicDescriptor.channels;
/* Converting from client format to device format. */ converterConfig.sampleRateIn = publicDescriptor.sampleRate;
ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); converterConfig.pChannelMapIn = publicDescriptor.channelMap;
converterConfig.formatIn = pDevice->playback.format; converterConfig.formatOut = internalDescriptor.format;
converterConfig.channelsIn = pDevice->playback.channels; converterConfig.channelsOut = internalDescriptor.channels;
converterConfig.sampleRateIn = pDevice->sampleRate; converterConfig.sampleRateOut = internalDescriptor.sampleRate;
converterConfig.pChannelMapIn = pDevice->playback.channelMap; converterConfig.pChannelMapOut = internalDescriptor.channelMap;
converterConfig.formatOut = pDevice->playback.internalFormat; converterConfig.channelMixMode = pDevice->capture.channelMixMode;
converterConfig.channelsOut = pDevice->playback.internalChannels; converterConfig.calculateLFEFromSpatialChannels = pDevice->capture.calculateLFEFromSpatialChannels;
converterConfig.sampleRateOut = pDevice->playback.internalSampleRate;
converterConfig.pChannelMapOut = pDevice->playback.internalChannelMap;
converterConfig.channelMixMode = pDevice->playback.channelMixMode;
converterConfig.calculateLFEFromSpatialChannels = pDevice->playback.calculateLFEFromSpatialChannels;
converterConfig.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
converterConfig.resampling.pBackendVTable = pDevice->resampling.pBackendVTable;
converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData;
/* Make sure the old converter is uninitialized first. */ /* Make sure the old converter is uninitialized first. */
if (ma_device_get_status(pDevice) != ma_device_status_uninitialized) { if (ma_device_get_status(pDevice) != ma_device_status_uninitialized) {
@@ -47505,6 +47561,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
} }
/* TODO: Reassess this. Doesn't feel right that this needs to be done here. Why can we not just used a fixed sized buffer like 1024? */
/* /*
If the device is doing playback (ma_device_type_playback or ma_device_type_duplex), there's If the device is doing playback (ma_device_type_playback or ma_device_type_duplex), there's
a couple of situations where we'll need a heap allocated cache. a couple of situations where we'll need a heap allocated cache.
@@ -47524,7 +47581,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
in fixed sized chunks and then cache any residual unused input frames, those of which will be in fixed sized chunks and then cache any residual unused input frames, those of which will be
processed at a later stage. processed at a later stage.
*/ */
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { if (deviceType == ma_device_type_playback) {
ma_uint64 unused; ma_uint64 unused;
pDevice->playback.inputCacheConsumed = 0; pDevice->playback.inputCacheConsumed = 0;
@@ -47538,9 +47595,9 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
ma_uint64 newInputCacheCap; ma_uint64 newInputCacheCap;
ma_uint64 newInputCacheSizeInBytes; ma_uint64 newInputCacheSizeInBytes;
newInputCacheCap = ma_calculate_frame_count_after_resampling(pDevice->playback.internalSampleRate, pDevice->sampleRate, pDevice->playback.internalPeriodSizeInFrames); newInputCacheCap = ma_calculate_frame_count_after_resampling(ma_device_get_internal_sample_rate(pDevice, ma_device_type_playback), ma_device_get_sample_rate(pDevice), pDevice->playback.internalPeriodSizeInFrames);
newInputCacheSizeInBytes = newInputCacheCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); newInputCacheSizeInBytes = newInputCacheCap * ma_get_bytes_per_frame(ma_device_get_format(pDevice, ma_device_type_playback), ma_device_get_channels(pDevice, ma_device_type_playback));
if (newInputCacheSizeInBytes > MA_SIZE_MAX) { if (newInputCacheSizeInBytes > MA_SIZE_MAX) {
ma_free(pDevice->playback.pInputCache, ma_device_get_allocation_callbacks(pDevice)); ma_free(pDevice->playback.pInputCache, ma_device_get_allocation_callbacks(pDevice));
pDevice->playback.pInputCache = NULL; pDevice->playback.pInputCache = NULL;
@@ -47566,53 +47623,115 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
} }
} }
/* Update the internal format, channels, rate, map. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
pDevice->capture.internalFormat = internalDescriptor.format;
pDevice->capture.internalChannels = internalDescriptor.channels;
pDevice->capture.internalSampleRate = internalDescriptor.sampleRate;
pDevice->capture.internalPeriodSizeInFrames = internalDescriptor.periodSizeInFrames;
pDevice->capture.internalPeriods = internalDescriptor.periodCount;
}
if (deviceType == ma_device_type_playback) {
pDevice->playback.internalFormat = internalDescriptor.format;
pDevice->playback.internalChannels = internalDescriptor.channels;
pDevice->playback.internalSampleRate = internalDescriptor.sampleRate;
pDevice->playback.internalPeriodSizeInFrames = internalDescriptor.periodSizeInFrames;
pDevice->playback.internalPeriods = internalDescriptor.periodCount;
}
/* Update the public format, channels, rate. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
pDevice->capture.format = publicDescriptor.format;
pDevice->capture.channels = publicDescriptor.channels;
}
if (deviceType == ma_device_type_playback) {
pDevice->playback.format = publicDescriptor.format;
pDevice->playback.channels = publicDescriptor.channels;
}
pDevice->sampleRate = publicDescriptor.sampleRate;
return MA_SUCCESS; return MA_SUCCESS;
} }
MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pDescriptorPlayback, const ma_device_descriptor* pDescriptorCapture)
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptorPlayback, const ma_device_descriptor* pPublicDescriptorCapture, const ma_device_descriptor* pInternalDescriptorPlayback, const ma_device_descriptor* pInternalDescriptorCapture)
{ {
ma_result result;
MA_ASSERT(pDevice != NULL);
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
result = ma_device_update_descriptor(pDevice, ma_device_type_capture, pPublicDescriptorCapture, pInternalDescriptorCapture);
if (result != MA_SUCCESS) {
return result;
}
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
result = ma_device_update_descriptor(pDevice, ma_device_type_playback, pPublicDescriptorPlayback, pInternalDescriptorPlayback);
if (result != MA_SUCCESS) {
return result;
}
}
return MA_SUCCESS;
}
MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceType, const ma_device_descriptor* pPublicDescriptorPlayback, const ma_device_descriptor* pPublicDescriptorCapture, const ma_device_descriptor* pInternalDescriptorPlayback, const ma_device_descriptor* pInternalDescriptorCapture)
{
ma_result result;
if (pDevice == NULL) { if (pDevice == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/* Capture. */ /* Capture. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
if (ma_device_descriptor_is_valid(pDescriptorCapture) == MA_FALSE) { if (ma_device_descriptor_is_valid(pInternalDescriptorCapture) == MA_FALSE) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
pDevice->capture.internalFormat = pDescriptorCapture->format; pDevice->capture.internalFormat = pInternalDescriptorCapture->format;
pDevice->capture.internalChannels = pDescriptorCapture->channels; pDevice->capture.internalChannels = pInternalDescriptorCapture->channels;
pDevice->capture.internalSampleRate = pDescriptorCapture->sampleRate; pDevice->capture.internalSampleRate = pInternalDescriptorCapture->sampleRate;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap)); MA_COPY_MEMORY(pDevice->capture.internalChannelMap, pInternalDescriptorCapture->channelMap, sizeof(pInternalDescriptorCapture->channelMap));
pDevice->capture.internalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; pDevice->capture.internalPeriodSizeInFrames = pInternalDescriptorCapture->periodSizeInFrames;
pDevice->capture.internalPeriods = pDescriptorCapture->periodCount; pDevice->capture.internalPeriods = pInternalDescriptorCapture->periodCount;
if (pDevice->capture.internalPeriodSizeInFrames == 0) { if (pDevice->capture.internalPeriodSizeInFrames == 0) {
pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorCapture->periodSizeInMilliseconds, pDescriptorCapture->sampleRate); pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pInternalDescriptorCapture->periodSizeInMilliseconds, pInternalDescriptorCapture->sampleRate);
} }
} }
/* Playback. */ /* Playback. */
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
if (ma_device_descriptor_is_valid(pDescriptorPlayback) == MA_FALSE) { if (ma_device_descriptor_is_valid(pInternalDescriptorPlayback) == MA_FALSE) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
pDevice->playback.internalFormat = pDescriptorPlayback->format; pDevice->playback.internalFormat = pInternalDescriptorPlayback->format;
pDevice->playback.internalChannels = pDescriptorPlayback->channels; pDevice->playback.internalChannels = pInternalDescriptorPlayback->channels;
pDevice->playback.internalSampleRate = pDescriptorPlayback->sampleRate; pDevice->playback.internalSampleRate = pInternalDescriptorPlayback->sampleRate;
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); MA_COPY_MEMORY(pDevice->playback.internalChannelMap, pInternalDescriptorPlayback->channelMap, sizeof(pInternalDescriptorPlayback->channelMap));
pDevice->playback.internalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; pDevice->playback.internalPeriodSizeInFrames = pInternalDescriptorPlayback->periodSizeInFrames;
pDevice->playback.internalPeriods = pDescriptorPlayback->periodCount; pDevice->playback.internalPeriods = pInternalDescriptorPlayback->periodCount;
if (pDevice->playback.internalPeriodSizeInFrames == 0) { if (pDevice->playback.internalPeriodSizeInFrames == 0) {
pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorPlayback->periodSizeInMilliseconds, pDescriptorPlayback->sampleRate); pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pInternalDescriptorPlayback->periodSizeInMilliseconds, pInternalDescriptorPlayback->sampleRate);
} }
} }
/* Update data conversion. */ /* Update data conversion. */
return ma_device__post_init_setup(pDevice, deviceType); /* TODO: Should probably rename ma_device__post_init_setup() to something better. */ result = ma_device__post_init_setup(pDevice, deviceType, pPublicDescriptorPlayback, pPublicDescriptorCapture, pInternalDescriptorPlayback, pInternalDescriptorCapture); /* TODO: Should probably rename ma_device__post_init_setup() to something better. */
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
} }
@@ -48817,6 +48936,8 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
{ {
ma_result result; ma_result result;
ma_device_backend_info backendInfo; ma_device_backend_info backendInfo;
ma_device_descriptor publicDescriptorPlayback;
ma_device_descriptor publicDescriptorCapture;
ma_device_descriptor descriptorPlayback; ma_device_descriptor descriptorPlayback;
ma_device_descriptor descriptorCapture; ma_device_descriptor descriptorCapture;
ma_threading_mode threadingMode; ma_threading_mode threadingMode;
@@ -48973,6 +49094,14 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
} }
#endif #endif
/*
The backend will change the descriptor from the public format to its internal format. We need to keep track of the
public descriptors in order to know how to initialize the data converter later on.
*/
publicDescriptorPlayback = descriptorPlayback;
publicDescriptorCapture = descriptorCapture;
/* We are now ready to initialize the backend. */
initParams.init.pDeviceBackendConfig = ma_device_config_find_backend_config(pConfig, pContext->pVTable); initParams.init.pDeviceBackendConfig = ma_device_config_find_backend_config(pConfig, pContext->pVTable);
initParams.init.pDescriptorPlayback = &descriptorPlayback; initParams.init.pDescriptorPlayback = &descriptorPlayback;
initParams.init.pDescriptorCapture = &descriptorCapture; initParams.init.pDescriptorCapture = &descriptorCapture;
@@ -49037,7 +49166,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
} }
} }
result = ma_device_post_init(pDevice, pConfig->deviceType, &descriptorPlayback, &descriptorCapture); result = ma_device_post_init(pDevice, pConfig->deviceType, &publicDescriptorPlayback, &publicDescriptorCapture, &descriptorPlayback, &descriptorCapture);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_device_uninit(pDevice); ma_device_uninit(pDevice);
return result; return result;
@@ -49141,11 +49270,16 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->capture.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->capture.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
{ {
ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_channel publicChannelMap[MA_MAX_CHANNELS];
char channelMapStr[1024]; char channelMapStr[1024];
ma_channel_map_to_string(pDevice->capture.internalChannelMap, pDevice->capture.internalChannels, channelMapStr, sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}", channelMapStr);
ma_channel_map_to_string(pDevice->capture.channelMap, pDevice->capture.channels, channelMapStr, sizeof(channelMapStr)); ma_device_get_internal_channel_map(pDevice, ma_device_type_capture, internalChannelMap, ma_countof(internalChannelMap));
ma_channel_map_to_string(internalChannelMap, ma_device_get_internal_channels(pDevice, ma_device_type_capture), channelMapStr, sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}", channelMapStr);
ma_device_get_channel_map(pDevice, ma_device_type_capture, publicChannelMap, ma_countof(publicChannelMap));
ma_channel_map_to_string(publicChannelMap, ma_device_get_channels(pDevice, ma_device_type_capture), channelMapStr, sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}", channelMapStr); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}", channelMapStr);
} }
} }
@@ -49165,11 +49299,16 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->playback.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->playback.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->playback.converter.isPassthrough ? "YES" : "NO");
{ {
ma_channel publicChannelMap[MA_MAX_CHANNELS];
ma_channel internalChannelMap[MA_MAX_CHANNELS];
char channelMapStr[1024]; char channelMapStr[1024];
ma_channel_map_to_string(pDevice->playback.channelMap, pDevice->playback.channels, channelMapStr, sizeof(channelMapStr));
ma_device_get_channel_map(pDevice, ma_device_type_playback, publicChannelMap, ma_countof(publicChannelMap));
ma_channel_map_to_string(publicChannelMap, ma_device_get_channels(pDevice, ma_device_type_playback), channelMapStr, sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}", channelMapStr); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}", channelMapStr);
ma_channel_map_to_string(pDevice->playback.internalChannelMap, pDevice->playback.internalChannels, channelMapStr, sizeof(channelMapStr)); ma_device_get_internal_channel_map(pDevice, ma_device_type_playback, internalChannelMap, ma_countof(internalChannelMap));
ma_channel_map_to_string(internalChannelMap, ma_device_get_internal_channels(pDevice, ma_device_type_playback), channelMapStr, sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}", channelMapStr); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}", channelMapStr);
} }
} }