Merge playqueue-contents from chme (support for history)

This commit is contained in:
ejurgensen 2014-05-04 22:44:38 +02:00
commit d8940bfd2d
3 changed files with 201 additions and 62 deletions

View File

@ -1131,23 +1131,76 @@ next_ps(struct player_source *ps, char shuffle)
return ps->pl_next;
}
static int
playqueuecontents_add_source(struct evbuffer *songlist, uint32_t source_id, int pos_in_queue, uint32_t plid)
{
struct evbuffer *song;
struct media_file_info *mfi;
int ret;
song = evbuffer_new();
if (!song)
{
DPRINTF(E_LOG, L_DACP, "Could not allocate song evbuffer for playqueue-contents\n");
return -1;
}
mfi = db_file_fetch_byid(source_id);
if (!mfi)
{
DPRINTF(E_LOG, L_DACP, "Could not fetch file id %d\n", source_id);
return -1;
}
dmap_add_container(song, "ceQs", 16);
dmap_add_raw_uint32(song, 1); /* Database */
dmap_add_raw_uint32(song, plid);
dmap_add_raw_uint32(song, 0); /* Should perhaps be playlist index? */
dmap_add_raw_uint32(song, mfi->id);
dmap_add_string(song, "ceQn", mfi->title);
dmap_add_string(song, "ceQr", mfi->artist);
dmap_add_string(song, "ceQa", mfi->album);
dmap_add_string(song, "ceQg", mfi->genre);
dmap_add_long(song, "asai", mfi->songalbumid);
dmap_add_int(song, "cmmk", mfi->media_kind);
dmap_add_int(song, "casa", 1); /* Unknown */
dmap_add_int(song, "astm", mfi->song_length);
dmap_add_char(song, "casc", 1); /* Maybe an indication of extra data? */
dmap_add_char(song, "caks", 6); /* Unknown */
dmap_add_int(song, "ceQI", pos_in_queue);
dmap_add_container(songlist, "mlit", EVBUFFER_LENGTH(song));
ret = evbuffer_add_buffer(songlist, song);
evbuffer_free(song);
free_mfi(mfi, 0);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
return ret;
}
return 0;
}
static void
dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf, char **uri,
struct evkeyvalq *query)
{
struct daap_session *s;
struct evbuffer *song;
struct evbuffer *songlist;
struct evbuffer *playlists;
struct media_file_info *mfi;
struct player_source *ps;
struct player_source *head;
struct player_status status;
struct player_history *history;
const char *param;
int span;
int i;
int n;
int songlist_length;
int ret;
int start_index;
/* /ctrl-int/1/playqueue-contents?span=50&session-id=... */
@ -1168,17 +1221,12 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
songlist = NULL;
i = 0;
n = 0;
n = 0; // count of songs in songlist
player_get_status(&status);
/* Get queue and make songlist only if playing or paused */
if ((status.status != PLAY_STOPPED) && (head = player_queue_get()))
{
/* Fast forward to song currently being played */
ps = head;
while ((ps->id != status.id) && (ps = next_ps(ps, status.shuffle)) && (ps != head))
i++;
/* Make song list for Up Next, begin with first song after playlist position */
/* Get queue and make songlist only if playing or paused */
if (status.status != PLAY_STOPPED)
{
songlist = evbuffer_new();
if (!songlist)
{
@ -1188,52 +1236,61 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
return;
}
while ((n < abs(span)) && (ps = next_ps(ps, status.shuffle)) && (ps != head))
/*
* If the span parameter is negativ make song list for Previously Played,
* otherwise make song list for Up Next and begin with first song after playlist position.
*/
if (span < 0)
{
n++;
song = evbuffer_new();
if (!song)
history = player_history_get();
if (abs(span) > history->count)
{
DPRINTF(E_LOG, L_DACP, "Could not allocate song evbuffer for playqueue-contents\n");
dmap_send_error(req, "ceQR", "Out of memory");
return;
start_index = history->start_index;
}
mfi = db_file_fetch_byid(ps->id);
dmap_add_container(song, "ceQs", 16);
dmap_add_raw_uint32(song, 1); /* Database */
dmap_add_raw_uint32(song, status.plid);
dmap_add_raw_uint32(song, 0); /* Should perhaps be playlist index? */
dmap_add_raw_uint32(song, mfi->id);
dmap_add_string(song, "ceQn", mfi->title);
dmap_add_string(song, "ceQr", mfi->artist);
dmap_add_string(song, "ceQa", mfi->album);
dmap_add_string(song, "ceQg", mfi->genre);
dmap_add_long(song, "asai", mfi->songalbumid);
dmap_add_int(song, "cmmk", mfi->media_kind);
dmap_add_int(song, "casa", 1); /* Unknown */
dmap_add_int(song, "astm", mfi->song_length);
dmap_add_char(song, "casc", 1); /* Maybe an indication of extra data? */
dmap_add_char(song, "caks", 6); /* Unknown */
dmap_add_int(song, "ceQI", n + i + 1);
dmap_add_container(songlist, "mlit", EVBUFFER_LENGTH(song));
ret = evbuffer_add_buffer(songlist, song);
evbuffer_free(song);
if (mfi)
free_mfi(mfi, 0);
if (ret < 0)
else
{
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
dmap_send_error(req, "ceQR", "Out of memory");
return;
start_index = (history->start_index + history->count - abs(span)) % MAX_HISTORY_COUNT;
}
}
for (n = 0; n < history->count && n < abs(span); n++)
{
ret = playqueuecontents_add_source(songlist, history->id[(start_index + n) % MAX_HISTORY_COUNT], (n + 1), status.plid);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
dmap_send_error(req, "ceQR", "Out of memory");
return;
}
}
}
else
{
/* Fast forward to song currently being played */
head = player_queue_get();
if (head)
{
ps = head;
while ((ps->id != status.id) && (ps = next_ps(ps, status.shuffle)) && (ps != head))
i++;
while ((n < abs(span)) && (ps = next_ps(ps, status.shuffle)) && (ps != head))
{
n++;
ret = playqueuecontents_add_source(songlist, ps->id, (n + i + 1), status.plid);
if (ret < 0)
{
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
dmap_send_error(req, "ceQR", "Out of memory");
return;
}
}
}
}
}
/* Playlists are hist, curr and main. Currently we don't support hist. */
/* Playlists are hist, curr and main. */
playlists = evbuffer_new();
if (!playlists)
{

View File

@ -204,6 +204,8 @@ static struct player_source *cur_streaming;
static uint32_t cur_plid;
static struct evbuffer *audio_buf;
/* Play history */
static struct player_history *history;
/* Command helpers */
static void
@ -1434,6 +1436,40 @@ source_check(void)
return pos;
}
struct player_history *
player_history_get(void)
{
return history;
}
/*
* Add the song with the given id to the list of previously played songs
*/
static void
history_add(uint32_t id)
{
unsigned int cur_index;
unsigned int next_index;
/* Check if the current song is already the last in the history to avoid duplicates */
cur_index = (history->start_index + history->count - 1) % MAX_HISTORY_COUNT;
if (id == history->id[cur_index])
{
DPRINTF(E_LOG, L_PLAYER, "Current playing/streaming song already in history\n");
return;
}
/* Calculate the next index and update the start-index and count for the id-buffer */
next_index = (history->start_index + history->count) % MAX_HISTORY_COUNT;
if (next_index == history->start_index && history->count > 0)
history->start_index = (history->start_index + 1) % MAX_HISTORY_COUNT;
history->id[next_index] = id;
if (history->count < MAX_HISTORY_COUNT)
history->count++;
}
static int
source_read(uint8_t *buf, int len, uint64_t rtptime)
{
@ -1454,6 +1490,9 @@ source_read(uint8_t *buf, int len, uint64_t rtptime)
new = 0;
// add song to the played history
history_add(cur_streaming->id);
ret = source_next(0);
if (ret < 0)
return -1;
@ -2268,9 +2307,15 @@ playback_stop(struct player_command *cmd)
pb_timer_fd = -1;
if (cur_playing)
source_stop(cur_playing);
else
source_stop(cur_streaming);
{
history_add(cur_playing->id);
source_stop(cur_playing);
}
else if (cur_streaming)
{
history_add(cur_streaming->id);
source_stop(cur_streaming);
}
cur_playing = NULL;
cur_streaming = NULL;
@ -2588,10 +2633,17 @@ playback_prev_bh(struct player_command *cmd)
{
int ret;
if (cur_playing)
source_stop(cur_playing);
else
source_stop(cur_streaming);
if (!cur_streaming)
{
DPRINTF(E_LOG, L_PLAYER, "Could not get current stream source\n");
return -1;
}
/* Only add to history if playback started. */
if (cur_streaming->end > cur_streaming->stream_start)
history_add(cur_streaming->id);
source_stop(cur_streaming);
ret = source_prev();
if (ret < 0)
@ -2620,10 +2672,17 @@ playback_next_bh(struct player_command *cmd)
{
int ret;
if (cur_playing)
source_stop(cur_playing);
else
source_stop(cur_streaming);
if (!cur_streaming)
{
DPRINTF(E_LOG, L_PLAYER, "Could not get current stream source\n");
return -1;
}
/* Only add to history if playback started. */
if (cur_streaming->end > cur_streaming->stream_start)
history_add(cur_streaming->id);
source_stop(cur_streaming);
ret = source_next(1);
if (ret < 0)
@ -4429,6 +4488,8 @@ player_init(void)
update_handler = NULL;
history = (struct player_history *) calloc(1, sizeof(struct player_history));
#if defined(__linux__)
/*
* Determine if the resolution of the system timer is > or < the size
@ -4620,6 +4681,8 @@ player_deinit(void)
if (source_head)
queue_clear(NULL);
free(history);
evbuffer_free(audio_buf);
laudio_deinit();

View File

@ -21,6 +21,9 @@
#define STOB(s) ((s) * 4)
#define BTOS(b) ((b) / 4)
/* Maximum number of previously played songs that are remembered */
#define MAX_HISTORY_COUNT 20
enum play_status {
PLAY_STOPPED = 2,
PLAY_PAUSED = 3,
@ -84,6 +87,19 @@ struct player_source
struct player_source *play_next;
};
struct player_history
{
/* Buffer index of the oldest remembered song */
unsigned int start_index;
/* Count of song ids in the buffer */
unsigned int count;
/* Circular buffer of song ids previously played by forked-daapd */
uint32_t id[MAX_HISTORY_COUNT];
};
int
player_get_current_pos(uint64_t *pos, struct timespec *ts, int commit);
@ -160,6 +176,9 @@ player_queue_clear(void);
void
player_queue_plid(uint32_t plid);
struct player_history *
player_history_get(void);
void
player_set_update_handler(player_status_handler handler);