From dad2088c39c1114fe7003f046b1a738aa3df0d89 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Oct 2015 15:11:54 +0200 Subject: [PATCH] Allow adding other sounds behind existing sounds --- src/engine.rs | 109 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 0a2ef7b..d5068f8 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -56,10 +56,7 @@ impl Engine { } } - /// Starts playing a sound and returns a `Handler` to control it. - pub fn play(&self, endpoint: &Endpoint, source: S) -> Handle - where S: Source + Send + 'static, S::Item: Sample, S::Item: Send - { + pub fn start(&self, endpoint: &Endpoint) -> Handle { // try looking for an existing voice, or create one if there isn't one let (new_voice, channels_count, samples_rate) = { let mut voices_formats = self.voices_formats.lock().unwrap(); @@ -99,36 +96,41 @@ impl Engine { (new_voice, c, s) }; - // boxing the source and obtaining an ID for it - let source = UniformSourceIterator::new(source, channels_count, samples_rate); - let source = Box::new(source) as Box + Send + 'static>; - let source_id = &*source as *const _ as *const u8 as usize; - - // getting some infos ; we are going to send the decoder to the background thread, so this - // is the last time we can get infos from it - // FIXME: wrong - let total_duration_ms = source.size_hint().0 * 1000 / (samples_rate as usize * channels_count as usize); + // the iterator that produces sounds + let next_sounds = Arc::new(Mutex::new(Vec::new())); + 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; // at each loop, the background thread will store the remaining time of the sound in this // value - let remaining_duration_ms = Arc::new(AtomicUsize::new(total_duration_ms as usize)); + // TODO: 0? + let remaining_duration_ms = Arc::new(AtomicUsize::new(0 as usize)); // send the play command - let commands = self.commands.lock().unwrap(); - commands.send(Command::Play(endpoint.clone(), new_voice, source, remaining_duration_ms.clone())).unwrap(); - - // unpark the background thread so that the sound starts playing immediately - if let Some(ref thread) = self.thread { - thread.unpark(); + { + let commands = self.commands.lock().unwrap(); + commands.send(Command::Play(endpoint.clone(), new_voice, source, remaining_duration_ms.clone())).unwrap(); } Handle { engine: self, source_id: source_id, - total_duration_ms: total_duration_ms as u32, remaining_duration_ms: remaining_duration_ms, + samples_rate: samples_rate, + channels: channels_count, + next_sounds: next_sounds, } } + + /// Starts playing a sound and returns a `Handler` to control it. + // TODO: remove me + pub fn play(&self, endpoint: &Endpoint, source: S) -> Handle + where S: Source + Send + 'static, S::Item: Sample, S::Item: Send + { + let handle = self.start(endpoint); + handle.append(source); + handle + } } /// Handle to a playing sound. @@ -137,11 +139,25 @@ impl Engine { pub struct Handle<'a> { engine: &'a Engine, source_id: usize, - total_duration_ms: u32, // FIXME: <-- incorrect handling remaining_duration_ms: Arc, + + samples_rate: u32, + channels: u16, + + // Holds a pointer to the list of iterators to be played after the current one has + // finished playing. + next_sounds: Arc + Send>>>>, } impl<'a> Handle<'a> { + + #[inline] + pub fn append(&self, source: S) where S: Source + Send + 'static, S::Item: Sample + Clone + Send { + let source = UniformSourceIterator::new(source, self.channels, self.samples_rate); + let source = Box::new(source); + self.next_sounds.lock().unwrap().push(source); + } + #[inline] pub fn set_volume(&self, value: f32) { let commands = self.engine.commands.lock().unwrap(); @@ -160,7 +176,7 @@ impl<'a> Handle<'a> { #[inline] pub fn get_total_duration_ms(&self) -> u32 { - self.total_duration_ms + unimplemented!() } #[inline] @@ -170,17 +186,17 @@ impl<'a> Handle<'a> { } pub enum Command { - Play(Endpoint, Option, Box + Send>, Arc), + Play(Endpoint, Option, QueueIterator, Arc), Stop(usize), SetVolume(usize, f32), } fn background(rx: Receiver) { // for each endpoint name, stores the voice and the list of sounds with their volume - let mut voices: HashMap + Send>, Arc, f32)>)> = HashMap::new(); + let mut voices: HashMap, f32)>)> = HashMap::new(); // list of sounds to stop playing - let mut sounds_to_remove: Vec<*const (Iterator + Send)> = Vec::new(); + let mut sounds_to_remove: Vec<*const Mutex + Send>>>> = Vec::new(); // stores the time when the next loop must start let mut next_loop_timer = time::precise_time_ns(); @@ -210,7 +226,7 @@ fn background(rx: Receiver) { Command::Stop(decoder) => { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { sounds.retain(|dec| { - &*dec.0 as *const _ as *const u8 as usize != decoder + &*dec.0.next as *const _ as *const u8 as usize != decoder }) } }, @@ -218,7 +234,7 @@ fn background(rx: Receiver) { Command::SetVolume(decoder, volume) => { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { if let Some(d) = sounds.iter_mut() - .find(|dec| &*dec.0 as *const _ as *const u8 as usize == decoder) + .find(|dec| &*dec.0.next as *const _ as *const u8 as usize == decoder) { d.2 = volume; } @@ -230,7 +246,7 @@ fn background(rx: Receiver) { // removing sounds that have finished playing for decoder in mem::replace(&mut sounds_to_remove, Vec::new()) { for (_, &mut (_, ref mut sounds)) in voices.iter_mut() { - sounds.retain(|dec| &*dec.0 as *const _ != decoder); + sounds.retain(|dec| &*dec.0.next as *const _ != decoder); } } @@ -281,3 +297,38 @@ fn background(rx: Receiver) { } } } + +struct QueueIterator { + current: Box + Send>, + next: Arc + Send>>>>, +} + +impl Iterator for QueueIterator { + type Item = f32; + + #[inline] + fn next(&mut self) -> Option { + loop { + if let Some(sample) = self.current.next() { + return Some(sample); + } + + let next = { + let mut next = self.next.lock().unwrap(); + if next.len() == 0 { + // if there's no iter waiting, we create a dummy iter with 1000 null samples + Box::new((0 .. 1000).map(|_| 0.0f32)) as Box + Send> + } else { + next.remove(0) + } + }; + + self.current = next; + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.current.size_hint().0, None) + } +}