Add support for vorbis decoding

This commit is contained in:
Pierre Krieger 2015-07-22 14:23:03 +02:00
parent 49b03e081a
commit 5a438bcdec
7 changed files with 93 additions and 13 deletions

View file

@ -12,3 +12,4 @@ documentation = "http://tomaka.github.io/rodio/rodio/index.html"
cpal = "0.1.1" cpal = "0.1.1"
hound = "1.0.0" hound = "1.0.0"
lazy_static = "0.1.12" lazy_static = "0.1.12"
vorbis = "0.0.12"

View file

@ -9,8 +9,12 @@ fn main() {
let file = std::fs::File::open("examples/beep2.wav").unwrap(); let file = std::fs::File::open("examples/beep2.wav").unwrap();
rodio::play_once(file); rodio::play_once(file);
std::thread::sleep_ms(1000);
let file = std::fs::File::open("examples/beep3.ogg").unwrap();
rodio::play_once(file);
std::thread::sleep_ms(1000); std::thread::sleep_ms(1000);
beep1.stop(); beep1.stop();
std::thread::sleep_ms(8000); std::thread::sleep_ms(7000);
} }

BIN
examples/beep3.ogg Normal file

Binary file not shown.

View file

@ -1,6 +1,7 @@
use std::io::Read; use std::io::{Read, Seek};
use cpal::Voice; use cpal::Voice;
mod vorbis;
mod wav; mod wav;
/// Trait for objects that produce an audio stream. /// Trait for objects that produce an audio stream.
@ -10,8 +11,15 @@ pub trait Decoder {
} }
/// Builds a new `Decoder` from a data stream by determining the correct format. /// Builds a new `Decoder` from a data stream by determining the correct format.
pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Send + 'static { pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Seek + Send + 'static {
if let Ok(decoder) = wav::WavDecoder::new(data) { let data = match wav::WavDecoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Box::new(decoder);
}
};
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
return Box::new(decoder); return Box::new(decoder);
} }

62
src/decoder/vorbis.rs Normal file
View file

@ -0,0 +1,62 @@
use std::io::{Read, Seek};
use std::mem;
use super::Decoder;
use cpal::{self, Voice};
use vorbis;
pub struct VorbisDecoder<R> where R: Read + Seek {
decoder: vorbis::Decoder<R>,
current_packet: Option<vorbis::Packet>,
}
impl<R> VorbisDecoder<R> where R: Read + Seek {
pub fn new(data: R) -> Result<VorbisDecoder<R>, ()> {
let decoder = match vorbis::Decoder::new(data) {
Err(_) => return Err(()),
Ok(r) => r
};
Ok(VorbisDecoder {
decoder: decoder,
current_packet: None,
})
}
}
impl<R> Decoder for VorbisDecoder<R> where R: Read + Seek {
fn write(&mut self, voice: &mut Voice) {
// setting the current packet to `None` if there is no data left in it
match &mut self.current_packet {
packet @ &mut Some(_) => {
if packet.as_ref().unwrap().data.len() == 0 {
*packet = None;
}
},
_ => ()
};
// getting the next packet
let packet = if let Some(ref mut packet) = self.current_packet {
packet
} else {
let next = match self.decoder.packets().next().and_then(|r| r.ok()) {
Some(p) => p,
None => return, // TODO: handle
};
self.current_packet = Some(next);
self.current_packet.as_mut().unwrap()
};
let mut buffer = voice.append_data(packet.channels, cpal::SamplesRate(packet.rate as u32),
packet.data.len());
let src = mem::replace(&mut packet.data, Vec::new());
let mut src = src.into_iter();
for (dest, src) in buffer.iter_mut().zip(src.by_ref()) {
*dest = src;
}
packet.data = src.collect();
}
}

View file

@ -1,4 +1,4 @@
use std::io::Read; use std::io::{Read, Seek, SeekFrom};
use super::Decoder; use super::Decoder;
use cpal::{self, Voice}; use cpal::{self, Voice};
@ -10,13 +10,17 @@ pub struct WavDecoder<R> where R: Read {
spec: WavSpec, spec: WavSpec,
} }
impl<R> WavDecoder<R> where R: Read { impl<R> WavDecoder<R> where R: Read + Seek {
pub fn new(data: R) -> Result<WavDecoder<R>, ()> { pub fn new(mut data: R) -> Result<WavDecoder<R>, R> {
let reader = match WavReader::new(data) { let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
Err(_) => return Err(()),
Ok(r) => r
};
if WavReader::new(data.by_ref()).is_err() {
data.seek(SeekFrom::Start(stream_pos)).unwrap();
return Err(data);
}
data.seek(SeekFrom::Start(stream_pos)).unwrap();
let reader = WavReader::new(data).unwrap();
let spec = reader.spec(); let spec = reader.spec();
Ok(WavDecoder { Ok(WavDecoder {

View file

@ -2,8 +2,9 @@ extern crate cpal;
extern crate hound; extern crate hound;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate vorbis;
use std::io::Read; use std::io::{Read, Seek};
mod decoder; mod decoder;
mod engine; mod engine;
@ -25,7 +26,7 @@ impl Handle {
} }
/// Plays a sound once. Returns a `Handle` that can be used to control the sound. /// Plays a sound once. Returns a `Handle` that can be used to control the sound.
pub fn play_once<R>(input: R) -> Handle where R: Read + Send + 'static { pub fn play_once<R>(input: R) -> Handle where R: Read + Seek + Send + 'static {
let decoder = decoder::decode(input); let decoder = decoder::decode(input);
Handle(ENGINE.play(decoder)) Handle(ENGINE.play(decoder))
} }