mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 05:32:32 +00:00
seek implemented through SourceExt trait
This commit is contained in:
parent
eda5934a20
commit
fafe4ba1af
10 changed files with 166 additions and 8 deletions
|
@ -14,7 +14,8 @@ cpal = "0.15"
|
|||
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 = { version = "0.5.4", optional = true}
|
||||
minimp3 = { git = "https://github.com/dskleingeld/minimp3-rs.git", optional = true }
|
||||
symphonia = { version = "0.5.2", optional = true, default-features = false }
|
||||
crossbeam-channel = { version = "0.5.8", optional = true }
|
||||
|
||||
|
|
14
examples/seek_mp3.rs
Normal file
14
examples/seek_mp3.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.mp3").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
sink.set_pos(1.0);
|
||||
|
||||
sink.sleep_until_end();
|
||||
}
|
|
@ -10,6 +10,7 @@ use std::str::FromStr;
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::Source;
|
||||
use crate::SourceExt;
|
||||
|
||||
#[cfg(feature = "symphonia")]
|
||||
use self::read_seek_source::ReadSeekSource;
|
||||
|
@ -367,6 +368,45 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
fn request_pos(&self, pos: f32) -> bool {
|
||||
match self.0 {
|
||||
#[cfg(feature = "wav")]
|
||||
DecoderImpl::Wav(ref source) => false,
|
||||
#[cfg(feature = "vorbis")]
|
||||
DecoderImpl::Vorbis(ref source) => false,
|
||||
#[cfg(feature = "flac")]
|
||||
DecoderImpl::Flac(ref source) => false,
|
||||
#[cfg(feature = "mp3")]
|
||||
DecoderImpl::Mp3(ref source) => source.request_pos(pos),
|
||||
DecoderImpl::None(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<R> SourceExt for Decoder<R>
|
||||
// where
|
||||
// R: Read + Seek,
|
||||
// {
|
||||
// fn request_pos(&self, pos: f32) -> bool {
|
||||
// match self.0 {
|
||||
// #[cfg(feature = "wav")]
|
||||
// DecoderImpl::Wav(ref source) => false,
|
||||
// #[cfg(feature = "vorbis")]
|
||||
// DecoderImpl::Vorbis(ref source) => false,
|
||||
// #[cfg(feature = "flac")]
|
||||
// DecoderImpl::Flac(ref source) => false,
|
||||
// #[cfg(feature = "mp3")]
|
||||
// DecoderImpl::Mp3(ref source) => {source.test(); false},
|
||||
// DecoderImpl::None(_) => false,
|
||||
// };
|
||||
// todo!();
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<R> Iterator for LoopedDecoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::Source;
|
||||
use crate::{Source, SourceExt};
|
||||
|
||||
use minimp3::{Decoder, Frame};
|
||||
use minimp3::{Frame, Decoder};
|
||||
// use minimp3::SeekDecoder as Decoder;
|
||||
|
||||
pub struct Mp3Decoder<R>
|
||||
where
|
||||
|
@ -61,6 +62,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> SourceExt for Mp3Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
fn request_pos(&self, pos: f32) -> bool {
|
||||
// self.seek_samples(0); //TODO
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Iterator for Mp3Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
|
|
@ -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;
|
||||
pub use crate::source::{Source, SourceExt};
|
||||
pub use crate::spatial_sink::SpatialSink;
|
||||
pub use crate::stream::{OutputStream, OutputStreamHandle, PlayError, StreamError};
|
||||
|
|
56
src/sink.rs
56
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};
|
||||
use crate::{queue, source::Done, Sample, Source, SourceExt};
|
||||
use cpal::FromSample;
|
||||
|
||||
/// Handle to an device that outputs sounds.
|
||||
|
@ -29,8 +29,13 @@ struct Controls {
|
|||
pause: AtomicBool,
|
||||
volume: Mutex<f32>,
|
||||
stopped: AtomicBool,
|
||||
<<<<<<< HEAD
|
||||
speed: Mutex<f32>,
|
||||
to_clear: Mutex<u32>,
|
||||
||||||| parent of 2cb7526 (seek implemented through SourceExt trait)
|
||||
=======
|
||||
set_pos: Mutex<Option<f32>>,
|
||||
>>>>>>> 2cb7526 (seek implemented through SourceExt trait)
|
||||
}
|
||||
|
||||
impl Sink {
|
||||
|
@ -54,8 +59,13 @@ impl Sink {
|
|||
pause: AtomicBool::new(false),
|
||||
volume: Mutex::new(1.0),
|
||||
stopped: AtomicBool::new(false),
|
||||
<<<<<<< HEAD
|
||||
speed: Mutex::new(1.0),
|
||||
to_clear: Mutex::new(0),
|
||||
||||||| parent of 2cb7526 (seek implemented through SourceExt trait)
|
||||
=======
|
||||
set_pos: Mutex::new(None),
|
||||
>>>>>>> 2cb7526 (seek implemented through SourceExt trait)
|
||||
}),
|
||||
sound_count: Arc::new(AtomicUsize::new(0)),
|
||||
detached: false,
|
||||
|
@ -115,6 +125,43 @@ impl Sink {
|
|||
*self.sleep_until_end.lock().unwrap() = Some(self.queue_tx.append_with_signal(source));
|
||||
}
|
||||
|
||||
/// Appends a sound to the queue of sounds to play.
|
||||
#[inline]
|
||||
pub fn append_seekable<S>(&self, source: S)
|
||||
where
|
||||
S: Source + Send + 'static,
|
||||
S: SourceExt + Send + 'static,
|
||||
S::Item: Sample,
|
||||
S::Item: Send,
|
||||
{
|
||||
let controls = self.controls.clone();
|
||||
|
||||
let source = source
|
||||
.pausable(false)
|
||||
.amplify(1.0)
|
||||
.stoppable()
|
||||
.periodic_access(Duration::from_millis(5), move |src| {
|
||||
if controls.stopped.load(Ordering::SeqCst) {
|
||||
src.stop();
|
||||
} else {
|
||||
src.inner_mut().set_factor(*controls.volume.lock().unwrap());
|
||||
src.inner_mut()
|
||||
.inner_mut()
|
||||
.set_paused(controls.pause.load(Ordering::SeqCst));
|
||||
if let Some(pos) = controls.set_pos.lock().unwrap().take() {
|
||||
src.inner_mut()
|
||||
.inner_mut()
|
||||
.inner_mut()
|
||||
.request_pos(pos);
|
||||
}
|
||||
}
|
||||
})
|
||||
.convert_samples();
|
||||
self.sound_count.fetch_add(1, Ordering::Relaxed);
|
||||
let source = Done::new(source, self.sound_count.clone());
|
||||
*self.sleep_until_end.lock().unwrap() = Some(self.queue_tx.append_with_signal(source));
|
||||
}
|
||||
|
||||
/// Gets the volume of the sound.
|
||||
///
|
||||
/// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
|
||||
|
@ -159,6 +206,13 @@ impl Sink {
|
|||
self.controls.pause.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// Pauses playback of this sink.
|
||||
///
|
||||
/// No effect if already paused.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source};
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
|
||||
/// Internal function that builds a `Amplify` object.
|
||||
pub fn amplify<I>(input: I, factor: f32) -> Amplify<I>
|
||||
|
@ -94,3 +94,14 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Amplify<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,3 +427,8 @@ where
|
|||
(**self).total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SourceExt {
|
||||
/// Seek to pos and whether the seek succeeded
|
||||
fn request_pos(&self, pos: f32) -> bool;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source};
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
|
||||
/// Internal function that builds a `Pausable` object.
|
||||
pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
|
||||
|
@ -116,3 +116,14 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Pausable<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{Sample, Source};
|
||||
use crate::{Sample, Source, SourceExt};
|
||||
|
||||
/// Internal function that builds a `Stoppable` object.
|
||||
pub fn stoppable<I>(source: I) -> Stoppable<I> {
|
||||
|
@ -89,3 +89,14 @@ where
|
|||
self.input.total_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> SourceExt for Stoppable<I>
|
||||
where
|
||||
I: Source,
|
||||
I: SourceExt,
|
||||
I::Item: Sample,
|
||||
{
|
||||
fn request_pos(&self, pos: f32) -> bool {
|
||||
self.input.request_pos(pos)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue