Skip to content

Commit 6627959

Browse files
feat(wasapi): enable resampling when necessary (#1097)
This allows non-native sample rates to be resampled by the WASAPI server.
1 parent 8cc1006 commit 6627959

2 files changed

Lines changed: 12 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- `DeviceBusy` error variant for retriable device access errors (EBUSY, EAGAIN).
1313
- **ALSA**: `Debug` implementations for `Host`, `Device`, `Stream`, and internal types.
1414
- **ALSA**: Example demonstrating ALSA error suppression during enumeration.
15+
- **WASAPI**: Allow non-native sample rates to be used via as-necessary resampling in the WASAPI server process.
1516

1617
### Changed
1718

src/host/wasapi/device.rs

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message};
3232
use windows::core::Interface;
3333
use windows::core::GUID;
3434
use windows::Win32::Devices::Properties;
35-
use windows::Win32::Foundation;
3635
use windows::Win32::Foundation::PROPERTYKEY;
3736
use windows::Win32::Media::Audio::IAudioRenderClient;
3837
use windows::Win32::Media::{Audio, KernelStreaming, Multimedia};
@@ -61,6 +60,10 @@ const PKEY_AUDIOENDPOINT_JACKSUBTYPE: PROPERTYKEY = PROPERTYKEY {
6160
pid: 8,
6261
};
6362

63+
const DEFAULT_FLAGS: u32 = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK
64+
| Audio::AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
65+
| Audio::AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
66+
6467
/// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
6568
#[derive(Clone)]
6669
struct IAudioClientWrapper(Audio::IAudioClient);
@@ -187,30 +190,13 @@ unsafe fn data_flow_from_immendpoint(endpoint: &Audio::IMMEndpoint) -> Audio::ED
187190

188191
// Given the audio client and format, returns whether or not the format is supported.
189192
pub unsafe fn is_format_supported(
190-
client: &Audio::IAudioClient,
191-
waveformatex_ptr: *const Audio::WAVEFORMATEX,
193+
_client: &Audio::IAudioClient,
194+
_waveformatex_ptr: *const Audio::WAVEFORMATEX,
192195
) -> Result<bool, SupportedStreamConfigsError> {
193-
// Check if the given format is supported.
194-
let mut closest_waveformatex_ptr: *mut Audio::WAVEFORMATEX = ptr::null_mut();
195-
196-
let result = client.IsFormatSupported(
197-
Audio::AUDCLNT_SHAREMODE_SHARED,
198-
waveformatex_ptr,
199-
Some(&mut closest_waveformatex_ptr as *mut _),
200-
);
196+
// Checking formats is not needed for shared mode with auto-conversion, therefore this check has been removed until someone implements WASAPI exclusive mode support
197+
// I used an NAudio issue as reference: https://github.com/naudio/NAudio/issues/819
201198

202-
if !closest_waveformatex_ptr.is_null() {
203-
Com::CoTaskMemFree(Some(closest_waveformatex_ptr as *mut std::ffi::c_void));
204-
}
205-
206-
// `IsFormatSupported` can return `S_FALSE` (which means that a compatible format
207-
// has been found, but not an exact match) so we also treat this as unsupported.
208-
match result {
209-
Audio::AUDCLNT_E_DEVICE_INVALIDATED => Err(SupportedStreamConfigsError::DeviceNotAvailable),
210-
r if r.is_err() => Ok(false),
211-
Foundation::S_FALSE => Ok(false),
212-
_ => Ok(true),
213-
}
199+
Ok(true)
214200
}
215201

216202
// Get a cpal Format from a WAVEFORMATEX.
@@ -696,7 +682,7 @@ impl Device {
696682
// will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported.
697683
let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate);
698684

699-
let mut stream_flags = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
685+
let mut stream_flags = DEFAULT_FLAGS;
700686

701687
if self.data_flow() == Audio::eRender {
702688
stream_flags |= Audio::AUDCLNT_STREAMFLAGS_LOOPBACK;
@@ -829,7 +815,7 @@ impl Device {
829815
audio_client
830816
.Initialize(
831817
share_mode,
832-
Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
818+
DEFAULT_FLAGS,
833819
buffer_duration,
834820
0,
835821
&format_attempt.Format,

0 commit comments

Comments
 (0)