mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
remove seek trait from source mods, added it to symphonia decoder, renamed the trait to SeekableSource
This commit is contained in:
parent
204a3f89c9
commit
d47842fe57
11 changed files with 65 additions and 98 deletions
|
@ -15,7 +15,7 @@ claxon = { version = "0.4.2", optional = true }
|
|||
hound = { version = "3.3.1", optional = true }
|
||||
lewton = { version = "0.10", optional = true }
|
||||
# minimp3_fixed = { version = "0.5.4", optional = true}
|
||||
minimp3_fixed = { package = "minimp3", git = "https://github.com/dvdsk/minimp3-rs.git", optional = true }
|
||||
minimp3 = { git = "https://github.com/dvdsk/minimp3-rs.git", optional = true }
|
||||
symphonia = { version = "0.5.2", optional = true, default-features = false }
|
||||
crossbeam-channel = { version = "0.5.8", optional = true }
|
||||
|
||||
|
@ -26,7 +26,7 @@ flac = ["claxon"]
|
|||
vorbis = ["lewton"]
|
||||
wav = ["hound"]
|
||||
mp3 = ["symphonia-mp3"]
|
||||
minimp3 = ["dep:minimp3_fixed"]
|
||||
minimp3 = ["dep:minimp3"]
|
||||
wasm-bindgen = ["cpal/wasm-bindgen"]
|
||||
symphonia-aac = ["symphonia/aac"]
|
||||
symphonia-all = ["symphonia-aac", "symphonia-flac", "symphonia-isomp4", "symphonia-mp3", "symphonia-vorbis", "symphonia-wav"]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::io::BufReader;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
|
@ -7,11 +8,11 @@ fn main() {
|
|||
let file = std::fs::File::open("examples/music.mp3").unwrap();
|
||||
sink.append_seekable(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
sink.set_pos(2.0);
|
||||
dbg!("setting pos");
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
sink.seek(Duration::from_secs(0));
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
sink.seek(Duration::from_secs(4));
|
||||
|
||||
sink.sleep_until_end();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::str::FromStr;
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::Source;
|
||||
use crate::SourceExt;
|
||||
use crate::SeekableSource;
|
||||
|
||||
#[cfg(feature = "symphonia")]
|
||||
use self::read_seek_source::ReadSeekSource;
|
||||
|
@ -368,44 +368,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
match &mut self.0 {
|
||||
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
|
||||
DecoderImpl::Wav(_) => false,
|
||||
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
|
||||
DecoderImpl::Vorbis(_) => false,
|
||||
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
|
||||
DecoderImpl::Flac(_) => false,
|
||||
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
|
||||
DecoderImpl::Mp3(source) => source.request_pos(pos),
|
||||
#[cfg(feature = "symphonia")]
|
||||
DecoderImpl::Symphonia(_) => false,
|
||||
DecoderImpl::None(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> SourceExt for Decoder<R>
|
||||
impl<R> SeekableSource for Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
fn seek(&mut self, pos: Duration) {
|
||||
match &mut self.0 {
|
||||
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
|
||||
DecoderImpl::Wav(_) => false,
|
||||
DecoderImpl::Wav(_) => (),
|
||||
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
|
||||
DecoderImpl::Vorbis(_) => false,
|
||||
DecoderImpl::Vorbis(_) => (),
|
||||
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
|
||||
DecoderImpl::Flac(_) => false,
|
||||
DecoderImpl::Flac(_) => (),
|
||||
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
|
||||
DecoderImpl::Mp3(source) => source.request_pos(pos),
|
||||
DecoderImpl::Mp3(source) => source.seek(pos),
|
||||
#[cfg(feature = "symphonia")]
|
||||
DecoderImpl::Symphonia(_) => false,
|
||||
DecoderImpl::None(_) => false,
|
||||
DecoderImpl::Symphonia(source) => source.seek(pos),
|
||||
DecoderImpl::None(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{Source, SourceExt};
|
||||
use crate::{SeekableSource, Source};
|
||||
|
||||
use minimp3::Frame;
|
||||
use minimp3::SeekDecoder as Decoder;
|
||||
use minimp3::{Decoder, SeekDecoder};
|
||||
|
||||
pub struct Mp3Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
decoder: Decoder<R>,
|
||||
decoder: SeekDecoder<R>,
|
||||
current_frame: Frame,
|
||||
current_frame_offset: usize,
|
||||
}
|
||||
|
@ -23,10 +23,14 @@ where
|
|||
if !is_mp3(data.by_ref()) {
|
||||
return Err(data);
|
||||
}
|
||||
let mut decoder = Decoder::new(data).map_err(|_| ())?;
|
||||
// TODO: figure out decode_frame vs next_frame <dvdsk noreply@davidsk.dev>
|
||||
// let current_frame = decoder.next_frame().unwrap();
|
||||
let current_frame = decoder.decode_frame().map_err(|_| ())?;
|
||||
let mut decoder = SeekDecoder::new(data)
|
||||
// paramaters are correct and minimp3 is used correctly
|
||||
// thus if we crash here one of these invariants is broken:
|
||||
.expect("should be able to allocate memory, perform IO");
|
||||
let current_frame = decoder.decode_frame()
|
||||
// the reader makes enough data availible therefore
|
||||
// if we crash here the invariant broken is:
|
||||
.expect("data should not corrupt");
|
||||
|
||||
Ok(Mp3Decoder {
|
||||
decoder,
|
||||
|
@ -64,15 +68,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> SourceExt for Mp3Decoder<R>
|
||||
where
|
||||
impl<R> SeekableSource for Mp3Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
let pos = (pos * self.sample_rate() as f32) as u64;
|
||||
fn seek(&mut self, pos: Duration) -> bool {
|
||||
let pos = (pos.as_secs_f32() * self.sample_rate() as f32) as u64;
|
||||
// do not trigger a sample_rate, channels and frame len update
|
||||
// as the seek only takes effect after the current frame is done
|
||||
dbg!("seek");
|
||||
self.decoder.seek_samples(pos).is_ok()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ use symphonia::{
|
|||
io::MediaSourceStream,
|
||||
meta::MetadataOptions,
|
||||
probe::Hint,
|
||||
units,
|
||||
units::{self, Time},
|
||||
},
|
||||
default::get_probe,
|
||||
};
|
||||
|
||||
use crate::Source;
|
||||
use crate::{SeekableSource, Source};
|
||||
|
||||
use super::DecoderError;
|
||||
|
||||
|
@ -119,6 +119,23 @@ impl SymphoniaDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
impl SeekableSource for SymphoniaDecoder {
|
||||
fn seek(&mut self, pos: Duration) {
|
||||
use symphonia::core::formats::{SeekMode, SeekTo};
|
||||
|
||||
let pos_fract = 1f64 / pos.subsec_nanos() as f64;
|
||||
self.format
|
||||
.seek(
|
||||
SeekMode::Accurate,
|
||||
SeekTo::Time {
|
||||
time: Time::new(pos.as_secs(), pos_fract),
|
||||
track_id: None,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Source for SymphoniaDecoder {
|
||||
#[inline]
|
||||
fn current_frame_len(&self) -> Option<usize> {
|
||||
|
|
|
@ -129,6 +129,6 @@ pub mod static_buffer;
|
|||
pub use crate::conversions::Sample;
|
||||
pub use crate::decoder::Decoder;
|
||||
pub use crate::sink::Sink;
|
||||
pub use crate::source::{Source, SourceExt};
|
||||
pub use crate::source::{Source, SeekableSource};
|
||||
pub use crate::spatial_sink::SpatialSink;
|
||||
pub use crate::stream::{OutputStream, OutputStreamHandle, PlayError, StreamError};
|
||||
|
|
16
src/sink.rs
16
src/sink.rs
|
@ -8,7 +8,7 @@ use crossbeam_channel::Receiver;
|
|||
use std::sync::mpsc::Receiver;
|
||||
|
||||
use crate::stream::{OutputStreamHandle, PlayError};
|
||||
use crate::{queue, source::Done, Sample, Source, SourceExt};
|
||||
use crate::{queue, source::Done, Sample, Source, SeekableSource};
|
||||
use cpal::FromSample;
|
||||
|
||||
/// Handle to an device that outputs sounds.
|
||||
|
@ -31,7 +31,7 @@ struct Controls {
|
|||
stopped: AtomicBool,
|
||||
speed: Mutex<f32>,
|
||||
to_clear: Mutex<u32>,
|
||||
set_pos: Mutex<Option<f32>>,
|
||||
seek: Mutex<Option<Duration>>,
|
||||
}
|
||||
|
||||
impl Sink {
|
||||
|
@ -57,7 +57,7 @@ impl Sink {
|
|||
stopped: AtomicBool::new(false),
|
||||
speed: Mutex::new(1.0),
|
||||
to_clear: Mutex::new(0),
|
||||
set_pos: Mutex::new(None),
|
||||
seek: Mutex::new(None),
|
||||
}),
|
||||
sound_count: Arc::new(AtomicUsize::new(0)),
|
||||
detached: false,
|
||||
|
@ -121,7 +121,7 @@ impl Sink {
|
|||
#[inline]
|
||||
pub fn append_seekable<S>(&self, source: S)
|
||||
where
|
||||
S: Source + SourceExt + Send + 'static,
|
||||
S: Source + SeekableSource + Send + 'static,
|
||||
f32: FromSample<S::Item>,
|
||||
S::Item: Sample + Send,
|
||||
{
|
||||
|
@ -162,8 +162,8 @@ impl Sink {
|
|||
.inner_mut()
|
||||
.set_factor(*controls.speed.lock().unwrap());
|
||||
let seekable = amp.inner_mut().inner_mut().inner_mut();
|
||||
if let Some(pos) = controls.set_pos.lock().unwrap().take() {
|
||||
seekable.request_pos(pos);
|
||||
if let Some(pos) = controls.seek.lock().unwrap().take() {
|
||||
seekable.seek(pos);
|
||||
}
|
||||
start_played.store(true, Ordering::SeqCst);
|
||||
})
|
||||
|
@ -220,8 +220,8 @@ impl Sink {
|
|||
/// Set position
|
||||
///
|
||||
/// No effect if source does not implement `SourceExt`
|
||||
pub fn set_pos(&self, pos: f32) {
|
||||
*self.controls.set_pos.lock().unwrap() = Some(pos);
|
||||
pub fn seek(&self, pos: Duration) {
|
||||
*self.controls.seek.lock().unwrap() = Some(pos);
|
||||
}
|
||||
|
||||
/// Pauses playback of this sink.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
use crate::{Sample, Source};
|
||||
|
||||
/// Internal function that builds a `Amplify` object.
|
||||
pub fn amplify<I>(input: I, factor: f32) -> Amplify<I>
|
||||
|
@ -94,14 +94,3 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Amplify<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait SourceExt {
|
||||
pub trait SeekableSource {
|
||||
/// Seek to pos and whether the seek succeeded
|
||||
fn request_pos(&mut self, pos: f32) -> bool;
|
||||
fn seek(&mut self, pos: Duration);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
use crate::{Sample, Source};
|
||||
|
||||
/// Internal function that builds a `Pausable` object.
|
||||
pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
|
||||
|
@ -116,14 +116,3 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Pausable<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
use crate::{Sample, Source};
|
||||
|
||||
/// Internal function that builds a `Stoppable` object.
|
||||
pub fn stoppable<I>(source: I) -> Stoppable<I> {
|
||||
|
@ -89,14 +89,3 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Stoppable<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&mut self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue