use crate::{media::TrackId, Error, FatalError}; use flow::{ok, return_error, Flow}; use gstreamer::{format::ClockTime, prelude::*, MessageView, StateChangeError}; use std::{ path::PathBuf, sync::mpsc::{channel, Receiver, Sender}, thread::{self, JoinHandle}, time::Duration, }; use urlencoding::encode; pub enum PlaybackControl { PlayTrack(TrackId), Stop, Exit, } pub enum PlaybackStatus { Stopped, } pub struct Playback { handle: JoinHandle>, control_tx: Sender, } impl Playback { pub fn new() -> Playback { let (control_tx, control_rx) = channel::(); let handle = thread::spawn(move || { let mut pipeline = None; loop { match control_rx.recv().unwrap() { PlaybackControl::PlayTrack(id) => match play_track(id) { Flow::Ok(pipeline_) => pipeline = Some(pipeline_), Flow::Fatal(err) => panic!("fatal error: {:?}", err), Flow::Err(err) => panic!("playback error: {:?}", err), }, PlaybackControl::Stop => { if let Some(ref pipeline) = pipeline { return_error!(Flow::from( pipeline .set_state(gstreamer::State::Paused) .map_err(|_| Error::CannotStop) )); } } PlaybackControl::Exit => return ok(()), } } }); Self { handle, control_tx } } pub fn play_track(&self, id: TrackId) { self.control_tx .send(PlaybackControl::PlayTrack(id)) .unwrap(); } } fn play_track(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 playbin = format!("playbin uri=file:///{}", path.display()); println!("setting up to play {}", playbin); let pipeline = return_error!(Flow::from( gstreamer::parse_launch(&playbin).map_err(|err| Error::GlibError(err)) )); println!("ready to play"); return_error!(Flow::from( pipeline .set_state(gstreamer::State::Playing) .map_err(|_| Error::CannotPlay) )); 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(()) } */