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 { handle: tokio::task::JoinHandle<()>, pipeline: gstreamer::Element, } impl Playback { pub fn new(id: TrackId) -> Flow { let pb = PathBuf::from(id.as_ref()); let path = pb .iter() .skip(1) .map(|component| encode(&component.to_string_lossy()).into_owned()) .collect::(); let pipeline = return_error!(Flow::from( gstreamer::parse_launch(&format!("playbin uri=file:///{}", path.display())) .map_err(|err| Error::GlibError(err)) )); pipeline.set_state(gstreamer::State::Playing); let handle = tokio::task::spawn_blocking({ let pipeline = pipeline.clone(); move || pipeline_status(pipeline) }); ok(Self { handle, pipeline }) } pub fn stop(&self) { self.handle.abort(); self.pipeline.set_state(gstreamer::State::Paused); } } impl Drop for Playback { fn drop(&mut self) { self.stop(); } } fn pipeline_status(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), } } } /* fn play_track(id: TrackId) -> Flow { println!("setting up to play {}", playbin); println!("ready to play"); return_error!(Flow::from( pipeline .set_state(gstreamer::State::Playing) .map_err(|err| Error::CannotPlay(err.to_string())) )); println!("playing started"); ok(pipeline) } */ /* fn play_track(id: TrackId) -> Flow<(), FatalError, Error> { let playbin = format!("playbin uri=file://{}", id.as_ref()); let pipeline = return_error!(Flow::from( gstreamer::parse_launch(&playbin).map_err(|err| Error::GlibError(err)) )); return_error!(Flow::from( pipeline .set_state(gstreamer::State::Playing) .map_err(|_| Error::CannotPlay) )); let message_handler = { let pipeline = pipeline.clone(); thread::spawn(move || { 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), } } }) }; let query_handler = { let pipeline = pipeline.clone(); thread::spawn(move || loop { let position: Option = pipeline.query_position(); let duration: Option = pipeline.query_duration(); println!("Position {:?} {:?}", position, duration); thread::sleep(Duration::from_millis(100)); }) }; ok(()) } */