Fixed buffering for GStreamer

This commit is contained in:
G2-Games 2024-05-20 04:03:38 -05:00
parent dd7f447d46
commit 48c7e29eca
4 changed files with 37 additions and 31 deletions

View file

@ -51,7 +51,10 @@ enum PlaybackInfo {
start: Duration, start: Duration,
end: Duration, end: Duration,
}, },
Finished // When this is sent, the thread will die!
/// When this is sent, the thread will die! Use it when the [Player] is
/// done playing
Finished
} }
/// An instance of a music player with a GStreamer backend /// An instance of a music player with a GStreamer backend
@ -66,7 +69,7 @@ pub struct GStreamer {
volume: f64, volume: f64,
start: Option<Duration>, start: Option<Duration>,
end: Option<Duration>, end: Option<Duration>,
paused: bool, paused: Arc<RwLock<bool>>,
position: Arc<RwLock<Option<Duration>>>, position: Arc<RwLock<Option<Duration>>>,
} }
@ -260,6 +263,8 @@ impl Player for GStreamer {
// Set up the thread to monitor bus messages // Set up the thread to monitor bus messages
let playbin_bus_ctrl = Arc::clone(&playbin); let playbin_bus_ctrl = Arc::clone(&playbin);
let paused = Arc::new(RwLock::new(false));
let bus_paused = Arc::clone(&paused);
let bus_watch = playbin let bus_watch = playbin
.read() .read()
.unwrap() .unwrap()
@ -267,23 +272,18 @@ impl Player for GStreamer {
.expect("Failed to get GStreamer message bus") .expect("Failed to get GStreamer message bus")
.add_watch(move |_bus, msg| { .add_watch(move |_bus, msg| {
match msg.view() { match msg.view() {
gst::MessageView::Eos(_) => {} gst::MessageView::Eos(_) => println!("End of stream"),
gst::MessageView::StreamStart(_) => println!("Stream start"), gst::MessageView::StreamStart(_) => println!("Stream start"),
gst::MessageView::Error(_) => { gst::MessageView::Error(err) => {
playbin_bus_ctrl println!("Error recieved: {}", err);
.write() return glib::ControlFlow::Break
.unwrap()
.set_state(gst::State::Ready)
.unwrap();
playbin_bus_ctrl
.write()
.unwrap()
.set_state(gst::State::Playing)
.unwrap();
} }
/* TODO: Fix buffering!!
gst::MessageView::Buffering(buffering) => { gst::MessageView::Buffering(buffering) => {
if *bus_paused.read().unwrap() == true {
return glib::ControlFlow::Continue
}
// If the player is not paused, pause it
let percent = buffering.percent(); let percent = buffering.percent();
if percent < 100 { if percent < 100 {
playbin_bus_ctrl playbin_bus_ctrl
@ -291,7 +291,8 @@ impl Player for GStreamer {
.unwrap() .unwrap()
.set_state(gst::State::Paused) .set_state(gst::State::Paused)
.unwrap(); .unwrap();
} else if !(buffering) { } else if percent >= 100 {
println!("Finished buffering");
playbin_bus_ctrl playbin_bus_ctrl
.write() .write()
.unwrap() .unwrap()
@ -299,7 +300,6 @@ impl Player for GStreamer {
.unwrap(); .unwrap();
} }
} }
*/
_ => (), _ => (),
} }
glib::ControlFlow::Continue glib::ControlFlow::Continue
@ -321,7 +321,7 @@ impl Player for GStreamer {
volume: 1.0, volume: 1.0,
start: None, start: None,
end: None, end: None,
paused: false, paused,
position, position,
}) })
} }
@ -355,20 +355,21 @@ impl Player for GStreamer {
/// If the player is paused or stopped, starts playback /// If the player is paused or stopped, starts playback
fn play(&mut self) -> Result<(), PlayerError> { fn play(&mut self) -> Result<(), PlayerError> {
*self.paused.write().unwrap() = false;
self.set_state(gst::State::Playing)?; self.set_state(gst::State::Playing)?;
Ok(()) Ok(())
} }
/// Pause, if playing /// Pause, if playing
fn pause(&mut self) -> Result<(), PlayerError> { fn pause(&mut self) -> Result<(), PlayerError> {
//self.paused = true; *self.paused.write().unwrap() = true;
self.set_state(gst::State::Paused)?; self.set_state(gst::State::Paused)?;
Ok(()) Ok(())
} }
/// Resume from being paused /// Resume from being paused
fn resume(&mut self) -> Result<(), PlayerError> { fn resume(&mut self) -> Result<(), PlayerError> {
//self.paused = false; *self.paused.write().unwrap() = false;
self.set_state(gst::State::Playing)?; self.set_state(gst::State::Playing)?;
Ok(()) Ok(())
} }
@ -473,9 +474,10 @@ fn playback_monitor(
) { ) {
let mut stats = PlaybackInfo::Idle; let mut stats = PlaybackInfo::Idle;
let mut pos_temp; let mut pos_temp;
let mut sent_atf = false;
loop { loop {
// Check for new messages to decide how to proceed // Check for new messages to decide how to proceed
if let Ok(result) = status_rx.recv_timeout(std::time::Duration::from_millis(100)) { if let Ok(result) = status_rx.recv_timeout(std::time::Duration::from_millis(10)) {
stats = result stats = result
} }
@ -489,15 +491,18 @@ fn playback_monitor(
PlaybackInfo::Playing{start, end} if pos_temp.is_some() => { PlaybackInfo::Playing{start, end} if pos_temp.is_some() => {
// Check if the current playback position is close to the end // Check if the current playback position is close to the end
let finish_point = end - Duration::milliseconds(250); let finish_point = end - Duration::milliseconds(250);
if pos_temp.unwrap() >= end { if pos_temp.unwrap().num_microseconds() >= end.num_microseconds() {
let _ = playback_tx.try_send(PlayerCommand::EndOfStream); let _ = playback_tx.try_send(PlayerCommand::EndOfStream);
playbin playbin
.write() .write()
.unwrap() .unwrap()
.set_state(gst::State::Ready) .set_state(gst::State::Ready)
.expect("Unable to set the pipeline state"); .expect("Unable to set the pipeline state");
} else if pos_temp.unwrap() >= finish_point { sent_atf = false
} else if pos_temp.unwrap().num_microseconds() >= finish_point.num_microseconds()
&& !sent_atf {
let _ = playback_tx.try_send(PlayerCommand::AboutToFinish); let _ = playback_tx.try_send(PlayerCommand::AboutToFinish);
sent_atf = true;
} }
// This has to be done AFTER the current time in the file // This has to be done AFTER the current time in the file
@ -508,7 +513,9 @@ fn playback_monitor(
*position.write().unwrap() = None; *position.write().unwrap() = None;
break break
}, },
PlaybackInfo::Idle | PlaybackInfo::Switching => {}, PlaybackInfo::Idle | PlaybackInfo::Switching => {
sent_atf = false
},
_ => () _ => ()
} }

View file

@ -31,7 +31,7 @@ pub enum PlayerState {
VoidPending, VoidPending,
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub enum PlayerCommand { pub enum PlayerCommand {
Play, Play,
Pause, Pause,

View file

@ -218,8 +218,8 @@ impl Song {
self.tags.remove(target_key); self.tags.remove(target_key);
} }
/// Creates a `Song` from a song file /// Creates a `Song` from a music file
pub fn from_file(target_file: &Path) -> Result<Self, Box<dyn Error>> { pub fn from_file<P: ?Sized + AsRef<Path>>(target_file: &P) -> Result<Self, Box<dyn Error>> {
let normal_options = ParseOptions::new().parsing_mode(lofty::ParsingMode::Relaxed); let normal_options = ParseOptions::new().parsing_mode(lofty::ParsingMode::Relaxed);
let blank_tag = &lofty::Tag::new(TagType::Id3v2); let blank_tag = &lofty::Tag::new(TagType::Id3v2);
@ -283,7 +283,7 @@ impl Song {
} }
// Find images around the music file that can be used // Find images around the music file that can be used
let mut found_images = find_images(target_file).unwrap(); let mut found_images = find_images(target_file.as_ref()).unwrap();
album_art.append(&mut found_images); album_art.append(&mut found_images);
// Get the format as a string // Get the format as a string
@ -548,7 +548,7 @@ impl URI {
match self { match self {
URI::Local(loc) => loc.try_exists(), URI::Local(loc) => loc.try_exists(),
URI::Cue { location, .. } => location.try_exists(), URI::Cue { location, .. } => location.try_exists(),
URI::Remote(_, _loc) => todo!(), URI::Remote(_, _loc) => Ok(true), // TODO: Investigate a way to do this?
} }
} }
} }

View file

@ -84,7 +84,6 @@ pub fn find_images(song_path: &Path) -> Result<Vec<AlbumArt>, Box<dyn Error>> {
.filter(|e| e.depth() < 3) .filter(|e| e.depth() < 3)
// Don't recurse very deep // Don't recurse very deep
{ {
println!("{:?}", target_file);
let path = target_file.path(); let path = target_file.path();
if !path.is_file() || !path.exists() { if !path.is_file() || !path.exists() {
continue; continue;