From eeef0d13ff6c4619affc1da80cdeab989150cd89 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 22 Jun 2018 16:03:00 +0300 Subject: [PATCH] PlayerWidget: Use the Gtk Main Context for the gst_player as well. There is no longer a need for sending stuff to the main-thread `Action` channel anymore thanks to this. --- hammond-gtk/src/app.rs | 10 +--- hammond-gtk/src/widgets/player.rs | 83 +++++++++++++++++-------------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index a2317f9..8d89c47 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -5,7 +5,6 @@ use gio::{ SimpleAction, SimpleActionExt, }; use glib; -use gst_player; use gtk; use gtk::prelude::*; use gtk::SettingsExt as GtkSettingsExt; @@ -19,7 +18,6 @@ use stacks::{Content, PopulatedState}; use utils; use widgets::appnotif::{InAppNotification, UndoState}; use widgets::player; -use widgets::player::PlayerExt; use widgets::{about_dialog, mark_all_notif, remove_show_notif}; use std::rc::Rc; @@ -57,9 +55,6 @@ pub enum Action { RemoveShow(Arc), ErrorNotification(String), InitEpisode(i32), - PlayerDurationChanged(player::Duration), - PlayerPositionUpdated(player::Position), - PlayerEndofStream(gst_player::Player), } #[derive(Debug)] @@ -138,7 +133,7 @@ impl App { window.show_all(); window.activate(); - gtk::timeout_add(15, clone!(sender, receiver => move || { + gtk::timeout_add(25, clone!(sender, receiver => move || { // Uses receiver, content, header, sender, overlay, playback match receiver.try_recv() { Ok(Action::RefreshAllViews) => content.update(), @@ -196,9 +191,6 @@ impl App { notif.show(&overlay); }, Ok(Action::InitEpisode(rowid)) => player.initialize_episode(rowid).unwrap(), - Ok(Action::PlayerDurationChanged(dur)) => player.timer.on_duration_changed(dur), - Ok(Action::PlayerPositionUpdated(pos)) => player.timer.on_position_updated(pos), - Ok(Action::PlayerEndofStream(_)) => player.stop(), Err(_) => (), } diff --git a/hammond-gtk/src/widgets/player.rs b/hammond-gtk/src/widgets/player.rs index eaa28d2..0dc73a5 100644 --- a/hammond-gtk/src/widgets/player.rs +++ b/hammond-gtk/src/widgets/player.rs @@ -11,6 +11,7 @@ use glib::SignalHandlerId; use chrono::NaiveTime; use crossbeam_channel::Sender; use failure::Error; +use send_cell::SendCell; use hammond_data::{dbqueries, USER_AGENT}; use hammond_data::{EpisodeWidgetQuery, PodcastCoverQuery}; @@ -23,12 +24,12 @@ use std::path::Path; use std::rc::Rc; #[derive(Debug, Clone, Copy)] -pub enum SeekDirection { +enum SeekDirection { Backwards, Forward, } -pub trait PlayerExt { +trait PlayerExt { fn play(&self); fn pause(&self); fn stop(&self); @@ -72,7 +73,7 @@ impl PlayerInfo { } #[derive(Debug, Clone)] -pub struct PlayerTimes { +struct PlayerTimes { container: gtk::Box, progressed: gtk::Label, duration: gtk::Label, @@ -82,7 +83,7 @@ pub struct PlayerTimes { } #[derive(Debug, Clone, Copy)] -pub struct Duration(ClockTime); +struct Duration(ClockTime); impl Deref for Duration { type Target = ClockTime; @@ -92,7 +93,7 @@ impl Deref for Duration { } #[derive(Debug, Clone, Copy)] -pub struct Position(ClockTime); +struct Position(ClockTime); impl Deref for Position { type Target = ClockTime; @@ -159,14 +160,19 @@ pub struct PlayerWidget { pub action_bar: gtk::ActionBar, player: gst_player::Player, controls: PlayerControls, - pub timer: PlayerTimes, + timer: PlayerTimes, info: PlayerInfo, rate: PlayerRate, } impl Default for PlayerWidget { fn default() -> Self { - let player = gst_player::Player::new(None, None); + let dispatcher = gst_player::PlayerGMainContextSignalDispatcher::new(None); + let player = gst_player::Player::new( + None, + // Use the gtk main thread + Some(&dispatcher.upcast::()), + ); let mut config = player.get_config(); config.set_user_agent(USER_AGENT); @@ -250,40 +256,10 @@ impl PlayerWidget { w } - #[cfg_attr(rustfmt, rustfmt_skip)] fn init(s: &Rc, sender: &Sender) { Self::connect_control_buttons(s); Self::connect_rate_buttons(s); - - // Log gst warnings. - s.player.connect_warning(move |_, warn| warn!("gst warning: {}", warn)); - - // Log gst errors. - s.player.connect_error(clone!(sender => move |_, error| { - // FIXME: should never occur and should not be user facing. - sender.send(Action::ErrorNotification(format!("Player Error: {}", error))) - .map_err(|err| error!("Error: {}", err)) - .ok(); - - })); - - s.player.connect_duration_changed(clone!(sender => move |_, clock| { - sender.send(Action::PlayerDurationChanged(Duration(clock))) - .map_err(|err| error!("Error: {}", err)) - .ok(); - })); - - s.player.connect_position_updated(clone!(sender => move |_, clock| { - sender.send(Action::PlayerPositionUpdated(Position(clock))) - .map_err(|err| error!("Error: {}", err)) - .ok(); - })); - - s.player.connect_end_of_stream(clone!(sender => move |player| { - sender.send(Action::PlayerEndofStream(player.clone())) - .map_err(|err| error!("Error: {}", err)) - .ok(); - })); + Self::connect_gst_signals(s, sender); } #[cfg_attr(rustfmt, rustfmt_skip)] @@ -302,6 +278,37 @@ impl PlayerWidget { s.controls.forward.connect_clicked(clone!(s => move |_| s.fast_forward())); } + #[cfg_attr(rustfmt, rustfmt_skip)] + fn connect_gst_signals(s: &Rc, sender: &Sender) { + // Log gst warnings. + s.player.connect_warning(move |_, warn| warn!("gst warning: {}", warn)); + + // Log gst errors. + s.player.connect_error(clone!(sender => move |_, error| { + // FIXME: should never occur and should not be user facing. + sender.send(Action::ErrorNotification(format!("Player Error: {}", error))) + .map_err(|err| error!("Error: {}", err)) + .ok(); + + })); + + // The followign callbacks require `Send` but are handled by the gtk main loop + let s2 = SendCell::new(s.clone()); + + // Update the duration label and the slider + s.player.connect_duration_changed(clone!(s2 => move |_, clock| { + s2.borrow().timer.on_duration_changed(Duration(clock)); + })); + + // Update the position label and the slider + s.player.connect_position_updated(clone!(s2 => move |_, clock| { + s2.borrow().timer.on_position_updated(Position(clock)); + })); + + // Reset the slider to 0 and show a play button + s.player.connect_end_of_stream(clone!(s2 => move |_| s2.borrow().stop())); + } + #[cfg_attr(rustfmt, rustfmt_skip)] fn connect_rate_buttons(s: &Rc) { s.rate.radio_normal.connect_toggled(clone!(s => move |_| s.on_rate_changed(1.00)));