From fd4fa10d8b50e810f3fb7b1b90e39da32768c59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Mon, 4 Oct 2021 21:22:06 +0200 Subject: [PATCH] Make WASAPI return accurate latency information --- drivers/wasapi/audio_driver_wasapi.cpp | 18 +++++++++++++++++- drivers/wasapi/audio_driver_wasapi.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 24c9b6954242..3b2f0781202d 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -274,7 +274,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); } - bool using_audio_client_3 = !p_capture; // IID_IAudioClient3 is only used for adjustable output latency (not input) + using_audio_client_3 = !p_capture; // IID_IAudioClient3 is only used for adjustable output latency (not input) if (using_audio_client_3) { hr = device->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client); if (hr != S_OK) { @@ -378,6 +378,13 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c // Due to WASAPI Shared Mode we have no control of the buffer size buffer_frames = max_frames; + + int64_t latency = 0; + audio_output.audio_client->GetStreamLatency(&latency); + // WASAPI REFERENCE_TIME units are 100 nanoseconds per unit + // https://docs.microsoft.com/en-us/windows/win32/directshow/reference-time + // Convert REFTIME to seconds as godot uses for latency + real_latency = (float)latency / (float)REFTIMES_PER_SEC; } else { IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client; @@ -411,6 +418,11 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c hr = device_audio_client_3->InitializeSharedAudioStream(0, period_frames, pwfex, nullptr); ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + "."); + uint32_t output_latency_in_frames; + WAVEFORMATEX *current_pwfex; + device_audio_client_3->GetCurrentSharedModeEnginePeriod(¤t_pwfex, &output_latency_in_frames); + real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec; + CoTaskMemFree(current_pwfex); } if (p_capture) { @@ -518,6 +530,10 @@ int AudioDriverWASAPI::get_mix_rate() const { return mix_rate; } +float AudioDriverWASAPI::get_latency() { + return real_latency; +} + AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channels); } diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 312b6a678106..21c59648ffdd 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -72,6 +72,8 @@ class AudioDriverWASAPI : public AudioDriver { int mix_rate = 0; int buffer_frames = 0; int target_latency_ms = 0; + float real_latency = 0.0; + bool using_audio_client_3 = false; bool thread_exited = false; mutable bool exit_thread = false; @@ -98,6 +100,7 @@ public: virtual Error init(); virtual void start(); virtual int get_mix_rate() const; + virtual float get_latency(); virtual SpeakerMode get_speaker_mode() const; virtual Array get_device_list(); virtual String get_device();