diff --git a/Cargo.toml b/Cargo.toml index 8c8c5b8..ffe4a1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,9 @@ repository = "https://github.com/tomaka/rodio" documentation = "http://tomaka.github.io/rodio/rodio/index.html" [dependencies] -cpal = "0.2.1" +cpal = "0.2.2" #hound = "1.0.0" hound = { git = "https://github.com/tomaka/hound", branch = "wavreader-ownership" } lazy_static = "0.1.12" +time = "0.1.32" vorbis = "0.0.13" diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 44f89b0..f9c4c05 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -9,8 +9,9 @@ mod wav; /// Trait for objects that produce an audio stream. pub trait Decoder { - /// Appends data to the voice. - fn write(&mut self); + /// Appends data to the voice. Returns the number of nanoseconds after which new data will need + /// to have been submitted. + fn write(&mut self) -> u64; } /// Builds a new `Decoder` from a data stream by determining the correct format. diff --git a/src/decoder/vorbis.rs b/src/decoder/vorbis.rs index 5bddc46..961f4de 100644 --- a/src/decoder/vorbis.rs +++ b/src/decoder/vorbis.rs @@ -44,7 +44,7 @@ impl VorbisDecoder { } impl Decoder for VorbisDecoder { - fn write(&mut self) { + fn write(&mut self) -> u64 { /*let (min, _) = self.reader.size_hint(); if min == 0 { @@ -52,11 +52,15 @@ impl Decoder for VorbisDecoder { return; }*/ - { + let len = { let mut buffer = self.voice.append_data(32768); + let len = buffer.len(); conversions::convert_and_write(self.reader.by_ref(), &mut buffer); - } + len + }; self.voice.play(); + + len as u64 * 1000000000 / self.voice.get_samples_rate().0 as u64 } } diff --git a/src/decoder/wav.rs b/src/decoder/wav.rs index b1b3180..b014b7d 100644 --- a/src/decoder/wav.rs +++ b/src/decoder/wav.rs @@ -80,19 +80,25 @@ fn is_wave(mut data: R) -> bool where R: Read + Seek { } impl Decoder for WavDecoder { - fn write(&mut self) { + fn write(&mut self) -> u64 { let (min, _) = self.reader.size_hint(); if min == 0 { // finished - return; + 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; self.voice.play(); + + duration } } diff --git a/src/engine.rs b/src/engine.rs index d95e6ef..2e0c5b9 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,3 +1,4 @@ +use std::cmp; use std::io::{Read, Seek}; use std::thread::{self, Builder}; use std::sync::mpsc::{self, Sender, Receiver}; @@ -9,6 +10,8 @@ use cpal::Voice; use decoder; use decoder::Decoder; +use time; + /// The internal engine of this library. /// /// Each `Engine` owns a thread that runs in the background and plays the audio. @@ -85,12 +88,21 @@ fn background(rx: Receiver) { } } + // stores + let mut next_step_ns = time::precise_time_ns(); + // updating the existing sounds - for &mut (_, ref mut decoder) in sounds.iter_mut() { - decoder.write(); + for &mut (_, ref mut decoder) in &mut sounds { + let val = decoder.write(); + let val = time::precise_time_ns() + val; + next_step_ns = cmp::min(next_step_ns, val); } // sleeping a bit? - thread::sleep_ms(1); + let sleep = next_step_ns as i64 - time::precise_time_ns() as i64; + let sleep = sleep - 500000; + if sleep >= 0 { + thread::sleep_ms(sleep as u32); + } } } diff --git a/src/lib.rs b/src/lib.rs index acf68cd..dfaf898 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ extern crate cpal; extern crate hound; #[macro_use] extern crate lazy_static; +extern crate time; extern crate vorbis; pub use cpal::{Endpoint, get_endpoints_list, get_default_endpoint};