132 lines
4.1 KiB
Rust
132 lines
4.1 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,
|
|
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<Flow<(), FatalError, Error>>,
|
|
control_tx: Sender<PlaybackControl>,
|
|
}
|
|
|
|
impl Playback {
|
|
pub fn new() -> Playback {
|
|
let (control_tx, control_rx) = channel::<PlaybackControl>();
|
|
|
|
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<gstreamer::Element, FatalError, 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 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<ClockTime> = pipeline.query_position();
|
|
let duration: Option<ClockTime> = pipeline.query_duration();
|
|
println!("Position {:?} {:?}", position, duration);
|
|
thread::sleep(Duration::from_millis(100));
|
|
})
|
|
};
|
|
|
|
ok(())
|
|
}
|
|
*/
|