Dropping the Sink now stops all sounds

This commit is contained in:
Pierre Krieger 2015-10-16 15:38:10 +02:00
parent d786f79e02
commit a23aeaa4ff
2 changed files with 36 additions and 15 deletions

View file

@ -100,7 +100,7 @@ impl Engine {
// the iterator that produces sounds // the iterator that produces sounds
let next_sounds = Arc::new(Mutex::new(Vec::new())); let next_sounds = Arc::new(Mutex::new(Vec::new()));
let source = QueueIterator { current: Box::new(None.into_iter()), next: next_sounds.clone() }; let source = QueueIterator { current: Box::new(None.into_iter()), next: next_sounds.clone() };
let source_id = &next_sounds as *const _ as *const u8 as usize; let source_id = &*next_sounds as *const Mutex<_> as *const u8 as usize;
// at each loop, the background thread will store the remaining time of the sound in this // at each loop, the background thread will store the remaining time of the sound in this
// value // value
@ -165,8 +165,10 @@ impl<'a> Handle<'a> {
commands.send(Command::SetVolume(self.source_id, value)).unwrap(); commands.send(Command::SetVolume(self.source_id, value)).unwrap();
} }
// note that this method could take `self` instead of `&self`, but it makes `Sink`'s life
// easier not to take `self`
#[inline] #[inline]
pub fn stop(self) { pub fn stop(&self) {
let commands = self.engine.commands.lock().unwrap(); let commands = self.engine.commands.lock().unwrap();
commands.send(Command::Stop(self.source_id)).unwrap(); commands.send(Command::Stop(self.source_id)).unwrap();
@ -222,7 +224,7 @@ fn background(rx: Receiver<Command>) {
Command::Stop(decoder) => { Command::Stop(decoder) => {
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
sounds.retain(|dec| { sounds.retain(|dec| {
&*dec.0.next as *const _ as *const u8 as usize != decoder &*dec.0.next as *const Mutex<_> as *const u8 as usize != decoder
}) })
} }
}, },
@ -230,7 +232,7 @@ fn background(rx: Receiver<Command>) {
Command::SetVolume(decoder, volume) => { Command::SetVolume(decoder, volume) => {
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
if let Some(d) = sounds.iter_mut() if let Some(d) = sounds.iter_mut()
.find(|dec| &*dec.0.next as *const _ as *const u8 as usize == decoder) .find(|dec| &*dec.0.next as *const Mutex<_> as *const u8 as usize == decoder)
{ {
d.2 = volume; d.2 = volume;
} }
@ -242,7 +244,7 @@ fn background(rx: Receiver<Command>) {
// removing sounds that have finished playing // removing sounds that have finished playing
for decoder in mem::replace(&mut sounds_to_remove, Vec::new()) { for decoder in mem::replace(&mut sounds_to_remove, Vec::new()) {
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
sounds.retain(|dec| &*dec.0.next as *const _ != decoder); sounds.retain(|dec| &*dec.0.next as *const Mutex<_> != decoder);
} }
} }

View file

@ -28,20 +28,30 @@ lazy_static! {
static ref ENGINE: engine::Engine = engine::Engine::new(); static ref ENGINE: engine::Engine = engine::Engine::new();
} }
/// Handle to a playing sound. /// Handle to an endpoint that outputs sounds.
/// ///
/// Note that dropping the handle doesn't stop the sound. You must call `stop` explicitely. /// Dropping the `Sink` stops all sounds. You can use `detach` if you want the sounds to continue
pub struct Sink(engine::Handle<'static>); /// playing.
pub struct Sink {
handle: engine::Handle<'static>,
// if true, then the sound will stop playing at the end
stop: bool,
}
impl Sink { impl Sink {
/// Builds a new `Sink`.
pub fn new(endpoint: &Endpoint) -> Sink { pub fn new(endpoint: &Endpoint) -> Sink {
Sink(ENGINE.start(&endpoint)) Sink {
handle: ENGINE.start(&endpoint),
stop: true,
}
} }
/// Appends a sound to the queue of sounds to play.
pub fn append<S>(&self, source: S) where S: Source + Send + 'static, pub fn append<S>(&self, source: S) where S: Source + Send + 'static,
S::Item: Sample, S::Item: Send S::Item: Sample, S::Item: Send
{ {
self.0.append(source); self.handle.append(source);
} }
/// Changes the volume of the sound. /// Changes the volume of the sound.
@ -50,13 +60,13 @@ impl Sink {
/// multiply each sample by this value. /// multiply each sample by this value.
#[inline] #[inline]
pub fn set_volume(&mut self, value: f32) { pub fn set_volume(&mut self, value: f32) {
self.0.set_volume(value); self.handle.set_volume(value);
} }
/// Stops the sound. /// Destroys the sink without stopping the sounds that are still playing.
#[inline] #[inline]
pub fn stop(self) { pub fn detach(mut self) {
self.0.stop() self.stop = false;
} }
/// Returns the minimum duration before the end of the sounds submitted to this sink. /// Returns the minimum duration before the end of the sounds submitted to this sink.
@ -64,7 +74,7 @@ impl Sink {
/// Note that this is a minimum value, and the sound can last longer. /// Note that this is a minimum value, and the sound can last longer.
#[inline] #[inline]
pub fn get_min_remaining_duration(&self) -> Duration { pub fn get_min_remaining_duration(&self) -> Duration {
self.0.get_min_remaining_duration() self.handle.get_min_remaining_duration()
} }
/// Sleeps the current thread until the sound ends. /// Sleeps the current thread until the sound ends.
@ -75,6 +85,15 @@ impl Sink {
} }
} }
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. /// Plays a sound once. Returns a `Sink` that can be used to control the sound.
#[inline] #[inline]
pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Sink pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Sink