From d72b546dcaf98336a958c0e21a62182c3d457570 Mon Sep 17 00:00:00 2001 From: JoshuaBatty Date: Thu, 21 May 2020 09:41:23 +0200 Subject: [PATCH] gets buffersize range and allows to set buffersize for alsa --- Cargo.toml | 4 ++-- examples/beep.rs | 2 +- examples/feedback.rs | 6 ++++-- src/host/alsa/mod.rs | 19 ++++++++++++------- src/lib.rs | 42 +++++++++++++++++++++++++++--------------- 5 files changed, 46 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 130cf2a..8eb6837 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ hound = "3.4" ringbuf = "0.1.6" [target.'cfg(target_os = "windows")'.dependencies] -winapi = { path = "../winapi-rs", version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "errhandlingapi", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "std", "synchapi", "winbase", "winuser"] } -# winapi = { version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "profileapi", "std", "synchapi", "winbase", "winuser"] } +# winapi = { path = "../winapi-rs", version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "errhandlingapi", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "std", "synchapi", "winbase", "winuser"] } +winapi = { version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "profileapi", "std", "synchapi", "winbase", "winuser"] } asio-sys = { version = "0.1", path = "asio-sys", optional = true } parking_lot = "0.9" diff --git a/examples/beep.rs b/examples/beep.rs index dec1fdf..ec40eda 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -9,7 +9,7 @@ fn main() -> Result<(), anyhow::Error> { .default_output_device() .expect("failed to find a default output device"); let config = device.default_output_config()?; - + println!("{:#?}", &config); match config.sample_format() { cpal::SampleFormat::F32 => run::(&device, &config.into())?, cpal::SampleFormat::I16 => run::(&device, &config.into())?, diff --git a/examples/feedback.rs b/examples/feedback.rs index e44f2d0..a623169 100644 --- a/examples/feedback.rs +++ b/examples/feedback.rs @@ -29,8 +29,9 @@ fn main() -> Result<(), anyhow::Error> { println!("Using default output device: \"{}\"", output_device.name()?); // We'll try and use the same configuration between streams to keep it simple. - let config: cpal::StreamConfig = input_device.default_input_config()?.into(); - + let mut config: cpal::StreamConfig = input_device.default_input_config()?.into(); + config.buffer_size = cpal::BufferSize::Fixed(1024); + // Create a delay in case the input and output devices aren't synced. let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32; let latency_samples = latency_frames as usize * config.channels as usize; @@ -47,6 +48,7 @@ fn main() -> Result<(), anyhow::Error> { } let input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| { + println!("data len = {}", data.len()); let mut output_fell_behind = false; for &sample in data { if producer.push(sample).is_err() { diff --git a/src/host/alsa/mod.rs b/src/host/alsa/mod.rs index f8b8305..f2eb07d 100644 --- a/src/host/alsa/mod.rs +++ b/src/host/alsa/mod.rs @@ -3,10 +3,10 @@ extern crate libc; use self::alsa::poll::Descriptors; use crate::{ - BackendSpecificError, BufferSize, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, - DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, - PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSizeRange, SupportedStreamConfig, - SupportedStreamConfigRange, SupportedStreamConfigsError, + BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError, + BufferSize, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, + PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSizeRange, + SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, }; use std::convert::TryInto; use std::sync::Arc; @@ -343,8 +343,8 @@ impl Device { let max_buffer_size = hw_params.get_buffer_size_max()?; let buffer_size_range = SupportedBufferSizeRange { - min: min_buffer_size, - max: max_buffer_size, + min: min_buffer_size as u32, + max: max_buffer_size as u32, requires_power_of_two: false, }; @@ -358,7 +358,7 @@ impl Device { channels: channels.clone(), min_sample_rate: SampleRate(min_rate as u32), max_sample_rate: SampleRate(max_rate as u32), - buffer_size: buffer_size_range, + buffer_size: buffer_size_range.clone(), sample_format: sample_format, }); } @@ -900,6 +900,11 @@ fn set_hw_params_from_format<'a>( hw_params.set_rate(config.sample_rate.0, alsa::ValueOr::Nearest)?; hw_params.set_channels(config.channels as u32)?; + match config.buffer_size { + BufferSize::Fixed(v) => hw_params.set_buffer_size(v as i64)?, + BufferSize::Default => (), + } + // If this isn't set manually a overlarge buffer may be used causing audio delay let mut hw_params_copy = hw_params.clone(); if let Err(_) = hw_params.set_buffer_time_near(100_000, alsa::ValueOr::Nearest) { diff --git a/src/lib.rs b/src/lib.rs index 86136df..351b127 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,7 +181,13 @@ pub type ChannelCount = u16; pub struct SampleRate(pub u32); /// The desired number of frames for the hardware buffer. -pub type BufferSize = u32; +pub type FrameCount = u32; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum BufferSize { + Default, + Fixed(FrameCount), +} /// The set of parameters used to describe how to open a stream. /// @@ -197,8 +203,8 @@ pub struct StreamConfig { /// and if requested buffersize must be a power of 2 value. #[derive(Clone, Debug, Eq, PartialEq)] pub struct SupportedBufferSizeRange { - pub min: BufferSize, - pub max: BufferSize, + pub min: FrameCount, + pub max: FrameCount, pub requires_power_of_two: bool, } @@ -223,7 +229,7 @@ pub struct SupportedStreamConfigRange { pub struct SupportedStreamConfig { channels: ChannelCount, sample_rate: SampleRate, - buffer_size: BufferSize, + buffer_size: SupportedBufferSizeRange, sample_format: SampleFormat, } @@ -305,8 +311,8 @@ impl SupportedStreamConfig { self.sample_rate } - pub fn buffer_size(&self) -> BufferSize { - self.buffer_size + pub fn buffer_size(&self) -> &SupportedBufferSizeRange { + &self.buffer_size } pub fn sample_format(&self) -> SampleFormat { @@ -317,7 +323,7 @@ impl SupportedStreamConfig { StreamConfig { channels: self.channels, sample_rate: self.sample_rate, - buffer_size: self.buffer_size, + buffer_size: BufferSize::Default, } } } @@ -523,23 +529,29 @@ impl SupportedStreamConfigRange { /// Retrieve a `SupportedStreamConfig` with the given sample rate and buffer size. /// - /// **panic!**s if the given `sample_rate` or the give `buffer_size` is outside the range specified within this + /// **panic!**s if the given `sample_rate` is outside the range specified within this /// `SupportedStreamConfigRange` instance. - pub fn with_sample_rate_and_buffer_size( + pub fn with_sample_rate( self, sample_rate: SampleRate, - buffer_size: BufferSize, ) -> SupportedStreamConfig { assert!(self.min_sample_rate <= sample_rate && sample_rate <= self.max_sample_rate); - assert!(self.buffer_size.min <= buffer_size && buffer_size <= self.buffer_size.max); - if self.buffer_size.requires_power_of_two { - assert!(buffer_size.is_power_of_two()); - } SupportedStreamConfig { channels: self.channels, sample_rate: self.max_sample_rate, sample_format: self.sample_format, - buffer_size, + buffer_size: self.buffer_size, + } + } + + /// Turns this `SupportedStreamConfigRange` into a `SupportedStreamConfig` corresponding to the maximum samples rate. + #[inline] + pub fn with_max_sample_rate(self) -> SupportedStreamConfig { + SupportedStreamConfig { + channels: self.channels, + sample_rate: self.max_sample_rate, + sample_format: self.sample_format, + buffer_size: self.buffer_size, } }