mpris.c (3383B)
1#include "log.h" 2#include "mpris.h" 3#include "player.h" 4#include "util.h" 5 6#include <stdbool.h> 7 8static void dbus_handle_getall(DBusMessage *msg); 9 10int dbus_active; 11DBusConnection *dbus_conn; 12 13static const char *const dbus_mpris_caps[] = { 14 "CanPlay", 15 "CanPause", 16 "CanGoPrevious", 17 "CanGoNext", 18 "CanControl" 19}; 20 21void 22dbus_handle_getall(DBusMessage *msg) 23{ 24 DBusMessage *reply; 25 DBusError err; 26 DBusMessageIter iter, aiter, eiter, viter; 27 const char *interface; 28 dbus_bool_t can; 29 int i, ok; 30 31 dbus_error_init(&err); 32 33 ok = dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &interface); 34 if (ok && strcmp(interface, "org.mpris.MediaPlayer2.Player")) { 35 dbus_error_free(&err); 36 return; 37 } 38 39 reply = dbus_message_new_method_return(msg); 40 41 /* TODO: change to more sane api like gio and gdbus (?) */ 42 43 /* connect argument iter to message */ 44 dbus_message_iter_init_append(reply, &iter); 45 46 /* add array of dict entries { string : variant } */ 47 ASSERT(dbus_message_iter_open_container(&iter, 'a', "{sv}", &aiter)); 48 49 for (i = 0; i < ARRLEN(dbus_mpris_caps); i++) { 50 /* add dict entry */ 51 ASSERT(dbus_message_iter_open_container(&aiter, 52 'e', NULL, &eiter)); 53 54 /* string key */ 55 ASSERT(dbus_message_iter_append_basic(&eiter, 56 's', &dbus_mpris_caps[i])); 57 58 /* variant container */ 59 ASSERT(dbus_message_iter_open_container(&eiter, 60 'v', "b", &viter)); 61 62 can = true; /* bool value */ 63 ASSERT(dbus_message_iter_append_basic(&viter, 'b', &can)); 64 65 dbus_message_iter_close_container(&eiter, &viter); 66 dbus_message_iter_close_container(&aiter, &eiter); 67 } 68 69 dbus_message_iter_close_container(&iter, &aiter); 70 71 dbus_connection_send(dbus_conn, reply, NULL); 72 73 dbus_message_unref(reply); 74 75 dbus_error_free(&err); 76} 77 78void 79dbus_init(void) 80{ 81 DBusError err; 82 int ret; 83 84 dbus_active = 0; 85 86 dbus_error_init(&err); 87 88 /* dont fail if dbus not available, not everyone has 89 * it or needs it to play music */ 90 dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &err); 91 if (dbus_error_is_set(&err) || !dbus_conn) { 92 dbus_error_free(&err); 93 return; 94 } 95 96 /* register as MPRIS compliant player for events */ 97 ret = dbus_bus_request_name(dbus_conn, "org.mpris.MediaPlayer2.tmus", 98 DBUS_NAME_FLAG_REPLACE_EXISTING, &err); 99 if (dbus_error_is_set(&err)) 100 ERRORX(SYSTEM, "mpris register failed"); 101 102 log_info("DBus active!\n"); 103 104 dbus_active = 1; 105 106 dbus_error_free(&err); 107} 108 109void 110dbus_deinit(void) 111{ 112 if (!dbus_active) return; 113 114 dbus_connection_unref(dbus_conn); 115} 116 117void 118dbus_update(void) 119{ 120 DBusMessage *msg; 121 const char *interface; 122 const char *method; 123 124 if (!dbus_active) return; 125 126 dbus_connection_read_write(dbus_conn, 0); 127 msg = dbus_connection_pop_message(dbus_conn); 128 if (msg == NULL) return; 129 130 method = dbus_message_get_member(msg); 131 interface = dbus_message_get_interface(msg); 132 if (!strcmp(interface, "org.freedesktop.DBus.Properties")) { 133 log_info("DBus: Properties requested\n"); 134 if (!strcmp(method, "GetAll")) 135 dbus_handle_getall(msg); 136 } else if (!strcmp(interface, "org.mpris.MediaPlayer2.Player")) { 137 log_info("MPRIS: Method %s\n", method); 138 if (!strcmp(method, "PlayPause")) { 139 player_toggle_pause(); 140 } else if (!strcmp(method, "Pause")) { 141 player_pause(); 142 } else if (!strcmp(method, "Play")) { 143 player_play(); 144 } else if (!strcmp(method, "Next")) { 145 player_next(); 146 } else if (!strcmp(method, "Previous")) { 147 player_prev(); 148 } 149 } 150 151 dbus_message_unref(msg); 152} 153