Commit 7e219c36 authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.16.x'

Conflicts: src/player_thread.c
parents 203f48d1 525a7919
......@@ -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
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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;
/**
......
......@@ -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;
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment