Skip to main content

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 OS-Sink handle to a physical device. For example, get a sink to the system's
7//!   default sound device with [`DeviceSinkBuilder::open_default_sink()`].
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 OS-Sink using [`MixerDeviceSink::mixer()`]
11//!   on the OS-Sink 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, MixerDeviceSink, source::Source};
19//!
20//! // Get an OS-Sink handle to the default physical sound device.
21//! // Note that the playback stops when the handle is dropped.//!
22//! let handle = rodio::DeviceSinkBuilder::open_default_sink()
23//!         .expect("open default audio stream");
24//! let player = rodio::Player::connect_new(&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//! 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, MixerDeviceSink, source::Source};
43//!
44//! // Get an OS-Sink handle to the default physical sound device.
45//! // Note that the playback stops when the sink_handle is dropped.
46//! let sink_handle = rodio::DeviceSinkBuilder::open_default_sink()
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 player is dropped
52//! let player = rodio::play(&sink_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//! ## Player
61//!
62//! In order to make it easier to control the playback, the rodio library also provides a type
63//! named [`Player`] which represents an audio track. [`Player`] 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 [`Player`], connect it to the OS-Sink,
67//! and [`.append()`](Player::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::{MixerDeviceSink, Player};
73//! use rodio::source::{SineWave, Source};
74//!
75//! // _stream must live as long as the sink
76//! let handle = rodio::DeviceSinkBuilder::open_default_sink()
77//!         .expect("open default audio stream");
78//! let player = rodio::Player::connect_new(&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//! player.append(source);
83//!
84//! // The sound plays in a separate thread. This call will block the current thread until the
85//! // player has finished playing all its queued sounds.
86//! player.sleep_until_end();
87//! ```
88//!
89//! The [`append`](Player::append) method will add the sound at the end of the
90//! player. It will be played when all the previous sounds have been played. If you want multiple
91//! sounds to play simultaneously consider building your own [`Player`] from rodio parts.
92//!
93//! The [`Player`] type also provides utilities such as playing/pausing or controlling the volume.
94//!
95//! <div class="warning">Note that playback through Player will end if the associated
96//! DeviceSink 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//! ## Decoder Backends
115//!
116//! [Symphonia](https://github.com/pdeljanov/Symphonia) is the default decoder library.
117//! Rodio supports enabling all of Symphonia's codecs using the `symphonia-all` feature
118//! or enabling specific codecs using one of the `symphonia-{codec name}` features.
119//! By default, decoders for the most common file types (flac, mp3, mp4, vorbis, wav) are enabled.
120//!
121//! ### Alternative Decoders
122//!
123//! Alternative decoder libraries are available for some filetypes:
124//!
125//! - claxon (flac)
126//! - hound (wav)
127//! - lewton (vorbis)
128//! - minimp3 (mp3)
129//!
130//! Symphonia is recommended for most usage. However, the alternative decoders are all licensed
131//! under either MIT or Apache 2.0 while Symphonia is licensed under MPL-2.0, so
132//! this may be a factor if you have strict licensing requirements.
133//!
134//! If you enable one of these, you may want to set `default-features = false`
135//! to avoid adding extra crates to your binary.
136//! See the [available feature flags](https://docs.rs/crate/rodio/latest/features) for all options.
137//!
138//! ## Optional Features
139//!
140//! Rodio provides several optional features that are guarded with feature gates.
141//!
142//! ### Feature "tracing"
143//!
144//! The "tracing" feature replaces the print to stderr when a stream error happens with a
145//! recording an error event with tracing.
146//!
147//! ### Feature "noise"
148//!
149//! The "noise" feature adds support for white and pink noise sources. This feature requires the
150//! "rand" crate.
151//!
152//! ### Feature "playback"
153//!
154//! The "playback" feature adds support for playing audio. This feature requires the "cpal" crate.
155//!
156//! ### Feature "64bit"
157//!
158//! The "64bit" feature enables 64-bit sample precision using `f64` for audio samples and most
159//! internal calculations. By default, rodio uses 32-bit floats (`f32`), which offers better
160//! performance and is sufficient for most use cases. The 64-bit mode addresses precision drift
161//! when chaining many audio operations together and in long-running signal generators where
162//! phase errors compound over time.
163//!
164//! ## How it works under the hood
165//!
166//! Rodio spawns a background thread that is dedicated to reading from the sources and sending
167//! the output to the device. Whenever you give up ownership of a [`Source`] in order to play it,
168//! it is sent to this background thread where it will be read by rodio.
169//!
170//! All the sounds are mixed together by rodio before being sent to the operating system or the
171//! hardware. Therefore, there is no restriction on the number of sounds that play simultaneously or
172//! on the number of sinks that can be created (except for the fact that creating too many will slow
173//! down your program).
174
175#![cfg_attr(
176    any(test, not(feature = "playback")),
177    deny(missing_docs),
178    allow(dead_code),
179    allow(unused_imports),
180    allow(unused_variables),
181    allow(unreachable_code)
182)]
183#![cfg_attr(docsrs, feature(doc_cfg))]
184
185#[cfg(feature = "playback")]
186pub use cpal::{
187    self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
188    SupportedStreamConfig,
189};
190
191mod common;
192mod player;
193mod spatial_player;
194#[cfg(all(feature = "playback", feature = "experimental"))]
195pub mod speakers;
196#[cfg(feature = "playback")]
197pub mod stream;
198#[cfg(feature = "wav_output")]
199mod wav_output;
200
201pub mod buffer;
202pub mod conversions;
203pub mod decoder;
204#[cfg(feature = "experimental")]
205pub mod fixed_source;
206pub mod math;
207#[cfg(feature = "recording")]
208/// Microphone input support for audio recording.
209pub mod microphone;
210pub mod mixer;
211pub mod queue;
212pub mod source;
213pub mod static_buffer;
214
215pub use crate::common::{BitDepth, ChannelCount, Float, Sample, SampleRate};
216pub use crate::decoder::Decoder;
217#[cfg(feature = "experimental")]
218pub use crate::fixed_source::FixedSource;
219pub use crate::player::Player;
220pub use crate::source::Source;
221pub use crate::spatial_player::SpatialPlayer;
222#[cfg(feature = "playback")]
223pub use crate::stream::{play, DeviceSinkBuilder, DeviceSinkError, MixerDeviceSink, PlayError};
224#[cfg(feature = "wav_output")]
225pub use crate::wav_output::wav_to_file;
226#[cfg(feature = "wav_output")]
227pub use crate::wav_output::wav_to_writer;