diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/decoder_api.c | 63 | ||||
-rw-r--r-- | src/decoder_internal.h | 19 | ||||
-rw-r--r-- | src/decoder_thread.c | 2 | ||||
-rw-r--r-- | src/player_thread.c | 10 | ||||
-rw-r--r-- | src/uri.h | 2 |
7 files changed, 81 insertions, 18 deletions
@@ -34,6 +34,7 @@ ver 0.16.5 (2010/??/??) * decoder: - ffmpeg: higher precision timestamps - ffmpeg: don't require key frame for seeking + - fix CUE track seeking * WIN32: close sockets properly diff --git a/configure.ac b/configure.ac index 8aa49103b..246355720 100644 --- a/configure.ac +++ b/configure.ac @@ -219,7 +219,7 @@ AC_ARG_ENABLE(raop-output, AC_ARG_ENABLE(id3, AS_HELP_STRING([--enable-id3], - [disable id3 support]),, + [enable id3 support]),, enable_id3=auto) AC_ARG_ENABLE(inotify, diff --git a/src/decoder_api.c b/src/decoder_api.c index 1f2075638..a34e19b1a 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -76,15 +76,40 @@ decoder_initialized(struct decoder *decoder, &af_string)); } -enum decoder_command decoder_get_command(G_GNUC_UNUSED struct decoder * decoder) +/** + * Returns the current decoder command. May return a "virtual" + * synthesized command, e.g. to seek to the beginning of the CUE + * track. + */ +G_GNUC_PURE +static enum decoder_command +decoder_get_virtual_command(struct decoder *decoder) { const struct decoder_control *dc = decoder->dc; - assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + return DECODE_COMMAND_SEEK; + + if (decoder->initial_seek_pending) { + if (dc->command == DECODE_COMMAND_NONE) { + decoder->initial_seek_pending = false; + decoder->initial_seek_running = true; + return DECODE_COMMAND_SEEK; + } + + decoder->initial_seek_pending = false; + } + return dc->command; } +enum decoder_command +decoder_get_command(struct decoder *decoder) +{ + return decoder_get_virtual_command(decoder); +} + void decoder_command_finished(struct decoder *decoder) { @@ -92,11 +117,24 @@ decoder_command_finished(struct decoder *decoder) decoder_lock(dc); - assert(dc->command != DECODE_COMMAND_NONE); + assert(dc->command != DECODE_COMMAND_NONE || + decoder->initial_seek_running); assert(dc->command != DECODE_COMMAND_SEEK || + decoder->initial_seek_running || dc->seek_error || decoder->seeking); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) { + assert(!decoder->seeking); + assert(decoder->chunk == NULL); + assert(music_pipe_empty(dc->pipe)); + + decoder->initial_seek_running = false; + decoder->timestamp = dc->song->start_ms / 1000.; + decoder_unlock(dc); + return; + } + if (decoder->seeking) { decoder->seeking = false; @@ -121,9 +159,13 @@ double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder) { const struct decoder_control *dc = decoder->dc; - assert(dc->command == DECODE_COMMAND_SEEK); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + return dc->song->start_ms / 1000.; + + assert(dc->command == DECODE_COMMAND_SEEK); + decoder->seeking = true; return dc->seek_where; @@ -133,9 +175,15 @@ void decoder_seek_error(struct decoder * decoder) { struct decoder_control *dc = decoder->dc; - assert(dc->command == DECODE_COMMAND_SEEK); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + /* d'oh, we can't seek to the sub-song start position, + what now? - no idea, ignoring the problem for now. */ + return; + + assert(dc->command == DECODE_COMMAND_SEEK); + dc->seek_error = true; decoder->seeking = false; @@ -289,7 +337,7 @@ decoder_data(struct decoder *decoder, assert(length % audio_format_frame_size(&dc->in_audio_format) == 0); decoder_lock(dc); - cmd = dc->command; + cmd = decoder_get_virtual_command(decoder); decoder_unlock(dc); if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK || @@ -420,6 +468,9 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, /* send only the decoder tag */ cmd = do_send_tag(decoder, tag); + if (cmd == DECODE_COMMAND_NONE) + cmd = decoder_get_virtual_command(decoder); + return cmd; } diff --git a/src/decoder_internal.h b/src/decoder_internal.h index 78a783f5e..d89e68cfc 100644 --- a/src/decoder_internal.h +++ b/src/decoder_internal.h @@ -36,6 +36,25 @@ struct decoder { */ double timestamp; + /** + * Is the initial seek (to the start position of the sub-song) + * pending, or has it been performed already? + */ + bool initial_seek_pending; + + /** + * Is the initial seek currently running? During this time, + * the decoder command is SEEK. This flag is set by + * decoder_get_virtual_command(), when the virtual SEEK + * command is generated for the first time. + */ + bool initial_seek_running; + + /** + * This flag is set by decoder_seek_where(), and checked by + * decoder_command_finished(). It is used to clean up after + * seeking. + */ bool seeking; /** diff --git a/src/decoder_thread.c b/src/decoder_thread.c index dff4ca08f..dbead655d 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -380,6 +380,8 @@ decoder_run_song(struct decoder_control *dc, { struct decoder decoder = { .dc = dc, + .initial_seek_pending = song->start_ms > 0, + .initial_seek_running = false, }; int ret; diff --git a/src/player_thread.c b/src/player_thread.c index 58682f2ca..7696c22c0 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -894,16 +894,6 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) if (!player_check_decoder_startup(&player)) break; - /* seek to the beginning of the range */ - const struct song *song = decoder_current_song(dc); - if (song != NULL && song->start_ms > 0 && - /* we must not send a seek command until - the decoder is initialized - completely */ - !player.decoder_starting && - !dc_seek(dc, song->start_ms / 1000.0)) - player_dc_stop(&player); - player_lock(pc); continue; } @@ -25,7 +25,7 @@ #include <stdbool.h> /** - * Checks whether the specified URI has a schema in the form + * Checks whether the specified URI has a scheme in the form * "scheme://". */ G_GNUC_PURE |