monorepo/music-player/server/src/playback.rs

139 lines
3.9 KiB
Rust
Raw Normal View History

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<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))
));
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<gstreamer::Element, FatalError, Error> {
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<ClockTime> = pipeline.query_position();
let duration: Option<ClockTime> = pipeline.query_duration();
println!("Position {:?} {:?}", position, duration);
thread::sleep(Duration::from_millis(100));
})
};
ok(())
}
*/