mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
Docs: Added where missing corrected where wrong
Specifically the documentation for - UniformSourceIterator was incomplete it did not mention that it can change the sample type
This commit is contained in:
parent
70c236c7ac
commit
22d90e71d8
17 changed files with 98 additions and 44 deletions
|
@ -23,6 +23,7 @@ mod mp3;
|
|||
#[cfg(feature = "symphonia")]
|
||||
mod read_seek_source;
|
||||
#[cfg(feature = "symphonia")]
|
||||
/// Symphonia decoders types
|
||||
pub mod symphonia;
|
||||
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
|
||||
mod vorbis;
|
||||
|
@ -36,11 +37,15 @@ pub struct Decoder<R>(DecoderImpl<R>)
|
|||
where
|
||||
R: Read + Seek;
|
||||
|
||||
/// Source of audio samples from decoding a file that never ends. When the
|
||||
/// end of the file is reached the decoder starts again from the beginning.
|
||||
///
|
||||
/// Supports MP3, WAV, Vorbis and Flac.
|
||||
pub struct LoopedDecoder<R>(DecoderImpl<R>)
|
||||
where
|
||||
R: Read + Seek;
|
||||
|
||||
// can not really reduce the size of the VorbisDecoder. There are not any
|
||||
// Cannot really reduce the size of the VorbisDecoder. There are not any
|
||||
// arrays just a lot of struct fields.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum DecoderImpl<R>
|
||||
|
@ -239,6 +244,10 @@ where
|
|||
#[cfg(not(feature = "symphonia"))]
|
||||
Err(DecoderError::UnrecognizedFormat)
|
||||
}
|
||||
|
||||
/// Builds a new looped decoder.
|
||||
///
|
||||
/// Attempts to automatically detect the format of the source of data.
|
||||
pub fn new_looped(data: R) -> Result<LoopedDecoder<R>, DecoderError> {
|
||||
Self::new(data).map(LoopedDecoder::new)
|
||||
}
|
||||
|
@ -329,6 +338,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)] // Reason: will be removed, see: #612
|
||||
#[derive(Debug)]
|
||||
pub enum Mp4Type {
|
||||
Mp4,
|
||||
|
|
|
@ -210,12 +210,16 @@ impl Source for SymphoniaDecoder {
|
|||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SeekError {
|
||||
/// Could not get next packet while refining seek position
|
||||
#[error("Could not get next packet while refining seek position: {0:?}")]
|
||||
Refining(symphonia::core::errors::Error),
|
||||
/// Format reader failed to seek
|
||||
#[error("Format reader failed to seek: {0:?}")]
|
||||
BaseSeek(symphonia::core::errors::Error),
|
||||
/// Decoding failed retrying on the next packet failed
|
||||
#[error("Decoding failed retrying on the next packet failed: {0:?}")]
|
||||
Retrying(symphonia::core::errors::Error),
|
||||
/// Decoding failed on multiple consecutive packets
|
||||
#[error("Decoding failed on multiple consecutive packets: {0:?}")]
|
||||
Decoding(symphonia::core::errors::Error),
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ where
|
|||
input_fadeout.mix(input_fadein)
|
||||
}
|
||||
|
||||
/// Mixes one sound fading out with another sound fading in for the given
|
||||
/// duration.
|
||||
///
|
||||
/// Only the crossfaded portion (beginning of fadeout, beginning of fadein) is
|
||||
/// covered.
|
||||
pub type Crossfade<I1, I2> = Mix<TakeDuration<I1>, FadeIn<TakeDuration<I2>>>;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// When the inner source is empty this decrements an `AtomicUsize`.
|
||||
/// When the inner source is empty this decrements a `AtomicUsize`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Done<I> {
|
||||
input: I,
|
||||
|
@ -15,6 +15,8 @@ pub struct Done<I> {
|
|||
}
|
||||
|
||||
impl<I> Done<I> {
|
||||
/// When the inner source is empty the AtomicUsize passed in is decremented.
|
||||
/// If it was zero it will overflow negatively.
|
||||
#[inline]
|
||||
pub fn new(input: I, signal: Arc<AtomicUsize>) -> Done<I> {
|
||||
Done {
|
||||
|
|
|
@ -17,6 +17,8 @@ impl<S> Default for Empty<S> {
|
|||
}
|
||||
|
||||
impl<S> Empty<S> {
|
||||
/// An empty source that immediately ends without ever returning a sample to
|
||||
/// play
|
||||
#[inline]
|
||||
pub fn new() -> Empty<S> {
|
||||
Empty(PhantomData)
|
||||
|
|
|
@ -13,9 +13,15 @@ pub struct EmptyCallback<S> {
|
|||
|
||||
impl<S> EmptyCallback<S> {
|
||||
#[inline]
|
||||
/// Create an empty source which executes a callback function.
|
||||
/// Example use-case:
|
||||
///
|
||||
/// Detect and do something when the source before this one has ended.
|
||||
pub fn new(callback: Box<dyn Send + Fn()>) -> EmptyCallback<S> {
|
||||
EmptyCallback {
|
||||
#[allow(missing_docs)] // See: https://github.com/RustAudio/rodio/issues/615
|
||||
phantom_data: PhantomData,
|
||||
#[allow(missing_docs)] // See: https://github.com/RustAudio/rodio/issues/615
|
||||
callback,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,6 +360,9 @@ where
|
|||
stoppable::stoppable(self)
|
||||
}
|
||||
|
||||
/// Adds a method [`Skippable::skip`] for skipping this source. Skipping
|
||||
/// makes Source::next() return None. Which in turn makes the Sink skip to
|
||||
/// the next source.
|
||||
fn skippable(self) -> Skippable<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -374,7 +377,7 @@ where
|
|||
/// in the position returned by [`get_pos`](TrackPosition::get_pos).
|
||||
///
|
||||
/// This can get confusing when using [`get_pos()`](TrackPosition::get_pos)
|
||||
/// together with [`Source::try_seek()`] as the the latter does take all
|
||||
/// together with [`Source::try_seek()`] as the latter does take all
|
||||
/// speedup's and delay's into account. Its recommended therefore to apply
|
||||
/// track_position after speedup's and delay's.
|
||||
fn track_position(self) -> TrackPosition<Self>
|
||||
|
@ -455,22 +458,32 @@ where
|
|||
|
||||
// We might add decoders requiring new error types, without non_exhaustive
|
||||
// this would break users builds
|
||||
/// Occurs when try_seek fails because the underlying decoder has an error or
|
||||
/// does not support seeking.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SeekError {
|
||||
#[error("Streaming is not supported by source: {underlying_source}")]
|
||||
/// On of the underlying sources does not support seeking
|
||||
#[error("Seeking is not supported by source: {underlying_source}")]
|
||||
NotSupported { underlying_source: &'static str },
|
||||
#[cfg(feature = "symphonia")]
|
||||
/// The symphonia decoder ran into an issue
|
||||
#[error("Error seeking: {0}")]
|
||||
SymphoniaDecoder(#[from] crate::decoder::symphonia::SeekError),
|
||||
#[cfg(feature = "wav")]
|
||||
#[error("Error seeking in wav source: {0}")]
|
||||
/// The hound (wav) decoder ran into an issue
|
||||
HoundDecoder(std::io::Error),
|
||||
// Prefer adding an enum variant to using this. Its meant for end users their
|
||||
// own try_seek implementations
|
||||
/// Any other error probably in a custom Source
|
||||
#[error("An error occurred")]
|
||||
Other(Box<dyn std::error::Error + Send>),
|
||||
}
|
||||
|
||||
impl SeekError {
|
||||
/// Will the source remain playing at its position before the seek or is it
|
||||
/// broken?
|
||||
pub fn source_intact(&self) -> bool {
|
||||
match self {
|
||||
SeekError::NotSupported { .. } => true,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// Internal function that builds a `Pausable` object.
|
||||
/// Builds a `Pausable` object.
|
||||
pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
|
||||
where
|
||||
I: Source,
|
||||
|
@ -22,6 +22,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Wraps a source and makes it pausable by calling [`Pausable::set_paused`] on
|
||||
/// this object. When the source is paused it returns zero value samples.
|
||||
///
|
||||
/// You can usually still use this from another source wrapping this one by
|
||||
/// calling `inner_mut` on it. Similarly this provides [`Pausable::inner`] and
|
||||
/// mutable/destructing variants for accessing the underlying source.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Pausable<I> {
|
||||
input: I,
|
||||
|
|
|
@ -17,6 +17,7 @@ pub fn track_position<I>(source: I) -> TrackPosition<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tracks the elapsed duration since the start of the underlying source.
|
||||
#[derive(Debug)]
|
||||
pub struct TrackPosition<I> {
|
||||
input: I,
|
||||
|
|
|
@ -6,11 +6,8 @@ use cpal::{FromSample, Sample as CpalSample};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// An iterator that reads from a `Source` and converts the samples to a specific rate and
|
||||
/// channels count.
|
||||
///
|
||||
/// It implements `Source` as well, but all the data is guaranteed to be in a single frame whose
|
||||
/// channels and samples rate have been passed to `new`.
|
||||
/// Wrap the input and lazily converts the samples it provides to the type
|
||||
/// specified by the generic parameter D
|
||||
#[derive(Clone)]
|
||||
pub struct SamplesConverter<I, D> {
|
||||
inner: I,
|
||||
|
@ -18,6 +15,8 @@ pub struct SamplesConverter<I, D> {
|
|||
}
|
||||
|
||||
impl<I, D> SamplesConverter<I, D> {
|
||||
/// Wrap the input and lazily converts the samples it provides to the type
|
||||
/// specified by the generic parameter D
|
||||
#[inline]
|
||||
pub fn new(input: I) -> SamplesConverter<I, D> {
|
||||
SamplesConverter {
|
||||
|
|
|
@ -5,7 +5,9 @@ use crate::Source;
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// Internal function that builds a `Skippable` object.
|
||||
/// Wrap the source in a skippable. It allows ending the current source early by
|
||||
/// calling [`Skippable::skip`]. If this source is in a queue such as the Sink
|
||||
/// ending the source early is equal to skipping the source.
|
||||
pub fn skippable<I>(source: I) -> Skippable<I> {
|
||||
Skippable {
|
||||
input: source,
|
||||
|
@ -13,6 +15,9 @@ pub fn skippable<I>(source: I) -> Skippable<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Wrap the source in a skippable. It allows ending the current source early by
|
||||
/// calling [`Skippable::skip`]. If this source is in a queue such as the Sink
|
||||
/// ending the source early is equal to skipping the source.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Skippable<I> {
|
||||
input: I,
|
||||
|
|
|
@ -29,6 +29,7 @@ where
|
|||
I: Source,
|
||||
I::Item: Sample,
|
||||
{
|
||||
/// Builds a new `SpatialSink`, beginning playback on a stream.
|
||||
pub fn new(
|
||||
input: I,
|
||||
emitter_position: [f32; 3],
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// Internal function that builds a `Stoppable` object.
|
||||
/// This is the same as [`skippable`](crate::source::skippable) see its docs
|
||||
pub fn stoppable<I>(source: I) -> Stoppable<I> {
|
||||
Stoppable {
|
||||
input: source,
|
||||
|
@ -12,6 +12,7 @@ pub fn stoppable<I>(source: I) -> Stoppable<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This is the same as [`Skippable`](crate::source::Skippable) see its docs
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Stoppable<I> {
|
||||
input: I,
|
||||
|
|
|
@ -91,10 +91,13 @@ where
|
|||
self.input
|
||||
}
|
||||
|
||||
/// Make the truncated source end with a FadeOut. The fadeout covers the
|
||||
/// entire length of the take source.
|
||||
pub fn set_filter_fadeout(&mut self) {
|
||||
self.filter = Some(DurationFilter::FadeOut);
|
||||
}
|
||||
|
||||
/// Remove any filter set.
|
||||
pub fn clear_filter(&mut self) {
|
||||
self.filter = None;
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// An iterator that reads from a `Source` and converts the samples to a specific rate and
|
||||
/// channels count.
|
||||
/// An iterator that reads from a `Source` and converts the samples to a
|
||||
/// specific type, sample-rate and channels count.
|
||||
///
|
||||
/// It implements `Source` as well, but all the data is guaranteed to be in a single frame whose
|
||||
/// channels and samples rate have been passed to `new`.
|
||||
/// It implements `Source` as well, but all the data is guaranteed to be in a
|
||||
/// single frame whose channels and samples rate have been passed to `new`.
|
||||
#[derive(Clone)]
|
||||
pub struct UniformSourceIterator<I, D>
|
||||
where
|
||||
|
@ -32,6 +32,8 @@ where
|
|||
I::Item: Sample,
|
||||
D: Sample,
|
||||
{
|
||||
/// Wrap a `Source` and lazily convert its samples to a specific type,
|
||||
/// sample-rate and channels count.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
input: I,
|
||||
|
|
|
@ -5,7 +5,9 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
/// An infinite source that produces zero.
|
||||
/// 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,
|
||||
|
@ -15,6 +17,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> {
|
||||
Zero {
|
||||
|
@ -24,6 +27,7 @@ impl<S> Zero<S> {
|
|||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
/// 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> {
|
||||
Zero {
|
||||
|
|
|
@ -29,7 +29,9 @@ impl OutputStream {
|
|||
pub fn try_from_device(
|
||||
device: &cpal::Device,
|
||||
) -> Result<(Self, OutputStreamHandle), StreamError> {
|
||||
let default_config = device.default_output_config()?;
|
||||
let default_config = device
|
||||
.default_output_config()
|
||||
.map_err(StreamError::DefaultStreamConfigError)?;
|
||||
OutputStream::try_from_device_config(device, default_config)
|
||||
}
|
||||
|
||||
|
@ -42,7 +44,7 @@ impl OutputStream {
|
|||
config: SupportedStreamConfig,
|
||||
) -> Result<(Self, OutputStreamHandle), StreamError> {
|
||||
let (mixer, _stream) = device.try_new_output_stream_config(config)?;
|
||||
_stream.play()?;
|
||||
_stream.play().map_err(StreamError::PlayStreamError)?;
|
||||
let out = Self { mixer, _stream };
|
||||
let handle = OutputStreamHandle {
|
||||
mixer: Arc::downgrade(&out.mixer),
|
||||
|
@ -130,39 +132,24 @@ impl error::Error for PlayError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Errors that might occur when interfacing with audio output.
|
||||
#[derive(Debug)]
|
||||
pub enum StreamError {
|
||||
/// Could not start playing the stream, see [cpal::PlayStreamError] for
|
||||
/// details.
|
||||
PlayStreamError(cpal::PlayStreamError),
|
||||
/// Failed to get the stream config for device the given device. See
|
||||
/// [cpal::DefaultStreamConfigError] for details
|
||||
DefaultStreamConfigError(cpal::DefaultStreamConfigError),
|
||||
/// Error opening stream with OS. See [cpal::BuildStreamError] for details
|
||||
BuildStreamError(cpal::BuildStreamError),
|
||||
/// Could not list supported stream configs for device. Maybe it
|
||||
/// disconnected, for details see: [cpal::SupportedStreamConfigsError].
|
||||
SupportedStreamConfigsError(cpal::SupportedStreamConfigsError),
|
||||
/// Could not find any output device
|
||||
NoDevice,
|
||||
}
|
||||
|
||||
impl From<cpal::DefaultStreamConfigError> for StreamError {
|
||||
fn from(err: cpal::DefaultStreamConfigError) -> Self {
|
||||
Self::DefaultStreamConfigError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<cpal::SupportedStreamConfigsError> for StreamError {
|
||||
fn from(err: cpal::SupportedStreamConfigsError) -> Self {
|
||||
Self::SupportedStreamConfigsError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<cpal::BuildStreamError> for StreamError {
|
||||
fn from(err: cpal::BuildStreamError) -> Self {
|
||||
Self::BuildStreamError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<cpal::PlayStreamError> for StreamError {
|
||||
fn from(err: cpal::PlayStreamError) -> Self {
|
||||
Self::PlayStreamError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for StreamError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -342,7 +329,10 @@ fn supported_output_formats(
|
|||
) -> Result<impl Iterator<Item = cpal::SupportedStreamConfig>, StreamError> {
|
||||
const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100);
|
||||
|
||||
let mut supported: Vec<_> = device.supported_output_configs()?.collect();
|
||||
let mut supported: Vec<_> = device
|
||||
.supported_output_configs()
|
||||
.map_err(StreamError::SupportedStreamConfigsError)?
|
||||
.collect();
|
||||
supported.sort_by(|a, b| b.cmp_default_heuristics(a));
|
||||
|
||||
Ok(supported.into_iter().flat_map(|sf| {
|
||||
|
|
Loading…
Reference in a new issue