2023-03-10 14:35:18 +00:00
|
|
|
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,
|
|
|
|
};
|
2023-03-11 18:02:52 +00:00
|
|
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
2023-03-10 14:35:18 +00:00
|
|
|
use urlencoding::encode;
|
|
|
|
|
|
|
|
pub enum PlaybackControl {
|
|
|
|
PlayTrack(TrackId),
|
|
|
|
Stop,
|
|
|
|
Exit,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum PlaybackStatus {
|
|
|
|
Stopped,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Playback {
|
2023-03-11 18:02:52 +00:00
|
|
|
handle: tokio::task::JoinHandle<()>,
|
|
|
|
pipeline: gstreamer::Element,
|
2023-03-10 14:35:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Playback {
|
2023-03-11 18:02:52 +00:00
|
|
|
pub fn new(id: TrackId) -> Flow<Self, 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 pipeline = return_error!(Flow::from(
|
|
|
|
gstreamer::parse_launch(&format!("playbin uri=file:///{}", path.display()))
|
|
|
|
.map_err(|err| Error::GlibError(err))
|
|
|
|
));
|
2023-03-10 14:35:18 +00:00
|
|
|
|
2023-03-11 18:02:52 +00:00
|
|
|
pipeline.set_state(gstreamer::State::Playing);
|
|
|
|
let handle = tokio::task::spawn_blocking({
|
|
|
|
let pipeline = pipeline.clone();
|
|
|
|
move || pipeline_status(pipeline)
|
2023-03-10 14:35:18 +00:00
|
|
|
});
|
|
|
|
|
2023-03-11 18:02:52 +00:00
|
|
|
ok(Self { handle, pipeline })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn stop(&self) {
|
|
|
|
self.handle.abort();
|
|
|
|
self.pipeline.set_state(gstreamer::State::Paused);
|
2023-03-10 14:35:18 +00:00
|
|
|
}
|
2023-03-11 18:02:52 +00:00
|
|
|
}
|
2023-03-10 14:35:18 +00:00
|
|
|
|
2023-03-11 18:02:52 +00:00
|
|
|
impl Drop for Playback {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.stop();
|
2023-03-10 14:35:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-11 18:02:52 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-03-10 14:35:18 +00:00
|
|
|
fn play_track(id: TrackId) -> Flow<gstreamer::Element, FatalError, Error> {
|
|
|
|
println!("setting up to play {}", playbin);
|
|
|
|
println!("ready to play");
|
|
|
|
return_error!(Flow::from(
|
|
|
|
pipeline
|
|
|
|
.set_state(gstreamer::State::Playing)
|
2023-03-11 18:02:52 +00:00
|
|
|
.map_err(|err| Error::CannotPlay(err.to_string()))
|
2023-03-10 14:35:18 +00:00
|
|
|
));
|
|
|
|
println!("playing started");
|
|
|
|
ok(pipeline)
|
|
|
|
}
|
2023-03-11 18:02:52 +00:00
|
|
|
*/
|
2023-03-10 14:35:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
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(())
|
|
|
|
}
|
|
|
|
*/
|