add signal/handling for managing queue list changes using incremental updates

this is a significantly more lightweight method of updating the current queue
after any changes have been made, allowing clients to perform updates on only
part of the current queue instead of receiving the entire thing in a giant
chunk any time a change occurs
This commit is contained in:
Mike Blumenkrantz 2016-02-08 11:52:46 -05:00
parent 4db0a19dd3
commit ba50156ec4
2 changed files with 66 additions and 24 deletions

View File

@ -77,6 +77,7 @@ typedef enum
EMPD_COMMAND_UPDATE,
EMPD_COMMAND_FIND,
EMPD_COMMAND_IDLE,
EMPD_COMMAND_QUEUE_CHANGES_META,
} EMPD_Command;
static const char *cmd_txt[] =
@ -113,6 +114,7 @@ static const char *cmd_txt[] =
CMD_TXT(EMPD_COMMAND_UPDATE)
CMD_TXT(EMPD_COMMAND_FIND)
CMD_TXT(EMPD_COMMAND_IDLE)
CMD_TXT(EMPD_COMMAND_QUEUE_CHANGES_META)
};
typedef enum
@ -124,6 +126,7 @@ typedef enum
EMPD_SIGNAL_STATUS,
EMPD_SIGNAL_CURRENT_SONG,
EMPD_SIGNAL_QUEUE_LIST,
EMPD_SIGNAL_QUEUE_CHANGES_META,
EMPD_SIGNAL_DATABASE_UPDATE_BEGIN,
EMPD_SIGNAL_DATABASE_UPDATE_END,
} EMPD_Signals;
@ -144,6 +147,7 @@ static const Eldbus_Signal empd_signals[] =
{"s", "artist"}, {"s", "composer"}, {"s", "title"}, {"s", "album"}, {"i", "track"},
{"s", "name"}, {"s", "date"}, {"s", "disc"}, {"s", "genre"}, {"i", "song_pos"}, {"i", "songid"}), 0},
[EMPD_SIGNAL_QUEUE_LIST] = {"QueueList", ELDBUS_ARGS({"a(stusssisssii)", "array_of_songs"}), 0},
[EMPD_SIGNAL_QUEUE_CHANGES_META] = {"QueueChangesMeta", ELDBUS_ARGS({"a(stusssisssii)", "array_of_songs"}), 0},
[EMPD_SIGNAL_DATABASE_UPDATE_BEGIN] = {"DatabaseUpdateBegin", NULL, 0},
[EMPD_SIGNAL_DATABASE_UPDATE_END] = {"DatabaseUpdateEnd", NULL, 0},
{NULL, NULL, 0}
@ -160,6 +164,7 @@ static Eldbus_Service_Interface *empd_iface = NULL;
static Eina_Bool fetching_queue = EINA_FALSE;
static unsigned int empd_queue_version = 0;
static unsigned int empd_queue_length = 0;
static int empd_songid = -1;
static int empd_dbupdate = 0;
@ -341,16 +346,13 @@ pinger_cb(void *d EINA_UNUSED)
}
static void
queue_list_send(Eldbus_Message *msg, unsigned int start, long num)
queue_list_info_send(Eldbus_Message *msg, Eina_List *queue_list, unsigned int start, long num, Eina_Bool sig)
{
Eldbus_Message_Iter *iter, *array, *struc;
Eina_List *l;
struct mpd_song *so;
unsigned int cur = 0;
Eina_Bool sig = !msg;
if (!msg)
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)");
EINA_LIST_FOREACH(queue_list, l, so)
@ -374,18 +376,14 @@ queue_list_send(Eldbus_Message *msg, unsigned int start, long num)
eldbus_service_signal_send(empd_iface, msg);
}
static Eina_Bool
queue_item_each_free(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
static void
queue_list_send(Eldbus_Message *msg, unsigned int start, long num)
{
mpd_song_free(data);
return EINA_TRUE;
}
Eina_Bool sig = !msg;
static Eina_Bool
lsinfo_item_each_free(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
{
mpd_entity_free(data);
return EINA_TRUE;
if (!msg)
msg = eldbus_service_signal_new(empd_iface, EMPD_SIGNAL_QUEUE_LIST);
queue_list_info_send(msg, empd->current_queue, start, num, sig);
}
static Eina_Bool
@ -488,7 +486,6 @@ fdh_func(void *d EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED)
case MPD_IDLE_QUEUE:
if (!empd->pinger)
pinger_cb(NULL);
queue_fetch();
break;
case MPD_IDLE_UPDATE:
if (!empd_dbupdate)
@ -551,18 +548,30 @@ fdh_func(void *d EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED)
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), empd_dbupdate);
if (((!empd->current_queue) && (!mpd_status_get_queue_length(st))) ||
((!empd_queue_version) && empd->current_queue &&
(eina_list_count(empd->current_queue) == mpd_status_get_queue_length(st))))
empd_queue_length = mpd_status_get_queue_length(st);
/* if (no queue exists) */
if ((!empd->current_queue) && (!empd_queue_length))
empd_queue_version = mpd_status_get_queue_version(st);
if ((empd_queue_version && (empd_queue_version != mpd_status_get_queue_version(st))) ||
((!empd->current_queue) && (mpd_status_get_queue_length(st))) ||
(empd->current_queue && mpd_status_get_queue_length(st) &&
(eina_list_count(empd->current_queue) != mpd_status_get_queue_length(st))))
/* if (queue exists but has not been fetched) */
else if ((!empd->current_queue) && (mpd_status_get_queue_length(st)))
{
if (queue_fetch())
empd_queue_version = mpd_status_get_queue_version(st);
queue_fetch();
empd_queue_version = mpd_status_get_queue_version(st);
}
else
{
unsigned int version = mpd_status_get_queue_version(st);
for (; empd_queue_version < version; empd_queue_version++)
{
char buf[64];
snprintf(buf, sizeof(buf), "%u", empd_queue_version);
cmd_append(EMPD_COMMAND_QUEUE_CHANGES_META);
mpd_async_send_command(empd->async, "plchanges", buf, NULL);
pinger_cb(NULL);
}
}
status_pending = EINA_FALSE;
switch (mpd_status_get_state(st))
{
case MPD_STATE_PLAY:
@ -601,6 +610,7 @@ fdh_func(void *d EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED)
}
case EMPD_COMMAND_CURRENT_SONG:
case EMPD_COMMAND_QUEUE_LIST:
case EMPD_COMMAND_QUEUE_CHANGES_META:
{
struct mpd_song *so;
@ -646,6 +656,35 @@ fdh_func(void *d EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED)
mpd_song_get_pos(so), mpd_song_get_id(so));
mpd_song_free(so);
}
else if (cmd_get() == EMPD_COMMAND_QUEUE_CHANGES_META)
{
Eina_List *l, *ll;
Eldbus_Message *msg;
if (res != MPD_PARSER_SUCCESS)
break;
msg = eldbus_service_signal_new(empd_iface, EMPD_SIGNAL_QUEUE_CHANGES_META);
queue_list_info_send(msg, empd->pending, 0, -1, 1);
if (!empd->pending)
{
while (eina_list_count(empd->current_queue) > empd_queue_length)
{
mpd_song_free(eina_list_last_data_get(empd->current_queue));
empd->current_queue = eina_list_remove_list(empd->current_queue,
eina_list_last(empd->current_queue));
}
break;
}
so = eina_list_data_get(empd->pending);
EINA_LIST_FOREACH_SAFE(eina_list_nth_list(empd->current_queue, mpd_song_get_pos(so)), l, ll, so)
{
mpd_song_free(so);
empd->current_queue = eina_list_remove_list(empd->current_queue, l);
}
empd->current_queue = eina_list_merge(empd->current_queue, empd->pending);
empd->pending = NULL;
}
else if (cmd_get() == EMPD_COMMAND_QUEUE_LIST)
{
if (res != MPD_PARSER_SUCCESS)

View File

@ -175,6 +175,9 @@
<signal name="QueueList">
<arg type="a(stusssisssii)" name="array_of_songs" direction="out" />
</signal>
<signal name="QueueChangesMeta">
<arg type="a(stusssisssii)" name="array_of_songs" direction="out" />
</signal>
<signal name="LoginFailed">
<arg type="s" name="host" direction="out" />
<arg type="u" name="port" direction="out" />