Skip to content

Commit ec5928d

Browse files
committed
feat(WASAPI): allow setting raw stream mode
1 parent cc1d221 commit ec5928d

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

src/host/asio/stream.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ fn check_config(
993993
channels,
994994
sample_rate,
995995
buffer_size,
996+
..
996997
} = config;
997998

998999
// Validate buffer size if `Fixed` is specified. This is necessary because ASIO's

src/host/wasapi/device.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::{
22
error::ResultExt,
33
host::{com::ComString, ErrorCallbackArc},
4-
BufferSize, Data, DeviceDescription, DeviceDescriptionBuilder, DeviceDirection, DeviceId,
5-
DeviceType, Error, ErrorKind, FrameCount, InputCallbackInfo, InterfaceType, OutputCallbackInfo,
6-
SampleFormat, SampleRate, StreamConfig, SupportedBufferSize, SupportedStreamConfig,
7-
SupportedStreamConfigRange, COMMON_SAMPLE_RATES,
4+
AudioProcessing, BufferSize, Data, DeviceDescription, DeviceDescriptionBuilder,
5+
DeviceDirection, DeviceId, DeviceType, Error, ErrorKind, FrameCount, InputCallbackInfo,
6+
InterfaceType, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig, SupportedBufferSize,
7+
SupportedStreamConfig, SupportedStreamConfigRange, COMMON_SAMPLE_RATES,
88
};
99

1010
impl From<Audio::EDataFlow> for DeviceDirection {
@@ -665,6 +665,7 @@ impl Device {
665665
channels: format.channels,
666666
sample_rate,
667667
buffer_size: BufferSize::Default,
668+
audio_processing: AudioProcessing::Default,
668669
},
669670
sample_format,
670671
) {
@@ -783,6 +784,18 @@ impl Device {
783784
.build_audioclient(activation_timeout)
784785
.context("failed to build audio client")?;
785786

787+
if config.audio_processing == AudioProcessing::PreferRaw {
788+
if let Ok(audio_client2) = audio_client.cast::<Audio::IAudioClient2>() {
789+
// Disable audio processing if `PreferRaw` is set and the interface supports it.
790+
let props = Audio::AudioClientProperties {
791+
cbSize: std::mem::size_of::<Audio::AudioClientProperties>() as u32,
792+
Options: Audio::AUDCLNT_STREAMOPTIONS_RAW,
793+
..Default::default()
794+
};
795+
audio_client2.SetClientProperties(&props).ok();
796+
}
797+
}
798+
786799
// Note: Buffer size validation is not needed here - `IAudioClient::Initialize`
787800
// will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported.
788801
let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate);
@@ -898,6 +911,18 @@ impl Device {
898911
.build_audioclient(activation_timeout)
899912
.context("failed to build audio client")?;
900913

914+
if config.audio_processing == AudioProcessing::PreferRaw {
915+
if let Ok(audio_client2) = audio_client.cast::<Audio::IAudioClient2>() {
916+
// Disable audio processing if `PreferRaw` is set and the interface supports it.
917+
let props = Audio::AudioClientProperties {
918+
cbSize: std::mem::size_of::<Audio::AudioClientProperties>() as u32,
919+
Options: Audio::AUDCLNT_STREAMOPTIONS_RAW,
920+
..Default::default()
921+
};
922+
audio_client2.SetClientProperties(&props).ok();
923+
}
924+
}
925+
901926
// Note: Buffer size validation is not needed here - `IAudioClient::Initialize`
902927
// will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported.
903928
let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate);

src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,22 @@ pub enum BufferSize {
344344
Fixed(FrameCount),
345345
}
346346

347+
/// Specifies whether audio signal processing should be applied to the stream.
348+
///
349+
/// On Windows, the audio stack applies default signal processing (e.g. echo cancellation,
350+
/// noise suppression, automatic gain control) to audio streams. Using the [`AudioProcessing::PreferRaw`]
351+
/// option allows applications to request that such processing be bypassed.
352+
///
353+
/// If raw streams are not supported (e.g. on older Windows versions), the default behavior
354+
/// will be used. This option has no effect on platforms that do not apply system audio processing
355+
/// or do not provide a way to bypass it.
356+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
357+
pub enum AudioProcessing {
358+
#[default]
359+
Default,
360+
PreferRaw,
361+
}
362+
347363
#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
348364
impl wasm_bindgen::describe::WasmDescribe for BufferSize {
349365
fn describe() {
@@ -387,6 +403,7 @@ pub struct StreamConfig {
387403
pub channels: ChannelCount,
388404
pub sample_rate: SampleRate,
389405
pub buffer_size: BufferSize,
406+
pub audio_processing: AudioProcessing,
390407
}
391408

392409
/// Describes the minimum and maximum supported buffer size for the device
@@ -498,6 +515,7 @@ impl SupportedStreamConfig {
498515
channels: self.channels,
499516
sample_rate: self.sample_rate,
500517
buffer_size: BufferSize::Default,
518+
audio_processing: AudioProcessing::Default,
501519
}
502520
}
503521
}

0 commit comments

Comments
 (0)