1extern crate dbus;
2extern crate glib;
3use dbus::arg::{RefArg, Variant};
4use dbus::tree::{Factory, Interface, MTFn};
5use dbus::{tree, BusType, Connection, Path, SignalArgs};
6use std::collections::HashMap;
7
8use std::cell::Cell;
9use std::cell::RefCell;
10use std::rc::Rc;
11use std::sync::Arc;
12use std::time::Duration;
13
14use generated::mediaplayer2::org_mpris_media_player2_server;
15use generated::mediaplayer2_player::{
16 org_mpris_media_player2_player_server, OrgFreedesktopDBusPropertiesPropertiesChanged,
17};
18
19use OrgMprisMediaPlayer2;
20use OrgMprisMediaPlayer2Player;
21
22use LoopStatus;
23use Metadata;
24use PlaybackStatus;
25
26pub struct MprisPlayer {
27 connection: Arc<Connection>,
28 factory: Arc<Factory<MTFn<TData>, TData>>,
29
30 can_quit: Cell<bool>, fullscreen: Cell<bool>, can_set_fullscreen: Cell<bool>, can_raise: Cell<bool>, has_track_list: Cell<bool>, identify: String, desktop_entry: String, supported_uri_schemes: RefCell<Vec<String>>, supported_mime_types: RefCell<Vec<String>>, playback_status: Cell<PlaybackStatus>, loop_status: Cell<LoopStatus>, rate: Cell<f64>, shuffle: Cell<bool>, metadata: RefCell<Metadata>, volume: Cell<f64>, position: Cell<i64>, minimum_rate: Cell<f64>, maximum_rate: Cell<f64>, can_go_next: Cell<bool>, can_go_previous: Cell<bool>, can_play: Cell<bool>, can_pause: Cell<bool>, can_seek: Cell<bool>, can_control: Cell<bool>, raise_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
60 quit_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
61 next_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
62 previous_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
63 pause_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
64 play_pause_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
65 stop_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
66 play_cb: RefCell<Vec<Rc<RefCell<dyn FnMut()>>>>,
67 seek_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(i64)>>>>,
68 open_uri_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(&str)>>>>,
69 fullscreen_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(bool)>>>>,
70 loop_status_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(LoopStatus)>>>>,
71 rate_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(f64)>>>>,
72 shuffle_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(bool)>>>>,
73 volume_cb: RefCell<Vec<Rc<RefCell<dyn FnMut(f64)>>>>,
74}
75
76impl MprisPlayer {
77 pub fn new(mpris_name: String, identify: String, desktop_entry: String) -> Arc<Self> {
78 let connection = Arc::new(Connection::get_private(BusType::Session).unwrap());
79 let factory = Arc::new(Factory::new_fn());
80
81 let mpris_player = Arc::new(MprisPlayer {
82 connection,
83 factory,
84
85 can_quit: Cell::new(false),
86 fullscreen: Cell::new(false),
87 can_set_fullscreen: Cell::new(false),
88 can_raise: Cell::new(false),
89 has_track_list: Cell::new(false),
90 identify,
91 desktop_entry,
92 supported_uri_schemes: RefCell::new(Vec::new()),
93 supported_mime_types: RefCell::new(Vec::new()),
94
95 playback_status: Cell::new(PlaybackStatus::Paused),
96 loop_status: Cell::new(LoopStatus::None),
97 rate: Cell::new(0_f64),
98 shuffle: Cell::new(false),
99 metadata: RefCell::new(Metadata::new()),
100 volume: Cell::new(0_f64),
101 position: Cell::new(0),
102 minimum_rate: Cell::new(0_f64),
103 maximum_rate: Cell::new(0_f64),
104 can_go_next: Cell::new(true),
105 can_go_previous: Cell::new(true),
106 can_play: Cell::new(true),
107 can_pause: Cell::new(true),
108 can_seek: Cell::new(false),
109 can_control: Cell::new(true),
110
111 raise_cb: RefCell::new(Vec::new()),
112 quit_cb: RefCell::new(Vec::new()),
113 next_cb: RefCell::new(Vec::new()),
114 previous_cb: RefCell::new(Vec::new()),
115 pause_cb: RefCell::new(Vec::new()),
116 play_pause_cb: RefCell::new(Vec::new()),
117 stop_cb: RefCell::new(Vec::new()),
118 play_cb: RefCell::new(Vec::new()),
119 seek_cb: RefCell::new(Vec::new()),
120 open_uri_cb: RefCell::new(Vec::new()),
121 fullscreen_cb: RefCell::new(Vec::new()),
122 loop_status_cb: RefCell::new(Vec::new()),
123 rate_cb: RefCell::new(Vec::new()),
124 shuffle_cb: RefCell::new(Vec::new()),
125 volume_cb: RefCell::new(Vec::new()),
126 });
127
128 let root_iface: Interface<MTFn<TData>, TData> =
130 org_mpris_media_player2_server(&mpris_player.factory, (), |m| {
131 let a: &Arc<MprisPlayer> = m.path.get_data();
132 let b: &MprisPlayer = a;
133 b
134 });
135
136 let player_iface: Interface<MTFn<TData>, TData> =
138 org_mpris_media_player2_player_server(&mpris_player.factory, (), |m| {
139 let a: &Arc<MprisPlayer> = m.path.get_data();
140 let b: &MprisPlayer = a;
141 b
142 });
143
144 let mut tree = mpris_player.factory.tree(());
146 tree = tree.add(
147 mpris_player
148 .factory
149 .object_path("/org/mpris/MediaPlayer2", mpris_player.clone())
150 .introspectable()
151 .add(root_iface)
152 .add(player_iface),
153 );
154
155 mpris_player
157 .connection
158 .register_name(&format!("org.mpris.MediaPlayer2.{}", mpris_name), 0)
159 .unwrap();
160 tree.set_registered(&mpris_player.connection, true).unwrap();
161 mpris_player.connection.add_handler(tree);
162
163 let connection = mpris_player.connection.clone();
164 glib::source::timeout_add_local(Duration::from_millis(250), move || {
165 connection.incoming(5).next();
166 glib::Continue(true)
167 });
168
169 mpris_player
170 }
171
172 pub fn property_changed<T: 'static>(&self, name: String, value: T)
173 where
174 T: dbus::arg::RefArg,
175 {
176 let mut changed_properties = HashMap::new();
177 let x = Box::new(value) as Box<dyn RefArg>;
178 changed_properties.insert(name, Variant(x));
179
180 let signal = OrgFreedesktopDBusPropertiesPropertiesChanged {
181 changed_properties,
182 interface_name: "org.mpris.MediaPlayer2.Player".to_string(),
183 invalidated_properties: Vec::new(),
184 };
185
186 self.connection
187 .send(signal.to_emit_message(&Path::new("/org/mpris/MediaPlayer2").unwrap()))
188 .unwrap();
189 }
190
191 pub fn set_supported_mime_types(&self, value: Vec<String>) {
196 if *self.supported_mime_types.borrow_mut() != value {
197 *self.supported_mime_types.borrow_mut() = value;
198 self.property_changed(
199 "SupportedMimeTypes".to_string(),
200 self.get_supported_mime_types().unwrap(),
201 );
202 }
203 }
204
205 pub fn set_supported_uri_schemes(&self, value: Vec<String>) {
206 if *self.supported_uri_schemes.borrow_mut() != value {
207 *self.supported_uri_schemes.borrow_mut() = value;
208 self.property_changed(
209 "SupportedUriSchemes".to_string(),
210 self.get_supported_uri_schemes().unwrap(),
211 );
212 }
213 }
214
215 pub fn set_can_quit(&self, value: bool) {
216 if self.can_quit.get() != value {
217 self.can_quit.set(value);
218 self.property_changed("CanQuit".to_string(), self.get_can_quit().unwrap());
219 }
220 }
221
222 pub fn set_can_raise(&self, value: bool) {
223 if self.can_raise.get() != value {
224 self.can_raise.set(value);
225 self.property_changed("CanRaise".to_string(), self.get_can_raise().unwrap());
226 }
227 }
228
229 pub fn set_can_set_fullscreen(&self, value: bool) {
230 if self.can_set_fullscreen.get() != value {
231 self.can_set_fullscreen.set(value);
232 self.property_changed(
233 "CanSetFullscreen".to_string(),
234 self.get_can_set_fullscreen().unwrap(),
235 );
236 }
237 }
238
239 pub fn set_has_track_list(&self, value: bool) {
240 if self.has_track_list.get() != value {
241 self.has_track_list.set(value);
242 self.property_changed(
243 "HasTrackList".to_string(),
244 self.get_has_track_list().unwrap(),
245 );
246 }
247 }
248
249 pub fn set_playback_status(&self, value: PlaybackStatus) {
254 if self.playback_status.get() != value {
255 self.playback_status.set(value);
256 self.property_changed(
257 "PlaybackStatus".to_string(),
258 self.get_playback_status().unwrap(),
259 );
260 }
261 }
262
263 pub fn set_loop_status(&self, value: LoopStatus) {
264 if self.loop_status.get() != value {
265 self.loop_status.set(value);
266 self.property_changed("LoopStatus".to_string(), self.get_loop_status().unwrap());
267 }
268 }
269
270 pub fn set_metadata(&self, metadata: Metadata) {
271 if *self.metadata.borrow_mut() != metadata {
272 *self.metadata.borrow_mut() = metadata;
273 self.property_changed("Metadata".to_string(), self.get_metadata().unwrap());
274 }
275 }
276
277 pub fn set_position(&self, value: i64) {
278 if self.position.get() != value {
279 self.position.set(value);
280 self.property_changed("Position".to_string(), self.get_position().unwrap());
281 }
282 }
283
284 pub fn set_minimum_rate(&self, value: f64) {
285 if self.minimum_rate.get() != value {
286 self.minimum_rate.set(value);
287 self.property_changed("MinimumRate".to_string(), self.get_minimum_rate().unwrap());
288 }
289 }
290
291 pub fn set_maximum_rate(&self, value: f64) {
292 if self.maximum_rate.get() != value {
293 self.maximum_rate.set(value);
294 self.property_changed("MaximumRate".to_string(), self.get_maximum_rate().unwrap());
295 }
296 }
297
298 pub fn set_can_go_next(&self, value: bool) {
299 if self.can_go_next.get() != value {
300 self.can_go_next.set(value);
301 self.property_changed("CanGoNext".to_string(), self.get_can_go_next().unwrap());
302 }
303 }
304
305 pub fn set_can_go_previous(&self, value: bool) {
306 if self.can_go_previous.get() != value {
307 self.can_go_previous.set(value);
308 self.property_changed(
309 "CanGoPrevious".to_string(),
310 self.get_can_go_previous().unwrap(),
311 );
312 }
313 }
314
315 pub fn set_can_play(&self, value: bool) {
316 if self.can_play.get() != value {
317 self.can_play.set(value);
318 self.property_changed("CanPlay".to_string(), self.get_can_play().unwrap());
319 }
320 }
321
322 pub fn set_can_pause(&self, value: bool) {
323 if self.can_pause.get() != value {
324 self.can_pause.set(value);
325 self.property_changed("CanPause".to_string(), self.get_can_pause().unwrap());
326 }
327 }
328
329 pub fn set_can_seek(&self, value: bool) {
330 if self.can_seek.get() != value {
331 self.can_seek.set(value);
332 self.property_changed("CanSeek".to_string(), self.get_can_seek().unwrap());
333 }
334 }
335
336 pub fn set_can_control(&self, value: bool) {
337 if self.can_control.get() != value {
338 self.can_control.set(value);
339 self.property_changed("CanControl".to_string(), self.get_can_control().unwrap());
340 }
341 }
342
343 pub fn connect_raise<F: FnMut() + 'static>(&self, callback: F) {
348 let cell = Rc::new(RefCell::new(callback));
349 self.raise_cb.borrow_mut().push(cell);
350 }
351
352 pub fn connect_quit<F: FnMut() + 'static>(&self, callback: F) {
353 let cell = Rc::new(RefCell::new(callback));
354 self.quit_cb.borrow_mut().push(cell);
355 }
356
357 pub fn connect_next<F: FnMut() + 'static>(&self, callback: F) {
358 let cell = Rc::new(RefCell::new(callback));
359 self.next_cb.borrow_mut().push(cell);
360 }
361
362 pub fn connect_previous<F: FnMut() + 'static>(&self, callback: F) {
363 let cell = Rc::new(RefCell::new(callback));
364 self.previous_cb.borrow_mut().push(cell);
365 }
366
367 pub fn connect_pause<F: FnMut() + 'static>(&self, callback: F) {
368 let cell = Rc::new(RefCell::new(callback));
369 self.pause_cb.borrow_mut().push(cell);
370 }
371
372 pub fn connect_play_pause<F: FnMut() + 'static>(&self, callback: F) {
373 let cell = Rc::new(RefCell::new(callback));
374 self.play_pause_cb.borrow_mut().push(cell);
375 }
376
377 pub fn connect_stop<F: FnMut() + 'static>(&self, callback: F) {
378 let cell = Rc::new(RefCell::new(callback));
379 self.stop_cb.borrow_mut().push(cell);
380 }
381
382 pub fn connect_play<F: FnMut() + 'static>(&self, callback: F) {
383 let cell = Rc::new(RefCell::new(callback));
384 self.play_cb.borrow_mut().push(cell);
385 }
386
387 pub fn connect_seek<F: FnMut(i64) + 'static>(&self, callback: F) {
388 let cell = Rc::new(RefCell::new(callback));
389 self.seek_cb.borrow_mut().push(cell);
390 }
391
392 pub fn connect_open_uri<F: FnMut(&str) + 'static>(&self, callback: F) {
393 let cell = Rc::new(RefCell::new(callback));
394 self.open_uri_cb.borrow_mut().push(cell);
395 }
396
397 pub fn connect_fullscreen<F: FnMut(bool) + 'static>(&self, callback: F) {
398 let cell = Rc::new(RefCell::new(callback));
399 self.fullscreen_cb.borrow_mut().push(cell);
400 }
401
402 pub fn connect_loop_status<F: FnMut(LoopStatus) + 'static>(&self, callback: F) {
403 let cell = Rc::new(RefCell::new(callback));
404 self.loop_status_cb.borrow_mut().push(cell);
405 }
406
407 pub fn connect_rate<F: FnMut(f64) + 'static>(&self, callback: F) {
408 let cell = Rc::new(RefCell::new(callback));
409 self.rate_cb.borrow_mut().push(cell);
410 }
411
412 pub fn connect_shuffle<F: FnMut(bool) + 'static>(&self, callback: F) {
413 let cell = Rc::new(RefCell::new(callback));
414 self.shuffle_cb.borrow_mut().push(cell);
415 }
416
417 pub fn connect_volume<F: FnMut(f64) + 'static>(&self, callback: F) {
418 let cell = Rc::new(RefCell::new(callback));
419 self.volume_cb.borrow_mut().push(cell);
420 }
421}
422
423impl OrgMprisMediaPlayer2 for MprisPlayer {
424 type Err = tree::MethodErr;
425
426 fn raise(&self) -> Result<(), Self::Err> {
427 for callback in self.raise_cb.borrow_mut().iter() {
428 let mut closure = callback.borrow_mut();
429 (&mut *closure)();
430 }
431 Ok(())
432 }
433
434 fn quit(&self) -> Result<(), Self::Err> {
435 for callback in self.quit_cb.borrow_mut().iter() {
436 let mut closure = callback.borrow_mut();
437 (&mut *closure)();
438 }
439 Ok(())
440 }
441
442 fn get_can_quit(&self) -> Result<bool, Self::Err> {
443 Ok(self.can_quit.get())
444 }
445
446 fn get_fullscreen(&self) -> Result<bool, Self::Err> {
447 Ok(self.fullscreen.get())
448 }
449
450 fn set_fullscreen(&self, value: bool) -> Result<(), Self::Err> {
451 self.fullscreen.set(value);
452 self.property_changed("Fullscreen".to_string(), self.get_fullscreen().unwrap());
453 for callback in self.fullscreen_cb.borrow_mut().iter() {
454 let mut closure = callback.borrow_mut();
455 (&mut *closure)(value);
456 }
457 Ok(())
458 }
459
460 fn get_can_set_fullscreen(&self) -> Result<bool, Self::Err> {
461 Ok(self.can_set_fullscreen.get())
462 }
463
464 fn get_can_raise(&self) -> Result<bool, Self::Err> {
465 Ok(self.can_raise.get())
466 }
467
468 fn get_has_track_list(&self) -> Result<bool, Self::Err> {
469 Ok(self.has_track_list.get())
470 }
471
472 fn get_identity(&self) -> Result<String, Self::Err> {
473 Ok(self.identify.clone())
474 }
475
476 fn get_desktop_entry(&self) -> Result<String, Self::Err> {
477 Ok(self.desktop_entry.clone())
478 }
479
480 fn get_supported_uri_schemes(&self) -> Result<Vec<String>, Self::Err> {
481 Ok(self.supported_uri_schemes.borrow().to_vec())
482 }
483
484 fn get_supported_mime_types(&self) -> Result<Vec<String>, Self::Err> {
485 Ok(self.supported_mime_types.borrow().to_vec())
486 }
487}
488
489impl OrgMprisMediaPlayer2Player for MprisPlayer {
490 type Err = tree::MethodErr;
491
492 fn next(&self) -> Result<(), Self::Err> {
493 for callback in self.next_cb.borrow_mut().iter() {
494 let mut closure = callback.borrow_mut();
495 (&mut *closure)();
496 }
497 Ok(())
498 }
499
500 fn previous(&self) -> Result<(), Self::Err> {
501 for callback in self.previous_cb.borrow_mut().iter() {
502 let mut closure = callback.borrow_mut();
503 (&mut *closure)();
504 }
505 Ok(())
506 }
507
508 fn pause(&self) -> Result<(), Self::Err> {
509 for callback in self.pause_cb.borrow_mut().iter() {
510 let mut closure = callback.borrow_mut();
511 (&mut *closure)();
512 }
513 Ok(())
514 }
515
516 fn play_pause(&self) -> Result<(), Self::Err> {
517 for callback in self.play_pause_cb.borrow_mut().iter() {
518 let mut closure = callback.borrow_mut();
519 (&mut *closure)();
520 }
521 Ok(())
522 }
523
524 fn stop(&self) -> Result<(), Self::Err> {
525 for callback in self.stop_cb.borrow_mut().iter() {
526 let mut closure = callback.borrow_mut();
527 (&mut *closure)();
528 }
529 Ok(())
530 }
531
532 fn play(&self) -> Result<(), Self::Err> {
533 for callback in self.play_cb.borrow_mut().iter() {
534 let mut closure = callback.borrow_mut();
535 (&mut *closure)();
536 }
537 Ok(())
538 }
539
540 fn seek(&self, offset: i64) -> Result<(), Self::Err> {
541 for callback in self.seek_cb.borrow_mut().iter() {
542 let mut closure = callback.borrow_mut();
543 (&mut *closure)(offset);
544 }
545 Ok(())
546 }
547
548 fn set_position(&self, _track_id: dbus::Path, position: i64) -> Result<(), Self::Err> {
549 self.position.set(position);
550 self.property_changed("Position".to_string(), self.get_position().unwrap());
551 Ok(())
552 }
553
554 fn open_uri(&self, uri: &str) -> Result<(), Self::Err> {
555 for callback in self.open_uri_cb.borrow_mut().iter() {
556 let mut closure = callback.borrow_mut();
557 (&mut *closure)(uri);
558 }
559 Ok(())
560 }
561
562 fn get_playback_status(&self) -> Result<String, Self::Err> {
563 Ok(self.playback_status.get().value())
564 }
565
566 fn get_loop_status(&self) -> Result<String, Self::Err> {
567 Ok(self.loop_status.get().value())
568 }
569
570 fn set_loop_status(&self, value: String) -> Result<(), Self::Err> {
571 let ls = match value.as_ref() {
572 "Track" => LoopStatus::Track,
573 "Playlist" => LoopStatus::Playlist,
574 _ => LoopStatus::None,
575 };
576 self.loop_status.set(ls);
577 self.property_changed("LoopStatus".to_string(), self.get_loop_status().unwrap());
578 for callback in self.loop_status_cb.borrow_mut().iter() {
579 let mut closure = callback.borrow_mut();
580 (&mut *closure)(ls);
581 }
582 Ok(())
583 }
584
585 fn get_rate(&self) -> Result<f64, Self::Err> {
586 Ok(self.rate.get())
587 }
588
589 fn set_rate(&self, value: f64) -> Result<(), Self::Err> {
590 self.rate.set(value);
591 self.property_changed("Rate".to_string(), self.get_rate().unwrap());
592 for callback in self.rate_cb.borrow_mut().iter() {
593 let mut closure = callback.borrow_mut();
594 (&mut *closure)(value);
595 }
596 Ok(())
597 }
598
599 fn get_shuffle(&self) -> Result<bool, Self::Err> {
600 Ok(self.shuffle.get())
601 }
602
603 fn set_shuffle(&self, value: bool) -> Result<(), Self::Err> {
604 self.shuffle.set(value);
605 self.property_changed("Shuffle".to_string(), self.get_volume().unwrap());
606 for callback in self.shuffle_cb.borrow_mut().iter() {
607 let mut closure = callback.borrow_mut();
608 (&mut *closure)(value);
609 }
610 Ok(())
611 }
612
613 fn get_metadata(
614 &self,
615 ) -> Result<HashMap<String, Variant<Box<dyn RefArg + 'static>>>, Self::Err> {
616 let metadata = self.metadata.borrow().to_hashmap();
617 Ok(metadata)
618 }
619
620 fn get_volume(&self) -> Result<f64, Self::Err> {
621 Ok(self.volume.get())
622 }
623
624 fn set_volume(&self, value: f64) -> Result<(), Self::Err> {
625 self.volume.set(value);
626 self.property_changed("Volume".to_string(), self.get_volume().unwrap());
627 for callback in self.volume_cb.borrow_mut().iter() {
628 let mut closure = callback.borrow_mut();
629 (&mut *closure)(value);
630 }
631 Ok(())
632 }
633
634 fn get_position(&self) -> Result<i64, Self::Err> {
635 Ok(self.position.get())
636 }
637
638 fn get_minimum_rate(&self) -> Result<f64, Self::Err> {
639 Ok(self.minimum_rate.get())
640 }
641
642 fn get_maximum_rate(&self) -> Result<f64, Self::Err> {
643 Ok(self.maximum_rate.get())
644 }
645
646 fn get_can_go_next(&self) -> Result<bool, Self::Err> {
647 Ok(self.can_go_next.get())
648 }
649
650 fn get_can_go_previous(&self) -> Result<bool, Self::Err> {
651 Ok(self.can_go_previous.get())
652 }
653
654 fn get_can_play(&self) -> Result<bool, Self::Err> {
655 Ok(self.can_play.get())
656 }
657
658 fn get_can_pause(&self) -> Result<bool, Self::Err> {
659 Ok(self.can_pause.get())
660 }
661
662 fn get_can_seek(&self) -> Result<bool, Self::Err> {
663 Ok(self.can_seek.get())
664 }
665
666 fn get_can_control(&self) -> Result<bool, Self::Err> {
667 Ok(self.can_control.get())
668 }
669}
670
671impl ::std::fmt::Debug for MprisPlayer {
672 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
673 write!(f, "mprisplayer")
674 }
675}
676
677#[derive(Copy, Clone, Default, Debug)]
678pub struct TData;
679impl tree::DataType for TData {
680 type Tree = ();
681 type ObjectPath = Arc<MprisPlayer>;
682 type Property = ();
683 type Interface = ();
684 type Method = ();
685 type Signal = ();
686}