diff --git a/CHANGELOG.md b/CHANGELOG.md index e5cbfb99..ee9544e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Breaking: `Sink::try_new` renamed to `connect_new` and does not return error anymore. `Sink::new_idle` was renamed to `new`. +### Fixed + +- Symphonia decoder `total_duration` incorrect value caused by conversion from `Time` to `Duration`. + # Version 0.20.1 (2024-11-08) ### Fixed diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs index 127c7202..31577cef 100644 --- a/src/decoder/symphonia.rs +++ b/src/decoder/symphonia.rs @@ -170,8 +170,7 @@ impl Source for SymphoniaDecoder { #[inline] fn total_duration(&self) -> Option { - self.total_duration - .map(|Time { seconds, frac }| Duration::new(seconds, (1f64 / frac) as u32)) + self.total_duration.map(time_to_duration) } fn try_seek(&mut self, pos: Duration) -> Result<(), source::SeekError> { @@ -305,6 +304,17 @@ fn skip_back_a_tiny_bit( Time { seconds, frac } } +fn time_to_duration(time: Time) -> Duration { + Duration::new( + time.seconds, + if time.frac > 0.0 { + (1f64 / time.frac) as u32 + } else { + 0 + }, + ) +} + impl Iterator for SymphoniaDecoder { type Item = i16; @@ -331,3 +341,48 @@ impl Iterator for SymphoniaDecoder { Some(sample) } } + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use symphonia::core::units::Time; + + use crate::decoder::symphonia::time_to_duration; + + #[test] + fn test_time_to_dur_zero_frac() { + let time = Time { + seconds: 7, + frac: 0.0, + }; + let duration = Duration::new( + time.seconds, + if time.frac > 0.0 { + (1f64 / time.frac) as u32 + } else { + 0 + }, + ); + + assert_eq!(time_to_duration(time), duration); + } + + #[test] + fn test_time_to_dur_non_zero_frac() { + let time = Time { + seconds: 7, + frac: 0.3, + }; + let duration = Duration::new( + time.seconds, + if time.frac > 0.0 { + (1f64 / time.frac) as u32 + } else { + 0 + }, + ); + + assert_eq!(time_to_duration(time), duration); + } +}