Merge pull request #183 from chme/queuerefactor3

Queue/player refactoring
This commit is contained in:
ejurgensen 2015-10-05 22:38:34 +02:00
commit 34cc45b12d
11 changed files with 2819 additions and 1928 deletions

View File

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

View File

@ -157,7 +157,7 @@ struct media_file_info {
uint32_t item_kind; /* song or movie */
uint32_t data_kind; /* dmap.datakind (asdk) */
uint64_t sample_count;
uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0
uint32_t compilation;
char artwork;

View File

@ -48,7 +48,9 @@
#include "httpd_dacp.h"
#include "dmap_common.h"
#include "db.h"
#include "daap_query.h"
#include "player.h"
#include "queue.h"
#include "listener.h"
/* httpd event base, from httpd.c */
@ -753,15 +755,219 @@ dacp_reply_ctrlint(struct evhttp_request *req, struct evbuffer *evbuf, char **ur
httpd_send_reply(req, HTTP_OK, "OK", evbuf);
}
static int
find_first_song_id(const char *query)
{
struct db_media_file_info dbmfi;
struct query_params qp;
int id;
int ret;
memset(&qp, 0, sizeof(struct query_params));
/* We only want the id of the first song */
qp.type = Q_ITEMS;
qp.idx_type = I_FIRST;
qp.sort = S_NONE;
qp.offset = 0;
qp.limit = 1;
qp.filter = daap_query_parse_sql(query);
if (!qp.filter)
{
DPRINTF(E_LOG, L_PLAYER, "Improper DAAP query!\n");
return -1;
}
ret = db_query_start(&qp);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not start query\n");
goto no_query_start;
}
if (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{
ret = safe_atoi32(dbmfi.id, &id);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Invalid song id in query result!\n");
goto no_result;
}
DPRINTF(E_DBG, L_PLAYER, "Found index song (id %d)\n", id);
ret = 1;
}
else
{
DPRINTF(E_LOG, L_PLAYER, "No song matches query (results %d): %s\n", qp.results, qp.filter);
goto no_result;
}
no_result:
db_query_end(&qp);
no_query_start:
if (qp.filter)
free(qp.filter);
if (ret == 1)
return id;
else
return -1;
}
static int
dacp_queueitem_make(struct queue_item **head, const char *query, const char *queuefilter, const char *sort, int quirk)
{
struct media_file_info *mfi;
struct query_params qp;
struct queue_item *items;
int64_t albumid;
int64_t artistid;
int plid;
int id;
int idx;
int ret;
int len;
char *s;
char buf[1024];
if (query)
{
id = find_first_song_id(query);
if (id < 0)
return -1;
}
else
id = 0;
memset(&qp, 0, sizeof(struct query_params));
qp.offset = 0;
qp.limit = 0;
qp.sort = S_NONE;
qp.idx_type = I_NONE;
if (quirk)
{
qp.sort = S_ALBUM;
qp.type = Q_ITEMS;
mfi = db_file_fetch_byid(id);
if (!mfi)
return -1;
snprintf(buf, sizeof(buf), "f.songalbumid = %" PRIi64, mfi->songalbumid);
free_mfi(mfi, 0);
qp.filter = strdup(buf);
}
else if (queuefilter)
{
len = strlen(queuefilter);
if ((len > 6) && (strncmp(queuefilter, "album:", 6) == 0))
{
qp.type = Q_ITEMS;
ret = safe_atoi64(strchr(queuefilter, ':') + 1, &albumid);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Invalid album id in queuefilter: %s\n", queuefilter);
return -1;
}
snprintf(buf, sizeof(buf), "f.songalbumid = %" PRIi64, albumid);
qp.filter = strdup(buf);
}
else if ((len > 7) && (strncmp(queuefilter, "artist:", 7) == 0))
{
qp.type = Q_ITEMS;
ret = safe_atoi64(strchr(queuefilter, ':') + 1, &artistid);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Invalid artist id in queuefilter: %s\n", queuefilter);
return -1;
}
snprintf(buf, sizeof(buf), "f.songartistid = %" PRIi64, artistid);
qp.filter = strdup(buf);
}
else if ((len > 9) && (strncmp(queuefilter, "playlist:", 9) == 0))
{
qp.type = Q_PLITEMS;
ret = safe_atoi32(strchr(queuefilter, ':') + 1, &plid);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Invalid playlist id in queuefilter: %s\n", queuefilter);
return -1;
}
qp.id = plid;
qp.filter = strdup("1 = 1");
}
else if ((len > 6) && (strncmp(queuefilter, "genre:", 6) == 0))
{
qp.type = Q_ITEMS;
s = db_escape_string(queuefilter + 6);
if (!s)
return -1;
snprintf(buf, sizeof(buf), "f.genre = '%s'", s);
qp.filter = strdup(buf);
}
else
{
DPRINTF(E_LOG, L_PLAYER, "Unknown queuefilter %s\n", queuefilter);
// If the queuefilter is unkown, ignore it and use the query parameter instead to build the sql query
id = 0;
qp.type = Q_ITEMS;
qp.filter = daap_query_parse_sql(query);
}
}
else
{
id = 0;
qp.type = Q_ITEMS;
qp.filter = daap_query_parse_sql(query);
}
if (sort)
{
if (strcmp(sort, "name") == 0)
qp.sort = S_NAME;
else if (strcmp(sort, "album") == 0)
qp.sort = S_ALBUM;
else if (strcmp(sort, "artist") == 0)
qp.sort = S_ARTIST;
}
items = queueitem_make_byquery(&qp);
if (qp.filter)
free(qp.filter);
if (items)
*head = items;
else
return -1;
// Get the position (0-based) of the first item
idx = queueitem_pos(items, id);
return idx;
}
static void
dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
struct player_status status;
struct player_source *ps;
struct queue_item *items;
const char *sort;
const char *cuequery;
const char *param;
uint32_t id;
uint32_t item_id;
uint32_t pos;
int clear;
struct player_history *history;
@ -789,7 +995,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
{
sort = evhttp_find_header(query, "sort");
ret = player_queue_make_daap(&ps, cuequery, NULL, sort, 0);
ret = dacp_queueitem_make(&items, cuequery, NULL, sort, 0);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not build song queue\n");
@ -798,7 +1004,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
return;
}
player_queue_add(ps);
player_queue_add(items);
}
else
{
@ -813,6 +1019,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
dacp_propset_shufflestate(param, NULL);
id = 0;
item_id = 0;
pos = 0;
param = evhttp_find_header(query, "index");
if (param)
@ -836,7 +1043,7 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
if (history->count > pos)
{
pos = (history->start_index + history->count - pos - 1) % MAX_HISTORY_COUNT;
id = history->id[pos];
item_id = history->item_id[pos];
}
else
{
@ -855,9 +1062,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 (hist)
ret = player_playback_startid(id, &id);
ret = player_playback_start_byitemid(item_id, &id);
else
ret = player_playback_startpos(pos, &id);
ret = player_playback_start_bypos(pos, &id);
if (ret < 0)
{
@ -926,7 +1133,7 @@ static void
dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
struct player_status status;
struct player_source *ps;
struct queue_item *items;
struct daap_session *s;
const char *param;
const char *shuffle;
@ -1008,8 +1215,13 @@ 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" : "");
ps = player_queue_make_pl(plid, &pos);
if (!ps)
items = NULL;
if (plid > 0)
items = queueitem_make_byplid(plid);
else if (pos > 0)
items = queueitem_make_byid(pos);
if (!items)
{
DPRINTF(E_LOG, L_DACP, "Could not build song queue from playlist %d\n", plid);
@ -1024,13 +1236,13 @@ dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **u
player_playback_stop();
player_queue_clear();
player_queue_add(ps);
player_queue_add(items);
player_queue_plid(plid);
if (shuffle)
dacp_propset_shufflestate(shuffle, NULL);
ret = player_playback_startpos(pos, &id);
ret = player_playback_start_bypos(pos, &id);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
@ -1264,11 +1476,13 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
struct evbuffer *playlists;
struct player_status status;
struct player_history *history;
struct player_queue *queue;
struct queue *queue;
struct queue_item *item;
const char *param;
size_t songlist_length;
size_t playlist_length;
int span;
int count;
int i;
int n;
int ret;
@ -1336,13 +1550,15 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
/* Get queue and make songlist only if playing or paused */
if (status.status != PLAY_STOPPED)
{
queue = player_queue_get(-1, abs(span), status.shuffle);
queue = player_queue_get_bypos(abs(span));
if (queue)
{
i = queue->start_pos;
for (n = 0; (n < queue->count) && (n < abs(span)); n++)
i = 0;
count = queue_count(queue);
for (n = 0; (n < count) && (n < abs(span)); n++)
{
ret = playqueuecontents_add_source(songlist, queue->queue[n], (n + i + 1), status.plid);
item = queue_get_byindex(queue, n, 0);
ret = playqueuecontents_add_source(songlist, queueitem_id(item), (n + i + 1), status.plid);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
@ -1351,8 +1567,8 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
return;
}
}
queue_free(queue);
}
queue_free(queue);
}
}
@ -1436,9 +1652,7 @@ static void
dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
const char *param;
int clear_hist;
clear_hist = 0;
param = evhttp_find_header(query, "mode");
/*
@ -1447,9 +1661,9 @@ dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbu
* otherwise the current playlist.
*/
if (strcmp(param,"0x68697374") == 0)
clear_hist = 1;
player_queue_empty(clear_hist);
player_queue_clear_history();
else
player_queue_clear();
dmap_add_container(evbuf, "cacr", 24); /* 8 + len */
dmap_add_int(evbuf, "mstt", 200); /* 12 */
@ -1470,7 +1684,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
// -> 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 *queuefilter;
const char *querymodifier;
@ -1522,7 +1736,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
if (!querymodifier || (strcmp(querymodifier, "containers") != 0))
{
quirkyquery = (mode == 1) && strstr(editquery, "dmap.itemid:") && ((!queuefilter) || strstr(queuefilter, "(null)"));
ret = player_queue_make_daap(&ps, editquery, queuefilter, sort, quirkyquery);
ret = dacp_queueitem_make(&items, editquery, queuefilter, sort, quirkyquery);
}
else
{
@ -1537,7 +1751,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
}
snprintf(modifiedquery, sizeof(modifiedquery), "playlist:%d", plid);
ret = player_queue_make_daap(&ps, NULL, modifiedquery, sort, 0);
ret = dacp_queueitem_make(&items, NULL, modifiedquery, sort, 0);
}
if (ret < 0)
@ -1552,11 +1766,11 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
if (mode == 3)
{
player_queue_add_next(ps);
player_queue_add_next(items);
}
else
{
player_queue_add(ps);
player_queue_add(items);
}
}
else
@ -1574,7 +1788,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);
ret = player_playback_startpos(idx, NULL);
ret = player_playback_start_bypos(idx, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
@ -1625,7 +1839,7 @@ dacp_reply_playqueueedit_move(struct evhttp_request *req, struct evbuffer *evbuf
return;
}
player_queue_move(src, dst);
player_queue_move_bypos(src, dst);
}
/* 204 No Content is the canonical reply */
@ -1657,7 +1871,7 @@ dacp_reply_playqueueedit_remove(struct evhttp_request *req, struct evbuffer *evb
return;
}
player_queue_remove(item_index);
player_queue_remove_bypos(item_index);
}
/* 204 No Content is the canonical reply */

161
src/mpd.c
View File

@ -57,6 +57,7 @@
#include "artwork.h"
#include "player.h"
#include "queue.h"
#include "filescanner.h"
@ -470,11 +471,12 @@ mpd_parse_args(char *args, int *argc, char **argv)
*
* @param evbuf the response event buffer
* @param mfi media information
* @param item_id queue-item id
* @param pos_pl position in the playqueue, if -1 the position is ignored
* @return the number of bytes added if successful, or -1 if an error occurred.
*/
static int
mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, int pos_pl)
mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, unsigned int item_id, int pos_pl)
{
char modified[32];
int ret;
@ -515,10 +517,9 @@ mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, int pos_p
"Pos: %d\n",
pos_pl);
//TODO mpd does not return the persistent id of a file but instead a unique id in the current playlist
ret = evbuffer_add_printf(evbuf,
"Id: %d\n",
mfi->id);
item_id);
}
@ -526,7 +527,7 @@ mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, int pos_p
}
static int
mpd_add_mediainfo_byid(struct evbuffer *evbuf, int id, int pos_pl)
mpd_add_mediainfo_byid(struct evbuffer *evbuf, int id, unsigned int item_id, int pos_pl)
{
struct media_file_info *mfi;
int ret;
@ -538,7 +539,7 @@ mpd_add_mediainfo_byid(struct evbuffer *evbuf, int id, int pos_pl)
return -1;
}
ret = mpd_add_mediainfo(evbuf, mfi, pos_pl);
ret = mpd_add_mediainfo(evbuf, mfi, item_id, pos_pl);
if (ret < 0)
{
DPRINTF(E_LOG, L_MPD, "Error adding media info for file with id: %d\n", id);
@ -649,7 +650,7 @@ mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **er
return 0;
}
ret = mpd_add_mediainfo_byid(evbuf, status.id, status.pos_pl);
ret = mpd_add_mediainfo_byid(evbuf, status.id, status.item_id, status.pos_pl);
if (ret < 0)
{
ret = asprintf(errmsg, "Error adding media info for file with id: %d", status.id);
@ -838,11 +839,11 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
"nextsong: %d\n"
"nextsongid: %d\n",
status.pos_pl,
status.id,
status.item_id,
(status.pos_ms / 1000), (status.len_ms / 1000),
(status.pos_ms / 1000.0),
status.next_pos_pl,
status.next_id);
status.next_item_id);
}
if (filescanner_scanning())
@ -1210,7 +1211,7 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
}
if (songpos > 0)
ret = player_playback_startpos(songpos, NULL);
ret = player_playback_start_byindex(songpos, NULL);
else
ret = player_playback_start(NULL);
@ -1263,7 +1264,7 @@ mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
}
if (id > 0)
ret = player_playback_startid(id, NULL);
ret = player_playback_start_byitemid(id, NULL);
else
ret = player_playback_start(NULL);
@ -1506,6 +1507,37 @@ mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return 0;
}
static struct queue_item *
mpd_queueitem_make(char *path, int recursive)
{
struct query_params qp;
struct queue_item *items;
memset(&qp, 0, sizeof(struct query_params));
qp.type = Q_ITEMS;
qp.idx_type = I_NONE;
qp.sort = S_ALBUM;
if (recursive)
{
qp.filter = sqlite3_mprintf("f.virtual_path LIKE '/%q%%'", path);
if (!qp.filter)
DPRINTF(E_DBG, L_PLAYER, "Out of memory\n");
}
else
{
qp.filter = sqlite3_mprintf("f.virtual_path LIKE '/%q'", path);
if (!qp.filter)
DPRINTF(E_DBG, L_PLAYER, "Out of memory\n");
}
items = queueitem_make_byquery(&qp);
sqlite3_free(qp.filter);
return items;
}
/*
* Command handler function for 'add'
* Adds the all songs under the given path to the end of the playqueue (directories add recursively).
@ -1514,7 +1546,7 @@ mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
static int
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct player_source *ps;
struct queue_item *items;
int ret;
if (argc < 2)
@ -1525,9 +1557,9 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_ARG;
}
ps = player_queue_make_mpd(argv[1], 1);
items = mpd_queueitem_make(argv[1], 1);
if (!ps)
if (!items)
{
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
if (ret < 0)
@ -1535,7 +1567,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_UNKNOWN;
}
player_queue_add(ps);
player_queue_add(items);
ret = player_playback_start(NULL);
if (ret < 0)
@ -1555,7 +1587,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
static int
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct player_source *ps;
struct queue_item *items;
int ret;
if (argc < 2)
@ -1572,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");
}
ps = player_queue_make_mpd(argv[1], 0);
items = mpd_queueitem_make(argv[1], 0);
if (!ps)
if (!items)
{
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
if (ret < 0)
@ -1583,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,
"addid: %s\n"
"Id: %d\n",
argv[1],
ps->id);
0); //ps->id);
ret = player_playback_start(NULL);
if (ret < 0)
@ -1637,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 (argc < 2)
{
player_queue_empty(0);
player_queue_clear();
return 0;
}
@ -1664,7 +1697,7 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_ARG;
}
ret = player_queue_remove(pos);
ret = player_queue_remove_bypos(pos);
if (ret < 0)
{
ret = asprintf(errmsg, "Failed to remove song at position '%d'", pos);
@ -1703,7 +1736,7 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
return ACK_ERROR_ARG;
}
ret = player_queue_removeid(songid);
ret = player_queue_remove_byitemid(songid);
if (ret < 0)
{
ret = asprintf(errmsg, "Failed to remove song with id '%s'", argv[1]);
@ -1725,9 +1758,11 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
static int
mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct player_queue *queue;
struct queue *queue;
struct queue_item *item;
uint32_t songid;
int pos_pl;
int count;
int i;
int ret;
@ -1746,7 +1781,7 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
}
// Get the whole queue (start_pos = 0, end_pos = -1)
queue = player_queue_get(0, -1, 0);
queue = player_queue_get_byindex(0, 0);
if (!queue)
{
@ -1754,15 +1789,17 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
return 0;
}
pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++)
pos_pl = 0;
count = queue_count(queue);
for (i = 0; i < count; i++)
{
if (songid == 0 || songid == queue->queue[i])
item = queue_get_byindex(queue, i, 0);
if (songid == 0 || songid == queueitem_item_id(item))
{
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl);
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
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", queueitem_id(item));
queue_free(queue);
@ -1791,15 +1828,17 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
static int
mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct player_queue *queue;
struct queue *queue;
struct queue_item *item;
int start_pos;
int end_pos;
int count;
int pos_pl;
int i;
int ret;
start_pos = 0;
end_pos = -1;
end_pos = 0;
if (argc > 1)
{
@ -1813,13 +1852,16 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
}
}
count = end_pos - start_pos;
if (start_pos < 0)
{
DPRINTF(E_DBG, L_MPD, "Command 'playlistinfo' called with pos < 0 (arg = '%s'), ignore arguments and return whole queue\n", argv[1]);
start_pos = 0;
end_pos = -1;
count = 0;
}
queue = player_queue_get(start_pos, end_pos, 0);
queue = player_queue_get_byindex(start_pos, count);
if (!queue)
{
@ -1827,13 +1869,15 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
return 0;
}
pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++)
pos_pl = start_pos;
count = queue_count(queue);
for (i = 0; i < count; i++)
{
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl);
item = queue_get_byindex(queue, i, 0);
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
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", queueitem_id(item));
queue_free(queue);
@ -1857,8 +1901,10 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
static int
mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct player_queue *queue;
struct queue *queue;
struct queue_item *item;
int pos_pl;
int count;
int i;
int ret;
@ -1866,7 +1912,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,
* therefor plchanges returns all songs in the queue as changed ignoring the given version.
*/
queue = player_queue_get(0, -1, 0);
queue = player_queue_get_byindex(0, 0);
if (!queue)
{
@ -1874,13 +1920,15 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
return 0;
}
pos_pl = queue->start_pos;
for (i = 0; i < queue->count; i++)
pos_pl = 0;
count = queue_count(queue);
for (i = 0; i < count; i++)
{
ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl);
item = queue_get_byindex(queue, i, 0);
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
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", queueitem_id(item));
queue_free(queue);
@ -2106,8 +2154,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
char path[PATH_MAX];
struct playlist_info *pli;
struct player_source *ps;
uint32_t pos;
struct queue_item *items;
int ret;
if (argc < 2)
@ -2138,9 +2185,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
ps = player_queue_make_pl(pli->id, &pos);
items = queueitem_make_byplid(pli->id);
if (!ps)
if (!items)
{
free_pli(pli, 0);
@ -2150,7 +2197,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
return ACK_ERROR_UNKNOWN;
}
player_queue_add(ps);
player_queue_add(items);
ret = player_playback_start(NULL);
if (ret < 0)
@ -2387,7 +2434,7 @@ static int
mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct query_params qp;
struct player_source *ps;
struct queue_item *items;
int ret;
if (argc < 3 || ((argc - 1) % 2) != 0)
@ -2406,9 +2453,9 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
mpd_get_query_params_find(argc - 1, argv + 1, &qp);
ps = player_queue_make(&qp);
items = queueitem_make_byquery(&qp);
if (!ps)
if (!items)
{
ret = asprintf(errmsg, "Failed to add songs to playlist");
if (ret < 0)
@ -2416,7 +2463,7 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
return ACK_ERROR_UNKNOWN;
}
player_queue_add(ps);
player_queue_add(items);
ret = player_playback_start(NULL);
if (ret < 0)
@ -2655,7 +2702,7 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
mfi = db_file_fetch_byvirtualpath(fi->virtual_path);
if (mfi)
{
ret = mpd_add_mediainfo(evbuf, mfi, -1);
ret = mpd_add_mediainfo(evbuf, mfi, 0, -1);
if (ret < 0)
{
DPRINTF(E_LOG, L_MPD, "Could not add mediainfo for path '%s'\n", fi->virtual_path);
@ -2861,7 +2908,7 @@ static int
mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
{
struct query_params qp;
struct player_source *ps;
struct queue_item *items;
int ret;
if (argc < 3 || ((argc - 1) % 2) != 0)
@ -2880,9 +2927,9 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
mpd_get_query_params_search(argc - 1, argv + 1, &qp);
ps = player_queue_make(&qp);
items = queueitem_make_byquery(&qp);
if (!ps)
if (!items)
{
ret = asprintf(errmsg, "Failed to add songs to playlist");
if (ret < 0)
@ -2890,7 +2937,7 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
return ACK_ERROR_UNKNOWN;
}
player_queue_add(ps);
player_queue_add(items);
ret = player_playback_start(NULL);
if (ret < 0)

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include <stdint.h>
#include "db.h"
#include "queue.h"
/* AirTunes v2 packet interval in ns */
/* (352 samples/packet * 1e9 ns/s) / 44100 samples/s = 7981859 ns/packet */
@ -27,12 +28,6 @@ enum play_status {
PLAY_PLAYING = 4,
};
enum repeat_mode {
REPEAT_OFF = 0,
REPEAT_SONG = 1,
REPEAT_ALL = 2,
};
struct spk_flags {
unsigned selected:1;
unsigned has_password:1;
@ -56,8 +51,10 @@ struct player_status {
uint32_t plversion;
/* Playlist length */
uint32_t playlistlength;
/* Playing song id*/
/* Id of the playing file/item in the files database */
uint32_t id;
/* Item-Id of the playing file/item in the queue */
uint32_t item_id;
/* Elapsed time in ms of playing item */
uint32_t pos_ms;
/* Length in ms of playing item */
@ -66,51 +63,14 @@ struct player_status {
int pos_pl;
/* Item id of next item in playlist */
uint32_t next_id;
/* Item-Id of the next file/item in the queue */
uint32_t next_item_id;
/* Playlist position of next item */
int next_pos_pl;
};
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
{
// The item id of the current playing item
uint32_t playingid;
// The number of items in the queue
unsigned int length;
// The position 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 item ids)
uint32_t *queue;
};
struct player_history
{
/* Buffer index of the oldest remembered song */
@ -121,6 +81,7 @@ struct player_history
/* Circular buffer of song ids previously played by forked-daapd */
uint32_t id[MAX_HISTORY_COUNT];
uint32_t item_id[MAX_HISTORY_COUNT];
};
@ -143,13 +104,16 @@ int
player_speaker_set(uint64_t *ids);
int
player_playback_start(uint32_t *idx_id);
player_playback_start(uint32_t *id);
int
player_playback_startpos(int pos, uint32_t *itemid);
player_playback_start_byindex(int pos, uint32_t *id);
int
player_playback_startid(uint32_t id, uint32_t *itemid);
player_playback_start_bypos(int pos, uint32_t *id);
int
player_playback_start_byitemid(uint32_t item_id, uint32_t *id);
int
player_playback_stop(void);
@ -182,48 +146,38 @@ player_repeat_set(enum repeat_mode mode);
int
player_shuffle_set(int enable);
struct player_source *
player_queue_make(struct query_params *qp);
struct queue *
player_queue_get_bypos(int count);
struct queue *
player_queue_get_byindex(int pos, int count);
int
player_queue_make_daap(struct player_source **head, const char *query, const char *queuefilter, const char *sort, int quirk);
struct player_source *
player_queue_make_pl(int plid, uint32_t *id);
struct player_source *
player_queue_make_mpd(char *path, int recursive);
struct player_queue *
player_queue_get(int start_pos, int end_pos, char shuffle);
void
queue_free(struct player_queue *queue);
player_queue_add(struct queue_item *items);
int
player_queue_add(struct player_source *ps);
player_queue_add_next(struct queue_item *items);
int
player_queue_add_next(struct player_source *ps);
player_queue_move_bypos(int ps_pos_from, int ps_pos_to);
int
player_queue_move(int ps_pos_from, int ps_pos_to);
player_queue_remove_bypos(int pos);
int
player_queue_remove(int ps_pos_remove);
int
player_queue_removeid(uint32_t id);
player_queue_remove_byitemid(uint32_t id);
void
player_queue_clear(void);
void
player_queue_empty(int clear_hist);
player_queue_clear_history(void);
void
player_queue_plid(uint32_t plid);
struct player_history *
player_history_get(void);

1176
src/queue.c Normal file

File diff suppressed because it is too large Load Diff

110
src/queue.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef SRC_QUEUE_H_
#define SRC_QUEUE_H_
#include "db.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;
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 id);
uint32_t
queueitem_id(struct queue_item *item);
unsigned int
queueitem_item_id(struct queue_item *item);
unsigned int
queueitem_len(struct queue_item *item);
enum data_kind
queueitem_data_kind(struct queue_item *item);
enum media_kind
queueitem_media_kind(struct queue_item *item);
struct queue_item *
queue_get_byitemid(struct queue *queue, unsigned int item_id);
struct queue_item *
queue_get_byindex(struct queue *queue, unsigned int index, char shuffle);
struct queue_item *
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 *
queue_next(struct queue *queue, unsigned int item_id, char shuffle, enum repeat_mode r_mode, int reshuffle);
struct queue_item *
queue_prev(struct queue *queue, unsigned int item_id, char shuffle, enum repeat_mode r_mode);
struct queue *
queue_new_byindex(struct queue *queue, unsigned int index, unsigned int count, char shuffle);
struct queue *
queue_new_bypos(struct queue *queue, unsigned int item_id, unsigned int count, char shuffle);
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 *
queueitem_make_byquery(struct query_params *qp);
struct queue_item *
queueitem_make_byplid(int plid);
struct queue_item *
queueitem_make_byid(uint32_t id);
#endif /* SRC_QUEUE_H_ */

View File

@ -912,12 +912,12 @@ audio_fifo_flush(void)
}
static int
playback_play(struct spotify_command *cmd)
playback_setup(struct spotify_command *cmd)
{
sp_track *track;
sp_error err;
DPRINTF(E_DBG, L_SPOTIFY, "Starting playback\n");
DPRINTF(E_DBG, L_SPOTIFY, "Setting up for playback\n");
if (SP_CONNECTION_STATE_LOGGED_IN != fptr_sp_session_connectionstate(g_sess))
{
@ -947,6 +947,16 @@ playback_play(struct spotify_command *cmd)
audio_fifo_flush();
return 0;
}
static int
playback_play(struct spotify_command *cmd)
{
sp_error err;
DPRINTF(E_DBG, L_SPOTIFY, "Starting playback\n");
err = fptr_sp_session_player_play(g_sess, 1);
if (SP_ERROR_OK != err)
{
@ -980,25 +990,6 @@ playback_pause(struct spotify_command *cmd)
return 0;
}
static int
playback_resume(struct spotify_command *cmd)
{
sp_error err;
DPRINTF(E_DBG, L_SPOTIFY, "Resuming playback\n");
err = fptr_sp_session_player_play(g_sess, 1);
if (SP_ERROR_OK != err)
{
DPRINTF(E_LOG, L_SPOTIFY, "Playback resume failed: %s\n", fptr_sp_error_message(err));
return -1;
}
g_state = SPOTIFY_STATE_PLAYING;
return 0;
}
static int
playback_stop(struct spotify_command *cmd)
{
@ -1071,7 +1062,7 @@ audio_get(struct spotify_command *cmd)
// If spotify was paused begin by resuming playback
if (g_state == SPOTIFY_STATE_PAUSED)
playback_resume(NULL);
playback_play(NULL);
pthread_mutex_lock(&g_audio_fifo->mutex);
@ -1626,13 +1617,13 @@ notify_cb(int fd, short what, void *arg)
/* Thread: player */
int
spotify_playback_play(struct media_file_info *mfi)
spotify_playback_setup(struct media_file_info *mfi)
{
struct spotify_command cmd;
sp_link *link;
int ret;
DPRINTF(E_DBG, L_SPOTIFY, "Playback request\n");
DPRINTF(E_DBG, L_SPOTIFY, "Playback setup request\n");
link = fptr_sp_link_create_from_string(mfi->path);
if (!link)
@ -1643,7 +1634,7 @@ spotify_playback_play(struct media_file_info *mfi)
command_init(&cmd);
cmd.func = playback_play;
cmd.func = playback_setup;
cmd.arg.link = link;
ret = sync_command(&cmd);
@ -1653,6 +1644,46 @@ spotify_playback_play(struct media_file_info *mfi)
return ret;
}
int
spotify_playback_play()
{
struct spotify_command cmd;
int ret;
DPRINTF(E_DBG, L_SPOTIFY, "Playback request\n");
command_init(&cmd);
cmd.func = playback_play;
cmd.arg.noarg = NULL;
ret = sync_command(&cmd);
command_deinit(&cmd);
return ret;
}
int
spotify_playback_pause()
{
struct spotify_command cmd;
int ret;
DPRINTF(E_DBG, L_SPOTIFY, "Pause request\n");
command_init(&cmd);
cmd.func = playback_pause;
cmd.arg.noarg = NULL;
ret = sync_command(&cmd);
command_deinit(&cmd);
return ret;
}
/* Thread: libspotify */
void
spotify_playback_pause_nonblock(void)
@ -1678,27 +1709,6 @@ spotify_playback_pause_nonblock(void)
nonblock_command(cmd);
}
/* Not used */
int
spotify_playback_resume(void)
{
struct spotify_command cmd;
int ret;
DPRINTF(E_DBG, L_SPOTIFY, "Resume request\n");
command_init(&cmd);
cmd.func = playback_resume;
cmd.arg.noarg = NULL;
ret = sync_command(&cmd);
command_deinit(&cmd);
return ret;
}
/* Thread: player and libspotify */
int
spotify_playback_stop(void)

View File

@ -11,7 +11,13 @@
#endif
int
spotify_playback_play(struct media_file_info *mfi);
spotify_playback_setup(struct media_file_info *mfi);
int
spotify_playback_play();
int
spotify_playback_pause();
void
spotify_playback_pause_nonblock(void);

View File

@ -731,7 +731,7 @@ transcode_setup(struct transcode_ctx **nctx, struct media_file_info *mfi, off_t
}
ctx->duration = mfi->song_length;
ctx->samples = mfi->sample_count;
ctx->samples = mfi->sample_count; //TODO [unused] sample count is never set and therefor always 0
ctx->wavhdr = wavhdr;
if (wavhdr)