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.
This commit is contained in:
Jordan Petridis 2018-06-22 16:03:00 +03:00
parent 0686fca3b0
commit eeef0d13ff
2 changed files with 46 additions and 47 deletions

View File

@ -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<Podcast>),
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(_) => (),
}

View File

@ -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::<gst_player::PlayerSignalDispatcher>()),
);
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<Self>, sender: &Sender<Action>) {
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<Self>, sender: &Sender<Action>) {
// 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<Self>) {
s.rate.radio_normal.connect_toggled(clone!(s => move |_| s.on_rate_changed(1.00)));