diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index c68fbb2d..ddc35b5f 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -727,12 +727,11 @@ where /// Returns the total duration of this audio source. /// - /// Always returns `None` for looped decoders since they have no fixed end point - - /// they will continue playing indefinitely by seeking back to the start when reaching - /// the end of the audio data. + /// Always returns `Duration::MAX` for looped decoders since they play + /// indefinitely by seeking back to the start when reaching the end. #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } /// Attempts to seek to a specific position in the audio stream. diff --git a/src/microphone.rs b/src/microphone.rs index cc9788a7..31a9f171 100644 --- a/src/microphone.rs +++ b/src/microphone.rs @@ -204,7 +204,7 @@ impl Source for Microphone { } fn total_duration(&self) -> Option { - None + Some(std::time::Duration::MAX) } } @@ -219,7 +219,7 @@ impl crate::FixedSource for Microphone { } fn total_duration(&self) -> Option { - None + Some(std::time::Duration::MAX) } } diff --git a/src/source/mod.rs b/src/source/mod.rs index 215662ed..9722dcc1 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -197,7 +197,10 @@ pub trait Source: Iterator { /// Returns the total duration of this source, if known. /// - /// `None` indicates at the same time "infinite" or "unknown". + /// `None` indicates that the duration is unknown. Infinite sources + /// (e.g. sine wave generators, repeating sources) return + /// `Some(Duration::MAX)` to distinguish them from sources with an + /// unknown but finite duration. fn total_duration(&self) -> Option; /// Stores the source in a buffer in addition to returning it. This iterator can be cloned. diff --git a/src/source/noise.rs b/src/source/noise.rs index 14a9c3f9..044a96f5 100644 --- a/src/source/noise.rs +++ b/src/source/noise.rs @@ -83,7 +83,7 @@ macro_rules! impl_noise_source { } fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } fn try_seek(&mut self, _pos: Duration) -> Result<(), crate::source::SeekError> { diff --git a/src/source/repeat.rs b/src/source/repeat.rs index ef29968e..231e819e 100644 --- a/src/source/repeat.rs +++ b/src/source/repeat.rs @@ -83,7 +83,7 @@ where #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/src/source/sawtooth.rs b/src/source/sawtooth.rs index 2bfc2309..9d3e717e 100644 --- a/src/source/sawtooth.rs +++ b/src/source/sawtooth.rs @@ -56,7 +56,7 @@ impl Source for SawtoothWave { #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/src/source/signal_generator.rs b/src/source/signal_generator.rs index 34ffa443..abf2a120 100644 --- a/src/source/signal_generator.rs +++ b/src/source/signal_generator.rs @@ -153,7 +153,7 @@ impl Source for SignalGenerator { #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/src/source/sine.rs b/src/source/sine.rs index 1481d6b2..1eadb4ba 100644 --- a/src/source/sine.rs +++ b/src/source/sine.rs @@ -56,7 +56,7 @@ impl Source for SineWave { #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/src/source/square.rs b/src/source/square.rs index d4acb321..7f98b7fa 100644 --- a/src/source/square.rs +++ b/src/source/square.rs @@ -56,7 +56,7 @@ impl Source for SquareWave { #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/src/source/take.rs b/src/source/take.rs index 9ec2f247..baae2f65 100644 --- a/src/source/take.rs +++ b/src/source/take.rs @@ -165,7 +165,7 @@ where Some(self.requested_duration) } } else { - None + Some(self.requested_duration) } } diff --git a/src/source/triangle.rs b/src/source/triangle.rs index 6cafc911..ab5f1848 100644 --- a/src/source/triangle.rs +++ b/src/source/triangle.rs @@ -56,7 +56,7 @@ impl Source for TriangleWave { #[inline] fn total_duration(&self) -> Option { - None + Some(Duration::MAX) } #[inline] diff --git a/tests/total_duration.rs b/tests/total_duration.rs index 8d56a8c4..2f05ab01 100644 --- a/tests/total_duration.rs +++ b/tests/total_duration.rs @@ -2,10 +2,12 @@ #![allow(unused_imports)] use std::io::{Read, Seek}; +use std::num::NonZero; use std::path::Path; use std::time::Duration; -use rodio::{Decoder, Source}; +use rodio::source::{SineWave, Source}; +use rodio::Decoder; use rstest::rstest; use rstest_reuse::{self, *}; @@ -105,3 +107,27 @@ fn decoder_returns_total_duration( "decoder got {res}, correct is: {correct_duration}" ); } + +#[test] +fn infinite_sources_return_duration_max() { + let sine = SineWave::new(440.0); + assert_eq!(sine.total_duration(), Some(Duration::MAX)); +} + +#[test] +fn take_duration_on_infinite_source() { + let sine = SineWave::new(440.0); + let take = sine.take_duration(Duration::from_secs(5)); + assert_eq!(take.total_duration(), Some(Duration::from_secs(5))); +} + +#[test] +fn repeat_returns_duration_max() { + let buf = rodio::buffer::SamplesBuffer::new( + NonZero::new(1).unwrap(), + NonZero::new(44100).unwrap(), + vec![0.0f32; 44100], + ); + let repeated = buf.repeat_infinite(); + assert_eq!(repeated.total_duration(), Some(Duration::MAX)); +}