Merge pull request #18 from tomaka/wakeup-commands

Fix wav waiting time and improve background thread sleeping functionn…
This commit is contained in:
tomaka 2015-09-22 20:42:36 +02:00
commit c3e7a43283
3 changed files with 33 additions and 13 deletions

View file

@ -9,7 +9,7 @@ repository = "https://github.com/tomaka/rodio"
documentation = "http://tomaka.github.io/rodio/rodio/index.html"
[dependencies]
cpal = "0.2.2"
cpal = "0.2.5"
hound = "1.0.0"
lazy_static = "0.1.12"
time = "0.1.32"

View file

@ -124,14 +124,13 @@ impl Decoder for WavDecoder {
return 1000000000;
}
let len = {
{
let mut buffer = self.voice.append_data(min);
let len = buffer.len();
conversions::convert_and_write(self.reader.by_ref(), &mut buffer);
len
};
}
let duration = len as u64 * 1000000000 / self.voice.get_samples_rate().0 as u64;
let duration = self.voice.get_pending_samples() as u64 * 1000000000 /
(self.voice.get_samples_rate().0 as u64 * self.voice.get_channels() as u64);
self.voice.play();

View file

@ -1,6 +1,6 @@
use std::cmp;
use std::io::{Read, Seek};
use std::thread::{self, Builder};
use std::thread::{self, Builder, Thread};
use std::sync::mpsc::{self, Sender, Receiver};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
@ -17,6 +17,8 @@ use time;
pub struct Engine {
/// Communication with the background thread.
commands: Mutex<Sender<Command>>,
/// The background thread that executes commands.
thread: Option<Thread>,
/// Counter that is incremented whenever a sound starts playing and that is used to track each
/// sound invidiually.
next_sound_id: AtomicUsize,
@ -26,11 +28,18 @@ impl Engine {
/// Builds the engine.
pub fn new() -> Engine {
let (tx, rx) = mpsc::channel();
// we ignore errors when creating the background thread
// the user won't get any audio, but that's better than a panic
let _ = Builder::new().name("rodio audio processing".to_string())
.spawn(move || background(rx));
Engine { commands: Mutex::new(tx), next_sound_id: AtomicUsize::new(1) }
let thread = Builder::new().name("rodio audio processing".to_string())
.spawn(move || background(rx))
.ok().map(|jg| jg.thread().clone());
Engine {
commands: Mutex::new(tx),
thread: thread,
next_sound_id: AtomicUsize::new(1),
}
}
/// Starts playing a sound and returns a `Handler` to control it.
@ -43,6 +52,10 @@ impl Engine {
let commands = self.commands.lock().unwrap();
commands.send(Command::Play(sound_id, decoder)).unwrap();
if let Some(ref thread) = self.thread {
thread.unpark();
}
Handle {
engine: self,
id: sound_id,
@ -63,12 +76,20 @@ impl<'a> Handle<'a> {
pub fn set_volume(&mut self, value: f32) {
let commands = self.engine.commands.lock().unwrap();
commands.send(Command::SetVolume(self.id, value)).unwrap();
// we do not wake up the commands thread
// the samples with the previous volume have already been submitted, therefore it won't
// change anything if we wake it up
}
#[inline]
pub fn stop(self) {
let commands = self.engine.commands.lock().unwrap();
commands.send(Command::Stop(self.id)).unwrap();
if let Some(ref thread) = self.engine.thread {
thread.unpark();
}
}
}
@ -104,7 +125,7 @@ fn background(rx: Receiver<Command>) {
}
// stores the time when this thread will have to be woken up
let mut next_step_ns = time::precise_time_ns() + 10000000; // 10ms
let mut next_step_ns = time::precise_time_ns() + 1000000000; // 1s
// updating the existing sounds
for &mut (_, ref mut decoder) in &mut sounds {
@ -115,9 +136,9 @@ fn background(rx: Receiver<Command>) {
// sleeping a bit if we can
let sleep = next_step_ns as i64 - time::precise_time_ns() as i64;
let sleep = sleep - 500000; // removing 50µs so that we don't risk an underflow
let sleep = sleep - 500000; // removing 500µs so that we don't risk an underflow
if sleep >= 0 {
thread::sleep_ms((sleep / 1000000) as u32);
thread::park_timeout_ms((sleep / 1000000) as u32);
}
}
}