mirror of
https://github.com/Dangoware/dango-music-player.git
synced 2025-04-19 10:02:53 -05:00
Fixed buffering for GStreamer
This commit is contained in:
parent
dd7f447d46
commit
48c7e29eca
4 changed files with 37 additions and 31 deletions
|
@ -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
|
||||||
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue