rodio/
lib.rs

1//! Audio playback library.
2//!
3//! The main concept of this library is the [`Source`] trait, which
4//! represents a sound (streaming or not). In order to play a sound, there are three steps:
5//!
6//! - Get an output stream handle to a physical device. For example, get a stream to the system's
7//!   default sound device with [`OutputStreamBuilder::open_default_stream()`].
8//! - Create an object that represents the streaming sound. It can be a sine wave, a buffer, a
9//!   [`decoder`], etc. or even your own type that implements the [`Source`] trait.
10//! - Add the source to the output stream using [`OutputStream::mixer()`](OutputStream::mixer)
11//!   on the output stream handle.
12//!
13//! Here is a complete example of how you would play an audio file:
14//!
15#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
16#![cfg_attr(feature = "playback", doc = "```no_run")]
17//! use std::fs::File;
18//! use rodio::{Decoder, OutputStream, source::Source};
19//!
20//! // Get an output stream handle to the default physical sound device.
21//! // Note that the playback stops when the stream_handle is dropped.//!
22//! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
23//!         .expect("open default audio stream");
24//! let sink = rodio::Sink::connect_new(&stream_handle.mixer());
25//! // Load a sound from a file, using a path relative to Cargo.toml
26//! let file = File::open("examples/music.ogg").unwrap();
27//! // Decode that sound file into a source
28//! let source = Decoder::try_from(file).unwrap();
29//! // Play the sound directly on the device
30//! stream_handle.mixer().add(source);
31//!
32//! // The sound plays in a separate audio thread,
33//! // so we need to keep the main thread alive while it's playing.
34//! std::thread::sleep(std::time::Duration::from_secs(5));
35//! ```
36//!
37//! [`rodio::play()`](crate::play) helps to simplify the above
38#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
39#![cfg_attr(feature = "playback", doc = "```no_run")]
40//! use std::fs::File;
41//! use std::io::BufReader;
42//! use rodio::{Decoder, OutputStream, source::Source};
43//!
44//! // Get an output stream handle to the default physical sound device.
45//! // Note that the playback stops when the stream_handle is dropped.
46//! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
47//!         .expect("open default audio stream");
48//!
49//! // Load a sound from a file, using a path relative to Cargo.toml
50//! let file = BufReader::new(File::open("examples/music.ogg").unwrap());
51//! // Note that the playback stops when the sink is dropped
52//! let sink = rodio::play(&stream_handle.mixer(), file).unwrap();
53//!
54//! // The sound plays in a separate audio thread,
55//! // so we need to keep the main thread alive while it's playing.
56//! std::thread::sleep(std::time::Duration::from_secs(5));
57//! ```
58//!
59//!
60//! ## Sink
61//!
62//! In order to make it easier to control the playback, the rodio library also provides a type
63//! named [`Sink`] which represents an audio track. [`Sink`] plays its input sources sequentially,
64//! one after another. To play sounds in simultaneously in parallel, use [`mixer::Mixer`] instead.
65//!
66//! To play a song Create a [`Sink`] connect it to the output stream,
67//! and [`.append()`](Sink::append) your sound to it.
68//!
69#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
70#![cfg_attr(feature = "playback", doc = "```no_run")]
71//! use std::time::Duration;
72//! use rodio::{OutputStream, Sink};
73//! use rodio::source::{SineWave, Source};
74//!
75//! // _stream must live as long as the sink
76//! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
77//!         .expect("open default audio stream");
78//! let sink = rodio::Sink::connect_new(&stream_handle.mixer());
79//!
80//! // Add a dummy source of the sake of the example.
81//! let source = SineWave::new(440.0).take_duration(Duration::from_secs_f32(0.25)).amplify(0.20);
82//! sink.append(source);
83//!
84//! // The sound plays in a separate thread. This call will block the current thread until the sink
85//! // has finished playing all its queued sounds.
86//! sink.sleep_until_end();
87//! ```
88//!
89//! The [`append`](Sink::append) method will add the sound at the end of the
90//! sink. It will be played when all the previous sounds have been played. If you want multiple
91//! sounds to play simultaneously, you should create multiple [`Sink`]s.
92//!
93//! The [`Sink`] type also provides utilities such as playing/pausing or controlling the volume.
94//!
95//! <div class="warning">Note that playback through Sink will end if the associated
96//! OutputStream is dropped.</div>
97//!
98//! ## Filters
99//!
100//! The [`Source`] trait provides various filters, similar to the standard [`Iterator`] trait.
101//!
102//! Example:
103//!
104#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
105#![cfg_attr(feature = "playback", doc = "```")]
106//! use rodio::Source;
107//! use std::time::Duration;
108//!
109//! // Repeats the first five seconds of the sound forever.
110//! # let source = rodio::source::SineWave::new(440.0);
111//! let source = source.take_duration(Duration::from_secs(5)).repeat_infinite();
112//! ```
113//!
114//! ## Alternative Decoder Backends
115//!
116//! [Symphonia](https://github.com/pdeljanov/Symphonia) is an alternative decoder library that can be used in place
117//! of many of the default backends.
118//! Currently, the main benefit is that Symphonia is the only backend that supports M4A and AAC,
119//! but it may be used to implement additional optional functionality in the future.
120//!
121//! To use, enable either the `symphonia-all` feature to enable all Symphonia codecs
122//! or enable specific codecs using one of the `symphonia-{codec name}` features.
123//! If you enable one or more of the Symphonia codecs, you may want to set `default-features = false` in order
124//! to avoid adding extra crates to your binary.
125//! See the [available feature flags](https://docs.rs/crate/rodio/latest/features) for all options.
126//!
127//! ## Optional Features
128//!
129//! Rodio provides several optional features that are guarded with feature gates.
130//!
131//! ### Feature "tracing"
132//!
133//! The "tracing" feature replaces the print to stderr when a stream error happens with a
134//! recording an error event with tracing.
135//!
136//! ### Feature "noise"
137//!
138//! The "noise" feature adds support for white and pink noise sources. This feature requires the
139//! "rand" crate.
140//!
141//! ### Feature "playback"
142//!
143//! The "playback" feature adds support for playing audio. This feature requires the "cpal" crate.
144//!
145//! ## How it works under the hood
146//!
147//! Rodio spawns a background thread that is dedicated to reading from the sources and sending
148//! the output to the device. Whenever you give up ownership of a [`Source`] in order to play it,
149//! it is sent to this background thread where it will be read by rodio.
150//!
151//! All the sounds are mixed together by rodio before being sent to the operating system or the
152//! hardware. Therefore, there is no restriction on the number of sounds that play simultaneously or
153//! on the number of sinks that can be created (except for the fact that creating too many will slow
154//! down your program).
155
156#![cfg_attr(
157    any(test, not(feature = "playback")),
158    deny(missing_docs),
159    allow(dead_code),
160    allow(unused_imports),
161    allow(unused_variables),
162    allow(unreachable_code)
163)]
164
165#[cfg(feature = "playback")]
166pub use cpal::{
167    self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
168    SupportedStreamConfig,
169};
170
171mod common;
172mod sink;
173mod spatial_sink;
174#[cfg(feature = "playback")]
175pub mod stream;
176#[cfg(feature = "wav_output")]
177mod wav_output;
178
179pub mod buffer;
180pub mod conversions;
181pub mod decoder;
182pub mod math;
183pub mod mixer;
184pub mod queue;
185pub mod source;
186pub mod static_buffer;
187
188pub use crate::common::{ChannelCount, Sample, SampleRate};
189pub use crate::decoder::Decoder;
190pub use crate::sink::Sink;
191pub use crate::source::Source;
192pub use crate::spatial_sink::SpatialSink;
193#[cfg(feature = "playback")]
194pub use crate::stream::{play, OutputStream, OutputStreamBuilder, PlayError, StreamError};
195#[cfg(feature = "wav_output")]
196pub use crate::wav_output::output_to_wav;