rage/src/bin/mpris.c

1191 lines
30 KiB
C

#include <Elementary.h>
/* no mpris support on Windows */
#ifndef _WIN32
#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 EINA_UNUSED,
Eldbus_Pending *pending EINA_UNUSED)
{
return;
/*
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");
*/
}
/* Implementing almost all of:
*
https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html
*
* Not implemented:
* Tracklist objects
* SetPosition (requires Tracklist objects)
*
* In rage generally and here:
*
* Loop playlist vs just loop current
* Shuffle play
* Playback rate
*/
#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)
{
// XXX: Implement Tracklist
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);
#define A(s) eldbus_message_iter_arguments_append(array, "s", s)
A("application/ogg");
A("audio/1d-interleaved-parityfec");
A("audio/32kadpcm");
A("audio/3gpp");
A("audio/3gpp2");
A("audio/AMR");
A("audio/AMR-WB");
A("audio/ATRAC-ADVANCED-LOSSLESS");
A("audio/ATRAC-X");
A("audio/ATRAC3");
A("audio/BV16");
A("audio/BV32");
A("audio/CN");
A("audio/DAT12");
A("audio/DV");
A("audio/DVI4");
A("audio/EVRC");
A("audio/EVRC-QCP");
A("audio/EVRC0");
A("audio/EVRC1");
A("audio/EVRCB");
A("audio/EVRCB0");
A("audio/EVRCB1");
A("audio/EVRCWB");
A("audio/EVRCWB0");
A("audio/EVRCWB1");
A("audio/G719");
A("audio/G722");
A("audio/G7221");
A("audio/G723");
A("audio/G726-16");
A("audio/G726-24");
A("audio/G726-32");
A("audio/G726-40");
A("audio/G728");
A("audio/G729");
A("audio/G7291");
A("audio/G729D");
A("audio/G729E");
A("audio/GSM");
A("audio/GSM-EFR");
A("audio/GSM-HR-08");
A("audio/L16");
A("audio/L20");
A("audio/L24");
A("audio/L8");
A("audio/LPC");
A("audio/MP4A-LATM");
A("audio/MPA");
A("audio/PCMA");
A("audio/PCMA-WB");
A("audio/PCMU");
A("audio/PCMU-WB");
A("audio/QCELP");
A("audio/RED");
A("audio/SMV");
A("audio/SMV-QCP");
A("audio/SMV0");
A("audio/UEMCLIP");
A("audio/VDVI");
A("audio/VMR-WB");
A("audio/aac");
A("audio/ac3");
A("audio/adpcm");
A("audio/amr");
A("audio/amr-wb");
A("audio/amr-wb+");
A("audio/annodex");
A("audio/asc");
A("audio/basic");
A("audio/bv16");
A("audio/bv32");
A("audio/clearmode");
A("audio/cn");
A("audio/csound");
A("audio/dat12");
A("audio/dls");
A("audio/dsr-es201108");
A("audio/dsr-es202050");
A("audio/dsr-es202211");
A("audio/dsr-es202212");
A("audio/dvi4");
A("audio/eac3");
A("audio/evrc");
A("audio/evrc-qcp");
A("audio/evrc0");
A("audio/evrc1");
A("audio/evrcb");
A("audio/evrcb0");
A("audio/evrcb1");
A("audio/evrcwb");
A("audio/evrcwb0");
A("audio/evrcwb1");
A("audio/example");
A("audio/flac");
A("audio/fwdred");
A("audio/g.722.1");
A("audio/g719");
A("audio/g722");
A("audio/g7221");
A("audio/g723");
A("audio/g726-16");
A("audio/g726-24");
A("audio/g726-32");
A("audio/g726-40");
A("audio/g728");
A("audio/g729");
A("audio/g7291");
A("audio/g729d");
A("audio/g729e");
A("audio/gsm");
A("audio/gsm-efr");
A("audio/iLBC");
A("audio/ilbc");
A("audio/ip-mr_v2.5");
A("audio/l16");
A("audio/l20");
A("audio/l24");
A("audio/l8");
A("audio/lpc");
A("audio/midi");
A("audio/mobile-xmf");
A("audio/mp2");
A("audio/mp4");
A("audio/mp4a-latm");
A("audio/mpa");
A("audio/mpa-robust");
A("audio/mpeg");
A("audio/mpeg4-generic");
A("audio/mpegurl");
A("audio/ogg");
A("audio/parityfec");
A("audio/pcma");
A("audio/pcma-wb");
A("audio/pcmu");
A("audio/pcmu-wb");
A("audio/prs.sid");
A("audio/qcelp");
A("audio/raptorfec");
A("audio/red");
A("audio/rtp-enc-aescm128");
A("audio/rtp-midi");
A("audio/rtx");
A("audio/s3m");
A("audio/silk");
A("audio/smv");
A("audio/smv-qcp");
A("audio/smv0");
A("audio/sp-midi");
A("audio/speex");
A("audio/t140c");
A("audio/t38");
A("audio/telephone-event");
A("audio/tone");
A("audio/ulpfec");
A("audio/vdvi");
A("audio/vmr-wb");
A("audio/vnd.3gpp.iufp");
A("audio/vnd.4SB");
A("audio/vnd.4sb");
A("audio/vnd.CELP");
A("audio/vnd.audiokoz");
A("audio/vnd.celp");
A("audio/vnd.cisco.nse");
A("audio/vnd.cmles.radio-events");
A("audio/vnd.cns.anp1");
A("audio/vnd.cns.inf1");
A("audio/vnd.dece.audio");
A("audio/vnd.digital-winds");
A("audio/vnd.dlna.adts");
A("audio/vnd.dolby.heaac.1");
A("audio/vnd.dolby.heaac.2");
A("audio/vnd.dolby.mlp");
A("audio/vnd.dolby.mps");
A("audio/vnd.dolby.pl2");
A("audio/vnd.dolby.pl2x");
A("audio/vnd.dolby.pl2z");
A("audio/vnd.dolby.pulse.1");
A("audio/vnd.dra");
A("audio/vnd.dts");
A("audio/vnd.dts.hd");
A("audio/vnd.dvb.file");
A("audio/vnd.everad.plj");
A("audio/vnd.hns.audio");
A("audio/vnd.lucent.voice");
A("audio/vnd.rn-realaudio");
A("audio/vnd.ms-playready.media.pya");
A("audio/vnd.nokia.mobile-xmf");
A("audio/vnd.nortel.vbk");
A("audio/vnd.nuera.ecelp4800");
A("audio/vnd.nuera.ecelp7470");
A("audio/vnd.nuera.ecelp9600");
A("audio/vnd.octel.sbc");
A("audio/vnd.qcelp");
A("audio/vnd.rhetorex.32kadpcm");
A("audio/vnd.rip");
A("audio/vnd.sealedmedia.softseal.mpeg");
A("audio/vnd.vmx.cvsd");
A("audio/vorbis");
A("audio/vorbis-config");
A("audio/webm");
A("audio/x-aac");
A("audio/x-adpcm");
A("audio/x-aifc");
A("audio/x-aiff");
A("audio/x-amzxml");
A("audio/x-ape");
A("audio/x-caf");
A("audio/x-flac");
A("audio/x-flac+ogg");
A("audio/x-gsm");
A("audio/x-iriver-pla");
A("audio/x-it");
A("audio/x-m4b");
A("audio/x-matroska");
A("audio/x-minipsf");
A("audio/x-mo3");
A("audio/x-mod");
A("audio/x-mpegurl");
A("audio/x-ms-asx");
A("audio/x-ms-wax");
A("audio/x-ms-wma");
A("audio/x-musepack");
A("audio/x-opus+ogg");
A("audio/x-pn-audibleaudio");
A("audio/x-pn-realaudio");
A("audio/x-pn-realaudio-plugin");
A("audio/x-psf");
A("audio/x-psflib");
A("audio/x-realaudio");
A("audio/x-riff");
A("audio/x-s3m");
A("audio/x-scpls");
A("audio/x-sd2");
A("audio/x-speex");
A("audio/x-speex+ogg");
A("audio/x-stm");
A("audio/x-tta");
A("audio/x-voc");
A("audio/x-vorbis+ogg");
A("audio/x-wav");
A("audio/x-wavpack");
A("audio/x-wavpack-correction");
A("audio/x-xi");
A("audio/x-xm");
A("audio/x-xmf");
A("audio/xm");
A("video/1d-interleaved-parityfec");
A("video/3gpp");
A("video/3gpp-tt");
A("video/3gpp2");
A("video/BMPEG");
A("video/BT656");
A("video/CelB");
A("video/DV");
A("video/H261");
A("video/H263");
A("video/H263-1998");
A("video/H263-2000");
A("video/H264");
A("video/H264-RCDO");
A("video/H264-SVC");
A("video/JPEG");
A("video/MJ2");
A("video/MP1S");
A("video/MP2P");
A("video/MP2T");
A("video/MP4V-ES");
A("video/MPV");
A("video/SMPTE292M");
A("video/annodex");
A("video/bmpeg");
A("video/bt656");
A("video/celb");
A("video/dl");
A("video/dv");
A("video/example");
A("video/fli");
A("video/gl");
A("video/h261");
A("video/h263");
A("video/h263-1998");
A("video/h263-2000");
A("video/h264");
A("video/isivideo");
A("video/jpeg");
A("video/jpeg2000");
A("video/jpm");
A("video/mj2");
A("video/mp1s");
A("video/mp2p");
A("video/mp2t");
A("video/mp4");
A("video/mp4v-es");
A("video/mpeg");
A("video/mpeg4-generic");
A("video/mpv");
A("video/nv");
A("video/ogg");
A("video/parityfec");
A("video/pointer");
A("video/quicktime");
A("video/raptorfec");
A("video/raw");
A("video/rtp-enc-aescm128");
A("video/rtx");
A("video/smpte292m");
A("video/ulpfec");
A("video/vc1");
A("video/vnd.CCTV");
A("video/vnd.cctv");
A("video/vnd.dece.hd");
A("video/vnd.dece.mobile");
A("video/vnd.dece.mp4");
A("video/vnd.dece.pd");
A("video/vnd.dece.sd");
A("video/vnd.dece.video");
A("video/vnd.directv.mpeg");
A("video/vnd.directv.mpeg-tts");
A("video/vnd.dlna.mpeg-tts");
A("video/vnd.dvb.file");
A("video/vnd.fvt");
A("video/vnd.hns.video");
A("video/vnd.iptvforum.1dparityfec-1010");
A("video/vnd.iptvforum.1dparityfec-2005");
A("video/vnd.iptvforum.2dparityfec-1010");
A("video/vnd.iptvforum.2dparityfec-2005");
A("video/vnd.iptvforum.ttsavc");
A("video/vnd.iptvforum.ttsmpeg2");
A("video/vnd.motorola.video");
A("video/vnd.motorola.videop");
A("video/vnd.mpegurl");
A("video/vnd.ms-playready.media.pyv");
A("video/vnd.mts");
A("video/vnd.nokia.interleaved-multimedia");
A("video/vnd.nokia.videovoip");
A("video/vnd.objectvideo");
A("video/vnd.rn-realvideo");
A("video/vnd.sealed.mpeg1");
A("video/vnd.sealed.mpeg4");
A("video/vnd.sealed.swf");
A("video/vnd.sealedmedia.softseal.mov");
A("video/vnd.uvvu.mp4");
A("video/vnd.vivo");
A("video/wavelet");
A("video/webm");
A("video/x-anim");
A("video/x-f4v");
A("video/x-fli");
A("video/x-flic");
A("video/x-flv");
A("video/x-javafx");
A("video/x-la-asf");
A("video/x-m4v");
A("video/x-matroska");
A("video/x-matroska-3d");
A("video/x-mng");
A("video/x-ms-asf");
A("video/x-ms-vob");
A("video/x-ms-wm");
A("video/x-ms-wmp");
A("video/x-ms-wmv");
A("video/x-ms-wmx");
A("video/x-ms-wvx");
A("video/x-msvideo");
A("video/x-nsv");
A("video/x-ogm+ogg");
A("video/x-sgi-movie");
A("video/x-smv");
A("video/x-theora+ogg");
// hope the other end understands globs?
A("video/*");
A("audio/*");
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);
A("file");
A("http");
A("https");
A("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),
{ NULL, NULL, NULL, NULL, 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),
{ NULL, NULL, NULL, NULL, 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;
// XXX: Implement playback rate
eldbus_message_iter_arguments_append(iter, "d", rate);
return EINA_TRUE;
}
SETTER(rate)
{
double rate = 1.0;
// XXX: Implement playback rate
eldbus_message_iter_arguments_get(iter, "d", &rate);
return eldbus_message_method_return_new(msg);
}
GETTER(shuffle)
{
Eina_Bool shuffle = EINA_FALSE;
// XXX: Implement shuffle mode
eldbus_message_iter_arguments_append(iter, "b", shuffle);
return EINA_TRUE;
}
SETTER(shuffle)
{
Eina_Bool shuffle = EINA_FALSE;
// XXX: Implement shuffle mode
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)
{
Inf *inf = evas_object_data_get(mainwin, "inf");
Eldbus_Message_Iter *array = NULL, *entry = NULL, *var, *var2;
uint64_t len = 0;
char *buf = NULL, *tmp = NULL, *p;
const char *s, *file;
if (!inf) return EINA_FALSE;
// XXX: TODO:
// mpris:trackid
eldbus_message_iter_arguments_append(iter, "a{sv}", &array);
s = video_file_get(inf->vid);
if (s)
{
if (s[0] == '/')
{
buf = alloca(strlen(s) + sizeof("file://") + 1);
sprintf(buf, "file://%s", s);
}
else if (strstr(s, "://"))
{
buf = alloca(strlen(s) + 1);
strcpy(buf, s);
}
else
{
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd) - 1))
{
cwd[sizeof(cwd) - 1] = 0;
buf = alloca(strlen(cwd) + 1 + strlen(s) + sizeof("file://") + 1);
sprintf(buf, "file://%s/%s", cwd, s);
}
}
}
if (buf)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:url");
var = eldbus_message_iter_container_new(entry, 'v', "s");
eldbus_message_iter_basic_append(var, 's', buf);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_artfile_get(inf->vid);
if (s)
{
buf = alloca(strlen(s) + sizeof("file://") + 1);
sprintf(buf, "file://%s", s);
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "mpris:artUrl");
var = eldbus_message_iter_container_new(entry, 'v', "s");
eldbus_message_iter_basic_append(var, 's', buf);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_title_get(inf->vid);
if (!s) s = video_meta_title_get(inf->vid);
if ((!s) && (inf->file_cur))
{
Winvid_Entry *vid = inf->file_cur->data;
if (vid)
{
file = vid->file;
s = ecore_file_file_get(vid->uri ? vid->uri->path : file);
if (s)
{
tmp = alloca(strlen(s) + 1);
strcpy(tmp, s);
for (p = tmp; *p; p++)
{
// nuke stupid characters from the label that may be in filename
if ((*p == '_') || (*p == '#') || (*p == '$') || (*p == '%') ||
(*p == '*') || (*p == '+') || (*p == '[') || (*p == ']') ||
(*p == ';') || (*p == '<') || (*p == '=') || (*p == '>') ||
(*p == '^') || (*p == '`') || (*p == '{') || (*p == '}') ||
(*p == '|') || (*p == '~') || (*p == 127) ||
(*p == '\'') || (*p == '\\'))
{
*p = ' ';
}
else if (*p == '.')
{
*p = 0;
break;
}
}
s = tmp;
}
}
}
if (s)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:title");
var = eldbus_message_iter_container_new(entry, 'v', "s");
eldbus_message_iter_basic_append(var, 's', s);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_meta_album_get(inf->vid);
if (s)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:album");
var = eldbus_message_iter_container_new(entry, 'v', "s");
eldbus_message_iter_basic_append(var, 's', buf);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_meta_artist_get(inf->vid);
if (s)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:artist");
var = eldbus_message_iter_container_new(entry, 'v', "as");
eldbus_message_iter_arguments_append(var, "as", &var2);
eldbus_message_iter_basic_append(var2, 's', s);
eldbus_message_iter_container_close(var, var2);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_meta_comment_get(inf->vid);
if (s)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:comment");
var = eldbus_message_iter_container_new(entry, 'v', "as");
eldbus_message_iter_arguments_append(var, "as", &var2);
eldbus_message_iter_basic_append(var2, 's', s);
eldbus_message_iter_container_close(var, var2);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
s = video_meta_genre_get(inf->vid);
if (s)
{
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "xesam:genre");
var = eldbus_message_iter_container_new(entry, 'v', "as");
eldbus_message_iter_arguments_append(var, "as", &var2);
eldbus_message_iter_basic_append(var2, 's', s);
eldbus_message_iter_container_close(var, var2);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
}
len = video_length_get(inf->vid) * 1000000.0;
eldbus_message_iter_arguments_append(array, "{sv}", &entry);
eldbus_message_iter_basic_append(entry, 's', "mpris:length");
var = eldbus_message_iter_container_new(entry, 'v', "x");
eldbus_message_iter_basic_append(var, 'x', len);
eldbus_message_iter_container_close(entry, var);
eldbus_message_iter_container_close(array, entry);
eldbus_message_iter_container_close(iter, array);
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),
{ NULL, NULL, NULL, NULL, 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;
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;
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),
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Signal signals_player[] =
{
[ 0 ] = { "Seeked", ELDBUS_ARGS({ "x", "Position" }), 0 },
{ NULL, NULL, 0 }
};
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_metadata_change(void)
{
if (!iface_player) return;
eldbus_service_property_changed(iface_player, "Metadata");
}
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;
}
#else
void
mpris_fullscreen_change(void)
{
}
void
mpris_volume_change(void)
{
}
void
mpris_loop_status_change(void)
{
}
void
mpris_playback_status_change(void)
{
}
void
mpris_position_change(double pos EINA_UNUSED)
{
}
void
mpris_metadata_change(void)
{
}
void
mpris_init(Evas_Object *win EINA_UNUSED)
{
}
void
mpris_shutdown(void)
{
}
#endif