From a549d871f30db65da597b6d9b478dd5bab1a62f9 Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Sun, 10 Oct 2010 09:57:57 -0700 Subject: Modify version string to post-release version 0.15.14~git --- NEWS | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 01fd82d13..805e19819 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +ver 0.15.14 (2010/??/??) + + ver 0.15.13 (2010/10/10) * output_thread: fix race condition after CANCEL command * output: diff --git a/configure.ac b/configure.ac index 69f195a0c..0edbbc4cc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.15.13, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.15.14~git, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2]) AM_CONFIG_HEADER(config.h) -- cgit v1.2.3 From 21223154aa3a3c794a3842aa8a5c85198ce85220 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 4 Nov 2010 21:51:02 +0100 Subject: output_control: lock object in audio_output_close() Protect the attributes "open" and "fail_timer". --- src/output_control.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/output_control.c b/src/output_control.c index 16c0dbb75..dd562f303 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -50,6 +50,20 @@ static void ao_command(struct audio_output *ao, enum audio_output_command cmd) ao_command_wait(ao); } +/** + * Like ao_command(), but assumes the object is locked by the caller. + */ +static void +ao_command_locked(struct audio_output *ao, enum audio_output_command cmd) +{ + assert(ao->command == AO_COMMAND_NONE); + ao->command = cmd; + + g_mutex_unlock(ao->mutex); + ao_command_wait(ao); + g_mutex_lock(ao->mutex); +} + static void ao_command_async(struct audio_output *ao, enum audio_output_command cmd) { @@ -162,21 +176,33 @@ void audio_output_cancel(struct audio_output *ao) ao_command_async(ao, AO_COMMAND_CANCEL); } -void audio_output_close(struct audio_output *ao) +static void +audio_output_close_locked(struct audio_output *ao) { + assert(ao != NULL); assert(!ao->open || ao->fail_timer == NULL); if (ao->mixer != NULL) mixer_auto_close(ao->mixer); if (ao->open) - ao_command(ao, AO_COMMAND_CLOSE); + ao_command_locked(ao, AO_COMMAND_CLOSE); else if (ao->fail_timer != NULL) { g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } } +void audio_output_close(struct audio_output *ao) +{ + assert(ao != NULL); + assert(!ao->open || ao->fail_timer == NULL); + + g_mutex_lock(ao->mutex); + audio_output_close_locked(ao); + g_mutex_unlock(ao->mutex); +} + void audio_output_finish(struct audio_output *ao) { audio_output_close(ao); -- cgit v1.2.3 From 9562f667412dc620bed7299477c8a5bd86e399c4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 4 Nov 2010 22:47:51 +0100 Subject: output_control: lock object in audio_output_open() Protect the attributes "open" and "fail_timer". --- src/output_control.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/output_control.c b/src/output_control.c index dd562f303..ecd226821 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -72,6 +72,12 @@ static void ao_command_async(struct audio_output *ao, notify_signal(&ao->notify); } +static void +audio_output_close_locked(struct audio_output *ao); + +/** + * Object must be locked (and unlocked) by the caller. + */ static bool audio_output_open(struct audio_output *ao, const struct audio_format *audio_format, @@ -98,7 +104,7 @@ audio_output_open(struct audio_output *ao, /* we're not using audio_output_cancel() here, because that function is asynchronous */ - ao_command(ao, AO_COMMAND_CANCEL); + ao_command_locked(ao, AO_COMMAND_CANCEL); } return true; @@ -109,7 +115,7 @@ audio_output_open(struct audio_output *ao, if (!ao->config_audio_format) { if (ao->open) - audio_output_close(ao); + audio_output_close_locked(ao); /* no audio format is configured: copy in->out, let the output's open() method determine the effective @@ -124,7 +130,7 @@ audio_output_open(struct audio_output *ao, open = ao->open; if (!open) { - ao_command(ao, AO_COMMAND_OPEN); + ao_command_locked(ao, AO_COMMAND_OPEN); open = ao->open; } @@ -141,12 +147,19 @@ audio_output_update(struct audio_output *ao, { assert(mp != NULL); + g_mutex_lock(ao->mutex); + if (ao->enabled) { if (ao->fail_timer == NULL || - g_timer_elapsed(ao->fail_timer, NULL) > REOPEN_AFTER) - return audio_output_open(ao, audio_format, mp); + g_timer_elapsed(ao->fail_timer, NULL) > REOPEN_AFTER) { + bool ret = audio_output_open(ao, audio_format, mp); + g_mutex_unlock(ao->mutex); + return ret; + } } else if (audio_output_is_open(ao)) - audio_output_close(ao); + audio_output_close_locked(ao); + + g_mutex_unlock(ao->mutex); return false; } -- cgit v1.2.3 From 2ee047a1ddf2bb4d7e25a259492952c6128a749d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 4 Nov 2010 23:40:43 +0100 Subject: output_internal: protect attribute "fail_timer" with mutex --- src/output_internal.h | 3 ++- src/output_thread.c | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/output_internal.h b/src/output_internal.h index 72596c1c3..b863c9ecc 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -131,7 +131,8 @@ struct audio_output { const struct music_pipe *pipe; /** - * This mutex protects #open, #chunk and #chunk_finished. + * This mutex protects #open, #fail_timer, #chunk and + * #chunk_finished. */ GMutex *mutex; diff --git a/src/output_thread.c b/src/output_thread.c index e652eae57..b97694169 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -105,7 +105,12 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) /* don't automatically reopen this device for 10 seconds */ + g_mutex_lock(ao->mutex); + + assert(ao->fail_timer == NULL); ao->fail_timer = g_timer_new(); + + g_mutex_unlock(ao->mutex); return false; } -- cgit v1.2.3 From 8d5fa754e8e9a0de7b03413bb5433e1626368927 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 4 Nov 2010 21:30:16 +0100 Subject: output_thread: fix assertion failure due to race condition in OPEN Change the assertion on "fail_timer==NULL" in OPEN to a runtime check. This assertion crashed when the output thread failed while the player thread was calling audio_output_open(). --- NEWS | 2 +- src/output_thread.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 805e19819..65c5def28 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ ver 0.15.14 (2010/??/??) - +* output_thread: fix assertion failure due to race condition in OPEN ver 0.15.13 (2010/10/10) * output_thread: fix race condition after CANCEL command diff --git a/src/output_thread.c b/src/output_thread.c index b97694169..035cf99c1 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -197,10 +197,18 @@ static gpointer audio_output_task(gpointer arg) case AO_COMMAND_OPEN: assert(!ao->open); - assert(ao->fail_timer == NULL); assert(ao->pipe != NULL); assert(ao->chunk == NULL); + if (ao->fail_timer != NULL) { + /* this can only happen when this + output thread fails while + audio_output_open() is run in the + player thread */ + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } + error = NULL; ret = ao_plugin_open(ao->plugin, ao->data, &ao->out_audio_format, -- cgit v1.2.3 From e8d8bd4c0db6322932b331638007e6f277a7e2bb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 02:01:35 +0100 Subject: decoder/{mp4ff,ffmpeg}: add extension ".m4b" (audio book) Same as ".m4a". --- NEWS | 3 +++ src/decoder/ffmpeg_plugin.c | 4 +++- src/decoder/mp4ff_plugin.c | 8 +++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 65c5def28..276956be0 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ ver 0.15.14 (2010/??/??) * output_thread: fix assertion failure due to race condition in OPEN +* decoders: + - mp4ff, ffmpeg: add extension ".m4b" (audio book) + ver 0.15.13 (2010/10/10) * output_thread: fix race condition after CANCEL command diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index 9bae39793..10894b633 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -501,7 +501,9 @@ static const char *const ffmpeg_suffixes[] = { "atrac", "au", "aud", "avi", "avm2", "avs", "bap", "bfi", "c93", "cak", "cin", "cmv", "cpk", "daud", "dct", "divx", "dts", "dv", "dvd", "dxa", "eac3", "film", "flac", "flc", "fli", "fll", "flx", "flv", "g726", - "gsm", "gxf", "iss", "m1v", "m2v", "m2t", "m2ts", "m4a", "m4v", "mad", + "gsm", "gxf", "iss", "m1v", "m2v", "m2t", "m2ts", + "m4a", "m4b", "m4v", + "mad", "mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+", "mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu", "mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv", diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index d5afe084b..4d4d47c6c 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -425,7 +425,13 @@ mp4_tag_dup(const char *file) return ret; } -static const char *const mp4_suffixes[] = { "m4a", "mp4", NULL }; +static const char *const mp4_suffixes[] = { + "m4a", + "m4b", + "mp4", + NULL +}; + static const char *const mp4_mime_types[] = { "audio/mp4", "audio/m4a", NULL }; const struct decoder_plugin mp4ff_decoder_plugin = { -- cgit v1.2.3 From a728d7a026896cc9b3fe68d00a689dee4c3312e1 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 18:23:48 +0100 Subject: input/rewind: fix double free bug Duplicate the "mime" attribute of the inner input_stream object, instead of copying the pointer. --- NEWS | 2 ++ src/input/rewind_input_plugin.c | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 276956be0..3a61e1149 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ ver 0.15.14 (2010/??/??) * output_thread: fix assertion failure due to race condition in OPEN +* input: + - rewind: fix double free bug * decoders: - mp4ff, ffmpeg: add extension ".m4b" (audio book) diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c index 43f0254c9..c03f7f031 100644 --- a/src/input/rewind_input_plugin.c +++ b/src/input/rewind_input_plugin.c @@ -244,4 +244,5 @@ input_rewind_open(struct input_stream *is) input stream */ is->plugin = &rewind_input_plugin; is->data = c; + is->mime = g_strdup(c->input.mime); } -- cgit v1.2.3 From dfd98eede742720c9b660a60b796f5b26d552de3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 18:25:29 +0100 Subject: input/rewind: add two assertions --- src/input/rewind_input_plugin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c index c03f7f031..ead5765c8 100644 --- a/src/input/rewind_input_plugin.c +++ b/src/input/rewind_input_plugin.c @@ -83,6 +83,9 @@ copy_attributes(struct input_stream *dest) const struct input_rewind *r = dest->data; const struct input_stream *src = &r->input; + assert(dest != src); + assert(dest->mime != src->mime); + dest->ready = src->ready; dest->seekable = src->seekable; dest->error = src->error; -- cgit v1.2.3 From 32d10eedbde70ef3d5ae0f1567cee3e25e4f9993 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 18:25:59 +0100 Subject: input/rewind: remove redundant NULL check before g_free() call --- src/input/rewind_input_plugin.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c index ead5765c8..1927c525a 100644 --- a/src/input/rewind_input_plugin.c +++ b/src/input/rewind_input_plugin.c @@ -93,8 +93,7 @@ copy_attributes(struct input_stream *dest) dest->offset = src->offset; if (src->mime != NULL) { - if (dest->mime != NULL) - g_free(dest->mime); + g_free(dest->mime); dest->mime = g_strdup(src->mime); } } -- cgit v1.2.3 From c594afeee70b29cc88e337a3b8fbd2a39ac37822 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 18:34:06 +0100 Subject: pipe: add helper function music_pipe_empty() --- src/output_all.c | 4 ++-- src/pipe.h | 6 ++++++ src/player_thread.c | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/output_all.c b/src/output_all.c index 4b5ba3a6f..86e78e13e 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -266,7 +266,7 @@ audio_output_all_open(const struct audio_format *audio_format, else /* if the pipe hasn't been cleared, the the audio format must not have changed */ - assert(music_pipe_size(g_mp) == 0 || + assert(music_pipe_empty(g_mp) || audio_format_equals(audio_format, &input_audio_format)); @@ -378,7 +378,7 @@ audio_output_all_check(void) assert(g_mp != NULL); while ((chunk = music_pipe_peek(g_mp)) != NULL) { - assert(music_pipe_size(g_mp) > 0); + assert(!music_pipe_empty(g_mp)); if (!chunk_is_consumed(chunk)) /* at least one output is not finished playing diff --git a/src/pipe.h b/src/pipe.h index f91fc1c7f..2825b320a 100644 --- a/src/pipe.h +++ b/src/pipe.h @@ -99,4 +99,10 @@ music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk); unsigned music_pipe_size(const struct music_pipe *mp); +static inline bool +music_pipe_empty(const struct music_pipe *mp) +{ + return music_pipe_size(mp) == 0; +} + #endif diff --git a/src/player_thread.c b/src/player_thread.c index e2c9b6f93..18b8121a9 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -736,7 +736,7 @@ static void do_play(void) if (player.paused) notify_wait(&pc.notify); - else if (music_pipe_size(player.pipe) > 0) { + else if (!music_pipe_empty(player.pipe)) { /* at least one music chunk is ready - send it to the audio output */ @@ -757,7 +757,7 @@ static void do_play(void) /* check the size of the pipe again, because the decoder thread may have added something since we last checked */ - if (music_pipe_size(player.pipe) == 0) + if (music_pipe_empty(player.pipe)) break; } else { /* the decoder is too busy and hasn't provided -- cgit v1.2.3 From 5223261f1907a642ebe741518b7981830c094924 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 19:08:54 +0100 Subject: player_thread: add helper function player_dc_at_next_song() Some abstraction for decoder_control.pipe access. --- src/player_thread.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/player_thread.c b/src/player_thread.c index 18b8121a9..a827e7505 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -118,6 +118,33 @@ static void player_command_finished(void) notify_signal(&main_notify); } +/** + * Is the decoder still busy on the same song as the player? + * + * Note: this function does not check if the decoder is already + * finished. + */ +static bool +player_dc_at_current_song(const struct player *player) +{ + assert(player != NULL); + assert(player->pipe != NULL); + + return dc.pipe == player->pipe; +} + +/** + * Has the decoder already begun decoding the next song? + * + * Note: this function does not check if the decoder is already + * finished. + */ +static bool +player_dc_at_next_song(const struct player *player) +{ + return dc.pipe != NULL && !player_dc_at_current_song(player); +} + /** * Stop the decoder and clears (and frees) its music pipe. */ @@ -364,7 +391,7 @@ static void player_process_command(struct player *player) case PLAYER_COMMAND_QUEUE: assert(pc.next_song != NULL); assert(!player->queued); - assert(dc.pipe == NULL || dc.pipe == player->pipe); + assert(!player_dc_at_next_song(player)); player->queued = true; player_command_finished(); @@ -409,7 +436,7 @@ static void player_process_command(struct player *player) return; } - if (dc.pipe != NULL && dc.pipe != player->pipe) + if (player_dc_at_next_song(player)) /* the decoder is already decoding the song - stop it and reset the position */ player_dc_stop(player); @@ -505,7 +532,7 @@ play_next_chunk(struct player *player) return true; if (player->xfade == XFADE_ENABLED && - dc.pipe != NULL && dc.pipe != player->pipe && + player_dc_at_next_song(player) && (cross_fade_position = music_pipe_size(player->pipe)) <= player->cross_fade_chunks) { /* perform cross fade */ @@ -706,14 +733,14 @@ static void do_play(void) /* the decoder has finished the current song; make it decode the next song */ assert(pc.next_song != NULL); - assert(dc.pipe == NULL || dc.pipe == player.pipe); + assert(!player_dc_at_next_song(&player)); player.queued = false; dc.pipe = music_pipe_new(); dc_start_async(pc.next_song); } - if (dc.pipe != NULL && dc.pipe != player.pipe && + if (player_dc_at_next_song(&player) && player.xfade == XFADE_UNKNOWN && !decoder_is_starting()) { /* enable cross fading in this song? if yes, @@ -748,7 +775,7 @@ static void do_play(void) /* XXX synchronize in a better way */ g_usleep(10000); - } else if (dc.pipe != NULL && dc.pipe != player.pipe) { + } else if (player_dc_at_next_song(&player)) { /* at the beginning of a new song */ if (!player_song_border(&player)) -- cgit v1.2.3 From cc261872c25be3a5792be8ae160e070d1bbedf0b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 17:42:08 +0100 Subject: decoder_control: pass music_pipe to dc_start() More abstraction for decoder_control.pipe. --- src/decoder_control.c | 15 +++++++++++---- src/decoder_control.h | 4 ++-- src/player_thread.c | 11 +++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/decoder_control.c b/src/decoder_control.c index 44bb63e15..618c78e7e 100644 --- a/src/decoder_control.c +++ b/src/decoder_control.c @@ -18,6 +18,7 @@ */ #include "decoder_control.h" +#include "pipe.h" #include @@ -58,22 +59,28 @@ static void dc_command_async(enum decoder_command cmd) } void -dc_start(struct notify *notify, struct song *song) +dc_start(struct notify *notify, struct song *song, struct music_pipe *pipe) { - assert(dc.pipe != NULL); + assert(dc.pipe == NULL); assert(song != NULL); + assert(pipe != NULL); + assert(music_pipe_empty(pipe)); dc.next_song = song; + dc.pipe = pipe; dc_command(notify, DECODE_COMMAND_START); } void -dc_start_async(struct song *song) +dc_start_async(struct song *song, struct music_pipe *pipe) { - assert(dc.pipe != NULL); + assert(dc.pipe == NULL); assert(song != NULL); + assert(pipe != NULL); + assert(music_pipe_empty(pipe)); dc.next_song = song; + dc.pipe = pipe; dc_command_async(DECODE_COMMAND_START); } diff --git a/src/decoder_control.h b/src/decoder_control.h index 6a04a1617..febf53335 100644 --- a/src/decoder_control.h +++ b/src/decoder_control.h @@ -118,10 +118,10 @@ void dc_command_wait(struct notify *notify); void -dc_start(struct notify *notify, struct song *song); +dc_start(struct notify *notify, struct song *song, struct music_pipe *pipe); void -dc_start_async(struct song *song); +dc_start_async(struct song *song, struct music_pipe *pipe); void dc_stop(struct notify *notify); diff --git a/src/player_thread.c b/src/player_thread.c index a827e7505..3d2ebcb42 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -324,10 +324,9 @@ static bool player_seek_decoder(struct player *player) /* clear music chunks which might still reside in the pipe */ music_pipe_clear(player->pipe, player_buffer); - dc.pipe = player->pipe; /* re-start the decoder */ - dc_start_async(pc.next_song); + dc_start_async(pc.next_song, player->pipe); ret = player_wait_for_decoder(player); if (!ret) { /* decoder failure */ @@ -665,8 +664,7 @@ static void do_play(void) player.pipe = music_pipe_new(); dc.buffer = player_buffer; - dc.pipe = player.pipe; - dc_start(&pc.notify, pc.next_song); + dc_start(&pc.notify, pc.next_song, player.pipe); if (!player_wait_for_decoder(&player)) { player_dc_stop(&player); player_command_finished(); @@ -735,9 +733,10 @@ static void do_play(void) assert(pc.next_song != NULL); assert(!player_dc_at_next_song(&player)); + dc.pipe = NULL; + player.queued = false; - dc.pipe = music_pipe_new(); - dc_start_async(pc.next_song); + dc_start_async(pc.next_song, music_pipe_new()); } if (player_dc_at_next_song(&player) && -- cgit v1.2.3 From 83ec0e55523b05c724dcf8ef68839e04d4911396 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 5 Nov 2010 19:24:42 +0100 Subject: player_thread: fix assertion failure due to wrong music pipe on seek When one song is played twice, and the decoder is working on the second "instance", but the first should be seeked, the check in player_seek_decoder() may assume that it can reuse the decoder without exchanging pipes. The last thing was the mistake: the pipe pointer was different, which led to an assertion failure. This patch adds another check which exchanges the player pipe. --- NEWS | 1 + src/player_thread.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/NEWS b/NEWS index 3a61e1149..29ce2dcc4 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,5 @@ ver 0.15.14 (2010/??/??) +* player_thread: fix assertion failure due to wrong music pipe on seek * output_thread: fix assertion failure due to race condition in OPEN * input: - rewind: fix double free bug diff --git a/src/player_thread.c b/src/player_thread.c index 3d2ebcb42..d428484c7 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -334,6 +334,14 @@ static bool player_seek_decoder(struct player *player) return false; } } else { + if (!player_dc_at_current_song(player)) { + /* the decoder is already decoding the "next" song, + but it is the same song file; exchange the pipe */ + music_pipe_clear(player->pipe, player_buffer); + music_pipe_free(player->pipe); + player->pipe = dc.pipe; + } + pc.next_song = NULL; player->queued = false; } -- cgit v1.2.3 From dec7090198a0bbdd91ab8c531b84624f8bde4da9 Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Sat, 6 Nov 2010 14:42:02 -0700 Subject: mpd version 0.15.14 --- NEWS | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 29ce2dcc4..0c8e03d88 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.15.14 (2010/??/??) +ver 0.15.14 (2010/11/06) * player_thread: fix assertion failure due to wrong music pipe on seek * output_thread: fix assertion failure due to race condition in OPEN * input: diff --git a/configure.ac b/configure.ac index 0edbbc4cc..b47360dad 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.15.14~git, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.15.14, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2]) AM_CONFIG_HEADER(config.h) -- cgit v1.2.3