diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ab01721..312a2b66b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - All sources now implement `ExactSizeIterator` when their inner source does. - All sources now implement `Iterator::size_hint()`. - `Chirp` now implements `try_seek`. +- Added `DEFAULT_SAMPLE_RATE` set to match `cpal::SAMPLE_RATE_48K`. ### Changed @@ -25,6 +26,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensured decoders to always return complete frames, as well as `TakeDuration` when expired. - Breaking: `Zero::new_samples()` now returns `Result` requiring a frame-aligned number of samples. - Improved queue, buffer, mixer and sample rate conversion performance. +- Default sample rate changed from 44.1 kHz to 48 kHz consistently. +- `open_sink_or_fallback` now tries 48 kHz and 44.1 kHz before the device's maximum sample rate. + +### Removed + +- Breaking: Removed `stream::supported_output_configs`. Use `cpal::Device::supported_output_configs`. ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 070c40961..dd1793809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,7 +235,7 @@ dependencies = [ [[package]] name = "cpal" version = "0.18.0" -source = "git+https://github.com/RustAudio/cpal#39b543e3d1f644869d1e9cd1f99322146503ce19" +source = "git+https://github.com/RustAudio/cpal#f938e338c9811fbe4d428517acf1d15cc6d694d4" dependencies = [ "alsa", "block2", diff --git a/UPGRADE.md b/UPGRADE.md index 317ebcb14..3520d6e15 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -6,6 +6,9 @@ The list below only contains required code changes. For a complete list of changes and new features, see [CHANGELOG.md](CHANGELOG.md). # rodio 0.22 to current github version +- `stream::supported_output_configs` is removed. To pick a non-default device config, + call `device.supported_output_configs()` directly and pass your chosen + `SupportedStreamConfig` to `DeviceSinkBuilder::with_supported_config`. - `Done` now calls a callback instead of decrementing an `Arc`. - To retain old behavior replace the `Arc` argument in `Done::new` with `move |_| { number.fetch_sub(1, std::sync::atomic::Ordering::Relaxed) }`. diff --git a/src/common.rs b/src/common.rs index ca2359e22..d1ed01366 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,9 +1,14 @@ use std::fmt::{Debug, Display}; use std::num::NonZero; +use crate::math::nz; + /// Sample rate (a frame rate or samples per second per channel). pub type SampleRate = NonZero; +/// The default sample rate used by rodio for generators and device sinks. +pub const DEFAULT_SAMPLE_RATE: SampleRate = nz!(48_000); + /// Number of channels in a stream. Can never be Zero pub type ChannelCount = NonZero; diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 507858efa..801220446 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -734,7 +734,7 @@ where fn sample_rate(&self) -> SampleRate { self.inner .as_ref() - .map_or(nz!(44100), |inner| inner.sample_rate()) + .map_or(crate::DEFAULT_SAMPLE_RATE, |inner| inner.sample_rate()) } /// Returns the total duration of this audio source. diff --git a/src/lib.rs b/src/lib.rs index ed7e205d0..fbca45f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,7 +215,7 @@ pub mod queue; pub mod source; pub mod static_buffer; -pub use crate::common::{BitDepth, ChannelCount, Float, Sample, SampleRate}; +pub use crate::common::{BitDepth, ChannelCount, Float, Sample, SampleRate, DEFAULT_SAMPLE_RATE}; pub use crate::decoder::Decoder; #[cfg(feature = "experimental")] pub use crate::fixed_source::FixedSource; diff --git a/src/microphone/config.rs b/src/microphone/config.rs index 5c33a513b..717a7ee1d 100644 --- a/src/microphone/config.rs +++ b/src/microphone/config.rs @@ -74,7 +74,7 @@ impl Default for InputConfig { fn default() -> Self { Self { channel_count: nz!(1), - sample_rate: nz!(44_100), + sample_rate: crate::DEFAULT_SAMPLE_RATE, buffer_size: cpal::BufferSize::Default, sample_format: cpal::SampleFormat::F32, } diff --git a/src/queue.rs b/src/queue.rs index 034f3aacc..542a05c88 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -419,8 +419,8 @@ mod tests { ); assert_eq!( rx.sample_rate(), - nz!(48000), - "Initial sample rate should be 48000 (keep_alive={keep_alive})" + crate::DEFAULT_SAMPLE_RATE, + "Initial sample rate should be DEFAULT_SAMPLE_RATE (keep_alive={keep_alive})" ); tx.append(SamplesBuffer::new( diff --git a/src/source/empty.rs b/src/source/empty.rs index 13b6843b5..308c02891 100644 --- a/src/source/empty.rs +++ b/src/source/empty.rs @@ -47,7 +47,7 @@ impl Source for Empty { #[inline] fn sample_rate(&self) -> SampleRate { - nz!(48000) + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/source/empty_callback.rs b/src/source/empty_callback.rs index d240102be..7f2deaa95 100644 --- a/src/source/empty_callback.rs +++ b/src/source/empty_callback.rs @@ -51,7 +51,7 @@ impl Source for EmptyCallback { #[inline] fn sample_rate(&self) -> SampleRate { - nz!(48000) + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/source/from_iter.rs b/src/source/from_iter.rs index e12520169..2b4544ec2 100644 --- a/src/source/from_iter.rs +++ b/src/source/from_iter.rs @@ -103,7 +103,7 @@ where src.sample_rate() } else { // Dummy value that only happens if the iterator was empty. - nz!(44100) + crate::DEFAULT_SAMPLE_RATE } } diff --git a/src/source/sawtooth.rs b/src/source/sawtooth.rs index e5bc97f16..e145ab156 100644 --- a/src/source/sawtooth.rs +++ b/src/source/sawtooth.rs @@ -18,13 +18,11 @@ pub struct SawtoothWave { } impl SawtoothWave { - const SAMPLE_RATE: SampleRate = nz!(48000); - /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SawtoothWave { SawtoothWave { - test_saw: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sawtooth), + test_saw: SignalGenerator::new(crate::DEFAULT_SAMPLE_RATE, freq, Function::Sawtooth), } } } @@ -56,7 +54,7 @@ impl Source for SawtoothWave { #[inline] fn sample_rate(&self) -> SampleRate { - Self::SAMPLE_RATE + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/source/sine.rs b/src/source/sine.rs index 17c97008f..d85c3b437 100644 --- a/src/source/sine.rs +++ b/src/source/sine.rs @@ -18,13 +18,11 @@ pub struct SineWave { } impl SineWave { - const SAMPLE_RATE: SampleRate = nz!(48000); - /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SineWave { SineWave { - test_sine: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sine), + test_sine: SignalGenerator::new(crate::DEFAULT_SAMPLE_RATE, freq, Function::Sine), } } } @@ -56,7 +54,7 @@ impl Source for SineWave { #[inline] fn sample_rate(&self) -> SampleRate { - Self::SAMPLE_RATE + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/source/square.rs b/src/source/square.rs index ebb16e82c..b7ad66fa5 100644 --- a/src/source/square.rs +++ b/src/source/square.rs @@ -18,13 +18,11 @@ pub struct SquareWave { } impl SquareWave { - const SAMPLE_RATE: SampleRate = nz!(48000); - /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SquareWave { SquareWave { - test_square: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Square), + test_square: SignalGenerator::new(crate::DEFAULT_SAMPLE_RATE, freq, Function::Square), } } } @@ -56,7 +54,7 @@ impl Source for SquareWave { #[inline] fn sample_rate(&self) -> SampleRate { - Self::SAMPLE_RATE + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/source/triangle.rs b/src/source/triangle.rs index 86a0c9700..429b03044 100644 --- a/src/source/triangle.rs +++ b/src/source/triangle.rs @@ -18,13 +18,11 @@ pub struct TriangleWave { } impl TriangleWave { - const SAMPLE_RATE: SampleRate = nz!(48000); - /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> TriangleWave { TriangleWave { - test_tri: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Triangle), + test_tri: SignalGenerator::new(crate::DEFAULT_SAMPLE_RATE, freq, Function::Triangle), } } } @@ -56,7 +54,7 @@ impl Source for TriangleWave { #[inline] fn sample_rate(&self) -> SampleRate { - Self::SAMPLE_RATE + crate::DEFAULT_SAMPLE_RATE } #[inline] diff --git a/src/speakers/config.rs b/src/speakers/config.rs index 5976038ee..6dfbf5f19 100644 --- a/src/speakers/config.rs +++ b/src/speakers/config.rs @@ -108,7 +108,7 @@ impl Default for OutputConfig { fn default() -> Self { Self { channel_count: nz!(1), - sample_rate: nz!(44_100), + sample_rate: crate::DEFAULT_SAMPLE_RATE, buffer_size: BufferSize::default(), sample_format: cpal::SampleFormat::F32, } diff --git a/src/stream.rs b/src/stream.rs index 89e1ed8c6..fc0a45317 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -30,8 +30,6 @@ use std::io::{Read, Seek}; use std::marker::Sync; use std::num::NonZero; -const HZ_44100: SampleRate = nz!(44_100); - /// `cpal::Stream` container. Use `mixer()` method to control output. /// ///
When dropped playback will end, and the associated @@ -128,7 +126,7 @@ impl Default for DeviceSinkConfig { fn default() -> Self { Self { channel_count: nz!(2), - sample_rate: HZ_44100, + sample_rate: crate::DEFAULT_SAMPLE_RATE, buffer_size: BufferSize::Default, sample_format: SampleFormat::F32, } @@ -350,8 +348,8 @@ where self } - /// Set available parameters from a CPAL supported config. You can get a list of - /// such configurations for an output device using [crate::stream::supported_output_configs()] + /// Set available parameters from a CPAL supported config. To enumerate what a device supports, + /// use [`cpal::Device::supported_output_configs`]. pub fn with_supported_config( mut self, config: &cpal::SupportedStreamConfig, @@ -573,8 +571,11 @@ impl MixerDeviceSink { } } -/// Return all formats supported by the device. -pub fn supported_output_configs( +/// Returns candidate output configurations for the device in preference order. +/// +/// For each supported format, yields 48 kHz and 44.1 kHz (where the device supports them), +/// followed by the device's maximum sample rate. +fn supported_output_configs( device: &cpal::Device, ) -> Result, DeviceSinkError> { let mut supported: Vec<_> = device @@ -586,12 +587,15 @@ pub fn supported_output_configs( Ok(supported.into_iter().flat_map(|sf| { let max_rate = sf.max_sample_rate(); let min_rate = sf.min_sample_rate(); - let mut formats = vec![sf.with_max_sample_rate()]; - let preferred_rate = HZ_44100.get(); - if preferred_rate < max_rate && preferred_rate > min_rate { - formats.push(sf.with_sample_rate(preferred_rate)) + let mut formats = Vec::new(); + for rate in [cpal::SAMPLE_RATE_48K, cpal::SAMPLE_RATE_CD] { + if rate >= min_rate && rate <= max_rate { + formats.push(sf.with_sample_rate(rate)); + } + } + if !formats.iter().any(|f| f.sample_rate() == max_rate) { + formats.push(sf.with_max_sample_rate()); } - formats.push(sf.with_sample_rate(min_rate)); formats })) }