From 95cc3bd4130252eb5ff211c1ffbacb915b53e04d Mon Sep 17 00:00:00 2001 From: Gloria Goertz Date: Fri, 23 Jan 2026 15:12:52 +0100 Subject: [PATCH 1/5] wasapi: Enable resampling and rate adjustment This allows non-native sample rates to be resampled by the WASAPI server. This should not have any meaningful performance impact, many pieces of software and middleware like SDL do this already. --- src/host/wasapi/device.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 0caa0bd6f..47f4bb42d 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -61,6 +61,8 @@ const PKEY_AUDIOENDPOINT_JACKSUBTYPE: PROPERTYKEY = PROPERTYKEY { pid: 8, }; +const DEFAULT_FLAGS: u32 = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK | Audio::AUDCLNT_STREAMFLAGS_RATEADJUST | Audio::AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | Audio::AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; + /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers. #[derive(Clone)] struct IAudioClientWrapper(Audio::IAudioClient); @@ -696,7 +698,7 @@ impl Device { // will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported. let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate); - let mut stream_flags = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + let mut stream_flags = DEFAULT_FLAGS; if self.data_flow() == Audio::eRender { stream_flags |= Audio::AUDCLNT_STREAMFLAGS_LOOPBACK; @@ -829,7 +831,7 @@ impl Device { audio_client .Initialize( share_mode, - Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + DEFAULT_FLAGS, buffer_duration, 0, &format_attempt.Format, From 961323ea2862e4c833aa7966f5df90d9ba4e5a1d Mon Sep 17 00:00:00 2001 From: Gloria Goertz Date: Fri, 23 Jan 2026 15:21:05 +0100 Subject: [PATCH 2/5] wasapi: Fix formatting --- src/host/wasapi/device.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 47f4bb42d..5670429e2 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -61,7 +61,10 @@ const PKEY_AUDIOENDPOINT_JACKSUBTYPE: PROPERTYKEY = PROPERTYKEY { pid: 8, }; -const DEFAULT_FLAGS: u32 = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK | Audio::AUDCLNT_STREAMFLAGS_RATEADJUST | Audio::AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | Audio::AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; +const DEFAULT_FLAGS: u32 = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK + | Audio::AUDCLNT_STREAMFLAGS_RATEADJUST + | Audio::AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY + | Audio::AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers. #[derive(Clone)] From c3ea12a807c92187842404147403c17ef663d023 Mon Sep 17 00:00:00 2001 From: Gloria Goertz Date: Fri, 23 Jan 2026 18:23:27 +0100 Subject: [PATCH 3/5] wasapi: Remove format check --- src/host/wasapi/device.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 5670429e2..b6a2770d3 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -32,7 +32,7 @@ use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message}; use windows::core::Interface; use windows::core::GUID; use windows::Win32::Devices::Properties; -use windows::Win32::Foundation; +//use windows::Win32::Foundation; use windows::Win32::Foundation::PROPERTYKEY; use windows::Win32::Media::Audio::IAudioRenderClient; use windows::Win32::Media::{Audio, KernelStreaming, Multimedia}; @@ -192,10 +192,12 @@ unsafe fn data_flow_from_immendpoint(endpoint: &Audio::IMMEndpoint) -> Audio::ED // Given the audio client and format, returns whether or not the format is supported. pub unsafe fn is_format_supported( - client: &Audio::IAudioClient, - waveformatex_ptr: *const Audio::WAVEFORMATEX, + _client: &Audio::IAudioClient, + _waveformatex_ptr: *const Audio::WAVEFORMATEX, ) -> Result { - // Check if the given format is supported. + // Checking formats is not needed for shared mode with auto-conversion, therefore this check has been removed until someone implements WASAPI exclusive mode support + // I used an NAudio issue as reference: https://github.com/naudio/NAudio/issues/819 + /* // Check if the given format is supported. let mut closest_waveformatex_ptr: *mut Audio::WAVEFORMATEX = ptr::null_mut(); let result = client.IsFormatSupported( @@ -215,7 +217,9 @@ pub unsafe fn is_format_supported( r if r.is_err() => Ok(false), Foundation::S_FALSE => Ok(false), _ => Ok(true), - } + }*/ + + Ok(true) } // Get a cpal Format from a WAVEFORMATEX. From 5af12c516c051f6c3f2ce6be92d7d373dd75e6f0 Mon Sep 17 00:00:00 2001 From: Gloria Goertz Date: Sun, 25 Jan 2026 17:58:10 +0100 Subject: [PATCH 4/5] wasapi: Remove unused format checks and flags --- src/host/wasapi/device.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index b6a2770d3..9c46099e9 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -32,7 +32,6 @@ use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message}; use windows::core::Interface; use windows::core::GUID; use windows::Win32::Devices::Properties; -//use windows::Win32::Foundation; use windows::Win32::Foundation::PROPERTYKEY; use windows::Win32::Media::Audio::IAudioRenderClient; use windows::Win32::Media::{Audio, KernelStreaming, Multimedia}; @@ -62,7 +61,6 @@ const PKEY_AUDIOENDPOINT_JACKSUBTYPE: PROPERTYKEY = PROPERTYKEY { }; const DEFAULT_FLAGS: u32 = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK - | Audio::AUDCLNT_STREAMFLAGS_RATEADJUST | Audio::AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | Audio::AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; @@ -197,27 +195,6 @@ pub unsafe fn is_format_supported( ) -> Result { // Checking formats is not needed for shared mode with auto-conversion, therefore this check has been removed until someone implements WASAPI exclusive mode support // I used an NAudio issue as reference: https://github.com/naudio/NAudio/issues/819 - /* // Check if the given format is supported. - let mut closest_waveformatex_ptr: *mut Audio::WAVEFORMATEX = ptr::null_mut(); - - let result = client.IsFormatSupported( - Audio::AUDCLNT_SHAREMODE_SHARED, - waveformatex_ptr, - Some(&mut closest_waveformatex_ptr as *mut _), - ); - - if !closest_waveformatex_ptr.is_null() { - Com::CoTaskMemFree(Some(closest_waveformatex_ptr as *mut std::ffi::c_void)); - } - - // `IsFormatSupported` can return `S_FALSE` (which means that a compatible format - // has been found, but not an exact match) so we also treat this as unsupported. - match result { - Audio::AUDCLNT_E_DEVICE_INVALIDATED => Err(SupportedStreamConfigsError::DeviceNotAvailable), - r if r.is_err() => Ok(false), - Foundation::S_FALSE => Ok(false), - _ => Ok(true), - }*/ Ok(true) } From 774f8f49da8ecc59736caa6aac100d058bb7b2bd Mon Sep 17 00:00:00 2001 From: Gloria Goertz Date: Sun, 25 Jan 2026 18:00:47 +0100 Subject: [PATCH 5/5] wasapi: Add Changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90a4e5e37..467b8dc06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DeviceBusy` error variant for retriable device access errors (EBUSY, EAGAIN). - **ALSA**: `Debug` implementations for `Host`, `Device`, `Stream`, and internal types. - **ALSA**: Example demonstrating ALSA error suppression during enumeration. +- **WASAPI**: Allow non-native sample rates to be used via as-necessary resampling in the WASAPI server process. ### Changed