#include #include #include #include "plugin.h" #include "song.h" typedef struct _MPRIS_Method MPRIS_Method; typedef struct _MPRIS_Signal MPRIS_Signal; static int _mpris_log_domain = -1; #ifdef CRITICAL #undef CRITICAL #endif #ifdef ERR #undef ERR #endif #ifdef WRN #undef WRN #endif #ifdef INF #undef INF #endif #ifdef DBG #undef DBG #endif #define CRITICAL(...) EINA_LOG_DOM_CRIT(_mpris_log_domain, __VA_ARGS__) #define ERR(...) EINA_LOG_DOM_ERR(_mpris_log_domain, __VA_ARGS__) #define WRN(...) EINA_LOG_DOM_WARN(_mpris_log_domain, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_mpris_log_domain, __VA_ARGS__) #define DBG(...) EINA_LOG_DOM_DBG(_mpris_log_domain, __VA_ARGS__) /* * Capabilities and player status values conform to the MPRIS 1.0 standard: * http://www.mpris.org/1.0/spec.html */ typedef enum { MPRIS_CAPABILITY_CAN_GO_NEXT = 1 << 0, MPRIS_CAPABILITY_CAN_GO_PREV = 1 << 1, MPRIS_CAPABILITY_CAN_PAUSE = 1 << 2, MPRIS_CAPABILITY_CAN_PLAY = 1 << 3, MPRIS_CAPABILITY_CAN_SEEK = 1 << 4, MPRIS_CAPABILITY_CAN_PROVIDE_METADATA = 1 << 5, MPRIS_CAPABILITY_HAS_TRACKLIST = 1 << 6 } Mpris_Capabilities; #define APPLICATION_NAME "org.mpris.enjoy" #define PLAYER_INTERFACE_NAME "org.freedesktop.MediaPlayer" #define ROOT_NAME "/Root" /* should really be "/", but this doesn't work correctly :( */ #define TRACKLIST_NAME "/TrackList" #define PLAYER_NAME "/Player" static void _mpris_signal_player_caps_change(int caps); static void _mpris_signal_player_status_change(int playback, int shuffle, int repeat, int endless); static void _mpris_signal_player_track_change(const Song *song); static void _mpris_signal_tracklist_tracklist_change(int size); static void _mpris_append_dict_entry(Eldbus_Message_Iter *array, const char *key, const char *value_type, ...); static Eldbus_Message *_mpris_player_next(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_previous(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_pause(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_stop(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_play(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_seek(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_root_identity(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_root_quit(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_root_version(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_caps_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_volume_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_volume_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_repeat_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_status_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_position_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_player_position_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_song_metadata_reply(const Eldbus_Message *msg, const Song *song); static Eldbus_Message *_mpris_player_metadata_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_tracklist_current_track_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_tracklist_count(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_tracklist_metadata_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static Eldbus_Message *_mpris_tracklist_shuffle_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg); static void _cb_dbus_request_name(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending); static Eldbus_Connection *conn = NULL; static Eldbus_Service_Interface *root, *player, *tracklist; static Eina_List *ev_handlers = NULL; enum { PLAYER_TRACK = 0, PLAYER_STATUS, PLAYER_CAPS }; static const Eldbus_Signal mpris_player_signals[] = { /* Emitted whenever a new song is played; gives the song metadata */ [PLAYER_TRACK] = { "TrackChange", ELDBUS_ARGS({"a{sv}", ""}), 0 }, /* Emitted whenever player's status changes */ [PLAYER_STATUS] = { "StatusChange", ELDBUS_ARGS({"(iiii)", ""}), 0 }, /* Emitted whenever player's capabilities changes */ [PLAYER_CAPS] = { "CapsChange", ELDBUS_ARGS({"i", ""}), 0 }, { } }; enum { TRACK_LIST = 0, }; static const Eldbus_Signal mpris_tracklist_signals[] = { /* Emitted whenever the tracklist changes; gives the number of items */ [TRACK_LIST] = { "TrackListChange", ELDBUS_ARGS({"i", ""}), 0 }, { } }; static const Eldbus_Method mpris_root_methods[] = { /* Returns a string representing the player name */ { "Identity", NULL, ELDBUS_ARGS({"s", "name"}), _mpris_root_identity, 0 }, /* Quits the player */ { "Quit", NULL, NULL, _mpris_root_quit, 0 }, /* Returns a tuple containing the version of MPRIS protocol implemented */ { "MprisVersion", NULL, ELDBUS_ARGS({"(qq)", ""}), _mpris_root_version, 0 }, { } }; static const Eldbus_Method mpris_player_methods[] = { /* Goes to the next song */ { "Next", NULL, NULL, _mpris_player_next, 0 }, /* Goes to the previous song */ { "Prev", NULL, NULL, _mpris_player_previous, 0 }, /* Pauses the song */ { "Pause", NULL, NULL, _mpris_player_pause, 0 }, /* Stops the song */ { "Stop", NULL, NULL, _mpris_player_stop, 0 }, /* If playing, rewind to the beginning of the current track; else, start playing */ { "Play", NULL, NULL, _mpris_player_play, 0 }, /* Seek the current song by given miliseconds */ { "Seek", ELDBUS_ARGS({"x", "time"}), NULL, _mpris_player_seek, 0 }, /* Toggle the current track repeat */ { "Repeat", ELDBUS_ARGS({"b", ""}), NULL, _mpris_player_repeat_set, 0 }, /* Return the status of the media player */ { "GetStatus", NULL, ELDBUS_ARGS({"(iiii)", ""}), _mpris_player_status_get, 0 }, /* Gets all the metadata for the currently played element */ { "GetMetadata", NULL, ELDBUS_ARGS({"a{sv}", "data"}), _mpris_player_metadata_get, 0 }, /* Returns the media player's current capabilities */ { "GetCaps", NULL, ELDBUS_ARGS({"i", ""}), _mpris_player_caps_get, 0 }, /* Sets the volume */ { "VolumeSet", ELDBUS_ARGS({"i", ""}), NULL, _mpris_player_volume_set, 0 }, /* Gets the current volume */ { "VolumeGet", NULL, ELDBUS_ARGS({"i", ""}), _mpris_player_volume_get, 0 }, /* Sets the playing position (in ms) */ { "PositionSet", ELDBUS_ARGS({"i", ""}), NULL, _mpris_player_position_set, 0 }, /* Gets the playing position (in ms) */ { "PositionGet", NULL, ELDBUS_ARGS({"i", ""}), _mpris_player_position_get, 0 }, { } }; static const Eldbus_Method mpris_tracklist_methods[] = { /* Gives all the metadata available at the given position in the track list */ { "GetMetadata", ELDBUS_ARGS({"i", ""}), ELDBUS_ARGS({"a{sv}", ""}), _mpris_tracklist_metadata_get, 0 }, /* Returns the position of the current URI in the track list */ { "GetCurrentTrack", NULL, ELDBUS_ARGS({"i", ""}), _mpris_tracklist_current_track_get, 0 }, /* Returns the number of elements in the track list */ { "GetLength", NULL, ELDBUS_ARGS({"i", ""}), _mpris_tracklist_count, 0 }, /* Appends an URI to the track list */ /*{ "AddTrack", ELDBUS_ARGS({"sb", ""}), ELDBUS_ARGS({"i", ""}), NULL, 0 },*/ /* Removes an URL from the track list */ /*{ "DelTrack", ELDBUS_ARGS({"i", ""}), NULL, NULL, 0 },*/ /* Toggle playlist loop */ /*{ "SetLoop", ELDBUS_ARGS({"b", ""}), NULL, NULL, 0 },*/ /* Toggle playlist shuffle/random */ { "SetRandom", ELDBUS_ARGS({"b", ""}), NULL, _mpris_tracklist_shuffle_set, 0 }, { } }; static int _caps_to_mpris_bits(const Enjoy_Player_Caps caps) { int bits = 0; if (caps.can_go_next) bits |= MPRIS_CAPABILITY_CAN_GO_NEXT; if (caps.can_go_prev) bits |= MPRIS_CAPABILITY_CAN_GO_PREV; if (caps.can_pause) bits |= MPRIS_CAPABILITY_CAN_PAUSE; if (caps.can_play) bits |= MPRIS_CAPABILITY_CAN_PLAY; if (caps.can_seek) bits |= MPRIS_CAPABILITY_CAN_SEEK; if (caps.can_provide_metadata) bits |= MPRIS_CAPABILITY_CAN_PROVIDE_METADATA; if (caps.has_tracklist) bits |= MPRIS_CAPABILITY_HAS_TRACKLIST; return bits; } static Eina_Bool _cb_player_caps_change(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { Enjoy_Player_Caps caps = enjoy_player_caps_get(); int bits = _caps_to_mpris_bits(caps); _mpris_signal_player_caps_change(bits); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _cb_player_status_change(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { Enjoy_Player_Status status = enjoy_player_status_get(); _mpris_signal_player_status_change (status.playback, status.shuffle, status.repeat, status.endless); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _cb_player_track_change(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { _mpris_signal_player_track_change(enjoy_song_current_get()); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _cb_player_tracklist_change(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { _mpris_signal_tracklist_tracklist_change(enjoy_playlist_count()); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool mpris_enable(Enjoy_Plugin *p __UNUSED__) { #define EV_HANDLER(ev, func, data) \ ev_handlers = eina_list_append \ (ev_handlers, ecore_event_handler_add(ev, func, data)) EV_HANDLER(ENJOY_EVENT_PLAYER_CAPS_CHANGE, _cb_player_caps_change, NULL); EV_HANDLER(ENJOY_EVENT_PLAYER_STATUS_CHANGE, _cb_player_status_change, NULL); EV_HANDLER(ENJOY_EVENT_PLAYER_TRACK_CHANGE, _cb_player_track_change, NULL); EV_HANDLER(ENJOY_EVENT_TRACKLIST_TRACKLIST_CHANGE, _cb_player_tracklist_change, NULL); #undef EV_HANDLER eldbus_name_request(conn, APPLICATION_NAME, ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, _cb_dbus_request_name, NULL); return EINA_TRUE; } static Eina_Bool mpris_disable(Enjoy_Plugin *p __UNUSED__) { Ecore_Event_Handler *eh; if (root) { eldbus_service_object_unregister(root); eldbus_service_object_unregister(tracklist); eldbus_service_object_unregister(player); root = NULL; tracklist = NULL; player = NULL; } EINA_LIST_FREE(ev_handlers, eh) ecore_event_handler_del(eh); return EINA_TRUE; } static const Enjoy_Plugin_Api api = { ENJOY_PLUGIN_API_VERSION, mpris_enable, mpris_disable }; static Eina_Bool mpris_init(void) { if (_mpris_log_domain < 0) { _mpris_log_domain = eina_log_domain_register ("enjoy-mpris", EINA_COLOR_LIGHTCYAN); if (_mpris_log_domain < 0) { EINA_LOG_CRIT("Could not register log domain 'enjoy-mpris'"); return EINA_FALSE; } } if (!ENJOY_ABI_CHECK()) { ERR("ABI versions differ: enjoy=%u, mpris=%u", enjoy_abi_version(), ENJOY_ABI_VERSION); goto error; } if (conn) return EINA_TRUE; eldbus_init(); conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); if (!conn) { ERR("Could not get DBus session bus"); goto error; } enjoy_plugin_register("listener/mpris", &api, ENJOY_PLUGIN_PRIORITY_HIGH); return EINA_TRUE; error: eina_log_domain_unregister(_mpris_log_domain); _mpris_log_domain = -1; return EINA_FALSE; } void mpris_shutdown(void) { if (!conn) return; eldbus_connection_unref(conn); eldbus_shutdown(); conn = NULL; if (_mpris_log_domain >= 0) { eina_log_domain_unregister(_mpris_log_domain); _mpris_log_domain = -1; } } static const Eldbus_Service_Interface_Desc root_desc = { PLAYER_INTERFACE_NAME, mpris_root_methods }; static const Eldbus_Service_Interface_Desc player_desc = { PLAYER_INTERFACE_NAME, mpris_player_methods, mpris_player_signals }; static const Eldbus_Service_Interface_Desc tracklist_desc = { PLAYER_INTERFACE_NAME, mpris_tracklist_methods, mpris_tracklist_signals }; static void _cb_dbus_request_name(void *data __UNUSED__, const Eldbus_Message *msg, Eldbus_Pending *pending __UNUSED__) { const char *error_name, *error_txt; unsigned flag; if (eldbus_message_error_get(msg, &error_name, &error_txt)) { ERR("Error %s %s", error_name, error_txt); return; } if (!eldbus_message_arguments_get(msg, "u", &flag)) { ERR("Error getting arguments."); return; } if (flag != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER) { ERR("Bus name in use by another application."); return; } root = eldbus_service_interface_register(conn, ROOT_NAME, &root_desc); player = eldbus_service_interface_register(conn, PLAYER_NAME, &player_desc); tracklist = eldbus_service_interface_register(conn, TRACKLIST_NAME, &tracklist_desc); } static void _mpris_append_dict_entry(Eldbus_Message_Iter *array, const char *key, const char *value_type, ...) { Eldbus_Message_Iter *dict, *val; va_list ap; va_start(ap, value_type); eldbus_message_iter_arguments_append(array, "{sv}", &dict); eldbus_message_iter_basic_append(dict, 's', key); val = eldbus_message_iter_container_new(dict, 'v', value_type); eldbus_message_iter_arguments_vappend(val, value_type, ap); eldbus_message_iter_container_close(dict, val); eldbus_message_iter_container_close(array, dict); va_end(ap); } static void _mpris_message_fill_song_metadata(Eldbus_Message *msg, const Song *song) { Eldbus_Message_Iter *array, *main_iter; if (!song) return; /* Other possible metadata: location s time u mtime u comment s rating u year u date u arturl s genre s mpris:length u trackno s */ main_iter = eldbus_message_iter_get(msg); eldbus_message_iter_arguments_append(main_iter, "a{sv}", &array); if (song->title) _mpris_append_dict_entry(array, "title", "s", song->title); if (song->flags.fetched_album && song->album) _mpris_append_dict_entry(array, "album", "s", song->album); if (song->flags.fetched_artist && song->artist) _mpris_append_dict_entry(array, "artist", "s", song->artist); if (song->flags.fetched_genre && song->genre) _mpris_append_dict_entry(array, "genre", "s", song->genre); _mpris_append_dict_entry(array, "rating", "u", song->rating); _mpris_append_dict_entry(array, "length", "u", song->length); _mpris_append_dict_entry(array, "enjoy:playcount", "i", song->playcnt); _mpris_append_dict_entry(array, "enjoy:filesize", "i", song->size); eldbus_message_iter_container_close(main_iter, array); } void _mpris_signal_player_caps_change(int caps) { static int old_caps = 0; if (caps != old_caps) { int32_t caps32 = caps; eldbus_service_signal_emit(player, PLAYER_CAPS, caps32); old_caps = caps; } } static void _mpris_signal_player_status_change(int playback, int shuffle, int repeat, int endless) { Eldbus_Message *sig; Eldbus_Message_Iter *st, *main_iter; static int old_playback = 0, old_shuffle = 0, old_repeat = 0, old_endless = 0; if (old_playback == playback && old_shuffle == shuffle && old_repeat == repeat && old_endless == endless) return; old_playback = playback; old_shuffle = shuffle; old_repeat = repeat; old_endless = endless; sig = eldbus_service_signal_new(player, PLAYER_STATUS); if (!sig) return; main_iter = eldbus_message_iter_get(sig); eldbus_message_iter_arguments_append(main_iter, "(iiii)", &st); eldbus_message_iter_basic_append(st, 'i', playback); eldbus_message_iter_basic_append(st, 'i', shuffle); eldbus_message_iter_basic_append(st, 'i', repeat); eldbus_message_iter_basic_append(st, 'i', endless); eldbus_message_iter_container_close(main_iter, st); eldbus_service_signal_send(player, sig); } static void _mpris_signal_player_track_change(const Song *song) { static const void *old_song = NULL; if (old_song != song) { Eldbus_Message *sig = eldbus_service_signal_new(player, PLAYER_TRACK); if (!sig) return; _mpris_message_fill_song_metadata(sig, song); eldbus_service_signal_send(player, sig); old_song = song; } } static void _mpris_signal_tracklist_tracklist_change(int size) { int32_t size32 = size; eldbus_service_signal_emit(tracklist, TRACK_LIST, size32); } static Eldbus_Message * _mpris_player_next(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { enjoy_control_next(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_previous(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { enjoy_control_previous(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_pause(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { enjoy_control_pause(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_stop(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { enjoy_control_stop(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_play(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Enjoy_Player_Status status = enjoy_player_status_get(); if (!status.playback) enjoy_position_set(0); enjoy_control_play(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_seek(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { int64_t position; if (!eldbus_message_arguments_get(msg, "x", &position)) goto end; enjoy_control_seek(position); end: return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_root_identity(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { const char *identity = PACKAGE_STRING; Eldbus_Message *reply = eldbus_message_method_return_new(msg); eldbus_message_arguments_append(reply, "s", identity); return reply; } static Eldbus_Message * _mpris_root_quit(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { enjoy_quit(); return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_root_version(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); Eldbus_Message_Iter *main_iter, *s; uint16_t v1 = 1, v2 = 0; main_iter = eldbus_message_iter_get(reply); eldbus_message_iter_arguments_append(main_iter, "(qq)", &s); eldbus_message_iter_arguments_append(s, "qq", v1, v2); eldbus_message_iter_container_close(main_iter, s); return reply; } static Eldbus_Message * _mpris_player_caps_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); int32_t bits = _caps_to_mpris_bits(enjoy_player_caps_get()); eldbus_message_arguments_append(reply, "i", bits); return reply; } static Eldbus_Message * _mpris_player_volume_set(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { int volume; if (!eldbus_message_arguments_get(msg, "i", &volume)) goto end; if (volume > 100) volume = 100; else if (volume < 0) volume = 0; enjoy_volume_set(volume); end: return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_volume_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); int32_t vol = enjoy_volume_get(); eldbus_message_arguments_append(reply, "i", vol); return reply; } static Eldbus_Message * _mpris_player_repeat_set(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eina_Bool repeat; if (!eldbus_message_arguments_get(msg, "b", &repeat)) goto end; enjoy_control_loop_set(repeat); end: return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_status_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); Enjoy_Player_Status status = enjoy_player_status_get(); Eldbus_Message_Iter *main_iter, *st; int32_t p, s, r, e; p = status.playback; s = status.shuffle; r = status.repeat; e = status.endless; main_iter = eldbus_message_iter_get(reply); eldbus_message_iter_arguments_append(main_iter, "(iiii)", &st); eldbus_message_iter_arguments_append(st, "iiii", p, s, r, e); eldbus_message_iter_container_close(main_iter, st); return reply; } static Eldbus_Message * _mpris_player_position_set(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { int position; if (!eldbus_message_arguments_get(msg, "i", &position)) goto end; enjoy_position_set(position); end: return eldbus_message_method_return_new(msg); } static Eldbus_Message * _mpris_player_position_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); int32_t pos = enjoy_position_get(); eldbus_message_arguments_append(reply, "i", pos); return reply; } static Eldbus_Message * _mpris_song_metadata_reply(const Eldbus_Message *msg, const Song *song) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); _mpris_message_fill_song_metadata(reply, song); return reply; } static Eldbus_Message * _mpris_player_metadata_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { return _mpris_song_metadata_reply(msg, enjoy_song_current_get()); } static Eldbus_Message * _mpris_tracklist_current_track_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); int32_t pos = enjoy_playlist_current_position_get(); eldbus_message_arguments_append(reply, "i", pos); return reply; } static Eldbus_Message * _mpris_tracklist_count(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply = eldbus_message_method_return_new(msg); int32_t count = enjoy_playlist_count(); eldbus_message_arguments_append(reply, "i", count); return reply; } static Eldbus_Message * _mpris_tracklist_metadata_get(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eldbus_Message *reply; const Song *song; int position; if (!eldbus_message_arguments_get(msg, "i", &position)) return NULL; song = enjoy_playlist_song_position_get(position); reply = _mpris_song_metadata_reply(msg, song); return reply; } static Eldbus_Message * _mpris_tracklist_shuffle_set(const Eldbus_Service_Interface *iface __UNUSED__, const Eldbus_Message *msg) { Eina_Bool param; if (!eldbus_message_arguments_get(msg, "b", ¶m)) goto end; enjoy_control_shuffle_set(param); end: return eldbus_message_method_return_new(msg); } EINA_MODULE_INIT(mpris_init); EINA_MODULE_SHUTDOWN(mpris_shutdown);