1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! # Usage
//!
//! There are two main concepts in this library:
//!
//! - Sources, represented with the `Source` trait, that provide sound data.
//! - Sinks, which accept sound data.
//!
//! In order to play a sound, you need to create a source, a sink, and connect the two. For example
//! here is how you play a sound file:
//!
//! ```no_run
//! use std::io::BufReader;
//! 
//! let endpoint = rodio::get_default_endpoint().unwrap();
//! let sink = rodio::Sink::new(&endpoint);
//! 
//! let file = std::fs::File::open("music.ogg").unwrap();
//! let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
//! sink.append(source);
//! ```
//!
//! The `append` method takes ownership of the source and starts playing it. If a sink is already
//! playing a sound when you call `append`, the sound is added to a queue and will start playing
//! when the existing source is over.
//!
//! If you want to play multiple sounds simultaneously, you should create multiple sinks.
//!
//! # How it works
//! 
//! Rodio spawns a background thread that is dedicated to reading from the sources and sending
//! the output to the endpoint.
//! 
//! All the sounds are mixed together by rodio before being sent. Since this is handled by the
//! software, there is no restriction for the number of sinks that can be created.
//! 
//! # Adding effects
//! 
//! The `Source` trait provides various filters, similarly to the standard `Iterator` trait.
//! 
//! Example:
//! 
//! ```ignore
//! use rodio::Source;
//! use std::time::Duration;
//! 
//! // repeats the first five seconds of this sound forever
//! let source = source.take_duration(Duration::from_secs(5)).repeat_infinite();
//! ```

#![cfg_attr(test, deny(missing_docs))]

extern crate cpal;
extern crate futures;
extern crate hound;
#[macro_use]
extern crate lazy_static;
extern crate lewton;
extern crate ogg;

pub use cpal::{Endpoint, get_endpoints_list, get_default_endpoint};

pub use conversions::Sample;
pub use decoder::Decoder;
pub use source::Source;

use std::io::{Read, Seek};

mod conversions;
mod engine;

pub mod decoder;
pub mod source;

lazy_static! {
    static ref ENGINE: engine::Engine = engine::Engine::new();
}

/// Handle to an endpoint that outputs sounds.
///
/// Dropping the `Sink` stops all sounds. You can use `detach` if you want the sounds to continue
/// playing.
pub struct Sink {
    handle: engine::Handle,
    // if true, then the sound will stop playing at the end
    stop: bool,
}

impl Sink {
    /// Builds a new `Sink`.
    #[inline]
    pub fn new(endpoint: &Endpoint) -> Sink {
        Sink {
            handle: ENGINE.start(&endpoint),
            stop: true,
        }
    }

    /// Appends a sound to the queue of sounds to play.
    #[inline]
    pub fn append<S>(&self, source: S) where S: Source + Send + 'static,
                                             S::Item: Sample, S::Item: Send
    {
        self.handle.append(source);
    }

    /// Changes the volume of the sound.
    ///
    /// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
    /// multiply each sample by this value.
    #[inline]
    pub fn set_volume(&mut self, value: f32) {
        self.handle.set_volume(value);
    }

    /// Destroys the sink without stopping the sounds that are still playing.
    #[inline]
    pub fn detach(mut self) {
        self.stop = false;
    }

    /// Sleeps the current thread until the sound ends.
    #[inline]
    pub fn sleep_until_end(&self) {
        self.handle.sleep_until_end();
    }
}

impl Drop for Sink {
    #[inline]
    fn drop(&mut self) {
        if self.stop {
            self.handle.stop();
        }
    }
}

/// Plays a sound once. Returns a `Sink` that can be used to control the sound.
#[inline]
pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Result<Sink, decoder::DecoderError>
                    where R: Read + Seek + Send + 'static
{
    let input = try!(decoder::Decoder::new(input));
    let sink = Sink::new(endpoint);
    sink.append(input);
    Ok(sink)
}