[queue] Refactor queue handling

Decouple the playing/streaming item from the queue. Move all queue
related functions to seperate file queue.h/c.
Introduce internal item "head" to make iterating over the play-queue and
shuffle-queue easier.
This commit is contained in:
chme 2015-08-08 18:02:49 +02:00
parent 10d7097f98
commit 1f53d7ab1a
7 changed files with 1825 additions and 1168 deletions

View File

@ -102,6 +102,7 @@ forked_daapd_SOURCES = main.c \
rsp_query.c rsp_query.h \ rsp_query.c rsp_query.h \
daap_query.c daap_query.h \ daap_query.c daap_query.h \
player.c player.h \ player.c player.h \
queue.c queue.h \
worker.c worker.h \ worker.c worker.h \
$(ALSA_SRC) $(OSS4_SRC) \ $(ALSA_SRC) $(OSS4_SRC) \
laudio_dummy.c \ laudio_dummy.c \

View File

@ -50,6 +50,7 @@
#include "db.h" #include "db.h"
#include "daap_query.h" #include "daap_query.h"
#include "player.h" #include "player.h"
#include "queue.h"
#include "listener.h" #include "listener.h"
/* httpd event base, from httpd.c */ /* httpd event base, from httpd.c */
@ -757,6 +758,7 @@ dacp_reply_ctrlint(struct evhttp_request *req, struct evbuffer *evbuf, char **ur
static int static int
find_first_song_id(const char *query) find_first_song_id(const char *query)
{ {
//TODO [refactor][performance] Unnecessary query, it is enough to extract the item id from the query string. Accessing the db to verify the item exists is not needed.
struct db_media_file_info dbmfi; struct db_media_file_info dbmfi;
struct query_params qp; struct query_params qp;
int id; int id;
@ -821,11 +823,11 @@ find_first_song_id(const char *query)
static int static int
make_queue_for_query(struct player_source **head, const char *query, const char *queuefilter, const char *sort, int quirk) make_queue_for_query(struct queue_item **head, const char *query, const char *queuefilter, const char *sort, int quirk)
{ {
struct media_file_info *mfi; struct media_file_info *mfi;
struct query_params qp; struct query_params qp;
struct player_source *ps; struct queue_item *items;
int64_t albumid; int64_t albumid;
int64_t artistid; int64_t artistid;
int plid; int plid;
@ -941,22 +943,18 @@ make_queue_for_query(struct player_source **head, const char *query, const char
qp.sort = S_ARTIST; qp.sort = S_ARTIST;
} }
ps = player_queue_make(&qp); items = queue_make(&qp);
if (qp.filter) if (qp.filter)
free(qp.filter); free(qp.filter);
if (ps) if (items)
*head = ps; *head = items;
else else
return -1; return -1;
idx = 0; // Get the position (0-based) of the first item
while (id && ps && ps->pl_next && (ps->id != id) && (ps->pl_next != *head)) idx = queueitem_pos(items, id);
{
idx++;
ps = ps->pl_next;
}
return idx; return idx;
} }
@ -965,7 +963,7 @@ static void
dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
struct player_status status; struct player_status status;
struct player_source *ps; struct queue_item *items;
const char *sort; const char *sort;
const char *cuequery; const char *cuequery;
const char *param; const char *param;
@ -997,7 +995,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
{ {
sort = evhttp_find_header(query, "sort"); sort = evhttp_find_header(query, "sort");
ret = make_queue_for_query(&ps, cuequery, NULL, sort, 0); ret = make_queue_for_query(&items, cuequery, NULL, sort, 0);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DACP, "Could not build song queue\n"); DPRINTF(E_LOG, L_DACP, "Could not build song queue\n");
@ -1006,7 +1004,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
return; return;
} }
player_queue_add(ps); player_queue_add(items);
} }
else else
{ {
@ -1063,9 +1061,9 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
/* If playing from history queue, the pos holds the id of the item to play */ /* If playing from history queue, the pos holds the id of the item to play */
if (hist) if (hist)
ret = player_playback_startid(id, &id); ret = player_playback_start_byitemid(id, &id);
else else
ret = player_playback_startpos(pos, &id); ret = player_playback_start_bypos(pos, &id);
if (ret < 0) if (ret < 0)
{ {
@ -1134,7 +1132,7 @@ static void
dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
struct player_status status; struct player_status status;
struct player_source *ps; struct queue_item *items;
struct daap_session *s; struct daap_session *s;
const char *param; const char *param;
const char *shuffle; const char *shuffle;
@ -1216,8 +1214,8 @@ dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **u
DPRINTF(E_DBG, L_DACP, "Playspec request for playlist %d, start song id %d%s\n", plid, pos, (shuffle) ? ", shuffle" : ""); DPRINTF(E_DBG, L_DACP, "Playspec request for playlist %d, start song id %d%s\n", plid, pos, (shuffle) ? ", shuffle" : "");
ps = player_queue_make_pl(plid, &pos); items = queue_make_pl(plid); //TODO [queue] get queue-item-id or pos for first song to play (dacp) --- , &pos);
if (!ps) if (!items)
{ {
DPRINTF(E_LOG, L_DACP, "Could not build song queue from playlist %d\n", plid); DPRINTF(E_LOG, L_DACP, "Could not build song queue from playlist %d\n", plid);
@ -1232,13 +1230,13 @@ dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **u
player_playback_stop(); player_playback_stop();
player_queue_clear(); player_queue_clear();
player_queue_add(ps); player_queue_add(items);
player_queue_plid(plid); player_queue_plid(plid);
if (shuffle) if (shuffle)
dacp_propset_shufflestate(shuffle, NULL); dacp_propset_shufflestate(shuffle, NULL);
ret = player_playback_startpos(pos, &id); ret = player_playback_start_bypos(pos, &id);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DACP, "Could not start playback\n"); DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
@ -1472,7 +1470,7 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
struct evbuffer *playlists; struct evbuffer *playlists;
struct player_status status; struct player_status status;
struct player_history *history; struct player_history *history;
struct player_queue *queue; struct queue_info *queue;
const char *param; const char *param;
size_t songlist_length; size_t songlist_length;
size_t playlist_length; size_t playlist_length;
@ -1544,13 +1542,13 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
/* Get queue and make songlist only if playing or paused */ /* Get queue and make songlist only if playing or paused */
if (status.status != PLAY_STOPPED) if (status.status != PLAY_STOPPED)
{ {
queue = player_queue_get_relative(abs(span)); queue = player_queue_get_bypos(abs(span));
if (queue) if (queue)
{ {
i = queue->start_pos; i = queue->start_pos;
for (n = 0; (n < queue->count) && (n < abs(span)); n++) for (n = 0; (n < queue->count) && (n < abs(span)); n++)
{ {
ret = playqueuecontents_add_source(songlist, queue->queue[n], (n + i + 1), status.plid); ret = playqueuecontents_add_source(songlist, queue->queue[n].dbmfi_id, (n + i + 1), status.plid);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n"); DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
@ -1559,8 +1557,8 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
return; return;
} }
} }
queue_info_free(queue);
} }
queue_free(queue);
} }
} }
@ -1644,9 +1642,7 @@ static void
dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
const char *param; const char *param;
int clear_hist;
clear_hist = 0;
param = evhttp_find_header(query, "mode"); param = evhttp_find_header(query, "mode");
/* /*
@ -1655,9 +1651,9 @@ dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbu
* otherwise the current playlist. * otherwise the current playlist.
*/ */
if (strcmp(param,"0x68697374") == 0) if (strcmp(param,"0x68697374") == 0)
clear_hist = 1; player_queue_clear_history();
else
player_queue_empty(clear_hist); player_queue_clear();
dmap_add_container(evbuf, "cacr", 24); /* 8 + len */ dmap_add_container(evbuf, "cacr", 24); /* 8 + len */
dmap_add_int(evbuf, "mstt", 200); /* 12 */ dmap_add_int(evbuf, "mstt", 200); /* 12 */
@ -1678,7 +1674,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
//?command=add&query='dmap.itemid:2'&query-modifier=containers&sort=name&mode=2&session-id=100 //?command=add&query='dmap.itemid:2'&query-modifier=containers&sort=name&mode=2&session-id=100
// -> mode 2: stop playblack, clear playqueue, add shuffled songs from playlist=itemid to playqueue // -> mode 2: stop playblack, clear playqueue, add shuffled songs from playlist=itemid to playqueue
struct player_source *ps; struct queue_item *items;
const char *editquery; const char *editquery;
const char *queuefilter; const char *queuefilter;
const char *querymodifier; const char *querymodifier;
@ -1730,7 +1726,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
if (!querymodifier || (strcmp(querymodifier, "containers") != 0)) if (!querymodifier || (strcmp(querymodifier, "containers") != 0))
{ {
quirkyquery = (mode == 1) && strstr(editquery, "dmap.itemid:") && ((!queuefilter) || strstr(queuefilter, "(null)")); quirkyquery = (mode == 1) && strstr(editquery, "dmap.itemid:") && ((!queuefilter) || strstr(queuefilter, "(null)"));
ret = make_queue_for_query(&ps, editquery, queuefilter, sort, quirkyquery); ret = make_queue_for_query(&items, editquery, queuefilter, sort, quirkyquery);
} }
else else
{ {
@ -1745,7 +1741,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
} }
snprintf(modifiedquery, sizeof(modifiedquery), "playlist:%d", plid); snprintf(modifiedquery, sizeof(modifiedquery), "playlist:%d", plid);
ret = make_queue_for_query(&ps, NULL, modifiedquery, sort, 0); ret = make_queue_for_query(&items, NULL, modifiedquery, sort, 0);
} }
if (ret < 0) if (ret < 0)
@ -1760,11 +1756,11 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
if (mode == 3) if (mode == 3)
{ {
player_queue_add_next(ps); player_queue_add_next(items);
} }
else else
{ {
player_queue_add(ps); player_queue_add(items);
} }
} }
else else
@ -1782,7 +1778,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
} }
DPRINTF(E_DBG, L_DACP, "Song queue built, playback starting at index %" PRIu32 "\n", idx); DPRINTF(E_DBG, L_DACP, "Song queue built, playback starting at index %" PRIu32 "\n", idx);
ret = player_playback_startpos(idx, NULL); ret = player_playback_start_bypos(idx, NULL);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DACP, "Could not start playback\n"); DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
@ -1833,7 +1829,7 @@ dacp_reply_playqueueedit_move(struct evhttp_request *req, struct evbuffer *evbuf
return; return;
} }
player_queue_move(src, dst); player_queue_move_bypos(src, dst);
} }
/* 204 No Content is the canonical reply */ /* 204 No Content is the canonical reply */
@ -1865,7 +1861,7 @@ dacp_reply_playqueueedit_remove(struct evhttp_request *req, struct evbuffer *evb
return; return;
} }
player_queue_remove_pos_relative(item_index); player_queue_remove_bypos(item_index);
} }
/* 204 No Content is the canonical reply */ /* 204 No Content is the canonical reply */

101
src/mpd.c
View File

@ -57,6 +57,7 @@
#include "artwork.h" #include "artwork.h"
#include "player.h" #include "player.h"
#include "queue.h"
#include "filescanner.h" #include "filescanner.h"
@ -1210,7 +1211,7 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
if (songpos > 0) if (songpos > 0)
ret = player_playback_startpos(songpos, NULL); ret = player_playback_start_byindex(songpos, NULL);
else else
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
@ -1263,7 +1264,7 @@ mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
if (id > 0) if (id > 0)
ret = player_playback_startid(id, NULL); ret = player_playback_start_byitemid(id, NULL);
else else
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
@ -1506,11 +1507,11 @@ mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return 0; return 0;
} }
static struct player_source * static struct queue_item *
make_queue_for_path(char *path, int recursive) make_queue_for_path(char *path, int recursive)
{ {
struct query_params qp; struct query_params qp;
struct player_source *ps; struct queue_item *items;
memset(&qp, 0, sizeof(struct query_params)); memset(&qp, 0, sizeof(struct query_params));
@ -1531,10 +1532,10 @@ make_queue_for_path(char *path, int recursive)
DPRINTF(E_DBG, L_PLAYER, "Out of memory\n"); DPRINTF(E_DBG, L_PLAYER, "Out of memory\n");
} }
ps = player_queue_make(&qp); items = queue_make(&qp);
sqlite3_free(qp.filter); sqlite3_free(qp.filter);
return ps; return items;
} }
/* /*
@ -1545,7 +1546,7 @@ make_queue_for_path(char *path, int recursive)
static int static int
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct player_source *ps; struct queue_item *items;
int ret; int ret;
if (argc < 2) if (argc < 2)
@ -1556,9 +1557,9 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
} }
ps = make_queue_for_path(argv[1], 1); items = make_queue_for_path(argv[1], 1);
if (!ps) if (!items)
{ {
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]); ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
if (ret < 0) if (ret < 0)
@ -1566,7 +1567,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_UNKNOWN; return ACK_ERROR_UNKNOWN;
} }
player_queue_add(ps); player_queue_add(items);
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
if (ret < 0) if (ret < 0)
@ -1586,7 +1587,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
static int static int
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct player_source *ps; struct queue_item *items;
int ret; int ret;
if (argc < 2) if (argc < 2)
@ -1603,9 +1604,9 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
DPRINTF(E_LOG, L_MPD, "Adding at a specified position not supported for 'addid', adding songs at end of queue.\n"); DPRINTF(E_LOG, L_MPD, "Adding at a specified position not supported for 'addid', adding songs at end of queue.\n");
} }
ps = make_queue_for_path(argv[1], 0); items = make_queue_for_path(argv[1], 0);
if (!ps) if (!items)
{ {
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]); ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
if (ret < 0) if (ret < 0)
@ -1614,13 +1615,14 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
player_queue_add(ps); player_queue_add(items);
//TODO [queue] Get queue-item-id for mpd-command addid
evbuffer_add_printf(evbuf, evbuffer_add_printf(evbuf,
"addid: %s\n" "addid: %s\n"
"Id: %d\n", "Id: %d\n",
argv[1], argv[1],
ps->id); 0); //ps->id);
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
if (ret < 0) if (ret < 0)
@ -1668,7 +1670,7 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
// If argv[1] is ommited clear the whole queue except the current playing one // If argv[1] is ommited clear the whole queue except the current playing one
if (argc < 2) if (argc < 2)
{ {
player_queue_empty(0); player_queue_clear();
return 0; return 0;
} }
@ -1695,7 +1697,7 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
} }
ret = player_queue_remove_pos_relative(pos); ret = player_queue_remove_bypos(pos);
if (ret < 0) if (ret < 0)
{ {
ret = asprintf(errmsg, "Failed to remove song at position '%d'", pos); ret = asprintf(errmsg, "Failed to remove song at position '%d'", pos);
@ -1734,7 +1736,7 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
} }
ret = player_queue_remove_queueitemid(songid); ret = player_queue_remove_byitemid(songid);
if (ret < 0) if (ret < 0)
{ {
ret = asprintf(errmsg, "Failed to remove song with id '%s'", argv[1]); ret = asprintf(errmsg, "Failed to remove song with id '%s'", argv[1]);
@ -1756,7 +1758,7 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
static int static int
mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct player_queue *queue; struct queue_info *queue;
uint32_t songid; uint32_t songid;
int pos_pl; int pos_pl;
int i; int i;
@ -1777,7 +1779,7 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
} }
// Get the whole queue (start_pos = 0, end_pos = -1) // Get the whole queue (start_pos = 0, end_pos = -1)
queue = player_queue_get(0, 0); queue = player_queue_get_byindex(0, 0);
if (!queue) if (!queue)
{ {
@ -1788,14 +1790,14 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
pos_pl = queue->start_pos; pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++) for (i = 0; i < queue->count; i++)
{ {
if (songid == 0 || songid == queue->queue[i]) if (songid == 0 || songid == queue->queue[i].item_id)
{ {
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl); ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i].dbmfi_id, pos_pl);
if (ret < 0) if (ret < 0)
{ {
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i]); ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i].dbmfi_id);
queue_free(queue); queue_info_free(queue);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_MPD, "Out of memory\n"); DPRINTF(E_LOG, L_MPD, "Out of memory\n");
@ -1806,7 +1808,7 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
pos_pl++; pos_pl++;
} }
queue_free(queue); queue_info_free(queue);
return 0; return 0;
} }
@ -1822,7 +1824,7 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
static int static int
mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct player_queue *queue; struct queue_info *queue;
int start_pos; int start_pos;
int end_pos; int end_pos;
int count; int count;
@ -1854,7 +1856,7 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
count = 0; count = 0;
} }
queue = player_queue_get(start_pos, count); queue = player_queue_get_byindex(start_pos, count);
if (!queue) if (!queue)
{ {
@ -1865,12 +1867,12 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
pos_pl = queue->start_pos; pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++) for (i = 0; i < queue->count; i++)
{ {
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl); ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i].dbmfi_id, pos_pl);
if (ret < 0) if (ret < 0)
{ {
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i]); ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i].dbmfi_id);
queue_free(queue); queue_info_free(queue);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_MPD, "Out of memory\n"); DPRINTF(E_LOG, L_MPD, "Out of memory\n");
@ -1880,7 +1882,7 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
pos_pl++; pos_pl++;
} }
queue_free(queue); queue_info_free(queue);
return 0; return 0;
} }
@ -1892,7 +1894,7 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
static int static int
mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct player_queue *queue; struct queue_info *queue;
int pos_pl; int pos_pl;
int i; int i;
int ret; int ret;
@ -1901,7 +1903,7 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
* forked-daapd does not keep track of changes in the queue based on the playlist version, * forked-daapd does not keep track of changes in the queue based on the playlist version,
* therefor plchanges returns all songs in the queue as changed ignoring the given version. * therefor plchanges returns all songs in the queue as changed ignoring the given version.
*/ */
queue = player_queue_get(0, 0); queue = player_queue_get_byindex(0, 0);
if (!queue) if (!queue)
{ {
@ -1912,12 +1914,12 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
pos_pl = queue->start_pos; pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++) for (i = 0; i < queue->count; i++)
{ {
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl); ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i].dbmfi_id, pos_pl);
if (ret < 0) if (ret < 0)
{ {
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i]); ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i].dbmfi_id);
queue_free(queue); queue_info_free(queue);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_MPD, "Out of memory\n"); DPRINTF(E_LOG, L_MPD, "Out of memory\n");
@ -1927,7 +1929,7 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
pos_pl++; pos_pl++;
} }
queue_free(queue); queue_info_free(queue);
return 0; return 0;
} }
@ -2141,8 +2143,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct playlist_info *pli; struct playlist_info *pli;
struct player_source *ps; struct queue_item *items;
uint32_t pos;
int ret; int ret;
if (argc < 2) if (argc < 2)
@ -2173,9 +2174,9 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
//TODO If a second parameter is given only add the specified range of songs to the playqueue //TODO If a second parameter is given only add the specified range of songs to the playqueue
ps = player_queue_make_pl(pli->id, &pos); items = queue_make_pl(pli->id);
if (!ps) if (!items)
{ {
free_pli(pli, 0); free_pli(pli, 0);
@ -2185,7 +2186,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_UNKNOWN; return ACK_ERROR_UNKNOWN;
} }
player_queue_add(ps); player_queue_add(items);
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
if (ret < 0) if (ret < 0)
@ -2422,7 +2423,7 @@ static int
mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct query_params qp; struct query_params qp;
struct player_source *ps; struct queue_item *items;
int ret; int ret;
if (argc < 3 || ((argc - 1) % 2) != 0) if (argc < 3 || ((argc - 1) % 2) != 0)
@ -2441,9 +2442,9 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
mpd_get_query_params_find(argc - 1, argv + 1, &qp); mpd_get_query_params_find(argc - 1, argv + 1, &qp);
ps = player_queue_make(&qp); items = queue_make(&qp);
if (!ps) if (!items)
{ {
ret = asprintf(errmsg, "Failed to add songs to playlist"); ret = asprintf(errmsg, "Failed to add songs to playlist");
if (ret < 0) if (ret < 0)
@ -2451,7 +2452,7 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
return ACK_ERROR_UNKNOWN; return ACK_ERROR_UNKNOWN;
} }
player_queue_add(ps); player_queue_add(items);
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
if (ret < 0) if (ret < 0)
@ -2896,7 +2897,7 @@ static int
mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{ {
struct query_params qp; struct query_params qp;
struct player_source *ps; struct queue_item *items;
int ret; int ret;
if (argc < 3 || ((argc - 1) % 2) != 0) if (argc < 3 || ((argc - 1) % 2) != 0)
@ -2915,9 +2916,9 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
mpd_get_query_params_search(argc - 1, argv + 1, &qp); mpd_get_query_params_search(argc - 1, argv + 1, &qp);
ps = player_queue_make(&qp); items = queue_make(&qp);
if (!ps) if (!items)
{ {
ret = asprintf(errmsg, "Failed to add songs to playlist"); ret = asprintf(errmsg, "Failed to add songs to playlist");
if (ret < 0) if (ret < 0)
@ -2925,7 +2926,7 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
return ACK_ERROR_UNKNOWN; return ACK_ERROR_UNKNOWN;
} }
player_queue_add(ps); player_queue_add(items);
ret = player_playback_start(NULL); ret = player_playback_start(NULL);
if (ret < 0) if (ret < 0)

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include <stdint.h> #include <stdint.h>
#include "db.h" #include "db.h"
#include "queue.h"
/* AirTunes v2 packet interval in ns */ /* AirTunes v2 packet interval in ns */
/* (352 samples/packet * 1e9 ns/s) / 44100 samples/s = 7981859 ns/packet */ /* (352 samples/packet * 1e9 ns/s) / 44100 samples/s = 7981859 ns/packet */
@ -27,12 +28,6 @@ enum play_status {
PLAY_PLAYING = 4, PLAY_PLAYING = 4,
}; };
enum repeat_mode {
REPEAT_OFF = 0,
REPEAT_SONG = 1,
REPEAT_ALL = 2,
};
struct spk_flags { struct spk_flags {
unsigned selected:1; unsigned selected:1;
unsigned has_password:1; unsigned has_password:1;
@ -72,30 +67,6 @@ struct player_status {
typedef void (*spk_enum_cb)(uint64_t id, const char *name, int relvol, struct spk_flags flags, void *arg); typedef void (*spk_enum_cb)(uint64_t id, const char *name, int relvol, struct spk_flags flags, void *arg);
struct player_source
{
uint32_t id;
uint32_t len_ms;
enum data_kind data_kind;
enum media_kind media_kind;
int setup_done;
uint64_t stream_start;
uint64_t output_start;
uint64_t end;
struct transcode_ctx *ctx;
struct player_source *pl_next;
struct player_source *pl_prev;
struct player_source *shuffle_next;
struct player_source *shuffle_prev;
struct player_source *play_next;
};
struct player_queue struct player_queue
{ {
// The item id of the current playing item // The item id of the current playing item
@ -146,10 +117,13 @@ int
player_playback_start(uint32_t *idx_id); player_playback_start(uint32_t *idx_id);
int int
player_playback_startpos(int pos, uint32_t *itemid); player_playback_start_byindex(int pos, uint32_t *itemid);
int int
player_playback_startid(uint32_t id, uint32_t *itemid); player_playback_start_bypos(int pos, uint32_t *itemid);
int
player_playback_start_byitemid(uint32_t id, uint32_t *itemid);
int int
player_playback_stop(void); player_playback_stop(void);
@ -182,51 +156,38 @@ player_repeat_set(enum repeat_mode mode);
int int
player_shuffle_set(int enable); player_shuffle_set(int enable);
struct player_source *
player_queue_make(struct query_params *qp);
//int struct queue_info *
//player_queue_make_daap(struct player_source **head, const char *query, const char *queuefilter, const char *sort, int quirk); player_queue_get_bypos(int count);
struct player_source * struct queue_info *
player_queue_make_pl(int plid, uint32_t *id); player_queue_get_byindex(int pos, int count);
//struct player_source *
//player_queue_make_mpd(char *path, int recursive);
struct player_queue *
player_queue_get_relative(int count);
struct player_queue *
player_queue_get(int pos, int count);
void
queue_free(struct player_queue *queue);
int int
player_queue_add(struct player_source *ps); player_queue_add(struct queue_item *items);
int int
player_queue_add_next(struct player_source *ps); player_queue_add_next(struct queue_item *items);
int int
player_queue_move(int ps_pos_from, int ps_pos_to); player_queue_move_bypos(int ps_pos_from, int ps_pos_to);
int int
player_queue_remove_pos_relative(int pos); player_queue_remove_bypos(int pos);
int int
player_queue_remove_queueitemid(uint32_t id); player_queue_remove_byitemid(uint32_t id);
void void
player_queue_clear(void); player_queue_clear(void);
void void
player_queue_empty(int clear_hist); player_queue_clear_history(void);
void void
player_queue_plid(uint32_t plid); player_queue_plid(uint32_t plid);
struct player_history * struct player_history *
player_history_get(void); player_history_get(void);

1091
src/queue.c Normal file

File diff suppressed because it is too large Load Diff

129
src/queue.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef SRC_QUEUE_H_
#define SRC_QUEUE_H_
enum repeat_mode {
REPEAT_OFF = 0,
REPEAT_SONG = 1,
REPEAT_ALL = 2,
};
/*
* Internal representation of a queue
*/
struct queue;
/*
* Internal representation of a list of queue items
*/
struct queue_item;
/*
* External representation of an item in a queue
*/
struct queue_item_info
{
/* Item-Id is a unique id for this queue item. If the same item appears multiple
times in the queue each corresponding queue item has its own id. */
unsigned int item_id;
/* Id of the file/item in the files database */
unsigned int dbmfi_id;
/* Length of the item in ms */
unsigned int len_ms;
/* Data type of the item */
enum data_kind data_kind;
/* Media type of the item */
enum media_kind media_kind;
};
/*
* External representation of a queue
*/
struct queue_info
{
// The number of items in the queue
unsigned int length;
// The position (0-based) in the queue for the first item in the queue array
unsigned int start_pos;
// The number of items in the queue array
unsigned int count;
// The queue array (array of items infos)
struct queue_item_info *queue;
};
struct queue *
queue_new();
void
queue_free(struct queue *queue);
unsigned int
queue_count(struct queue *queue);
int
queueitem_pos(struct queue_item *item, uint32_t dbmfi_id);
struct queue_item_info *
queue_get_byitemid(struct queue *queue, unsigned int item_id);
struct queue_item_info *
queue_get_byindex(struct queue *queue, unsigned int index, char shuffle);
struct queue_item_info *
queue_get_bypos(struct queue *queue, unsigned int item_id, unsigned int pos, char shuffle);
int
queue_index_byitemid(struct queue *queue, unsigned int item_id, char shuffle);
struct queue_item_info *
queue_next(struct queue *queue, unsigned int item_id, char shuffle, enum repeat_mode r_mode);
struct queue_item_info *
queue_prev(struct queue *queue, unsigned int item_id, char shuffle, enum repeat_mode r_mode);
struct queue_info *
queue_info_new_byindex(struct queue *queue, unsigned int index, unsigned int count, char shuffle);
struct queue_info *
queue_info_new_bypos(struct queue *queue, unsigned int item_id, unsigned int count, char shuffle);
void
queue_info_free(struct queue_info *qi);
void
queue_add(struct queue *queue, struct queue_item *item);
void
queue_add_after(struct queue *queue, struct queue_item *item, unsigned int item_id);
void
queue_move_bypos(struct queue *queue, unsigned int item_id, unsigned int from_pos, unsigned int to_offset, char shuffle);
void
queue_remove_byitemid(struct queue *queue, unsigned int item_id);
void
queue_remove_byindex(struct queue *queue, unsigned int index, char shuffle);
void
queue_remove_bypos(struct queue *queue, unsigned int item_id, unsigned int pos, char shuffle);
void
queue_clear(struct queue *queue);
void
queue_shuffle(struct queue *queue, unsigned int item_id);
struct queue_item *
queue_make(struct query_params *qp);
struct queue_item *
queue_make_pl(int plid);
#endif /* SRC_QUEUE_H_ */