90 lines
2.4 KiB
Rust
90 lines
2.4 KiB
Rust
use crate::{media::TrackId, Error, FatalError};
|
|
use flow::{ok, return_error, Flow};
|
|
use gstreamer::{format::ClockTime, prelude::*, MessageView, StateChangeError};
|
|
use std::{
|
|
path::PathBuf,
|
|
thread::{self, JoinHandle},
|
|
time::Duration,
|
|
};
|
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
|
use urlencoding::encode;
|
|
|
|
pub enum PlaybackControl {
|
|
PlayTrack(TrackId),
|
|
Stop,
|
|
Exit,
|
|
}
|
|
|
|
pub enum PlaybackStatus {
|
|
Stopped,
|
|
}
|
|
|
|
pub struct Playback {
|
|
events_handle: tokio::task::JoinHandle<()>,
|
|
pipeline: gstreamer::Element,
|
|
}
|
|
|
|
impl Playback {
|
|
pub fn new(id: TrackId) -> Result<Self, Error> {
|
|
let pb = PathBuf::from(id.as_ref());
|
|
let path = pb
|
|
.iter()
|
|
.skip(1)
|
|
.map(|component| encode(&component.to_string_lossy()).into_owned())
|
|
.collect::<PathBuf>();
|
|
let pipeline = gstreamer::parse_launch(&format!("playbin uri=file:///{}", path.display()))
|
|
.map_err(|err| Error::GlibError(err))?;
|
|
|
|
pipeline
|
|
.set_state(gstreamer::State::Playing)
|
|
.map_err(|err| Error::CannotPlay(err.to_string()))?;
|
|
let events_handle = tokio::task::spawn_blocking({
|
|
let pipeline = pipeline.clone();
|
|
move || pipeline_events(pipeline)
|
|
});
|
|
|
|
Ok(Self {
|
|
events_handle,
|
|
pipeline,
|
|
})
|
|
}
|
|
|
|
pub fn stop(&self) -> Result<(), Error> {
|
|
self.events_handle.abort();
|
|
self.pipeline
|
|
.set_state(gstreamer::State::Paused)
|
|
.map_err(|_| Error::CannotStop)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn position(&self) -> (Option<ClockTime>, Option<ClockTime>) {
|
|
let position = self.pipeline.query_position();
|
|
let duration = self.pipeline.query_duration();
|
|
(position, duration)
|
|
}
|
|
}
|
|
|
|
impl Drop for Playback {
|
|
fn drop(&mut self) {
|
|
self.stop();
|
|
}
|
|
}
|
|
|
|
fn pipeline_events(pipeline: gstreamer::Element) {
|
|
let bus = pipeline.bus().unwrap();
|
|
for msg in bus.iter_timed(gstreamer::ClockTime::NONE) {
|
|
match msg.view() {
|
|
MessageView::Eos(_) => (),
|
|
MessageView::Error(err) => {
|
|
println!(
|
|
"Error from {:?}: {} ({:?})",
|
|
err.src().map(|s| s.path_string()),
|
|
err.error(),
|
|
err.debug()
|
|
);
|
|
}
|
|
msg => println!("{:?}", msg),
|
|
}
|
|
}
|
|
}
|