rework mpris notification of PropertiesChanged
as sending out PropertiesChanged events was triggered asynchronously by a message queue, retrieving the metadata during message formatting is too late. this resulted in two PropertiesChanged messages announcing the new track as playing. this should prevent such a scenario. as discussed in #89
This commit is contained in:
49
src/mpris.rs
49
src/mpris.rs
@@ -10,6 +10,10 @@ use dbus::{Path, SignalArgs};
|
|||||||
|
|
||||||
use queue::{Queue, RepeatSetting};
|
use queue::{Queue, RepeatSetting};
|
||||||
use spotify::{PlayerEvent, Spotify};
|
use spotify::{PlayerEvent, Spotify};
|
||||||
|
use track::Track;
|
||||||
|
|
||||||
|
type Metadata = HashMap<String, Variant<Box<RefArg>>>;
|
||||||
|
struct MprisState(String, Option<Track>);
|
||||||
|
|
||||||
fn get_playbackstatus(spotify: Arc<Spotify>) -> String {
|
fn get_playbackstatus(spotify: Arc<Spotify>) -> String {
|
||||||
match spotify.get_current_status() {
|
match spotify.get_current_status() {
|
||||||
@@ -20,11 +24,9 @@ fn get_playbackstatus(spotify: Arc<Spotify>) -> String {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_metadata(queue: Arc<Queue>) -> HashMap<String, Variant<Box<RefArg>>> {
|
fn get_metadata(track: Option<Track>) -> Metadata {
|
||||||
let mut hm: HashMap<String, Variant<Box<RefArg>>> = HashMap::new();
|
let mut hm: Metadata = HashMap::new();
|
||||||
|
let track = track.as_ref();
|
||||||
let t = queue.get_current();
|
|
||||||
let track = t.as_ref(); // TODO
|
|
||||||
|
|
||||||
hm.insert(
|
hm.insert(
|
||||||
"mpris:trackid".to_string(),
|
"mpris:trackid".to_string(),
|
||||||
@@ -81,7 +83,7 @@ fn get_metadata(queue: Arc<Queue>) -> HashMap<String, Variant<Box<RefArg>>> {
|
|||||||
hm
|
hm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Queue>, rx: mpsc::Receiver<()>) {
|
fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Queue>, rx: mpsc::Receiver<MprisState>) {
|
||||||
let conn = Rc::new(
|
let conn = Rc::new(
|
||||||
dbus::Connection::get_private(dbus::BusType::Session).expect("Failed to connect to dbus"),
|
dbus::Connection::get_private(dbus::BusType::Session).expect("Failed to connect to dbus"),
|
||||||
);
|
);
|
||||||
@@ -193,7 +195,7 @@ fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Queue>, rx: mpsc::Receiver<
|
|||||||
f.property::<HashMap<String, Variant<Box<RefArg>>>, _>("Metadata", ())
|
f.property::<HashMap<String, Variant<Box<RefArg>>>, _>("Metadata", ())
|
||||||
.access(Access::Read)
|
.access(Access::Read)
|
||||||
.on_get(move |iter, _| {
|
.on_get(move |iter, _| {
|
||||||
let hm = get_metadata(queue.clone());
|
let hm = get_metadata(queue.clone().get_current());
|
||||||
|
|
||||||
iter.append(hm);
|
iter.append(hm);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -397,43 +399,54 @@ fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Queue>, rx: mpsc::Receiver<
|
|||||||
warn!("Unhandled dbus message: {:?}", m);
|
warn!("Unhandled dbus message: {:?}", m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if rx.try_recv().is_ok() {
|
if let Ok(state) = rx.try_recv() {
|
||||||
let mut changed: PropertiesPropertiesChanged = Default::default();
|
let mut changed: PropertiesPropertiesChanged = Default::default();
|
||||||
|
debug!("mpris PropertiesChanged: status {}, track: {:?}", state.0, state.1);
|
||||||
|
|
||||||
changed.interface_name = "org.mpris.MediaPlayer2.Player".to_string();
|
changed.interface_name = "org.mpris.MediaPlayer2.Player".to_string();
|
||||||
changed.changed_properties.insert(
|
changed.changed_properties.insert(
|
||||||
"Metadata".to_string(),
|
"Metadata".to_string(),
|
||||||
Variant(Box::new(get_metadata(queue.clone()))),
|
Variant(Box::new(get_metadata(state.1))),
|
||||||
);
|
);
|
||||||
|
|
||||||
changed.changed_properties.insert(
|
changed.changed_properties.insert(
|
||||||
"PlaybackStatus".to_string(),
|
"PlaybackStatus".to_string(),
|
||||||
Variant(Box::new(get_playbackstatus(spotify.clone()))),
|
Variant(Box::new(state.0)),
|
||||||
);
|
);
|
||||||
|
|
||||||
conn.send(
|
conn.send(
|
||||||
changed.to_emit_message(&Path::new("/org/mpris/MediaPlayer2".to_string()).unwrap()),
|
changed.to_emit_message(&Path::new("/org/mpris/MediaPlayer2".to_string()).unwrap()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MprisManager {
|
pub struct MprisManager {
|
||||||
tx: mpsc::Sender<()>,
|
tx: mpsc::Sender<MprisState>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
spotify: Arc<Spotify>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MprisManager {
|
impl MprisManager {
|
||||||
pub fn new(spotify: Arc<Spotify>, queue: Arc<Queue>) -> Self {
|
pub fn new(spotify: Arc<Spotify>, queue: Arc<Queue>) -> Self {
|
||||||
let (tx, rx) = mpsc::channel::<()>();
|
let (tx, rx) = mpsc::channel::<MprisState>();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
{
|
||||||
run_dbus_server(spotify, queue, rx);
|
let spotify = spotify.clone();
|
||||||
});
|
let queue = queue.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
run_dbus_server(spotify.clone(), queue.clone(), rx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
MprisManager { tx }
|
MprisManager { tx, queue, spotify }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self) {
|
pub fn update(&self) {
|
||||||
self.tx.send(()).unwrap();
|
let status = get_playbackstatus(self.spotify.clone());
|
||||||
|
let track = self.queue.get_current();
|
||||||
|
self.tx.send(MprisState(status, track)).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user