Commit 244db693 authored by David Reid's avatar David Reid

WASAPI: Start using experimental default buffer size system.

parent b73b27ad
...@@ -2197,6 +2197,11 @@ void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint ...@@ -2197,6 +2197,11 @@ void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint
// This is a slow API because it performs a profiling test. // This is a slow API because it performs a profiling test.
float mal_calculate_cpu_speed_factor(); float mal_calculate_cpu_speed_factor();
// Adjust buffer size based on a scaling factor.
//
// This just multiplies the base size by the scaling factor, making sure it's a size of at least 1.
mal_uint32 mal_scale_buffer_size(mal_uint32 baseBufferSize, float scale);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
...@@ -5505,8 +5510,9 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type, ...@@ -5505,8 +5510,9 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type,
mal_result result = MAL_SUCCESS; mal_result result = MAL_SUCCESS;
const char* errorMsg = ""; const char* errorMsg = "";
MAL_AUDCLNT_SHAREMODE shareMode = MAL_AUDCLNT_SHAREMODE_SHARED; MAL_AUDCLNT_SHAREMODE shareMode = MAL_AUDCLNT_SHAREMODE_SHARED;
MAL_REFERENCE_TIME bufferDurationInMicroseconds = ((mal_uint64)pDevice->bufferSizeInFrames * 1000 * 1000) / pConfig->sampleRate;
WAVEFORMATEXTENSIBLE* pBestFormatTemp = NULL; WAVEFORMATEXTENSIBLE* pBestFormatTemp = NULL;
MAL_REFERENCE_TIME bufferDurationInMicroseconds;
#ifdef MAL_WIN32_DESKTOP #ifdef MAL_WIN32_DESKTOP
mal_IMMDevice* pMMDevice = NULL; mal_IMMDevice* pMMDevice = NULL;
...@@ -5640,21 +5646,38 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type, ...@@ -5640,21 +5646,38 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type,
// Get the internal channel map based on the channel mask. // Get the internal channel map based on the channel mask.
mal_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap); mal_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap);
// Slightly different initialization for shared and exclusive modes. // If we're using a default buffer size we need to calculate it based on the efficiency of the system.
if (shareMode == MAL_AUDCLNT_SHAREMODE_SHARED) { if (pDevice->usingDefaultBufferSize) {
// Shared. // CPU speed is a factor to consider when determine how large of a buffer we need.
MAL_REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; float fCPUSpeed = mal_calculate_cpu_speed_factor();
hr = mal_IAudioClient_Initialize((mal_IAudioClient*)pDevice->wasapi.pAudioClient, shareMode, MAL_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL);
if (FAILED(hr)) { // We need a slightly bigger buffer if we're using shared mode to cover the inherent tax association with shared mode.
if (hr == E_ACCESSDENIED) { float fShareMode;
errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MAL_ACCESS_DENIED; if (pConfig->shareMode == mal_share_mode_shared) {
fShareMode = 1.0f;
} else { } else {
errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; fShareMode = 0.8f;
} }
goto done; // In my testing, capture seems to have worse latency than playback for some reason.
float fType;
if (type == mal_device_type_playback) {
fType = 1.0f;
} else {
fType = 2.0f;
} }
if (pConfig->performanceProfile == mal_performance_profile_low_latency) {
pDevice->bufferSizeInFrames = mal_scale_buffer_size((pConfig->sampleRate/1000) * MAL_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY, fCPUSpeed*fShareMode*fType);
} else { } else {
pDevice->bufferSizeInFrames = mal_scale_buffer_size((pConfig->sampleRate/1000) * MAL_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE, fCPUSpeed*fShareMode*fType);
}
}
bufferDurationInMicroseconds = ((mal_uint64)pDevice->bufferSizeInFrames * 1000 * 1000) / pConfig->sampleRate;
// Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode.
if (shareMode == MAL_AUDCLNT_SHAREMODE_EXCLUSIVE) {
// Exclusive. // Exclusive.
MAL_REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; MAL_REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10;
...@@ -5701,7 +5724,25 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type, ...@@ -5701,7 +5724,25 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type,
} }
if (FAILED(hr)) { if (FAILED(hr)) {
// Failed to initialize in exclusive mode. We don't return an error here, but instead fall back to shared mode.
shareMode = MAL_AUDCLNT_SHAREMODE_SHARED;
//errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
//goto done;
}
}
if (shareMode == MAL_AUDCLNT_SHAREMODE_SHARED) {
// Shared.
MAL_REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10;
hr = mal_IAudioClient_Initialize((mal_IAudioClient*)pDevice->wasapi.pAudioClient, shareMode, MAL_AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL);
if (FAILED(hr)) {
if (hr == E_ACCESSDENIED) {
errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MAL_ACCESS_DENIED;
} else {
errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
}
goto done; goto done;
} }
} }
...@@ -20327,7 +20368,15 @@ mal_uint32 mal_calculate_cpu_speed_factor__on_read(mal_dsp* pDSP, mal_uint32 fra ...@@ -20327,7 +20368,15 @@ mal_uint32 mal_calculate_cpu_speed_factor__on_read(mal_dsp* pDSP, mal_uint32 fra
float mal_calculate_cpu_speed_factor() float mal_calculate_cpu_speed_factor()
{ {
// Our profiling test is based on how quick it can process 1 second worth of samples through mini_al's data conversion pipeline. // Our profiling test is based on how quick it can process 1 second worth of samples through mini_al's data conversion pipeline.
const float f = 1000;
// This factor is multiplied with the profiling time. May need to fiddle with this to get an accurate value.
float f = 1000;
// Experiment: Reduce the factor a little when debug mode is used to reduce a blowout.
#ifndef NDEBUG
f /= 2;
#endif
mal_uint32 sampleRateIn = 44100; mal_uint32 sampleRateIn = 44100;
mal_uint32 sampleRateOut = 48000; mal_uint32 sampleRateOut = 48000;
mal_uint32 channelsIn = 2; mal_uint32 channelsIn = 2;
...@@ -20358,13 +20407,21 @@ float mal_calculate_cpu_speed_factor() ...@@ -20358,13 +20407,21 @@ float mal_calculate_cpu_speed_factor()
return 1; return 1;
} }
int iterationCount = 2;
mal_timer timer; mal_timer timer;
mal_timer_init(&timer); mal_timer_init(&timer);
double startTime = mal_timer_get_time_in_seconds(&timer); double startTime = mal_timer_get_time_in_seconds(&timer);
{ {
for (int i = 0; i < iterationCount; ++i) {
mal_dsp_read(&dsp, sampleRateOut, pOutputFrames, &data); mal_dsp_read(&dsp, sampleRateOut, pOutputFrames, &data);
data.pInputFrames = pInputFrames;
data.framesRemaining = sampleRateIn;
}
} }
double executionTimeInSeconds = mal_timer_get_time_in_seconds(&timer) - startTime; double executionTimeInSeconds = mal_timer_get_time_in_seconds(&timer) - startTime;
executionTimeInSeconds /= iterationCount;
mal_aligned_free(pInputFrames); mal_aligned_free(pInputFrames);
...@@ -20373,6 +20430,11 @@ float mal_calculate_cpu_speed_factor() ...@@ -20373,6 +20430,11 @@ float mal_calculate_cpu_speed_factor()
return (float)(executionTimeInSeconds * f); return (float)(executionTimeInSeconds * f);
} }
mal_uint32 mal_scale_buffer_size(mal_uint32 baseBufferSize, float scale)
{
return mal_max(1, (mal_uint32)(baseBufferSize*scale));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
......
...@@ -2293,6 +2293,7 @@ int do_playback_test(mal_backend backend) ...@@ -2293,6 +2293,7 @@ int do_playback_test(mal_backend backend)
haveDevice = MAL_TRUE; haveDevice = MAL_TRUE;
printf(" Is Passthrough: %s\n", (device.dsp.isPassthrough) ? "YES" : "NO"); printf(" Is Passthrough: %s\n", (device.dsp.isPassthrough) ? "YES" : "NO");
printf(" Buffer Size in Frames: %d\n", device.bufferSizeInFrames);
} }
printf(" Opening Decoder... "); printf(" Opening Decoder... ");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment