Rage video and audio player
https://www.enlightenment.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
586 lines
14 KiB
586 lines
14 KiB
#include <Elementary.h> |
|
#include "main.h" |
|
#include "win.h" |
|
#include "browser.h" |
|
#include "video.h" |
|
#include "winvid.h" |
|
#include "winlist.h" |
|
#include "config.h" |
|
#include "mpris.h" |
|
|
|
static Evas_Object *mainwin = NULL; |
|
static Eldbus_Connection *conn = NULL; |
|
static Eldbus_Service_Interface *iface = NULL; |
|
static Eldbus_Service_Interface *iface_player = NULL; |
|
|
|
#define SERVICE "org.mpris.MediaPlayer2.rage" |
|
#define PATH "/org/mpris/MediaPlayer2" |
|
|
|
static void |
|
_cb_name_request(void *data EINA_UNUSED, const Eldbus_Message *msg, |
|
Eldbus_Pending *pending EINA_UNUSED) |
|
{ |
|
unsigned int flag; |
|
|
|
if (eldbus_message_error_get(msg, NULL, NULL)) |
|
{ |
|
fprintf(stderr, "Could not request bus name"); |
|
return; |
|
} |
|
if (!eldbus_message_arguments_get(msg, "u", &flag)) |
|
{ |
|
fprintf(stderr, "Could not get arguments on on_name_request"); |
|
return; |
|
} |
|
if (!(flag & ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER)) |
|
fprintf(stderr, "Name already in use\n"); |
|
} |
|
|
|
/* |
|
https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html |
|
*/ |
|
|
|
#define API(fn) \ |
|
static Eldbus_Message * \ |
|
_cb_api_##fn(const Eldbus_Service_Interface *iface EINA_UNUSED, \ |
|
const Eldbus_Message *msg) |
|
#define GETTER(fn) \ |
|
static Eina_Bool \ |
|
_cb_prop_##fn##_get(const Eldbus_Service_Interface *iface EINA_UNUSED, \ |
|
const char *propname EINA_UNUSED, \ |
|
Eldbus_Message_Iter *iter, \ |
|
const Eldbus_Message *request_msg EINA_UNUSED, \ |
|
Eldbus_Message **error EINA_UNUSED) |
|
|
|
#define SETTER(fn) \ |
|
static Eldbus_Message * \ |
|
_cb_prop_##fn##_set(const Eldbus_Service_Interface *iface EINA_UNUSED, \ |
|
const char *propname EINA_UNUSED, \ |
|
Eldbus_Message_Iter *iter, \ |
|
const Eldbus_Message *msg) |
|
#define PROP_RO(str, type, prop) \ |
|
{ str, type, _cb_prop_##prop##_get, NULL, 0 } |
|
#define PROP_RW(str, type, prop) \ |
|
{ str, type, _cb_prop_##prop##_get, _cb_prop_##prop##_set, 0 } |
|
#define METHOD(str, type, fn) \ |
|
{ str, NULL, type, _cb_api_##fn, 0 } |
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
|
|
GETTER(can_quit) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(fullscreen) |
|
{ |
|
Eina_Bool fs = elm_win_fullscreen_get(mainwin); |
|
eldbus_message_iter_arguments_append(iter, "b", fs); |
|
return EINA_TRUE; |
|
} |
|
|
|
SETTER(fullscreen) |
|
{ |
|
Eina_Bool fs = EINA_FALSE; |
|
eldbus_message_iter_arguments_get(iter, "d", &fs); |
|
elm_win_fullscreen_set(mainwin, fs); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
GETTER(can_set_fullscreen) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_raise) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(has_track_list) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_FALSE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(identity) |
|
{ |
|
char buf[] = "Rage"; |
|
|
|
eldbus_message_iter_arguments_append(iter, "s", buf); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(desktop_entry) |
|
{ |
|
char buf[] = "rage"; |
|
eldbus_message_iter_arguments_append(iter, "s", buf); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(supported_mime_types) |
|
{ |
|
Eldbus_Message_Iter *array = NULL; |
|
|
|
eldbus_message_iter_arguments_append(iter, "as", &array); |
|
eldbus_message_iter_arguments_append(array, "s", "application/ogg"); |
|
eldbus_message_iter_arguments_append(array, "s", "video/mpeg"); |
|
eldbus_message_iter_arguments_append(array, "s", "audio/*"); |
|
eldbus_message_iter_arguments_append(array, "s", "video/*"); |
|
eldbus_message_iter_arguments_append(array, "s", "item3"); |
|
eldbus_message_iter_container_close(iter, array); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(supported_uri_schemes) |
|
{ |
|
Eldbus_Message_Iter *array = NULL; |
|
|
|
eldbus_message_iter_arguments_append(iter, "as", &array); |
|
eldbus_message_iter_arguments_append(array, "s", "file"); |
|
eldbus_message_iter_arguments_append(array, "s", "http"); |
|
eldbus_message_iter_arguments_append(array, "s", "https"); |
|
eldbus_message_iter_arguments_append(array, "s", "rtsp"); |
|
eldbus_message_iter_container_close(iter, array); |
|
return EINA_TRUE; |
|
} |
|
|
|
static const Eldbus_Property properties[] = |
|
{ |
|
PROP_RO("CanQuit", "b", can_quit), |
|
PROP_RW("Fullscreen", "b", fullscreen), |
|
PROP_RO("CanSetFullscreen", "b", can_set_fullscreen), |
|
PROP_RO("CanRaise", "b", can_raise), |
|
PROP_RO("HasTrackList", "b", has_track_list), |
|
PROP_RO("Identity", "s", identity), |
|
PROP_RO("DesktopEntry", "s", desktop_entry), |
|
PROP_RO("SupportedMimeTypes", "as", supported_mime_types), |
|
PROP_RO("SupportedUriSchemes", "as", supported_uri_schemes), |
|
{ 0 } |
|
}; |
|
|
|
API(quit) |
|
{ |
|
evas_object_del(mainwin); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(raize) |
|
{ |
|
elm_win_raise(mainwin); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
static const Eldbus_Method methods[] = |
|
{ |
|
METHOD("Quit", NULL, quit), |
|
METHOD("Raise", NULL, raize), |
|
{ 0 } |
|
}; |
|
|
|
static const Eldbus_Service_Interface_Desc desc = { |
|
"org.mpris.MediaPlayer2", methods, NULL, properties, NULL, NULL |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
|
|
GETTER(playback_status) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
const char *buf = "Stopped"; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
if (video_play_get(inf->vid)) buf = "Playing"; |
|
else buf = "Paused"; |
|
end: |
|
eldbus_message_iter_arguments_append(iter, "s", buf); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(loop_status) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
const char *buf = "None"; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
if (video_loop_get(inf->vid)) buf = "Track"; |
|
else buf = "None"; |
|
// "Playlist"; |
|
end: |
|
eldbus_message_iter_arguments_append(iter, "s", buf); |
|
return EINA_TRUE; |
|
} |
|
|
|
SETTER(loop_status) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
const char *buf = NULL; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
eldbus_message_iter_arguments_get(iter, "s", &buf); |
|
if (buf) |
|
{ |
|
if (!strcmp(buf, "None")) |
|
{ |
|
video_loop_set(inf->vid, EINA_FALSE); |
|
mpris_loop_status_change(); |
|
} |
|
else if (!strcmp(buf, "Track")) |
|
{ |
|
video_loop_set(inf->vid, EINA_TRUE); |
|
mpris_loop_status_change(); |
|
} |
|
else if (!strcmp(buf, "Playlist")) |
|
{ |
|
fprintf(stderr, "Cannot do playlist loop yet.\n"); |
|
} |
|
if (video_loop_get(inf->vid)) |
|
elm_layout_signal_emit(inf->lay, "action,loop", "rage"); |
|
else |
|
elm_layout_signal_emit(inf->lay, "action,sequential", "rage"); |
|
} |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
GETTER(rate) |
|
{ |
|
double rate = 1.0; |
|
eldbus_message_iter_arguments_append(iter, "d", rate); |
|
return EINA_TRUE; |
|
} |
|
|
|
SETTER(rate) |
|
{ |
|
double rate = 1.0; |
|
eldbus_message_iter_arguments_get(iter, "d", &rate); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
GETTER(shuffle) |
|
{ |
|
Eina_Bool shuffle = EINA_FALSE; |
|
eldbus_message_iter_arguments_append(iter, "b", shuffle); |
|
return EINA_TRUE; |
|
} |
|
|
|
SETTER(shuffle) |
|
{ |
|
Eina_Bool shuffle = EINA_FALSE; |
|
fprintf(stderr, "Cannot set shuffle mode yet.\n"); |
|
eldbus_message_iter_arguments_get(iter, "b", &shuffle); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
/* |
|
GETTER(metadata) |
|
{ |
|
// XXX: return metadata |
|
eldbus_message_iter_arguments_append(iter, "a{sv}", NULL); |
|
return EINA_TRUE; |
|
} |
|
*/ |
|
|
|
GETTER(volume) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
double vol = 1.0; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
vol = video_volume_get(inf->vid); |
|
end: |
|
eldbus_message_iter_arguments_append(iter, "d", vol); |
|
return EINA_TRUE; |
|
} |
|
|
|
SETTER(volume) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
double vol = 1.0; // max |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
eldbus_message_iter_arguments_get(iter, "d", &vol); |
|
if (vol < 0.0) vol = 0.0; |
|
if (vol > 1.0) vol = 1.0; |
|
video_volume_set(inf->vid, vol); |
|
mpris_volume_change(); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
GETTER(position) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
uint64_t pos = 0; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
pos = video_position_get(inf->vid) * 1000000.0; |
|
end: |
|
eldbus_message_iter_arguments_append(iter, "x", pos); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(minimum_rate) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "d", 1.0); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(maximum_rate) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "d", 1.0); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_go_next) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_go_previous) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_play) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_pause) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_seek) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
GETTER(can_control) |
|
{ |
|
eldbus_message_iter_arguments_append(iter, "b", EINA_TRUE); |
|
return EINA_TRUE; |
|
} |
|
|
|
static const Eldbus_Property properties_player[] = |
|
{ |
|
PROP_RO("PlaybackStatus", "s", playback_status), |
|
PROP_RW("LoopStatus", "s", loop_status), |
|
PROP_RW("Rate", "d", rate), |
|
PROP_RW("Shuffle", "b", shuffle), |
|
// PROP_RO("Metadata", "a{sv}", metadata), |
|
PROP_RW("Volume", "d", volume), |
|
PROP_RO("Position", "x", position), |
|
PROP_RO("MinimumRate", "d", minimum_rate), |
|
PROP_RO("MaximumRate", "d", maximum_rate), |
|
PROP_RO("CanGoNext", "b", can_go_next), |
|
PROP_RO("CanGoPrevious", "b", can_go_previous), |
|
PROP_RO("CanPlay", "b", can_play), |
|
PROP_RO("CanPause", "b", can_pause), |
|
PROP_RO("CanSeek", "b", can_seek), |
|
PROP_RO("CanControl", "b", can_control), |
|
{ 0 } |
|
}; |
|
|
|
API(next) |
|
{ |
|
if (browser_visible()) goto end; |
|
win_do_next(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(previous) |
|
{ |
|
if (browser_visible()) goto end; |
|
win_do_prev(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(pause) |
|
{ |
|
if (browser_visible()) goto end; |
|
win_do_pause(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(play_pause) |
|
{ |
|
if (browser_visible()) goto end; |
|
win_do_play_pause(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(stop) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
video_stop(inf->vid); |
|
elm_layout_signal_emit(inf->lay, "action,stop", "rage"); |
|
elm_layout_signal_emit(inf->lay, "state,default", "rage"); |
|
if (inf->browse_mode) browser_show(mainwin); |
|
else evas_object_del(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(play) |
|
{ |
|
if (browser_visible()) goto end; |
|
win_do_play(mainwin); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(seek) |
|
{ |
|
Inf *inf = evas_object_data_get(mainwin, "inf"); |
|
uint64_t pos = 0; |
|
|
|
if (!inf) goto end; |
|
if (browser_visible()) goto end; |
|
// XXX: seek to pos in usec |
|
if (!eldbus_message_arguments_get(msg, "x", &pos)) |
|
return eldbus_message_error_new(msg, "Invalid arguments", "Error getting position"); |
|
video_position_set(inf->vid, (double)pos / 1000000.0); |
|
end: |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(set_position) |
|
{ |
|
fprintf(stderr, "Cannot do set_position yet.\n"); |
|
// XXX: get track + position |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
API(open_uri) |
|
{ |
|
char *uri = NULL; |
|
|
|
// XXX: handle uri open |
|
if (!eldbus_message_arguments_get(msg, "s", &uri)) |
|
return eldbus_message_error_new(msg, "Invalid arguments", "Error getting URI string"); |
|
win_video_insert(mainwin, uri); |
|
win_video_next(mainwin); |
|
win_list_content_update(mainwin); |
|
browser_hide(mainwin); |
|
return eldbus_message_method_return_new(msg); |
|
} |
|
|
|
static const Eldbus_Method methods_player[] = |
|
{ |
|
METHOD("Next", NULL, next), |
|
METHOD("Previous", NULL, previous), |
|
METHOD("Pause", NULL, pause), |
|
METHOD("PlayPause", NULL, play_pause), |
|
METHOD("Stop", NULL, stop), |
|
METHOD("Play", NULL, play), |
|
METHOD("Seek", ELDBUS_ARGS({"x", "Offset"}), seek), |
|
METHOD("SetPosition", ELDBUS_ARGS({ "ox", "Path,Position"}), set_position), |
|
METHOD("OpenUri", ELDBUS_ARGS({"s", "Uri"}), open_uri), |
|
{ 0 } |
|
}; |
|
|
|
static const Eldbus_Signal signals_player[] = |
|
{ |
|
[ 0 ] = { "Seeked", ELDBUS_ARGS({ "x", "Position" }), 0 }, |
|
{ 0 } |
|
}; |
|
// XXX: Signal: Seeked (x: Position) |
|
|
|
static const Eldbus_Service_Interface_Desc desc_player = { |
|
"org.mpris.MediaPlayer2.Player", methods_player, signals_player, properties_player, NULL, NULL |
|
}; |
|
|
|
void |
|
mpris_fullscreen_change(void) |
|
{ |
|
if (!iface) return; |
|
eldbus_service_property_changed(iface, "Fullscreen"); |
|
} |
|
|
|
void |
|
mpris_volume_change(void) |
|
{ |
|
if (!iface_player) return; |
|
eldbus_service_property_changed(iface_player, "Volume"); |
|
} |
|
|
|
void |
|
mpris_loop_status_change(void) |
|
{ |
|
if (!iface_player) return; |
|
eldbus_service_property_changed(iface_player, "LoopStatus"); |
|
} |
|
|
|
void |
|
mpris_playback_status_change(void) |
|
{ |
|
if (!iface_player) return; |
|
eldbus_service_property_changed(iface_player, "PlaybackStatus"); |
|
} |
|
|
|
void |
|
mpris_position_change(double pos) |
|
{ |
|
uint64_t p = pos * 1000000.0; |
|
|
|
if (!iface_player) return; |
|
eldbus_service_signal_emit(iface_player, 0, p); |
|
eldbus_service_property_changed(iface_player, "Position"); |
|
} |
|
|
|
void |
|
mpris_init(Evas_Object *win) |
|
{ |
|
elm_need_eldbus(); |
|
conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); |
|
if (!conn) return; |
|
mainwin = win; |
|
eldbus_name_request(conn, SERVICE, 0, _cb_name_request, NULL); |
|
iface = eldbus_service_interface_register(conn, PATH, &desc); |
|
iface_player = eldbus_service_interface_register(conn, PATH, &desc_player); |
|
} |
|
|
|
void |
|
mpris_shutdown(void) |
|
{ |
|
if (!conn) return; |
|
mainwin = NULL; |
|
// if (iface_player) eldbus_service_object_unregister(iface_player); |
|
iface_player = NULL; |
|
// if (iface) eldbus_service_object_unregister(iface); |
|
iface = NULL; |
|
// eldbus_name_release(conn, SERVICE, NULL, NULL); |
|
// eldbus_connection_unref(conn); |
|
conn = NULL; |
|
}
|
|
|