612 lines
20 KiB
C
612 lines
20 KiB
C
#include "empd.h"
|
|
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <Ecore_Con.h>
|
|
#include <Eldbus.h>
|
|
#include <mpd/client.h>
|
|
#include <mpd/parser.h>
|
|
#include <mpd/async.h>
|
|
|
|
#define STRING_SAFETY(X) X ?: ""
|
|
#define S(X) #X
|
|
|
|
typedef struct E_Slist E_Slist;
|
|
struct E_Slist
|
|
{
|
|
E_Slist *next;
|
|
unsigned int command;
|
|
};
|
|
|
|
typedef struct EMPD
|
|
{
|
|
Ecore_Con_Server *svr;
|
|
Ecore_Fd_Handler *fdh;
|
|
Ecore_Poller *pinger;
|
|
struct mpd_settings *settings;
|
|
struct mpd_async *async;
|
|
struct mpd_parser *parser;
|
|
|
|
|
|
Eina_Array *pending;
|
|
void *cur;
|
|
E_Slist *cmds, *last;
|
|
} EMPD;
|
|
|
|
typedef enum
|
|
{
|
|
EMPD_COMMAND_NONE = 0,
|
|
EMPD_COMMAND_PASSWORD,
|
|
EMPD_COMMAND_STATUS,
|
|
EMPD_COMMAND_CURRENT_SONG,
|
|
EMPD_COMMAND_PLAY,
|
|
EMPD_COMMAND_PAUSE,
|
|
EMPD_COMMAND_TOGGLE_PAUSE,
|
|
EMPD_COMMAND_STOP,
|
|
EMPD_COMMAND_NEXT,
|
|
EMPD_COMMAND_PREVIOUS,
|
|
EMPD_COMMAND_SEEK,
|
|
EMPD_COMMAND_PLAY_ID,
|
|
EMPD_COMMAND_QUEUE_LIST,
|
|
} EMPD_Command;
|
|
|
|
static const char *cmd_txt[] =
|
|
{
|
|
#define CMD_TXT(X) \
|
|
[X] = S(X),
|
|
CMD_TXT(EMPD_COMMAND_NONE)
|
|
CMD_TXT(EMPD_COMMAND_PASSWORD)
|
|
CMD_TXT(EMPD_COMMAND_STATUS)
|
|
CMD_TXT(EMPD_COMMAND_CURRENT_SONG)
|
|
CMD_TXT(EMPD_COMMAND_PLAY)
|
|
CMD_TXT(EMPD_COMMAND_PAUSE)
|
|
CMD_TXT(EMPD_COMMAND_TOGGLE_PAUSE)
|
|
CMD_TXT(EMPD_COMMAND_STOP)
|
|
CMD_TXT(EMPD_COMMAND_NEXT)
|
|
CMD_TXT(EMPD_COMMAND_PREVIOUS)
|
|
CMD_TXT(EMPD_COMMAND_SEEK)
|
|
CMD_TXT(EMPD_COMMAND_PLAY_ID)
|
|
CMD_TXT(EMPD_COMMAND_QUEUE_LIST)
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
EMPD_SIGNAL_CONNECTED,
|
|
EMPD_SIGNAL_DISCONNECTED,
|
|
EMPD_SIGNAL_STATUS,
|
|
EMPD_SIGNAL_CURRENT_SONG,
|
|
EMPD_SIGNAL_QUEUE_LIST,
|
|
} EMPD_Signals;
|
|
|
|
static const Eldbus_Signal empd_signals[] =
|
|
{
|
|
[EMPD_SIGNAL_CONNECTED] = {"Connected", NULL, 0},
|
|
[EMPD_SIGNAL_DISCONNECTED] = {"Disconnected", NULL, 0},
|
|
[EMPD_SIGNAL_STATUS] = {"Status", ELDBUS_ARGS({"i", "volume"}, {"b", "repeat"}, {"b", "random"},
|
|
{"b", "single"}, {"b", "consume"}, {"u", "queue_version"}, {"u", "queue_length"},
|
|
{"d", "mixrampdb"}, {"u", "state"}, {"i", "song_pos"}, {"i", "songid"},
|
|
{"u", "song_length"}, {"u", "song_elapsed"}, {"u", "bitrate"},
|
|
{"u", "sample_rate"}, {"u", "sample_bits"}, {"u", "sample_channels"}, {"i", "next_song_pos"}, {"i", "next_songid"}), 0},
|
|
[EMPD_SIGNAL_CURRENT_SONG] = {"CurrentSong", ELDBUS_ARGS({"s", "uri"}, {"t", "last_modified"}, {"u", "duration"},
|
|
{"s", "artist"}, {"s", "title"}, {"s", "album"}, {"i", "track"},
|
|
{"s", "name"}, {"s", "date"}, {"s", "disc"}, {"i", "song_pos"}, {"i", "songid"}), 0},
|
|
[EMPD_SIGNAL_QUEUE_LIST] = {"QueueList", ELDBUS_ARGS({"a(stusssisssii)", "array_of_songs"}), 0},
|
|
{NULL, NULL, 0}
|
|
};
|
|
|
|
static EMPD *empd = NULL;
|
|
static Eina_List *handlers = NULL;
|
|
static Eina_Mempool *slist_mempool = NULL;
|
|
|
|
static Eldbus_Connection *dbus_conn = NULL;
|
|
static Eldbus_Service_Interface *empd_iface = NULL;
|
|
|
|
static inline void
|
|
fdh_update(void)
|
|
{
|
|
int flags;
|
|
|
|
flags = mpd_async_events(empd->async);
|
|
flags &= ~MPD_ASYNC_EVENT_ERROR & ~MPD_ASYNC_EVENT_HUP;
|
|
ecore_main_fd_handler_active_set(empd->fdh, flags);
|
|
}
|
|
|
|
static inline void
|
|
cmd_append(EMPD_Command cmd)
|
|
{
|
|
E_Slist *es;
|
|
|
|
es = eina_mempool_malloc(slist_mempool, sizeof(E_Slist));
|
|
es->command = cmd;
|
|
es->next = NULL;
|
|
if (empd->cmds)
|
|
empd->last->next = es;
|
|
else
|
|
empd->cmds = es;
|
|
fprintf(stderr, "CMD ADD: %s\n", cmd_txt[es->command]);
|
|
empd->last = es;
|
|
es = empd->cmds;
|
|
while (es)
|
|
{
|
|
fprintf(stderr, "CMD ADD CYCLE: %s\n", cmd_txt[es->command]);
|
|
es = es->next;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
cmd_remove(void)
|
|
{
|
|
E_Slist *es = empd->cmds;
|
|
|
|
if (!es) return;
|
|
fprintf(stderr, "CMD REMOVE: %s\n", cmd_txt[es->command]);
|
|
if (es->next)
|
|
fprintf(stderr, "CMD NEXT: %s\n", cmd_txt[es->next->command]);
|
|
else
|
|
fprintf(stderr, "CMD END\n");
|
|
empd->cmds = es->next;
|
|
eina_mempool_free(slist_mempool, es);
|
|
if (!empd->cmds)
|
|
empd->last = NULL;
|
|
empd->cur = NULL;
|
|
es = empd->cmds;
|
|
while (es)
|
|
{
|
|
fprintf(stderr, "CMD REMOVE CYCLE: %s\n", cmd_txt[es->command]);
|
|
if (es == es->next) abort();
|
|
es = es->next;
|
|
}
|
|
}
|
|
|
|
static inline EMPD_Command
|
|
cmd_get(void)
|
|
{
|
|
return empd->cmds ? empd->cmds->command : EMPD_COMMAND_NONE;
|
|
}
|
|
|
|
static inline Ecore_Con_Type
|
|
conn_type_get(const char *host)
|
|
{
|
|
if (host[0] == '/') return ECORE_CON_LOCAL_SYSTEM;
|
|
return ECORE_CON_REMOTE_TCP;
|
|
}
|
|
|
|
static Eina_Bool
|
|
pinger_cb(void *d EINA_UNUSED)
|
|
{
|
|
mpd_async_send_command(empd->async, "status", NULL);
|
|
cmd_append(EMPD_COMMAND_STATUS);
|
|
fdh_update();
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
fdh_func(void *d EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED)
|
|
{
|
|
char *txt;
|
|
|
|
if (!mpd_async_io(empd->async, MPD_ASYNC_EVENT_READ | MPD_ASYNC_EVENT_WRITE))
|
|
{
|
|
ecore_main_loop_quit();
|
|
return EINA_FALSE;
|
|
}
|
|
fdh_update();
|
|
txt = mpd_async_recv_line(empd->async);
|
|
if (!txt) return EINA_TRUE;
|
|
while (txt)
|
|
{
|
|
const char *name, *value;
|
|
enum mpd_parser_result res = mpd_parser_feed(empd->parser, txt);
|
|
switch (res)
|
|
{
|
|
case MPD_PARSER_MALFORMED: abort(); //FIXME
|
|
/**
|
|
* MPD has returned "ACK" with an error code. Call
|
|
* mpd_parser_get_server_error() to get the error code.
|
|
*/
|
|
case MPD_PARSER_ERROR:
|
|
if (cmd_get() == EMPD_COMMAND_PASSWORD)
|
|
{
|
|
/* login failure */
|
|
ecore_main_loop_quit();
|
|
return EINA_TRUE;
|
|
}
|
|
if (mpd_async_get_error(empd->async) == MPD_ERROR_CLOSED)
|
|
ecore_app_restart();
|
|
break;
|
|
/**
|
|
* MPD has returned a name-value pair. Call
|
|
* mpd_parser_get_name() and mpd_parser_get_value().
|
|
*/
|
|
case MPD_PARSER_PAIR:
|
|
/**
|
|
* MPD has returned "OK" or "list_OK" (check with
|
|
* mpd_parser_is_discrete()).
|
|
*/
|
|
name = mpd_parser_get_name(empd->parser);
|
|
value = mpd_parser_get_value(empd->parser);
|
|
fprintf(stderr, "[%s]|%s: %s\n", cmd_txt[cmd_get()], name, value);
|
|
break;
|
|
case MPD_PARSER_SUCCESS:
|
|
fprintf(stderr, "[%s]|SUCCESS\n", cmd_txt[cmd_get()]);
|
|
if (cmd_get() == EMPD_COMMAND_PASSWORD)
|
|
{
|
|
eldbus_service_signal_emit(empd_iface, EMPD_SIGNAL_CONNECTED);
|
|
empd->pinger = ecore_poller_add(ECORE_POLLER_CORE, 8, pinger_cb, NULL);
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (cmd_get())
|
|
{
|
|
case EMPD_COMMAND_STATUS:
|
|
{
|
|
struct mpd_status *st;
|
|
|
|
if (!empd->cur)
|
|
empd->cur = mpd_status_begin();
|
|
st = empd->cur;
|
|
|
|
fprintf(stderr, "[%s]|HIT\n", cmd_txt[cmd_get()]);
|
|
|
|
if (res == MPD_PARSER_PAIR)
|
|
{
|
|
fprintf(stderr, "[%s]|FEED\n", cmd_txt[cmd_get()]);
|
|
mpd_status_feed(st, &(struct mpd_pair){name, value});
|
|
}
|
|
else
|
|
{
|
|
const struct mpd_audio_format *af = mpd_status_get_audio_format(st);
|
|
|
|
fprintf(stderr, "[%s]|SENT\n", cmd_txt[cmd_get()]);
|
|
eldbus_service_signal_emit(empd_iface, EMPD_SIGNAL_STATUS,
|
|
mpd_status_get_volume(st), mpd_status_get_repeat(st), mpd_status_get_random(st),
|
|
mpd_status_get_single(st), mpd_status_get_consume(st), mpd_status_get_queue_version(st), mpd_status_get_queue_length(st),
|
|
mpd_status_get_mixrampdb(st), mpd_status_get_state(st), mpd_status_get_song_pos(st), mpd_status_get_song_id(st),
|
|
mpd_status_get_total_time(st), mpd_status_get_elapsed_time(st), mpd_status_get_kbit_rate(st),
|
|
af ? af->sample_rate : 0, af ? af->bits : 0, af ? af->channels : 0,
|
|
mpd_status_get_next_song_pos(st), mpd_status_get_next_song_id(st));
|
|
mpd_status_free(st);
|
|
}
|
|
}
|
|
break;
|
|
case EMPD_COMMAND_CURRENT_SONG:
|
|
case EMPD_COMMAND_QUEUE_LIST:
|
|
{
|
|
struct mpd_song *so;
|
|
|
|
so = empd->cur;
|
|
fprintf(stderr, "[%s]|HIT: %d\n", cmd_txt[cmd_get()], res);
|
|
|
|
if (res == MPD_PARSER_PAIR)
|
|
{
|
|
if (!empd->cur)
|
|
{
|
|
empd->cur = mpd_song_begin(&(struct mpd_pair){name, value});
|
|
break;
|
|
}
|
|
mpd_song_feed(so, &(struct mpd_pair){name, value});
|
|
fprintf(stderr, "[%s]|FEED\n", cmd_txt[cmd_get()]);
|
|
if (cmd_get() != EMPD_COMMAND_CURRENT_SONG)
|
|
{
|
|
if (!strcmp(name, "Id"))
|
|
{
|
|
/* at end of current song, push to array
|
|
* for sending all at once later
|
|
*/
|
|
if (!empd->pending)
|
|
empd->pending = eina_array_new(1);
|
|
eina_array_push(empd->pending, so);
|
|
empd->cur = NULL;
|
|
}
|
|
}
|
|
}
|
|
else if (cmd_get() == EMPD_COMMAND_CURRENT_SONG)
|
|
{
|
|
const char *track = mpd_song_get_tag(so, MPD_TAG_TRACK, 0);
|
|
|
|
fprintf(stderr, "CURRENT\n");
|
|
|
|
eldbus_service_signal_emit(empd_iface, EMPD_SIGNAL_CURRENT_SONG,
|
|
STRING_SAFETY(mpd_song_get_uri(so)), mpd_song_get_last_modified(so), mpd_song_get_duration(so),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_ARTIST, 0)), STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_TITLE, 0)),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_ALBUM, 0)),
|
|
track ? atoi(track) : 0, STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_NAME, 0)), STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_DATE, 0)),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_DISC, 0)), mpd_song_get_pos(so), mpd_song_get_id(so));
|
|
mpd_song_free(so);
|
|
}
|
|
else if (cmd_get() == EMPD_COMMAND_QUEUE_LIST)
|
|
{
|
|
Eldbus_Message *msg;
|
|
Eldbus_Message_Iter *iter, *array, *struc;
|
|
Eina_Iterator *it;
|
|
struct mpd_song *so;
|
|
|
|
fprintf(stderr, "QUEUE\n");
|
|
|
|
msg = eldbus_service_signal_new(empd_iface, EMPD_SIGNAL_QUEUE_LIST);
|
|
iter = eldbus_message_iter_get(msg);
|
|
array = eldbus_message_iter_container_new(iter, 'a', "(stusssisssii)");
|
|
it = eina_array_iterator_new(empd->pending);
|
|
EINA_ITERATOR_FOREACH(it, so)
|
|
{
|
|
/* holy shit. */
|
|
const char *track = mpd_song_get_tag(so, MPD_TAG_TRACK, 0);
|
|
|
|
eldbus_message_iter_arguments_append(array, "(stusssisssii)", &struc);
|
|
eldbus_message_iter_arguments_append(struc, "stusssisssii",
|
|
STRING_SAFETY(mpd_song_get_uri(so)), mpd_song_get_last_modified(so), mpd_song_get_duration(so),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_ARTIST, 0)), STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_TITLE, 0)),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_ALBUM, 0)),
|
|
track ? atoi(track) : 0, STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_NAME, 0)), STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_DATE, 0)),
|
|
STRING_SAFETY(mpd_song_get_tag(so, MPD_TAG_DISC, 0)), mpd_song_get_pos(so), mpd_song_get_id(so));
|
|
mpd_song_free(so);
|
|
eldbus_message_iter_container_close(array, struc);
|
|
}
|
|
eina_iterator_free(it);
|
|
eina_array_free(empd->pending);
|
|
empd->pending = NULL;
|
|
eldbus_message_iter_container_close(iter, array);
|
|
fprintf(stderr, "[%s]|SENT\n", cmd_txt[cmd_get()]);
|
|
eldbus_service_signal_send(empd_iface, msg);
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
if (res == MPD_PARSER_SUCCESS)
|
|
cmd_remove();
|
|
txt = mpd_async_recv_line(empd->async);
|
|
fprintf(stderr, "[%s]|NEXT LINE\n", cmd_txt[cmd_get()]);
|
|
}
|
|
fprintf(stderr, "[%s]|FDH_DONE\n", cmd_txt[cmd_get()]);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
con(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event_Server_Add *ev)
|
|
{
|
|
return ECORE_CALLBACK_DONE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
del(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event_Server_Del *ev)
|
|
{
|
|
if (!empd->async)
|
|
ecore_main_loop_quit();
|
|
return ECORE_CALLBACK_DONE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
data(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event_Server_Data *ev)
|
|
{
|
|
int fd, flags;
|
|
char *txt;
|
|
|
|
fd = dup(ecore_con_server_fd_get(ev->server));
|
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
|
|
flags = fcntl(fd, F_GETFD);
|
|
flags |= FD_CLOEXEC;
|
|
fcntl(fd, F_SETFD, flags);
|
|
empd->fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ | ECORE_FD_ERROR, fdh_func, NULL, NULL, NULL);
|
|
empd->async = mpd_async_new(fd);
|
|
ecore_con_server_del(ev->server);
|
|
empd->svr = NULL;
|
|
|
|
/* this will always just be the first line
|
|
* OK MPD 0.18.0\n
|
|
*/
|
|
txt = ev->data;
|
|
txt[ev->size - 1] = 0;
|
|
empd->parser = mpd_parser_new();
|
|
if (mpd_settings_get_password(empd->settings))
|
|
{
|
|
mpd_async_send_command(empd->async, "password", mpd_settings_get_password(empd->settings), NULL);
|
|
cmd_append(EMPD_COMMAND_PASSWORD);
|
|
fdh_update();
|
|
}
|
|
else
|
|
{
|
|
eldbus_service_signal_emit(empd_iface, EMPD_SIGNAL_CONNECTED);
|
|
empd->pinger = ecore_poller_add(ECORE_POLLER_CORE, 8, pinger_cb, NULL);
|
|
}
|
|
return ECORE_CALLBACK_DONE;
|
|
}
|
|
|
|
static void
|
|
_dbus_request_name_cb(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\n");
|
|
else if (!eldbus_message_arguments_get(msg, "u", &flag))
|
|
fprintf(stderr, "Could not get arguments on on_name_request\n");
|
|
else if (!(flag & ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER))
|
|
fprintf(stderr, "Name already in use\n");
|
|
}
|
|
|
|
#define DBUS_BASIC_CB(name, CMD) \
|
|
static Eldbus_Message * \
|
|
_dbus_##name##_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) \
|
|
{ \
|
|
mpd_async_send_command(empd->async, S(name), NULL); \
|
|
fdh_update(); \
|
|
cmd_append(EMPD_COMMAND_##CMD); \
|
|
return eldbus_message_method_return_new(msg); \
|
|
}
|
|
|
|
DBUS_BASIC_CB(status, STATUS)
|
|
DBUS_BASIC_CB(currentsong, CURRENT_SONG)
|
|
DBUS_BASIC_CB(play, PLAY)
|
|
|
|
static Eldbus_Message *
|
|
_dbus_pause_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
|
|
{
|
|
Eina_Bool mode;
|
|
const char *sig;
|
|
|
|
sig = eldbus_message_signature_get(msg);
|
|
if (sig && (!strcmp(sig, "b")) && eldbus_message_arguments_get(msg, "b", &mode))
|
|
{
|
|
mpd_async_send_command(empd->async, "pause", mode ? "1" : "0", NULL);
|
|
cmd_append(EMPD_COMMAND_PAUSE);
|
|
}
|
|
else
|
|
{
|
|
mpd_async_send_command(empd->async, "pause", NULL);
|
|
cmd_append(EMPD_COMMAND_TOGGLE_PAUSE);
|
|
}
|
|
fdh_update();
|
|
return eldbus_message_method_return_new(msg);
|
|
}
|
|
|
|
DBUS_BASIC_CB(stop, STOP)
|
|
DBUS_BASIC_CB(next, NEXT)
|
|
DBUS_BASIC_CB(previous, PREVIOUS)
|
|
|
|
static Eldbus_Message *
|
|
_dbus_seek_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
|
|
{
|
|
unsigned int songid, seconds;
|
|
|
|
if (eldbus_message_arguments_get(msg, "uu", &songid, &seconds))
|
|
{
|
|
char id[256], pos[256];
|
|
|
|
snprintf(id, sizeof(id), "%u", songid);
|
|
snprintf(pos, sizeof(pos), "%u", seconds);
|
|
mpd_async_send_command(empd->async, "seekid", id, pos, NULL);
|
|
cmd_append(EMPD_COMMAND_SEEK);
|
|
fdh_update();
|
|
}
|
|
return eldbus_message_method_return_new(msg);
|
|
}
|
|
|
|
static Eldbus_Message *
|
|
_dbus_playid_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
|
|
{
|
|
unsigned int songid;
|
|
|
|
if (eldbus_message_arguments_get(msg, "u", &songid))
|
|
{
|
|
char id[256];
|
|
|
|
snprintf(id, sizeof(id), "%u", songid);
|
|
mpd_async_send_command(empd->async, "playid", id, NULL);
|
|
cmd_append(EMPD_COMMAND_PLAY_ID);
|
|
fdh_update();
|
|
}
|
|
return eldbus_message_method_return_new(msg);
|
|
}
|
|
|
|
static Eldbus_Message *
|
|
_dbus_queue_list_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
|
|
{
|
|
int start, end;
|
|
const char *sig;
|
|
|
|
sig = eldbus_message_signature_get(msg);
|
|
if (sig && (!strcmp(sig, "ii")) && eldbus_message_arguments_get(msg, "ii", &start, &end))
|
|
{
|
|
char s[256];
|
|
|
|
if ((end != -1) && (end < start))
|
|
return eldbus_message_method_return_new(msg);
|
|
if (end == -1)
|
|
snprintf(s, sizeof(s), "%d:", start);
|
|
else
|
|
snprintf(s, sizeof(s), "%d:%d", start, end);
|
|
mpd_async_send_command(empd->async, "playlistinfo", s, NULL);
|
|
}
|
|
else
|
|
mpd_async_send_command(empd->async, "playlistinfo", NULL);
|
|
cmd_append(EMPD_COMMAND_QUEUE_LIST);
|
|
fdh_update();
|
|
return eldbus_message_method_return_new(msg);
|
|
}
|
|
|
|
|
|
static const Eldbus_Method empd_methods[] =
|
|
{
|
|
{ "Status", NULL, NULL, _dbus_status_cb, 0},
|
|
{ "CurrentSong", NULL, NULL, _dbus_currentsong_cb, 0},
|
|
{ "Play", NULL, NULL, _dbus_play_cb, 0},
|
|
{ "Pause", ELDBUS_ARGS({"b", "mode"}), NULL, _dbus_pause_cb, 0},
|
|
{ "TogglePause", NULL, NULL, _dbus_pause_cb, 0},
|
|
{ "Stop", NULL, NULL, _dbus_stop_cb, 0},
|
|
{ "Next", NULL, NULL, _dbus_next_cb, 0},
|
|
{ "Previous", NULL, NULL, _dbus_previous_cb, 0},
|
|
{ "Seek", ELDBUS_ARGS({"u", "songid"}, {"u", "position_in_seconds"}), NULL, _dbus_seek_cb, 0},
|
|
{ "PlayId", ELDBUS_ARGS({"u", "songid"}), NULL, _dbus_playid_cb, 0},
|
|
{ "QueueList", NULL, NULL, _dbus_queue_list_cb, 0},
|
|
{ "QueueListRange", ELDBUS_ARGS({"i", "start"}, {"i", "num"}), NULL, _dbus_queue_list_cb, 0},
|
|
{NULL, NULL, NULL, NULL, 0}
|
|
};
|
|
|
|
static const Eldbus_Service_Interface_Desc base_desc =
|
|
{
|
|
EMPD_METHOD_BASE, empd_methods, empd_signals, NULL, NULL, NULL
|
|
};
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
const char *h;
|
|
struct mpd_settings *settings;
|
|
|
|
if (argc < 2)
|
|
{
|
|
int port = DEFAULT_PORT;
|
|
char *p;
|
|
|
|
h = getenv("MPD_HOST");
|
|
if (!h) return 1;
|
|
p = strchr(h, ':');
|
|
if (p)
|
|
{
|
|
char host[1024] = {0};
|
|
port = strtol(p + 1, NULL, 10);
|
|
memcpy(host, h, p - h);
|
|
settings = mpd_settings_new(host, port, 3000, NULL, NULL);
|
|
}
|
|
else
|
|
settings = mpd_settings_new(h, port, 3000, NULL, NULL);
|
|
}
|
|
else
|
|
settings = mpd_settings_new(argv[1], atoi(argv[2]), 3000, NULL, NULL);
|
|
|
|
if (!settings) return 1;
|
|
empd = calloc(1, sizeof(EMPD));
|
|
empd->settings = settings;
|
|
ecore_con_init();
|
|
eldbus_init();
|
|
ecore_app_args_set(argc, (const char**)argv);
|
|
|
|
{
|
|
const char *t;
|
|
t = getenv("EINA_MEMPOOL");
|
|
if ((!t) || (!t[0])) t = "chained_mempool";
|
|
|
|
slist_mempool = eina_mempool_add(t, "E_Slist", NULL, sizeof(E_Slist), 64);
|
|
if (!slist_mempool)
|
|
slist_mempool = eina_mempool_add("pass_through", "E_Slist", NULL, sizeof(E_Slist), 64);
|
|
}
|
|
|
|
dbus_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
|
|
eldbus_name_request(dbus_conn, EMPD_METHOD_BASE, 0, _dbus_request_name_cb, NULL);
|
|
empd_iface = eldbus_service_interface_register(dbus_conn, "/", &base_desc);
|
|
|
|
E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_SERVER_ADD, con, NULL);
|
|
E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_SERVER_DEL, del, NULL);
|
|
E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_SERVER_DATA, data, NULL);
|
|
|
|
h = mpd_settings_get_host(settings);
|
|
empd->svr = ecore_con_server_connect(conn_type_get(h), h, (int)mpd_settings_get_port(settings), empd);
|
|
ecore_main_loop_begin();
|
|
|
|
return 0;
|
|
}
|