diff --git a/symphonia-play/src/output.rs b/symphonia-play/src/output.rs index e5445438..509588fe 100644 --- a/symphonia-play/src/output.rs +++ b/symphonia-play/src/output.rs @@ -256,6 +256,7 @@ mod cpal { } else { // Use the default config for Windows. + // We can't control amount of channels or sample rate in received default config, so process case of difference later. device .default_output_config() .expect("Failed to get the default output config.") @@ -297,10 +298,22 @@ mod cpal { } let sample_buf = SampleBuffer::::new(duration, spec); - - let resampler = if spec.rate != config.sample_rate.0 { - info!("resampling {} Hz to {} Hz", spec.rate, config.sample_rate.0); - Some(Resampler::new(spec, config.sample_rate.0 as usize, duration)) + let resampler = if spec.rate != config.sample_rate.0 + || spec.channels.count() != config.channels as usize + { + info!( + "resampling {} Hz ({} channels) to {} Hz ({} channels)", + spec.rate, + spec.channels.count(), + config.sample_rate.0, + config.channels + ); + Some(Resampler::new( + spec, + config.sample_rate.0 as usize, + duration, + config.channels as usize, + )) } else { None diff --git a/symphonia-play/src/resampler.rs b/symphonia-play/src/resampler.rs index df2d8d04..68e9919a 100644 --- a/symphonia-play/src/resampler.rs +++ b/symphonia-play/src/resampler.rs @@ -15,6 +15,7 @@ pub struct Resampler { output: Vec>, interleaved: Vec, duration: usize, + output_channels: usize, } impl Resampler @@ -45,13 +46,14 @@ where } // Interleave the planar samples from Rubato. - let num_channels = self.output.len(); + // In some cases amount of channels in audio stream isn't equal to the amount of channels in the output device, so fill excess output channels with default values. + let num_channels = self.output_channels; self.interleaved.resize(num_channels * self.output[0].len(), T::MID); for (i, frame) in self.interleaved.chunks_exact_mut(num_channels).enumerate() { for (ch, s) in frame.iter_mut().enumerate() { - *s = self.output[ch][i].into_sample(); + *s = self.output.get(ch).map(|x| x[i].into_sample()).unwrap_or(T::MID); } } @@ -63,7 +65,13 @@ impl Resampler where T: Sample + FromSample + IntoSample, { - pub fn new(spec: SignalSpec, to_sample_rate: usize, duration: u64) -> Self { + pub fn new( + spec: SignalSpec, + to_sample_rate: usize, + duration: u64, + output_channels: usize, + ) -> Self { + assert!(output_channels > 0); let duration = duration as usize; let num_channels = spec.channels.count(); @@ -80,7 +88,14 @@ where let input = vec![Vec::with_capacity(duration); num_channels]; - Self { resampler, input, output, duration, interleaved: Default::default() } + Self { + resampler, + input, + output, + duration, + interleaved: Default::default(), + output_channels, + } } /// Resamples a planar/non-interleaved input.