diff --git a/src/mpd.c b/src/mpd.c index 1456ed29..0f638673 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -559,10 +559,10 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) "nextsongid: %d\n", status.pos_pl, status.id, - (status.pos_ms / 1000), (status.songlength_ms / 1000), + (status.pos_ms / 1000), (status.len_ms / 1000), (status.pos_ms / 1000.0), - status.nextsong_pos_pl, - status.nextsong_id); + status.next_pos_pl, + status.next_id); } if (filescanner_scanning()) @@ -575,8 +575,8 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) evbuffer_add_printf(evbuf, "nextsong: %d\n" "nextsongid: %d\n", - status.nextsong_pos_pl, - status.nextsong_id); + status.next_pos_pl, + status.next_id); } return 0; diff --git a/src/player.c b/src/player.c index bc68d97a..f4e5ed36 100644 --- a/src/player.c +++ b/src/player.c @@ -105,6 +105,16 @@ enum range_type RANGEARG_RANGE }; +/* + * Identifies an item or a range of items + * + * Depending on item_range.type the item(s) are identified by: + * - item id (type = RANGEARG_ID) given in item_range.id + * - item position (type = RANGEARG_POS) given in item_range.start_pos + * - start and end position (type = RANGEARG_RANGE) given in item_range.start_pos to item_range.end_pos + * + * The pointer id_ptr may be set to an item id by the called function. + */ struct item_range { enum range_type type; @@ -112,7 +122,6 @@ struct item_range uint32_t id; int start_pos; int end_pos; - int to_pos; char shuffle; @@ -719,7 +728,7 @@ player_queue_make(struct query_params *qp, const char *sort) memset(ps, 0, sizeof(struct player_source)); ps->id = id; - ps->song_length = song_length; + ps->len_ms = song_length; if (!q_head) q_head = ps; @@ -2329,6 +2338,14 @@ playback_abort(void) metadata_purge(); } +static struct player_source * +next_ps(struct player_source *ps, char shuffle) +{ + if (shuffle) + return ps->shuffle_next; + else + return ps->pl_next; +} /* Actual commands, executed in the player thread */ static int @@ -2354,20 +2371,20 @@ get_status(struct player_command *cmd) switch (player_state) { case PLAY_STOPPED: - DPRINTF(E_SPAM, L_PLAYER, "Player status: stopped\n"); + DPRINTF(E_DBG, L_PLAYER, "Player status: stopped\n"); status->status = PLAY_STOPPED; break; case PLAY_PAUSED: - DPRINTF(E_SPAM, L_PLAYER, "Player status: paused\n"); + DPRINTF(E_DBG, L_PLAYER, "Player status: paused\n"); status->status = PLAY_PAUSED; status->id = cur_streaming->id; pos = last_rtptime + AIRTUNES_V2_PACKET_SAMPLES - cur_streaming->stream_start; status->pos_ms = (pos * 1000) / 44100; - status->songlength_ms = cur_streaming->song_length; + status->len_ms = cur_streaming->len_ms; status->pos_pl = source_position(cur_streaming, 0); @@ -2376,7 +2393,7 @@ get_status(struct player_command *cmd) case PLAY_PLAYING: if (!cur_playing) { - DPRINTF(E_SPAM, L_PLAYER, "Player status: playing (buffering)\n"); + DPRINTF(E_DBG, L_PLAYER, "Player status: playing (buffering)\n"); status->status = PLAY_PAUSED; ps = cur_streaming; @@ -2386,7 +2403,7 @@ get_status(struct player_command *cmd) } else { - DPRINTF(E_SPAM, L_PLAYER, "Player status: playing\n"); + DPRINTF(E_DBG, L_PLAYER, "Player status: playing\n"); status->status = PLAY_PLAYING; ps = cur_playing; @@ -2406,14 +2423,14 @@ get_status(struct player_command *cmd) } status->pos_ms = (pos * 1000) / 44100; - status->songlength_ms = ps->song_length; + status->len_ms = ps->len_ms; status->id = ps->id; status->pos_pl = source_position(ps, 0); ps = next_ps(ps, shuffle); - status->nextsong_id = ps->id; - status->nextsong_pos_pl = source_position(ps, 0); + status->next_id = ps->id; + status->next_pos_pl = source_position(ps, 0); status->playlistlength = source_count(); break; @@ -2545,13 +2562,45 @@ playback_start_bh(struct player_command *cmd) return -1; } +static struct player_source * +queue_get_source_byid(uint32_t id) +{ + struct player_source *ps; + + if (!source_head) + return NULL; + + ps = source_head->pl_next; + while (ps->id != id && ps != source_head) + { + ps = ps->pl_next; + } + + return ps; +} + +static struct player_source * +queue_get_source_bypos(int pos) +{ + struct player_source *ps; + int i; + + if (!source_head) + return NULL; + + ps = source_head; + for (i = pos; i > 0; i--) + ps = ps->pl_next; + + return ps; +} + static int playback_start(struct player_command *cmd) { struct raop_device *rd; uint32_t *idx_id; - uint32_t pos; - uint32_t id; + struct player_source *ps; int ret; if (!source_head) @@ -2586,11 +2635,29 @@ playback_start(struct player_command *cmd) // Update global playback position pb_pos = last_rtptime + AIRTUNES_V2_PACKET_SAMPLES - 88200; - if (cmd->arg.item_range.type == RANGEARG_POS - || cmd->arg.item_range.type == RANGEARG_ID) + /* + * If either an item id or an item position is given, get the corresponding + * player_source from the queue. + */ + if (cmd->arg.item_range.type == RANGEARG_ID) + ps = queue_get_source_byid(cmd->arg.item_range.id); + else if (cmd->arg.item_range.type == RANGEARG_POS) + ps = queue_get_source_bypos(cmd->arg.item_range.start_pos); + else + ps = NULL; + + /* + * Update queue and cur_streaming depending on + * - given player_source to start playing + * - player state + */ + if (ps) { /* - * A song is specified in the arguments (by id or pos) + * A song is specified in the arguments (by id or pos) and the corresponding + * player_source (ps) from the queue was found. + * + * Stop playback (if it was paused) and prepare to start playback on ps. */ if (cur_playing) source_stop(cur_playing); @@ -2601,41 +2668,9 @@ playback_start(struct player_command *cmd) cur_streaming = NULL; if (shuffle) - { - source_reshuffle(); - cur_streaming = shuffle_head; - } - else - cur_streaming = source_head; + source_reshuffle(); - if (cmd->arg.item_range.type == RANGEARG_POS) - { - /* - * Find start song by position in playqueue - */ - pos = cmd->arg.item_range.start_pos; - if (pos > 0) - { - cur_streaming = source_head; - for (; pos > 0; pos--) - cur_streaming = cur_streaming->pl_next; - } - } - else - { - /* - * Find start song by id - */ - id = cmd->arg.item_range.id; - if (id > 0) - { - cur_streaming = source_head->pl_next; - while (cur_streaming->id != id && cur_streaming != source_head) - { - cur_streaming = cur_streaming->pl_next; - } - } - } + cur_streaming = ps; if (shuffle) shuffle_head = cur_streaming; @@ -2643,7 +2678,7 @@ playback_start(struct player_command *cmd) ret = source_open(cur_streaming, 0); if (ret < 0) { - DPRINTF(E_LOG, L_PLAYER, "Couldn't jump to queue position %d\n", pos); + DPRINTF(E_LOG, L_PLAYER, "Couldn't jump to source %d in queue\n", cur_streaming->id); playback_abort(); return -1; @@ -2657,6 +2692,9 @@ playback_start(struct player_command *cmd) } else if (!cur_streaming) { + /* + * Player was stopped, start playing the queue + */ if (shuffle) source_reshuffle(); @@ -2674,7 +2712,10 @@ playback_start(struct player_command *cmd) } else { - /* After a pause, the source is still open so source_open() doesn't get + /* + * Player was paused, resume playing cur_streaming + * + * After a pause, the source is still open so source_open() doesn't get * called and we have to handle metadata ourselves. */ metadata_send(cur_streaming, 1); @@ -3545,6 +3586,7 @@ queue_get(struct player_command *cmd) start_pos = cmd->arg.item_range.start_pos; if (start_pos < 0) { + // Set start_pos to the position of the current item + 1 ps = cur_playing ? cur_playing : cur_streaming; start_pos = ps ? source_position(ps, qshuffle) + 1 : 0; } @@ -3765,23 +3807,23 @@ queue_remove(struct player_command *cmd) ps = cur_playing ? cur_playing : cur_streaming; if (!ps) { - DPRINTF(E_LOG, L_PLAYER, "Current playing/streaming song not found\n"); + DPRINTF(E_LOG, L_PLAYER, "Current playing/streaming item not found\n"); return -1; } if (cmd->arg.item_range.type == RANGEARG_ID) { id = cmd->arg.item_range.id; - DPRINTF(E_DBG, L_PLAYER, "Removing song with id %d\n", id); + DPRINTF(E_DBG, L_PLAYER, "Removing item with id %d\n", id); if (id < 1) { - DPRINTF(E_LOG, L_PLAYER, "Can't remove song, invalid id %d\n", id); + DPRINTF(E_LOG, L_PLAYER, "Can't remove item, invalid id %d\n", id); return -1; } else if (id == ps->id) { - DPRINTF(E_LOG, L_PLAYER, "Can't remove current playing song, id %d\n", id); + DPRINTF(E_LOG, L_PLAYER, "Can't remove current playing item, id %d\n", id); return -1; } @@ -3794,11 +3836,11 @@ queue_remove(struct player_command *cmd) else { pos = cmd->arg.item_range.start_pos; - DPRINTF(E_DBG, L_PLAYER, "Removing song from position %d\n", pos); + DPRINTF(E_DBG, L_PLAYER, "Removing item from position %d\n", pos); if (pos < 1) { - DPRINTF(E_LOG, L_PLAYER, "Can't remove song, invalid position %d\n", pos); + DPRINTF(E_LOG, L_PLAYER, "Can't remove item, invalid position %d\n", pos); return -1; } @@ -4067,6 +4109,19 @@ player_now_playing(uint32_t *id) return ret; } +/* + * Starts/resumes playback + * + * Depending on the player state, this will either resumes playing the current item (player is paused) + * or begins playing the queue from the beginning. + * + * If shuffle is set, the queue is reshuffled prior to starting playback. + * + * If a pointer is given as argument "itemid", its value will be set to the playing item id. + * + * @param *itemid if not NULL, will be set to the playing item id + * @return 0 if successful, -1 if an error occurred + */ int player_playback_start(uint32_t *itemid) { @@ -4087,6 +4142,16 @@ player_playback_start(uint32_t *itemid) return ret; } +/* + * Starts playback at item number "pos" of the current queue + * + * If shuffle is set, the queue is reshuffled prior to starting playback. + * + * If a pointer is given as argument "itemid", its value will be set to the playing item id. + * + * @param *itemid if not NULL, will be set to the playing item id + * @return 0 if successful, -1 if an error occurred + */ int player_playback_startpos(int pos, uint32_t *itemid) { @@ -4107,6 +4172,16 @@ player_playback_startpos(int pos, uint32_t *itemid) return ret; } +/* + * Starts playback at item with "id" of the current queue + * + * If shuffle is set, the queue is reshuffled prior to starting playback. + * + * If a pointer is given as argument "itemid", its value will be set to the playing item id. + * + * @param *itemid if not NULL, will be set to the playing item id + * @return 0 if successful, -1 if an error occurred + */ int player_playback_startid(uint32_t id, uint32_t *itemid) { @@ -4357,6 +4432,20 @@ player_shuffle_set(int enable) return ret; } +/* + * Retrieves a list of item ids in the queue from postion 'start_pos' to 'end_pos' + * + * If start_pos is -1, the list starts with the item next from the current playing item. + * If end_pos is -1, this list contains all songs starting from 'start_pos' + * + * The 'shuffle' argument determines if the items are taken from the playqueue (shuffle = 0) + * or the shufflequeue (shuffle = 1). + * + * @param start_pos Start the listing from 'start_pos' + * @param end_pos End the listing at 'end_pos' + * @param shuffle If set to 1 use the shuffle queue, otherwise the playqueue + * @return List of items (ids) in the queue + */ struct player_queue * player_queue_get(int start_pos, int end_pos, char shuffle) { @@ -4367,6 +4456,7 @@ player_queue_get(int start_pos, int end_pos, char shuffle) cmd.func = queue_get; cmd.func_bh = NULL; + cmd.arg.item_range.type = RANGEARG_POS; cmd.arg.item_range.start_pos = start_pos; cmd.arg.item_range.end_pos = end_pos; cmd.arg.item_range.shuffle = shuffle; @@ -4382,15 +4472,6 @@ player_queue_get(int start_pos, int end_pos, char shuffle) return cmd.queue; } -struct player_source * -next_ps(struct player_source *ps, char shuffle) -{ - if (shuffle) - return ps->shuffle_next; - else - return ps->pl_next; -} - int player_queue_add(struct player_source *ps) { diff --git a/src/player.h b/src/player.h index 0767e61f..93ade6d1 100644 --- a/src/player.h +++ b/src/player.h @@ -57,16 +57,16 @@ struct player_status { uint32_t playlistlength; /* Playing song id*/ uint32_t id; - /* Elapsed time in ms of playing song */ + /* Elapsed time in ms of playing item */ uint32_t pos_ms; - /* Song length in ms of playing song */ - uint32_t songlength_ms; - /* Playlist position of playing song*/ + /* Length in ms of playing item */ + uint32_t len_ms; + /* Playlist position of playing item*/ int pos_pl; - /* Song id of next song in playlist */ - uint32_t nextsong_id; - /* Playlist position of next song */ - int nextsong_pos_pl; + /* Item id of next item in playlist */ + uint32_t next_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); @@ -75,7 +75,7 @@ typedef void (*player_status_handler)(void); struct player_source { uint32_t id; - uint32_t song_length; + uint32_t len_ms; enum source_type type; int setup_done; @@ -97,11 +97,16 @@ struct player_source 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; }; @@ -188,9 +193,6 @@ player_queue_get(int start_pos, int end_pos, char shuffle); void queue_free(struct player_queue *queue); -struct player_source * -next_ps(struct player_source *ps, char shuffle); - int player_queue_add(struct player_source *ps);