diff --git a/src/decoder_api.c b/src/decoder_api.c index dde27727b..704f6dbf7 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -328,8 +328,9 @@ decoder_data(struct decoder *decoder, } dest = music_chunk_write(chunk, &dc->out_audio_format, - decoder->timestamp, kbit_rate, - &nbytes); + decoder->timestamp - + dc->song->start_ms / 1000.0, + kbit_rate, &nbytes); if (dest == NULL) { /* the chunk is full, flush it */ decoder_flush_chunk(decoder); @@ -366,6 +367,12 @@ decoder_data(struct decoder *decoder, decoder->timestamp += (double)nbytes / audio_format_time_to_size(&dc->in_audio_format); + + if (dc->song->end_ms > 0 && + decoder->timestamp >= dc->song->end_ms / 1000.0) + /* the end of this range has been reached: + stop decoding */ + return DECODE_COMMAND_STOP; } return DECODE_COMMAND_NONE; diff --git a/src/player_thread.c b/src/player_thread.c index 1a92a3182..5823b433e 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -227,6 +227,26 @@ player_wait_for_decoder(struct player *player) return true; } +/** + * Returns the real duration of the song, comprising the duration + * indicated by the decoder plugin. + */ +static double +real_song_duration(const struct song *song, double decoder_duration) +{ + assert(song != NULL); + + if (decoder_duration <= 0.0) + /* the decoder plugin didn't provide information; fall + back to song_get_duration() */ + return song_get_duration(song); + + if (song->end_ms > 0 && song->end_ms / 1000.0 < decoder_duration) + return (song->end_ms - song->start_ms) / 1000.0; + + return decoder_duration - song->start_ms / 1000.0; +} + /** * The decoder has acknowledged the "START" command (see * player_wait_for_decoder()). This function checks if the decoder @@ -265,7 +285,7 @@ player_check_decoder_startup(struct player *player) return true; player_lock(); - pc.total_time = dc->total_time; + pc.total_time = real_song_duration(dc->song, dc->total_time); pc.audio_format = dc->in_audio_format; player_unlock(); @@ -351,13 +371,14 @@ player_send_silence(struct player *player) */ static bool player_seek_decoder(struct player *player) { + struct song *song = pc.next_song; struct decoder_control *dc = player->dc; double where; bool ret; assert(pc.next_song != NULL); - if (decoder_current_song(dc) != pc.next_song) { + if (decoder_current_song(dc) != song) { /* the decoder is already decoding the "next" song - stop it and start the previous song again */ @@ -399,7 +420,7 @@ static bool player_seek_decoder(struct player *player) if (where < 0.0) where = 0.0; - ret = dc_seek(dc, where); + ret = dc_seek(dc, where + song->start_ms / 1000.0); if (!ret) { /* decoder failure */ player_command_finished(); @@ -801,11 +822,18 @@ static void do_play(struct decoder_control *dc) if (player.decoder_starting) { /* wait until the decoder is initialized completely */ bool success; + const struct song *song; success = player_check_decoder_startup(&player); if (!success) break; + /* seek to the beginning of the range */ + song = decoder_current_song(dc); + if (song != NULL && song->start_ms > 0 && + !dc_seek(dc, song->start_ms / 1000.0)) + player_dc_stop(&player); + player_lock(); continue; }