diff --git a/Cargo.toml b/Cargo.toml
index 599cb059..81b39df8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,11 +10,11 @@ exclude = ["assets/**", "tests/**"]
 edition = "2021"
 
 [dependencies]
-cpal = "0.15.3"
+cpal = { version = "0.15.3", optional = true }
 claxon = { version = "0.4.2", optional = true }
 hound = { version = "3.3.1", optional = true }
 lewton = { version = "0.10", optional = true }
-minimp3_fixed = { version = "0.5.4", optional = true}
+minimp3_fixed = { version = "0.5.4", optional = true }
 symphonia = { version = "0.5.4", optional = true, default-features = false }
 crossbeam-channel = { version = "0.5.8", optional = true }
 
@@ -25,7 +25,7 @@ atomic_float = { version = "1.1.0", optional = true }
 num-rational = "0.4.2"
 
 [features]
-default = ["flac", "vorbis", "wav", "mp3"]
+default = ["flac", "vorbis", "wav", "mp3", "cpal"]
 tracing = ["dep:tracing"]
 experimental = ["dep:atomic_float"]
 
diff --git a/benches/shared.rs b/benches/shared.rs
index 77e426d7..6122f64f 100644
--- a/benches/shared.rs
+++ b/benches/shared.rs
@@ -30,11 +30,11 @@ impl<T: rodio::Sample> Source for TestSource<T> {
         None // forever
     }
 
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
diff --git a/examples/custom_config.rs b/examples/custom_config.rs
index 40b6ca47..4e1ff76a 100644
--- a/examples/custom_config.rs
+++ b/examples/custom_config.rs
@@ -1,5 +1,5 @@
 use cpal::traits::HostTrait;
-use cpal::{BufferSize, SampleFormat, SampleRate};
+use cpal::{BufferSize, SampleFormat};
 use rodio::source::SineWave;
 use rodio::Source;
 use std::error::Error;
@@ -15,7 +15,7 @@ fn main() -> Result<(), Box<dyn Error>> {
         // No need to set all parameters explicitly here,
         // the defaults were set from the device's description.
         .with_buffer_size(BufferSize::Fixed(256))
-        .with_sample_rate(SampleRate(48_000))
+        .with_sample_rate(48_000)
         .with_sample_format(SampleFormat::F32)
         // Note that the function below still tries alternative configs if the specified one fails.
         // If you need to only use the exact specified configuration,
diff --git a/examples/noise_generator.rs b/examples/noise_generator.rs
index 577f9d01..23a86b90 100644
--- a/examples/noise_generator.rs
+++ b/examples/noise_generator.rs
@@ -22,11 +22,9 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     thread::sleep(interval_duration);
 
-    stream_handle.mixer().add(
-        pink(cpal::SampleRate(48000))
-            .amplify(0.1)
-            .take_duration(noise_duration),
-    );
+    stream_handle
+        .mixer()
+        .add(pink(48000).amplify(0.1).take_duration(noise_duration));
     println!("Playing pink noise");
 
     thread::sleep(interval_duration);
diff --git a/examples/signal_generator.rs b/examples/signal_generator.rs
index e746692d..1ae4048e 100644
--- a/examples/signal_generator.rs
+++ b/examples/signal_generator.rs
@@ -11,7 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     let test_signal_duration = Duration::from_millis(1000);
     let interval_duration = Duration::from_millis(1500);
-    let sample_rate = cpal::SampleRate(48000);
+    let sample_rate = 48000;
 
     println!("Playing 1000 Hz tone");
     stream_handle.mixer().add(
diff --git a/src/buffer.rs b/src/buffer.rs
index 1522faf9..ebaf114b 100644
--- a/src/buffer.rs
+++ b/src/buffer.rs
@@ -10,18 +10,18 @@
 //! ```
 //!
 
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::SeekError;
 use crate::{Sample, Source};
+use std::time::Duration;
 
 /// A buffer of samples treated as a source.
 #[derive(Debug, Clone)]
 pub struct SamplesBuffer<S> {
     data: Vec<S>,
     pos: usize,
-    channels: u16,
-    sample_rate: u32,
+    channels: ChannelCount,
+    sample_rate: SampleRate,
     duration: Duration,
 }
 
@@ -38,7 +38,7 @@ where
     /// - Panics if the length of the buffer is larger than approximately 16 billion elements.
     ///   This is because the calculation of the duration would overflow.
     ///
-    pub fn new<D>(channels: u16, sample_rate: u32, data: D) -> SamplesBuffer<S>
+    pub fn new<D>(channels: ChannelCount, sample_rate: SampleRate, data: D) -> SamplesBuffer<S>
     where
         D: Into<Vec<S>>,
     {
@@ -74,12 +74,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
@@ -174,12 +174,13 @@ mod tests {
     #[cfg(test)]
     mod try_seek {
         use super::*;
+        use crate::common::{ChannelCount, SampleRate};
         use std::time::Duration;
 
         #[test]
         fn channel_order_stays_correct() {
-            const SAMPLE_RATE: u32 = 100;
-            const CHANNELS: u16 = 2;
+            const SAMPLE_RATE: SampleRate = 100;
+            const CHANNELS: ChannelCount = 2;
             let mut buf = SamplesBuffer::new(
                 CHANNELS,
                 SAMPLE_RATE,
diff --git a/src/conversions/channels.rs b/src/conversions/channels.rs
index 45bf767f..ac8980b9 100644
--- a/src/conversions/channels.rs
+++ b/src/conversions/channels.rs
@@ -1,3 +1,4 @@
+use crate::common::ChannelCount;
 use cpal::Sample;
 
 /// Iterator that converts from a certain channel count to another.
@@ -7,10 +8,10 @@ where
     I: Iterator,
 {
     input: I,
-    from: cpal::ChannelCount,
-    to: cpal::ChannelCount,
+    from: ChannelCount,
+    to: ChannelCount,
     sample_repeat: Option<I::Item>,
-    next_output_sample_pos: cpal::ChannelCount,
+    next_output_sample_pos: ChannelCount,
 }
 
 impl<I> ChannelCountConverter<I>
@@ -24,11 +25,7 @@ where
     /// Panics if `from` or `to` are equal to 0.
     ///
     #[inline]
-    pub fn new(
-        input: I,
-        from: cpal::ChannelCount,
-        to: cpal::ChannelCount,
-    ) -> ChannelCountConverter<I> {
+    pub fn new(input: I, from: ChannelCount, to: ChannelCount) -> ChannelCountConverter<I> {
         assert!(from >= 1);
         assert!(to >= 1);
 
@@ -118,6 +115,7 @@ where
 #[cfg(test)]
 mod test {
     use super::ChannelCountConverter;
+    use crate::common::ChannelCount;
 
     #[test]
     fn remove_channels() {
@@ -147,7 +145,7 @@ mod test {
 
     #[test]
     fn size_hint() {
-        fn test(input: &[i16], from: cpal::ChannelCount, to: cpal::ChannelCount) {
+        fn test(input: &[i16], from: ChannelCount, to: ChannelCount) {
             let mut converter = ChannelCountConverter::new(input.iter().copied(), from, to);
             let count = converter.clone().count();
             for left_in_iter in (0..=count).rev() {
diff --git a/src/conversions/sample_rate.rs b/src/conversions/sample_rate.rs
index 05f8a2e9..3d882d9f 100644
--- a/src/conversions/sample_rate.rs
+++ b/src/conversions/sample_rate.rs
@@ -1,5 +1,6 @@
 use crate::conversions::Sample;
 
+use crate::common::{ChannelCount, SampleRate};
 use num_rational::Ratio;
 use std::mem;
 
@@ -16,7 +17,7 @@ where
     /// We convert chunks of `from` samples into chunks of `to` samples.
     to: u32,
     /// Number of channels in the stream
-    channels: cpal::ChannelCount,
+    channels: ChannelCount,
     /// One sample per channel, extracted from `input`.
     current_span: Vec<I::Item>,
     /// Position of `current_sample` modulo `from`.
@@ -51,12 +52,12 @@ where
     #[inline]
     pub fn new(
         mut input: I,
-        from: cpal::SampleRate,
-        to: cpal::SampleRate,
-        num_channels: cpal::ChannelCount,
+        from: SampleRate,
+        to: SampleRate,
+        num_channels: ChannelCount,
     ) -> SampleRateConverter<I> {
-        let from = from.0;
-        let to = to.0;
+        let from = from;
+        let to = to;
 
         assert!(num_channels >= 1);
         assert!(from >= 1);
@@ -251,8 +252,8 @@ where
 #[cfg(test)]
 mod test {
     use super::SampleRateConverter;
+    use crate::common::{ChannelCount, SampleRate};
     use core::time::Duration;
-    use cpal::{ChannelCount, SampleRate};
     use quickcheck::{quickcheck, TestResult};
 
     quickcheck! {
@@ -264,8 +265,8 @@ mod test {
             {
                 return TestResult::discard();
             }
-            let from = SampleRate(from as u32);
-            let to   = SampleRate(to as u32);
+            let from = from as SampleRate;
+            let to   = to as SampleRate;
 
             let input: Vec<u16> = Vec::new();
             let output =
@@ -279,7 +280,7 @@ mod test {
         /// Check that resampling to the same rate does not change the signal.
         fn identity(from: u16, channels: u8, input: Vec<u16>) -> TestResult {
             if channels == 0 || channels > 128 || from == 0 { return TestResult::discard(); }
-            let from = SampleRate(from as u32);
+            let from = from as SampleRate;
 
             let output =
                 SampleRateConverter::new(input.clone().into_iter(), from, from, channels as ChannelCount)
@@ -295,7 +296,7 @@ mod test {
                 return TestResult::discard();
             }
 
-            let to = SampleRate(to as u32);
+            let to = to as SampleRate;
             let from = to * k as u32;
 
             // Truncate the input, so it contains an integer number of spans.
@@ -321,7 +322,7 @@ mod test {
                 return TestResult::discard();
             }
 
-            let from = SampleRate(from as u32);
+            let from = from as SampleRate;
             let to = from * k as u32;
 
             // Truncate the input, so it contains an integer number of spans.
@@ -345,19 +346,19 @@ mod test {
         /// Check that resampling does not change the audio duration,
         ///  except by a negligible amount (± 1ms).  Reproduces #316.
         /// Ignored, pending a bug fix.
-        fn preserve_durations(d: Duration, freq: f32, to: u32) -> TestResult {
+        fn preserve_durations(d: Duration, freq: f32, to: SampleRate) -> TestResult {
             if to == 0 { return TestResult::discard(); }
 
             use crate::source::{SineWave, Source};
 
-            let to = SampleRate(to);
+            let to = to;
             let source = SineWave::new(freq).take_duration(d);
-            let from = SampleRate(source.sample_rate());
+            let from = source.sample_rate();
 
             let resampled =
                 SampleRateConverter::new(source, from, to, 1);
             let duration =
-                Duration::from_secs_f32(resampled.count() as f32 / to.0 as f32);
+                Duration::from_secs_f32(resampled.count() as f32 / to as f32);
 
             let delta = if d < duration { duration - d } else { d - duration };
             TestResult::from_bool(delta < Duration::from_millis(1))
@@ -367,8 +368,7 @@ mod test {
     #[test]
     fn upsample() {
         let input = vec![2u16, 16, 4, 18, 6, 20, 8, 22];
-        let output =
-            SampleRateConverter::new(input.into_iter(), SampleRate(2000), SampleRate(3000), 2);
+        let output = SampleRateConverter::new(input.into_iter(), 2000, 3000, 2);
         assert_eq!(output.len(), 12); // Test the source's Iterator::size_hint()
 
         let output = output.collect::<Vec<_>>();
@@ -378,8 +378,7 @@ mod test {
     #[test]
     fn upsample2() {
         let input = vec![1u16, 14];
-        let output =
-            SampleRateConverter::new(input.into_iter(), SampleRate(1000), SampleRate(7000), 1);
+        let output = SampleRateConverter::new(input.into_iter(), 1000, 7000, 1);
         let size_estimation = output.len();
         let output = output.collect::<Vec<_>>();
         assert_eq!(output, [1, 2, 4, 6, 8, 10, 12, 14]);
@@ -389,8 +388,7 @@ mod test {
     #[test]
     fn downsample() {
         let input = Vec::from_iter(0u16..17);
-        let output =
-            SampleRateConverter::new(input.into_iter(), SampleRate(12000), SampleRate(2400), 1);
+        let output = SampleRateConverter::new(input.into_iter(), 12000, 2400, 1);
         let size_estimation = output.len();
         let output = output.collect::<Vec<_>>();
         assert_eq!(output, [0, 5, 10, 15]);
diff --git a/src/decoder/flac.rs b/src/decoder/flac.rs
index a3ab8532..9773f9d8 100644
--- a/src/decoder/flac.rs
+++ b/src/decoder/flac.rs
@@ -6,6 +6,7 @@ use std::time::Duration;
 use crate::source::SeekError;
 use crate::Source;
 
+use crate::common::{ChannelCount, SampleRate};
 use claxon::FlacReader;
 
 /// Decoder for the Flac format.
@@ -18,8 +19,8 @@ where
     current_block_channel_len: usize,
     current_block_off: usize,
     bits_per_sample: u32,
-    sample_rate: u32,
-    channels: u16,
+    sample_rate: SampleRate,
+    channels: ChannelCount,
     samples: Option<u64>,
 }
 
@@ -45,7 +46,7 @@ where
             current_block_off: 0,
             bits_per_sample: spec.bits_per_sample,
             sample_rate: spec.sample_rate,
-            channels: spec.channels as u16,
+            channels: spec.channels as ChannelCount,
             samples: spec.samples,
         })
     }
@@ -64,12 +65,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs
index 29ba027a..ad1e61d7 100644
--- a/src/decoder/mod.rs
+++ b/src/decoder/mod.rs
@@ -13,6 +13,7 @@ use crate::Source;
 
 #[cfg(feature = "symphonia")]
 use self::read_seek_source::ReadSeekSource;
+use crate::common::{ChannelCount, SampleRate};
 #[cfg(feature = "symphonia")]
 use ::symphonia::core::io::{MediaSource, MediaSourceStream};
 
@@ -118,7 +119,7 @@ impl<R: Read + Seek> DecoderImpl<R> {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         match self {
             #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
             DecoderImpl::Wav(source) => source.channels(),
@@ -135,7 +136,7 @@ impl<R: Read + Seek> DecoderImpl<R> {
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         match self {
             #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
             DecoderImpl::Wav(source) => source.sample_rate(),
@@ -418,11 +419,11 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.0.channels()
     }
 
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.0.sample_rate()
     }
 
@@ -516,12 +517,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.0.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.0.sample_rate()
     }
 
diff --git a/src/decoder/mp3.rs b/src/decoder/mp3.rs
index ebc9a759..f85605c7 100644
--- a/src/decoder/mp3.rs
+++ b/src/decoder/mp3.rs
@@ -59,12 +59,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.current_span.channels as _
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.current_span.sample_rate as _
     }
 
diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs
index 77da85ac..c466e6ee 100644
--- a/src/decoder/symphonia.rs
+++ b/src/decoder/symphonia.rs
@@ -14,9 +14,9 @@ use symphonia::{
     default::get_probe,
 };
 
-use crate::{source, Source};
-
 use super::DecoderError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{source, Source};
 
 // Decoder errors are not considered fatal.
 // The correct action is to just get a new packet and try again.
@@ -159,12 +159,12 @@ impl Source for SymphoniaDecoder {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
-        self.spec.channels.count() as u16
+    fn channels(&self) -> ChannelCount {
+        self.spec.channels.count() as ChannelCount
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.spec.rate
     }
 
diff --git a/src/decoder/vorbis.rs b/src/decoder/vorbis.rs
index dcf6a441..2e936171 100644
--- a/src/decoder/vorbis.rs
+++ b/src/decoder/vorbis.rs
@@ -4,6 +4,7 @@ use std::time::Duration;
 use crate::source::SeekError;
 use crate::Source;
 
+use crate::common::{ChannelCount, SampleRate};
 use lewton::inside_ogg::OggStreamReader;
 
 /// Decoder for an OGG file that contains Vorbis sound format.
@@ -62,12 +63,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
-        self.stream_reader.ident_hdr.audio_channels as u16
+    fn channels(&self) -> ChannelCount {
+        self.stream_reader.ident_hdr.audio_channels as ChannelCount
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.stream_reader.ident_hdr.audio_sample_rate
     }
 
diff --git a/src/decoder/wav.rs b/src/decoder/wav.rs
index b4a3eaa2..76c27150 100644
--- a/src/decoder/wav.rs
+++ b/src/decoder/wav.rs
@@ -4,6 +4,7 @@ use std::time::Duration;
 use crate::source::SeekError;
 use crate::Source;
 
+use crate::common::{ChannelCount, SampleRate};
 use hound::{SampleFormat, WavReader};
 
 /// Decoder for the WAV format.
@@ -13,8 +14,8 @@ where
 {
     reader: SamplesIterator<R>,
     total_duration: Duration,
-    sample_rate: u32,
-    channels: u16,
+    sample_rate: SampleRate,
+    channels: ChannelCount,
 }
 
 impl<R> WavDecoder<R>
@@ -43,8 +44,8 @@ where
         Ok(WavDecoder {
             reader,
             total_duration,
-            sample_rate,
-            channels,
+            sample_rate: sample_rate as SampleRate,
+            channels: channels as ChannelCount,
         })
     }
     pub fn into_inner(self) -> R {
@@ -115,12 +116,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
diff --git a/src/file_output.rs b/src/file_output.rs
index 322c94a2..21f2c41a 100644
--- a/src/file_output.rs
+++ b/src/file_output.rs
@@ -10,7 +10,7 @@ pub fn output_to_wav<S: Sample>(
     wav_file: impl AsRef<path::Path>,
 ) -> Result<(), Box<dyn std::error::Error>> {
     let format = WavSpec {
-        channels: source.channels(),
+        channels: source.channels() as u16,
         sample_rate: source.sample_rate(),
         bits_per_sample: 32,
         sample_format: SampleFormat::Float,
@@ -26,6 +26,7 @@ pub fn output_to_wav<S: Sample>(
 #[cfg(test)]
 mod test {
     use super::output_to_wav;
+    use crate::common::ChannelCount;
     use crate::Source;
     use std::io::BufReader;
     use std::time::Duration;
@@ -46,7 +47,7 @@ mod test {
             hound::WavReader::new(BufReader::new(file)).expect("wav file can be read back");
         let reference = make_source();
         assert_eq!(reference.sample_rate(), reader.spec().sample_rate);
-        assert_eq!(reference.channels(), reader.spec().channels);
+        assert_eq!(reference.channels(), reader.spec().channels as ChannelCount);
 
         let actual_samples: Vec<f32> = reader.samples::<f32>().map(|x| x.unwrap()).collect();
         let expected_samples: Vec<f32> = reference.convert_samples().collect();
diff --git a/src/lib.rs b/src/lib.rs
index 339f319f..0450eb95 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,7 +21,7 @@
 //! use rodio::{Decoder, OutputStream, source::Source};
 //!
 //! // Get an output stream handle to the default physical sound device.
-//! // Note that the playback stops when the stream_handle is dropped.
+//! // Note that the playback stops when the stream_handle is dropped.//!
 //! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
 //!         .expect("open default audio stream");
 //! let sink = rodio::Sink::connect_new(&stream_handle.mixer());
@@ -150,14 +150,17 @@
 //! down your program).
 
 #![cfg_attr(test, deny(missing_docs))]
+#[cfg(feature = "cpal")]
 pub use cpal::{
     self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
     SupportedStreamConfig,
 };
 
+mod common;
 mod conversions;
 mod sink;
 mod spatial_sink;
+#[cfg(feature = "cpal")]
 mod stream;
 
 pub mod buffer;
@@ -168,10 +171,12 @@ pub mod queue;
 pub mod source;
 pub mod static_buffer;
 
+pub use crate::common::{ChannelCount, SampleRate};
 pub use crate::conversions::Sample;
 pub use crate::decoder::Decoder;
 pub use crate::file_output::output_to_wav;
 pub use crate::sink::Sink;
 pub use crate::source::Source;
 pub use crate::spatial_sink::SpatialSink;
+#[cfg(feature = "cpal")]
 pub use crate::stream::{play, OutputStream, OutputStreamBuilder, PlayError, StreamError};
diff --git a/src/mixer.rs b/src/mixer.rs
index 313e4654..f2719c83 100644
--- a/src/mixer.rs
+++ b/src/mixer.rs
@@ -1,19 +1,19 @@
 //! Mixer that plays multiple sounds at the same time.
 
+use crate::common::{ChannelCount, SampleRate};
+use crate::source::{SeekError, Source, UniformSourceIterator};
+use crate::Sample;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex};
 use std::time::Duration;
 
-use crate::source::{SeekError, Source, UniformSourceIterator};
-use crate::Sample;
-
 /// Builds a new mixer.
 ///
 /// You can choose the characteristics of the output thanks to this constructor. All the sounds
 /// added to the mixer will be converted to these values.
 ///
 /// After creating a mixer, you can add new sounds with the controller.
-pub fn mixer<S>(channels: u16, sample_rate: u32) -> (Arc<Mixer<S>>, MixerSource<S>)
+pub fn mixer<S>(channels: ChannelCount, sample_rate: SampleRate) -> (Arc<Mixer<S>>, MixerSource<S>)
 where
     S: Sample + Send + 'static,
 {
@@ -39,8 +39,8 @@ where
 pub struct Mixer<S> {
     has_pending: AtomicBool,
     pending_sources: Mutex<Vec<Box<dyn Source<Item = S> + Send>>>,
-    channels: u16,
-    sample_rate: u32,
+    channels: ChannelCount,
+    sample_rate: SampleRate,
 }
 
 impl<S> Mixer<S>
@@ -90,12 +90,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate
     }
 
diff --git a/src/queue.rs b/src/queue.rs
index cb17973b..2a2f434f 100644
--- a/src/queue.rs
+++ b/src/queue.rs
@@ -7,6 +7,7 @@ use std::time::Duration;
 use crate::source::{Empty, SeekError, Source, Zero};
 use crate::Sample;
 
+use crate::common::{ChannelCount, SampleRate};
 #[cfg(feature = "crossbeam-channel")]
 use crossbeam_channel::{unbounded as channel, Receiver, Sender};
 #[cfg(not(feature = "crossbeam-channel"))]
@@ -159,12 +160,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.current.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.current.sample_rate()
     }
 
diff --git a/src/source/agc.rs b/src/source/agc.rs
index 88958558..1268e9fb 100644
--- a/src/source/agc.rs
+++ b/src/source/agc.rs
@@ -23,6 +23,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
 use std::time::Duration;
 
+use crate::common::{ChannelCount, SampleRate};
 #[cfg(feature = "tracing")]
 use tracing;
 
@@ -472,12 +473,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/amplify.rs b/src/source/amplify.rs
index 14382ceb..11225e1b 100644
--- a/src/source/amplify.rs
+++ b/src/source/amplify.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `Amplify` object.
 pub fn amplify<I>(input: I, factor: f32) -> Amplify<I>
@@ -82,12 +82,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/blt.rs b/src/source/blt.rs
index 1ba26198..6a973d7b 100644
--- a/src/source/blt.rs
+++ b/src/source/blt.rs
@@ -1,8 +1,8 @@
+use crate::common::{ChannelCount, SampleRate};
+use crate::Source;
 use std::f32::consts::PI;
 use std::time::Duration;
 
-use crate::Source;
-
 use super::SeekError;
 
 // Implemented following http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
@@ -163,12 +163,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/buffered.rs b/src/source/buffered.rs
index 52b5ff7a..dc85db73 100644
--- a/src/source/buffered.rs
+++ b/src/source/buffered.rs
@@ -3,9 +3,9 @@ use std::mem;
 use std::sync::{Arc, Mutex};
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `Buffered` object.
 #[inline]
@@ -63,8 +63,8 @@ where
     I::Item: Sample,
 {
     data: Vec<I::Item>,
-    channels: u16,
-    rate: u32,
+    channels: ChannelCount,
+    rate: SampleRate,
     next: Mutex<Arc<Span<I>>>,
 }
 
@@ -220,7 +220,7 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         match *self.current_span {
             Span::Data(SpanData { channels, .. }) => channels,
             Span::End => 1,
@@ -229,7 +229,7 @@ where
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         match *self.current_span {
             Span::Data(SpanData { rate, .. }) => rate,
             Span::End => 44100,
diff --git a/src/source/channel_volume.rs b/src/source/channel_volume.rs
index 7dce1a6f..84862875 100644
--- a/src/source/channel_volume.rs
+++ b/src/source/channel_volume.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Combines channels in input into a single mono source, then plays that mono sound
 /// to each channel at the volume given for that channel.
@@ -129,12 +129,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
-        self.channel_volumes.len() as u16
+    fn channels(&self) -> ChannelCount {
+        self.channel_volumes.len() as ChannelCount
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/chirp.rs b/src/source/chirp.rs
index 11d97d31..4b99eb85 100644
--- a/src/source/chirp.rs
+++ b/src/source/chirp.rs
@@ -1,13 +1,13 @@
 //! Chirp/sweep source.
 
-use std::{f32::consts::TAU, time::Duration};
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::Source;
+use std::{f32::consts::TAU, time::Duration};
 
 /// Convenience function to create a new `Chirp` source.
 #[inline]
 pub fn chirp(
-    sample_rate: cpal::SampleRate,
+    sample_rate: SampleRate,
     start_frequency: f32,
     end_frequency: f32,
     duration: Duration,
@@ -21,14 +21,14 @@ pub fn chirp(
 pub struct Chirp {
     start_frequency: f32,
     end_frequency: f32,
-    sample_rate: cpal::SampleRate,
+    sample_rate: SampleRate,
     total_samples: u64,
     elapsed_samples: u64,
 }
 
 impl Chirp {
     fn new(
-        sample_rate: cpal::SampleRate,
+        sample_rate: SampleRate,
         start_frequency: f32,
         end_frequency: f32,
         duration: Duration,
@@ -37,7 +37,7 @@ impl Chirp {
             sample_rate,
             start_frequency,
             end_frequency,
-            total_samples: (duration.as_secs_f64() * (sample_rate.0 as f64)) as u64,
+            total_samples: (duration.as_secs_f64() * (sample_rate as f64)) as u64,
             elapsed_samples: 0,
         }
     }
@@ -61,16 +61,16 @@ impl Source for Chirp {
         None
     }
 
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
-    fn sample_rate(&self) -> u32 {
-        self.sample_rate.0
+    fn sample_rate(&self) -> SampleRate {
+        self.sample_rate
     }
 
     fn total_duration(&self) -> Option<Duration> {
-        let secs: f64 = self.total_samples as f64 / self.sample_rate.0 as f64;
+        let secs: f64 = self.total_samples as f64 / self.sample_rate as f64;
         Some(Duration::new(1, 0).mul_f64(secs))
     }
 }
diff --git a/src/source/delay.rs b/src/source/delay.rs
index 80384981..a10e5311 100644
--- a/src/source/delay.rs
+++ b/src/source/delay.rs
@@ -1,10 +1,14 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
-fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> usize {
+fn remaining_samples(
+    until_playback: Duration,
+    sample_rate: SampleRate,
+    channels: ChannelCount,
+) -> usize {
     let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64;
     let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000;
     samples as usize
@@ -95,12 +99,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/done.rs b/src/source/done.rs
index c3087434..3ce8a5a3 100644
--- a/src/source/done.rs
+++ b/src/source/done.rs
@@ -2,9 +2,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Arc;
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// When the inner source is empty this decrements a `AtomicUsize`.
 #[derive(Debug, Clone)]
@@ -78,12 +78,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/empty.rs b/src/source/empty.rs
index db61defe..c546e5be 100644
--- a/src/source/empty.rs
+++ b/src/source/empty.rs
@@ -1,9 +1,9 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// An empty source.
 #[derive(Debug, Copy, Clone)]
@@ -44,12 +44,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         48000
     }
 
diff --git a/src/source/empty_callback.rs b/src/source/empty_callback.rs
index 0f7864eb..df7e2a20 100644
--- a/src/source/empty_callback.rs
+++ b/src/source/empty_callback.rs
@@ -1,9 +1,9 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// An empty source which executes a callback function
 pub struct EmptyCallback<S> {
@@ -47,12 +47,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         48000
     }
 
diff --git a/src/source/fadein.rs b/src/source/fadein.rs
index af884fb7..3eb202c9 100644
--- a/src/source/fadein.rs
+++ b/src/source/fadein.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError};
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `FadeIn` object.
 pub fn fadein<I>(input: I, duration: Duration) -> FadeIn<I>
@@ -81,12 +81,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.inner().channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.inner().sample_rate()
     }
 
diff --git a/src/source/fadeout.rs b/src/source/fadeout.rs
index e3a07fe6..24cac2b3 100644
--- a/src/source/fadeout.rs
+++ b/src/source/fadeout.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError};
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `FadeOut` object.
 pub fn fadeout<I>(input: I, duration: Duration) -> FadeOut<I>
@@ -81,12 +81,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.inner().channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.inner().sample_rate()
     }
 
diff --git a/src/source/from_iter.rs b/src/source/from_iter.rs
index fe8d9fe6..f1709301 100644
--- a/src/source/from_iter.rs
+++ b/src/source/from_iter.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Builds a source that chains sources provided by an iterator.
 ///
@@ -114,7 +114,7 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         if let Some(src) = &self.current_source {
             src.channels()
         } else {
@@ -124,7 +124,7 @@ where
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         if let Some(src) = &self.current_source {
             src.sample_rate()
         } else {
diff --git a/src/source/linear_ramp.rs b/src/source/linear_ramp.rs
index c1ddebfa..bf03855c 100644
--- a/src/source/linear_ramp.rs
+++ b/src/source/linear_ramp.rs
@@ -1,6 +1,7 @@
 use std::time::Duration;
 
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
 use crate::{Sample, Source};
 
 /// Internal function that builds a `LinearRamp` object.
@@ -121,12 +122,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/mix.rs b/src/source/mix.rs
index d32e55b1..9c573811 100644
--- a/src/source/mix.rs
+++ b/src/source/mix.rs
@@ -1,6 +1,7 @@
 use std::cmp;
 use std::time::Duration;
 
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::uniform::UniformSourceIterator;
 use crate::source::SeekError;
 use crate::{Sample, Source};
@@ -101,12 +102,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input1.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input1.sample_rate()
     }
 
diff --git a/src/source/mod.rs b/src/source/mod.rs
index a5f6a3e9..3211301e 100644
--- a/src/source/mod.rs
+++ b/src/source/mod.rs
@@ -3,9 +3,9 @@
 use core::fmt;
 use core::time::Duration;
 
-use cpal::FromSample;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::Sample;
+use cpal::FromSample;
 
 pub use self::agc::AutomaticGainControl;
 pub use self::amplify::Amplify;
@@ -165,10 +165,10 @@ where
     fn current_span_len(&self) -> Option<usize>;
 
     /// Returns the number of channels. Channels are always interleaved.
-    fn channels(&self) -> u16;
+    fn channels(&self) -> ChannelCount;
 
     /// Returns the rate at which the source should be played. In number of samples per second.
-    fn sample_rate(&self) -> u32;
+    fn sample_rate(&self) -> SampleRate;
 
     /// Returns the total duration of this source, if known.
     ///
@@ -669,12 +669,12 @@ macro_rules! source_pointer_impl {
             }
 
             #[inline]
-            fn channels(&self) -> u16 {
+            fn channels(&self) -> ChannelCount {
                 (**self).channels()
             }
 
             #[inline]
-            fn sample_rate(&self) -> u32 {
+            fn sample_rate(&self) -> SampleRate {
                 (**self).sample_rate()
             }
 
diff --git a/src/source/noise.rs b/src/source/noise.rs
index 350050a9..60937446 100644
--- a/src/source/noise.rs
+++ b/src/source/noise.rs
@@ -6,17 +6,18 @@ use crate::Source;
 
 use super::SeekError;
 
+use crate::common::SampleRate;
 use rand::{rngs::SmallRng, RngCore, SeedableRng};
 
 /// Convenience function to create a new `WhiteNoise` noise source.
 #[inline]
-pub fn white(sample_rate: cpal::SampleRate) -> WhiteNoise {
+pub fn white(sample_rate: SampleRate) -> WhiteNoise {
     WhiteNoise::new(sample_rate)
 }
 
 /// Convenience function to create a new `PinkNoise` noise source.
 #[inline]
-pub fn pink(sample_rate: cpal::SampleRate) -> PinkNoise {
+pub fn pink(sample_rate: SampleRate) -> PinkNoise {
     PinkNoise::new(sample_rate)
 }
 
@@ -24,7 +25,7 @@ pub fn pink(sample_rate: cpal::SampleRate) -> PinkNoise {
 /// samples as provided by the `rand::rngs::SmallRng` randomness source.
 #[derive(Clone, Debug)]
 pub struct WhiteNoise {
-    sample_rate: cpal::SampleRate,
+    sample_rate: SampleRate,
     rng: SmallRng,
 }
 
@@ -38,7 +39,7 @@ impl WhiteNoise {
     }
 
     /// Create a new white noise generator, seeding the RNG with system entropy.
-    pub fn new(sample_rate: cpal::SampleRate) -> Self {
+    pub fn new(sample_rate: SampleRate) -> Self {
         Self {
             sample_rate,
             rng: SmallRng::from_entropy(),
@@ -64,12 +65,12 @@ impl Source for WhiteNoise {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate.0
     }
 
@@ -99,7 +100,7 @@ pub struct PinkNoise {
 
 impl PinkNoise {
     /// Create new pink noise source with given sample rate.
-    pub fn new(sample_rate: cpal::SampleRate) -> Self {
+    pub fn new(sample_rate: SampleRate) -> Self {
         Self {
             white_noise: WhiteNoise::new(sample_rate),
             b: [0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32],
@@ -139,11 +140,11 @@ impl Source for PinkNoise {
         None
     }
 
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.white_noise.sample_rate()
     }
 
diff --git a/src/source/pausable.rs b/src/source/pausable.rs
index fa3a5266..220ed69b 100644
--- a/src/source/pausable.rs
+++ b/src/source/pausable.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Builds a `Pausable` object.
 pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
@@ -31,8 +31,8 @@ where
 #[derive(Clone, Debug)]
 pub struct Pausable<I> {
     input: I,
-    paused_channels: Option<u16>,
-    remaining_paused_samples: u16,
+    paused_channels: Option<ChannelCount>,
+    remaining_paused_samples: ChannelCount,
 }
 
 impl<I> Pausable<I>
@@ -110,12 +110,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/periodic.rs b/src/source/periodic.rs
index 08e4f25c..5ce4f74b 100644
--- a/src/source/periodic.rs
+++ b/src/source/periodic.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `PeriodicAccess` object.
 pub fn periodic<I, F>(source: I, period: Duration, modifier: F) -> PeriodicAccess<I, F>
@@ -106,12 +106,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/position.rs b/src/source/position.rs
index 92758568..b06cc021 100644
--- a/src/source/position.rs
+++ b/src/source/position.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `TrackPosition` object. See trait docs for
 /// details
@@ -23,8 +23,8 @@ pub struct TrackPosition<I> {
     input: I,
     samples_counted: usize,
     offset_duration: f64,
-    current_span_sample_rate: u32,
-    current_span_channels: u16,
+    current_span_sample_rate: SampleRate,
+    current_span_channels: ChannelCount,
     current_span_len: Option<usize>,
 }
 
@@ -130,12 +130,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/repeat.rs b/src/source/repeat.rs
index 122f24c8..5ccb879e 100644
--- a/src/source/repeat.rs
+++ b/src/source/repeat.rs
@@ -2,9 +2,9 @@ use std::time::Duration;
 
 use crate::source::buffered::Buffered;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `Repeat` object.
 pub fn repeat<I>(input: I) -> Repeat<I>
@@ -67,7 +67,7 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         match self.inner.current_span_len() {
             Some(0) => self.next.channels(),
             _ => self.inner.channels(),
@@ -75,7 +75,7 @@ where
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         match self.inner.current_span_len() {
             Some(0) => self.next.sample_rate(),
             _ => self.inner.sample_rate(),
diff --git a/src/source/samples_converter.rs b/src/source/samples_converter.rs
index 2dbd42bc..173d262b 100644
--- a/src/source/samples_converter.rs
+++ b/src/source/samples_converter.rs
@@ -1,11 +1,11 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 
+use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
 use crate::{Sample, Source};
 use cpal::{FromSample, Sample as CpalSample};
 
-use super::SeekError;
-
 /// Wrap the input and lazily converts the samples it provides to the type
 /// specified by the generic parameter D
 #[derive(Clone)]
@@ -83,12 +83,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.inner.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.inner.sample_rate()
     }
 
diff --git a/src/source/sawtooth.rs b/src/source/sawtooth.rs
index 58e56d03..c6ae01f3 100644
--- a/src/source/sawtooth.rs
+++ b/src/source/sawtooth.rs
@@ -1,7 +1,7 @@
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::{Function, SignalGenerator};
 use crate::Source;
+use std::time::Duration;
 
 use super::SeekError;
 
@@ -17,14 +17,13 @@ pub struct SawtoothWave {
 }
 
 impl SawtoothWave {
-    const SAMPLE_RATE: u32 = 48000;
+    const SAMPLE_RATE: SampleRate = 48000;
 
     /// The frequency of the sine.
     #[inline]
     pub fn new(freq: f32) -> SawtoothWave {
-        let sr = cpal::SampleRate(Self::SAMPLE_RATE);
         SawtoothWave {
-            test_saw: SignalGenerator::new(sr, freq, Function::Sawtooth),
+            test_saw: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sawtooth),
         }
     }
 }
@@ -45,12 +44,12 @@ impl Source for SawtoothWave {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         Self::SAMPLE_RATE
     }
 
diff --git a/src/source/signal_generator.rs b/src/source/signal_generator.rs
index e724297b..e0c33bb8 100644
--- a/src/source/signal_generator.rs
+++ b/src/source/signal_generator.rs
@@ -9,13 +9,13 @@
 //! ```
 //! use rodio::source::{SignalGenerator,Function};
 //!
-//! let tone = SignalGenerator::new(cpal::SampleRate(48000), 440.0, Function::Sine);
+//! let tone = SignalGenerator::new(48000, 440.0, Function::Sine);
 //! ```
-use std::f32::consts::TAU;
-use std::time::Duration;
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
 use crate::Source;
+use std::f32::consts::TAU;
+use std::time::Duration;
 
 /// Generator function.
 ///
@@ -71,7 +71,7 @@ fn sawtooth_signal(phase: f32) -> f32 {
 /// An infinite source that produces one of a selection of test waveforms.
 #[derive(Clone, Debug)]
 pub struct SignalGenerator {
-    sample_rate: cpal::SampleRate,
+    sample_rate: SampleRate,
     function: GeneratorFunction,
     phase_step: f32,
     phase: f32,
@@ -86,7 +86,7 @@ impl SignalGenerator {
     ///
     /// Will panic if `frequency` is equal to zero.
     #[inline]
-    pub fn new(sample_rate: cpal::SampleRate, frequency: f32, f: Function) -> Self {
+    pub fn new(sample_rate: SampleRate, frequency: f32, f: Function) -> Self {
         let function: GeneratorFunction = match f {
             Function::Sine => sine_signal,
             Function::Triangle => triangle_signal,
@@ -105,12 +105,12 @@ impl SignalGenerator {
     /// Will panic if `frequency` is equal to zero.
     #[inline]
     pub fn with_function(
-        sample_rate: cpal::SampleRate,
+        sample_rate: SampleRate,
         frequency: f32,
         generator_function: GeneratorFunction,
     ) -> Self {
         assert!(frequency != 0.0, "frequency must be greater than zero");
-        let period = sample_rate.0 as f32 / frequency;
+        let period = sample_rate as f32 / frequency;
         let phase_step = 1.0f32 / period;
 
         SignalGenerator {
@@ -142,13 +142,13 @@ impl Source for SignalGenerator {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
-        self.sample_rate.0
+    fn sample_rate(&self) -> SampleRate {
+        self.sample_rate
     }
 
     #[inline]
@@ -158,7 +158,7 @@ impl Source for SignalGenerator {
 
     #[inline]
     fn try_seek(&mut self, duration: Duration) -> Result<(), SeekError> {
-        let seek = duration.as_secs_f32() * (self.sample_rate.0 as f32) / self.period;
+        let seek = duration.as_secs_f32() * (self.sample_rate as f32) / self.period;
         self.phase = seek.rem_euclid(1.0f32);
         Ok(())
     }
@@ -171,7 +171,7 @@ mod tests {
 
     #[test]
     fn square() {
-        let mut wf = SignalGenerator::new(cpal::SampleRate(2000), 500.0f32, Function::Square);
+        let mut wf = SignalGenerator::new(2000, 500.0f32, Function::Square);
         assert_eq!(wf.next(), Some(1.0f32));
         assert_eq!(wf.next(), Some(1.0f32));
         assert_eq!(wf.next(), Some(-1.0f32));
@@ -184,7 +184,7 @@ mod tests {
 
     #[test]
     fn triangle() {
-        let mut wf = SignalGenerator::new(cpal::SampleRate(8000), 1000.0f32, Function::Triangle);
+        let mut wf = SignalGenerator::new(8000, 1000.0f32, Function::Triangle);
         assert_eq!(wf.next(), Some(-1.0f32));
         assert_eq!(wf.next(), Some(-0.5f32));
         assert_eq!(wf.next(), Some(0.0f32));
@@ -205,7 +205,7 @@ mod tests {
 
     #[test]
     fn saw() {
-        let mut wf = SignalGenerator::new(cpal::SampleRate(200), 50.0f32, Function::Sawtooth);
+        let mut wf = SignalGenerator::new(200, 50.0f32, Function::Sawtooth);
         assert_eq!(wf.next(), Some(0.0f32));
         assert_eq!(wf.next(), Some(0.5f32));
         assert_eq!(wf.next(), Some(-1.0f32));
@@ -217,7 +217,7 @@ mod tests {
 
     #[test]
     fn sine() {
-        let mut wf = SignalGenerator::new(cpal::SampleRate(1000), 100f32, Function::Sine);
+        let mut wf = SignalGenerator::new(1000, 100f32, Function::Sine);
 
         assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32);
         assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32);
diff --git a/src/source/sine.rs b/src/source/sine.rs
index c10c536c..e3814435 100644
--- a/src/source/sine.rs
+++ b/src/source/sine.rs
@@ -1,7 +1,7 @@
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::{Function, SignalGenerator};
 use crate::Source;
+use std::time::Duration;
 
 use super::SeekError;
 
@@ -22,9 +22,8 @@ impl SineWave {
     /// The frequency of the sine.
     #[inline]
     pub fn new(freq: f32) -> SineWave {
-        let sr = cpal::SampleRate(Self::SAMPLE_RATE);
         SineWave {
-            test_sine: SignalGenerator::new(sr, freq, Function::Sine),
+            test_sine: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sine),
         }
     }
 }
@@ -45,12 +44,12 @@ impl Source for SineWave {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         Self::SAMPLE_RATE
     }
 
diff --git a/src/source/skip.rs b/src/source/skip.rs
index 96ebd3c9..ef80227e 100644
--- a/src/source/skip.rs
+++ b/src/source/skip.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 const NS_PER_SECOND: u128 = 1_000_000_000;
 
@@ -143,12 +143,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
@@ -171,11 +171,12 @@ mod tests {
     use std::time::Duration;
 
     use crate::buffer::SamplesBuffer;
+    use crate::common::{ChannelCount, SampleRate};
     use crate::source::Source;
 
     fn test_skip_duration_samples_left(
-        channels: u16,
-        sample_rate: u32,
+        channels: ChannelCount,
+        sample_rate: SampleRate,
         seconds: u32,
         seconds_to_skip: u32,
     ) {
diff --git a/src/source/skippable.rs b/src/source/skippable.rs
index 9bcd559a..d77447cf 100644
--- a/src/source/skippable.rs
+++ b/src/source/skippable.rs
@@ -1,7 +1,7 @@
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::Sample;
 use crate::Source;
+use std::time::Duration;
 
 use super::SeekError;
 
@@ -83,12 +83,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/spatial.rs b/src/source/spatial.rs
index 3c0f4b70..f8a2b5ca 100644
--- a/src/source/spatial.rs
+++ b/src/source/spatial.rs
@@ -1,10 +1,10 @@
 use std::time::Duration;
 
+use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::ChannelVolume;
 use crate::{Sample, Source};
 
-use super::SeekError;
-
 /// A simple spatial audio source. The underlying source is transformed to Mono
 /// and then played in stereo. The left and right channel's volume are amplified
 /// differently depending on the distance of the left and right ear to the source.
@@ -108,12 +108,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/speed.rs b/src/source/speed.rs
index 76f00e4f..6409dff2 100644
--- a/src/source/speed.rs
+++ b/src/source/speed.rs
@@ -47,9 +47,9 @@
 
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `Speed` object.
 pub fn speed<I>(input: I, factor: f32) -> Speed<I> {
@@ -129,12 +129,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         (self.input.sample_rate() as f32 * self.factor) as u32
     }
 
diff --git a/src/source/square.rs b/src/source/square.rs
index 40c10511..ac6bd678 100644
--- a/src/source/square.rs
+++ b/src/source/square.rs
@@ -1,7 +1,7 @@
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::{Function, SignalGenerator};
 use crate::Source;
+use std::time::Duration;
 
 use super::SeekError;
 
@@ -22,9 +22,8 @@ impl SquareWave {
     /// The frequency of the sine.
     #[inline]
     pub fn new(freq: f32) -> SquareWave {
-        let sr = cpal::SampleRate(Self::SAMPLE_RATE);
         SquareWave {
-            test_square: SignalGenerator::new(sr, freq, Function::Square),
+            test_square: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Square),
         }
     }
 }
@@ -45,12 +44,12 @@ impl Source for SquareWave {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         Self::SAMPLE_RATE
     }
 
diff --git a/src/source/stoppable.rs b/src/source/stoppable.rs
index cde1b1d2..116efe39 100644
--- a/src/source/stoppable.rs
+++ b/src/source/stoppable.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// This is the same as [`skippable`](crate::source::skippable) see its docs
 pub fn stoppable<I>(source: I) -> Stoppable<I> {
@@ -78,12 +78,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/take.rs b/src/source/take.rs
index 6b8f4bbf..9e036f6e 100644
--- a/src/source/take.rs
+++ b/src/source/take.rs
@@ -1,8 +1,8 @@
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// Internal function that builds a `TakeDuration` object.
 pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
@@ -160,12 +160,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.input.channels()
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.input.sample_rate()
     }
 
diff --git a/src/source/triangle.rs b/src/source/triangle.rs
index 89889a98..eb73801d 100644
--- a/src/source/triangle.rs
+++ b/src/source/triangle.rs
@@ -1,7 +1,7 @@
-use std::time::Duration;
-
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::{Function, SignalGenerator};
 use crate::Source;
+use std::time::Duration;
 
 use super::SeekError;
 
@@ -17,14 +17,13 @@ pub struct TriangleWave {
 }
 
 impl TriangleWave {
-    const SAMPLE_RATE: u32 = 48000;
+    const SAMPLE_RATE: SampleRate = 48000;
 
     /// The frequency of the sine.
     #[inline]
     pub fn new(freq: f32) -> TriangleWave {
-        let sr = cpal::SampleRate(Self::SAMPLE_RATE);
         TriangleWave {
-            test_tri: SignalGenerator::new(sr, freq, Function::Triangle),
+            test_tri: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Triangle),
         }
     }
 }
@@ -45,12 +44,12 @@ impl Source for TriangleWave {
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         1
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         Self::SAMPLE_RATE
     }
 
diff --git a/src/source/uniform.rs b/src/source/uniform.rs
index 8454927d..30472ed9 100644
--- a/src/source/uniform.rs
+++ b/src/source/uniform.rs
@@ -3,11 +3,11 @@ use std::time::Duration;
 
 use cpal::FromSample;
 
+use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
 use crate::conversions::{ChannelCountConverter, DataConverter, SampleRateConverter};
 use crate::{Sample, Source};
 
-use super::SeekError;
-
 /// An iterator that reads from a `Source` and converts the samples to a
 /// specific type, sample-rate and channels count.
 ///
@@ -21,8 +21,8 @@ where
     D: Sample,
 {
     inner: Option<DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D>>,
-    target_channels: u16,
-    target_sample_rate: u32,
+    target_channels: ChannelCount,
+    target_sample_rate: SampleRate,
     total_duration: Option<Duration>,
 }
 
@@ -37,8 +37,8 @@ where
     #[inline]
     pub fn new(
         input: I,
-        target_channels: u16,
-        target_sample_rate: u32,
+        target_channels: ChannelCount,
+        target_sample_rate: SampleRate,
     ) -> UniformSourceIterator<I, D> {
         let total_duration = input.total_duration();
         let input = UniformSourceIterator::bootstrap(input, target_channels, target_sample_rate);
@@ -54,8 +54,8 @@ where
     #[inline]
     fn bootstrap(
         input: I,
-        target_channels: u16,
-        target_sample_rate: u32,
+        target_channels: ChannelCount,
+        target_sample_rate: SampleRate,
     ) -> DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D> {
         // Limit the span length to something reasonable
         let span_len = input.current_span_len().map(|x| x.min(32768));
@@ -67,12 +67,8 @@ where
             iter: input,
             n: span_len,
         };
-        let input = SampleRateConverter::new(
-            input,
-            cpal::SampleRate(from_sample_rate),
-            cpal::SampleRate(target_sample_rate),
-            from_channels,
-        );
+        let input =
+            SampleRateConverter::new(input, from_sample_rate, target_sample_rate, from_channels);
         let input = ChannelCountConverter::new(input, from_channels, target_channels);
 
         DataConverter::new(input)
@@ -128,12 +124,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.target_channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.target_sample_rate
     }
 
diff --git a/src/source/zero.rs b/src/source/zero.rs
index 8fe2dda7..69e3a295 100644
--- a/src/source/zero.rs
+++ b/src/source/zero.rs
@@ -1,17 +1,17 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 
-use crate::{Sample, Source};
-
 use super::SeekError;
+use crate::common::{ChannelCount, SampleRate};
+use crate::{Sample, Source};
 
 /// An source that produces samples with value zero (silence). Depending on if
 /// it where created with [`Zero::new`] or [`Zero::new_samples`] it can be never
 /// ending or finite.
 #[derive(Clone, Debug)]
 pub struct Zero<S> {
-    channels: u16,
-    sample_rate: u32,
+    channels: ChannelCount,
+    sample_rate: SampleRate,
     num_samples: Option<usize>,
     marker: PhantomData<S>,
 }
@@ -19,7 +19,7 @@ pub struct Zero<S> {
 impl<S> Zero<S> {
     /// Create a new source that never ends and produces total silence.
     #[inline]
-    pub fn new(channels: u16, sample_rate: u32) -> Zero<S> {
+    pub fn new(channels: ChannelCount, sample_rate: SampleRate) -> Zero<S> {
         Zero {
             channels,
             sample_rate,
@@ -29,7 +29,11 @@ impl<S> Zero<S> {
     }
     /// Create a new source that never ends and produces total silence.
     #[inline]
-    pub fn new_samples(channels: u16, sample_rate: u32, num_samples: usize) -> Zero<S> {
+    pub fn new_samples(
+        channels: ChannelCount,
+        sample_rate: SampleRate,
+        num_samples: usize,
+    ) -> Zero<S> {
         Zero {
             channels,
             sample_rate,
@@ -70,12 +74,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
diff --git a/src/static_buffer.rs b/src/static_buffer.rs
index b43c1917..4b2c650e 100644
--- a/src/static_buffer.rs
+++ b/src/static_buffer.rs
@@ -13,6 +13,7 @@
 use std::slice::Iter as SliceIter;
 use std::time::Duration;
 
+use crate::common::{ChannelCount, SampleRate};
 use crate::source::SeekError;
 use crate::{Sample, Source};
 
@@ -23,8 +24,8 @@ where
     S: 'static,
 {
     data: SliceIter<'static, S>,
-    channels: u16,
-    sample_rate: u32,
+    channels: ChannelCount,
+    sample_rate: SampleRate,
     duration: Duration,
 }
 
@@ -41,7 +42,11 @@ where
     /// - Panics if the length of the buffer is larger than approximately 16 billion elements.
     ///   This is because the calculation of the duration would overflow.
     ///
-    pub fn new(channels: u16, sample_rate: u32, data: &'static [S]) -> StaticSamplesBuffer<S> {
+    pub fn new(
+        channels: ChannelCount,
+        sample_rate: SampleRate,
+        data: &'static [S],
+    ) -> StaticSamplesBuffer<S> {
         assert!(channels != 0);
         assert!(sample_rate != 0);
 
@@ -72,12 +77,12 @@ where
     }
 
     #[inline]
-    fn channels(&self) -> u16 {
+    fn channels(&self) -> ChannelCount {
         self.channels
     }
 
     #[inline]
-    fn sample_rate(&self) -> u32 {
+    fn sample_rate(&self) -> SampleRate {
         self.sample_rate
     }
 
diff --git a/src/stream.rs b/src/stream.rs
index 246f0c98..48616eea 100644
--- a/src/stream.rs
+++ b/src/stream.rs
@@ -3,16 +3,14 @@ use std::marker::Sync;
 use std::sync::Arc;
 use std::{error, fmt};
 
+use crate::common::{ChannelCount, SampleRate};
 use crate::decoder;
 use crate::mixer::{mixer, Mixer, MixerSource};
 use crate::sink::Sink;
 use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
-use cpal::{
-    BufferSize, ChannelCount, FrameCount, Sample, SampleFormat, SampleRate, StreamConfig,
-    SupportedBufferSize,
-};
+use cpal::{BufferSize, FrameCount, Sample, SampleFormat, StreamConfig, SupportedBufferSize};
 
-const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100);
+const HZ_44100: SampleRate = 44_100;
 
 /// `cpal::Stream` container.
 /// Use `mixer()` method to control output.
@@ -85,14 +83,14 @@ impl OutputStreamBuilder {
     }
 
     /// Sets number of output stream's channels.
-    pub fn with_channels(mut self, channel_count: cpal::ChannelCount) -> OutputStreamBuilder {
+    pub fn with_channels(mut self, channel_count: ChannelCount) -> OutputStreamBuilder {
         assert!(channel_count > 0);
         self.config.channel_count = channel_count;
         self
     }
 
     /// Sets output stream's sample rate.
-    pub fn with_sample_rate(mut self, sample_rate: cpal::SampleRate) -> OutputStreamBuilder {
+    pub fn with_sample_rate(mut self, sample_rate: SampleRate) -> OutputStreamBuilder {
         self.config.sample_rate = sample_rate;
         self
     }
@@ -118,8 +116,8 @@ impl OutputStreamBuilder {
         config: &cpal::SupportedStreamConfig,
     ) -> OutputStreamBuilder {
         self.config = OutputStreamConfig {
-            channel_count: config.channels(),
-            sample_rate: config.sample_rate(),
+            channel_count: config.channels() as ChannelCount,
+            sample_rate: config.sample_rate().0 as SampleRate,
             // In case of supported range limit buffer size to avoid unexpectedly long playback delays.
             buffer_size: clamp_supported_buffer_size(config.buffer_size(), 1024),
             sample_format: config.sample_format(),
@@ -130,8 +128,8 @@ impl OutputStreamBuilder {
     /// Set all output stream parameters at once from CPAL stream config.
     pub fn with_config(mut self, config: &cpal::StreamConfig) -> OutputStreamBuilder {
         self.config = OutputStreamConfig {
-            channel_count: config.channels,
-            sample_rate: config.sample_rate,
+            channel_count: config.channels as ChannelCount,
+            sample_rate: config.sample_rate.0 as SampleRate,
             buffer_size: config.buffer_size,
             ..self.config
         };
@@ -220,8 +218,8 @@ where
 impl From<&OutputStreamConfig> for StreamConfig {
     fn from(config: &OutputStreamConfig) -> Self {
         cpal::StreamConfig {
-            channels: config.channel_count,
-            sample_rate: config.sample_rate,
+            channels: config.channel_count as cpal::ChannelCount,
+            sample_rate: cpal::SampleRate(config.sample_rate),
             buffer_size: config.buffer_size,
         }
     }
@@ -307,7 +305,7 @@ impl OutputStream {
         device: &cpal::Device,
         config: &OutputStreamConfig,
     ) -> Result<OutputStream, StreamError> {
-        let (controller, source) = mixer(config.channel_count, config.sample_rate.0);
+        let (controller, source) = mixer(config.channel_count, config.sample_rate);
         Self::init_stream(device, config, source)
             .map_err(StreamError::BuildStreamError)
             .and_then(|stream| {
@@ -458,8 +456,9 @@ fn supported_output_configs(
         let max_rate = sf.max_sample_rate();
         let min_rate = sf.min_sample_rate();
         let mut formats = vec![sf.with_max_sample_rate()];
-        if HZ_44100 < max_rate && HZ_44100 > min_rate {
-            formats.push(sf.with_sample_rate(HZ_44100))
+        let preferred_rate = cpal::SampleRate(HZ_44100);
+        if preferred_rate < max_rate && preferred_rate > min_rate {
+            formats.push(sf.with_sample_rate(preferred_rate))
         }
         formats.push(sf.with_sample_rate(min_rate));
         formats
diff --git a/tests/seek.rs b/tests/seek.rs
index 4c49ad80..0cc47c97 100644
--- a/tests/seek.rs
+++ b/tests/seek.rs
@@ -1,11 +1,10 @@
+use rodio::{ChannelCount, Decoder, Source};
+use rstest::rstest;
+use rstest_reuse::{self, *};
 use std::io::{BufReader, Read, Seek};
 use std::path::Path;
 use std::time::Duration;
 
-use rodio::{Decoder, Source};
-use rstest::rstest;
-use rstest_reuse::{self, *};
-
 #[template]
 #[rstest]
 // note: disabled, broken decoder see issue: #516 and #539
@@ -203,17 +202,22 @@ where
         .next_multiple_of(channels);
 
     let samples = &samples[beep_starts..beep_starts + 100];
-    assert!(is_silent(samples, channels as u16, 0), "{samples:?}");
-    assert!(!is_silent(samples, channels as u16, 1), "{samples:?}");
+    assert!(
+        is_silent(samples, channels as ChannelCount, 0),
+        "{samples:?}"
+    );
+    assert!(
+        !is_silent(samples, channels as ChannelCount, 1),
+        "{samples:?}"
+    );
 
     beep_starts..beep_ends
 }
 
-fn is_silent(samples: &[f32], channels: u16, channel: usize) -> bool {
+fn is_silent(samples: &[f32], channels: ChannelCount, channel: usize) -> bool {
     assert_eq!(samples.len(), 100);
     let channel = samples.iter().skip(channel).step_by(channels as usize);
-    let volume =
-        channel.map(|s| s.abs()).sum::<f32>() as f32 / samples.len() as f32 * channels as f32;
+    let volume = channel.map(|s| s.abs()).sum::<f32>() / samples.len() as f32 * channels as f32;
 
     const BASICALLY_ZERO: f32 = 0.0001;
     volume < BASICALLY_ZERO