seek implemented through SourceExt trait

This commit is contained in:
dskleingeld 2021-01-03 00:40:54 +01:00 committed by dvdsk
parent eda5934a20
commit fafe4ba1af
No known key found for this signature in database
GPG key ID: 6CF9D20C5709A836
10 changed files with 166 additions and 8 deletions

View file

@ -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
View 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();
}

View file

@ -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,

View file

@ -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,

View file

@ -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};

View file

@ -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.

View file

@ -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)
}
}

View file

@ -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;
}

View file

@ -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)
}
}

View file

@ -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)
}
}