diff --git a/src/application.rs b/src/application.rs index c6e59c1..98bcb6f 100644 --- a/src/application.rs +++ b/src/application.rs @@ -24,23 +24,30 @@ mod imp { let window = ui::Window::new(self.obj().as_ref()); window.present(); - let mpris = crate::Mpris::new(&window); - let mpris_player = crate::mpris::Player::new(); - - glib::spawn_future_local(async { + glib::spawn_future_local(async move { // run this in glib's main loop let conn = zbus::connection::Builder::session() - .expect("could not create dbus connection builder") + .expect("could not connect to the session bus") .internal_executor(false) - .name("org.mpris.MediaPlayer2.audrey") - .expect("could not register name in session bus") - .serve_at("/org/mpris/MediaPlayer2", mpris) - .expect("could not serve mpris") - .serve_at("/org/mpris/MediaPlayer2", mpris_player) - .expect("could not serve mpris player") .build() .await - .expect("could not build dbus connection"); + .expect("could not build connection to the session bus"); + + crate::Mpris::setup(conn.object_server(), &window) + .await + .expect("could not serve mpris"); + crate::mpris::Player::setup( + conn.object_server(), + &window.playbin().unwrap(), + ) + .await + .expect("could not serve mpris player"); + + // always set up handlers before requesting service name + conn.request_name("org.mpris.MediaPlayer2.audrey") + .await + .expect("could not register name in session bus"); + loop { conn.executor().tick().await; } diff --git a/src/mpris.rs b/src/mpris.rs index 71b3efb..0813578 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -9,22 +9,34 @@ pub struct Mpris { } impl Mpris { - pub fn new(window: &crate::ui::Window) -> Self { - Self { + pub async fn setup( + object_server: &zbus::ObjectServer, + window: &crate::ui::Window, + ) -> Result<(), zbus::Error> { + let mpris = Self { window: window.downgrade().into(), - } + }; + + object_server.at("/org/mpris/MediaPlayer2", mpris).await?; + + //let _mpris = object_server.interface::<_, Self>("/org/mpris/MediaPlayer2").await?; + + Ok(()) } } #[zbus::interface(name = "org.mpris.MediaPlayer2")] impl Mpris { fn raise(&self) { - self.window.upgrade().expect("main window was finalized").present(); + self.window + .upgrade() + .expect("main window was finalized") + .present(); } fn quit(&self) { match self.window.upgrade() { - None => {}, // guess there's nothing to do + None => {} // guess there's nothing to do Some(window) => window.close(), } } diff --git a/src/mpris/player.rs b/src/mpris/player.rs index 3e6dba8..2ea06e4 100644 --- a/src/mpris/player.rs +++ b/src/mpris/player.rs @@ -1,11 +1,45 @@ +use glib::SendWeakRef; +use gtk::glib; use zbus::object_server::SignalEmitter; use zbus::zvariant::{ObjectPath, Value}; -pub struct Player {} +pub struct Player { + playbin: SendWeakRef, + metadata: Vec<(String, String)>, +} impl Player { - pub fn new() -> Self { - Self {} + pub async fn setup( + object_server: &zbus::ObjectServer, + playbin: &crate::Playbin, + ) -> Result<(), zbus::Error> { + use adw::prelude::*; + + let player = Self { + playbin: playbin.downgrade().into(), + metadata: Default::default(), + }; + + object_server.at("/org/mpris/MediaPlayer2", player).await?; + + let player = object_server + .interface::<_, Self>("/org/mpris/MediaPlayer2") + .await?; + + playbin.connect_closure( + "new-track", + false, + glib::closure_local!( + #[strong] + player, + move |_playbin: &crate::Playbin| { + let _player = player.get_mut(); + // TODO + } + ), + ); + + Ok(()) } } @@ -52,7 +86,11 @@ impl Player { #[zbus(property)] fn playback_status(&self) -> String { - "Stopped".into() // TODO + match self.playbin.upgrade().unwrap().state() { + crate::playbin::State::Stopped => "Stopped".into(), + crate::playbin::State::Playing => "Playing".into(), + crate::playbin::State::Paused => "Paused".into(), + } } #[zbus(property)] @@ -76,18 +114,21 @@ impl Player { } #[zbus(property)] - fn shuffle(&self) -> zbus::fdo::Result { - Err(zbus::fdo::Error::NotSupported("Shuffle".into())) + fn shuffle(&self) -> bool { + false } #[zbus(property)] - fn set_shuffle(&self, _shuffle: bool) { - todo!() + fn set_shuffle(&self, _shuffle: bool) -> zbus::Result<()> { + Err(zbus::Error::Unsupported) } #[zbus(property)] fn metadata(&self) -> Vec<(String, Value)> { - vec![] // TODO + self.metadata + .iter() + .map(|(k, v)| (k.clone(), v.into())) + .collect() } #[zbus(property)] @@ -102,7 +143,7 @@ impl Player { #[zbus(property(emits_changed_signal = "false"))] fn position(&self) -> i64 { - 0 // TODO + (self.playbin.upgrade().unwrap().position() * 1e9) as i64 } #[zbus(property)] diff --git a/src/playbin.rs b/src/playbin.rs index e822edd..ceb0f94 100644 --- a/src/playbin.rs +++ b/src/playbin.rs @@ -22,6 +22,7 @@ pub mod ffi { pub fn audrey_playbin_get_state(self_: *mut AudreyPlaybin) -> super::state::ffi::State; pub fn audrey_playbin_pause(self_: *mut AudreyPlaybin); pub fn audrey_playbin_play(self_: *mut AudreyPlaybin); + pub fn audrey_playbin_stop(self_: *mut AudreyPlaybin); pub fn audrey_playbin_get_volume(self_: *mut AudreyPlaybin) -> std::ffi::c_int; pub fn audrey_playbin_set_volume(self_: *mut AudreyPlaybin, volume: std::ffi::c_int); pub fn audrey_playbin_seek(self_: *mut AudreyPlaybin, position: f64); @@ -121,4 +122,8 @@ impl Playbin { pub fn select_track(&self, position: u32) { unsafe { ffi::audrey_playbin_select_track(self.to_glib_none().0, position) } } + + pub fn stop(&self) { + unsafe { ffi::audrey_playbin_stop(self.to_glib_none().0) } + } } diff --git a/src/ui/window.rs b/src/ui/window.rs index d1df364..5376ec6 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -14,10 +14,14 @@ pub mod ffi { extern "C" { pub fn audrey_ui_window_get_type() -> glib::ffi::GType; pub fn audrey_ui_window_new(app: *mut gtk::ffi::GtkApplication) -> *mut AudreyUiWindow; + pub fn audrey_ui_window_get_playbin( + self_: *mut AudreyUiWindow, + ) -> *mut crate::playbin::ffi::AudreyPlaybin; } } use adw::prelude::*; +use glib::translate::{from_glib_none, ToGlibPtr}; use gtk::{gio, glib}; glib::wrapper! { @@ -32,8 +36,10 @@ glib::wrapper! { impl Window { pub fn new(app: &impl IsA) -> Self { - use glib::translate::*; - unsafe { from_glib_none(ffi::audrey_ui_window_new(app.as_ref().to_glib_none().0)) } } + + pub fn playbin(&self) -> Option { + unsafe { from_glib_none(ffi::audrey_ui_window_get_playbin(self.to_glib_none().0)) } + } }