aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--configure.ac2
-rw-r--r--src/decoder_api.c63
-rw-r--r--src/decoder_internal.h19
-rw-r--r--src/decoder_thread.c2
-rw-r--r--src/player_thread.c10
-rw-r--r--src/uri.h2
7 files changed, 81 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index 746af72e..806c2b97 100644
--- a/NEWS
+++ b/NEWS
@@ -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 8aa49103..24635572 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 1f207563..a34e19b1 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 78a783f5..d89e68cf 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 dff4ca08..dbead655 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 58682f2c..7696c22c 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;
}
diff --git a/src/uri.h b/src/uri.h
index 85eeebe2..5a9b472f 100644
--- a/src/uri.h
+++ b/src/uri.h
@@ -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