diff options
Diffstat (limited to '')
-rw-r--r-- | src/decoder/_flac_common.h | 2 | ||||
-rw-r--r-- | src/decoder/mad_decoder_plugin.c | 4 | ||||
-rw-r--r-- | src/decoder/sidplay_decoder_plugin.cxx | 8 | ||||
-rw-r--r-- | src/decoder_control.c | 33 | ||||
-rw-r--r-- | src/decoder_control.h | 94 | ||||
-rw-r--r-- | src/decoder_error.h | 35 | ||||
-rw-r--r-- | src/decoder_thread.c | 21 |
7 files changed, 172 insertions, 25 deletions
diff --git a/src/decoder/_flac_common.h b/src/decoder/_flac_common.h index 0d90ba656..c898a47cf 100644 --- a/src/decoder/_flac_common.h +++ b/src/decoder/_flac_common.h @@ -27,8 +27,6 @@ #include "decoder_api.h" #include "pcm_buffer.h" -#include <glib.h> - #include <FLAC/stream_decoder.h> #include <FLAC/metadata.h> diff --git a/src/decoder/mad_decoder_plugin.c b/src/decoder/mad_decoder_plugin.c index a69284be5..ec54e6633 100644 --- a/src/decoder/mad_decoder_plugin.c +++ b/src/decoder/mad_decoder_plugin.c @@ -76,9 +76,9 @@ mad_fixed_to_24_sample(mad_fixed_t sample) sample = sample + (1L << (MAD_F_FRACBITS - bits)); /* clip */ - if (sample > MAX) + if (gcc_unlikely(sample > MAX)) sample = MAX; - else if (sample < MIN) + else if (gcc_unlikely(sample < MIN)) sample = MIN; /* quantize */ diff --git a/src/decoder/sidplay_decoder_plugin.cxx b/src/decoder/sidplay_decoder_plugin.cxx index 5d162f179..de2e599e9 100644 --- a/src/decoder/sidplay_decoder_plugin.cxx +++ b/src/decoder/sidplay_decoder_plugin.cxx @@ -104,7 +104,7 @@ sidplay_init(const struct config_param *param) return true; } -void +static void sidplay_finish() { g_pattern_spec_free(path_with_subtune); @@ -136,7 +136,7 @@ get_container_name(const char *path_fs) * returns tune number from file.sid/tune_xxx.sid style path or 1 if * no subtune is appended */ -static int +static unsigned get_song_num(const char *path_fs) { if(g_pattern_match(path_with_subtune, @@ -172,7 +172,7 @@ get_song_length(const char *path_fs) char md5sum[SIDTUNE_MD5_LENGTH+1]; tune.createMD5(md5sum); - int song_num=get_song_num(path_fs); + const unsigned song_num = get_song_num(path_fs); gsize num_items; gchar **values=g_key_file_get_string_list(songlength_database, @@ -330,7 +330,7 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) decoder_command_finished(decoder); } - if (song_len > 0 && player.time() >= song_len) + if (song_len > 0 && player.time() >= (unsigned)song_len) break; } while (cmd != DECODE_COMMAND_STOP); diff --git a/src/decoder_control.c b/src/decoder_control.c index 70f34b331..afcb16cdf 100644 --- a/src/decoder_control.c +++ b/src/decoder_control.c @@ -20,6 +20,7 @@ #include "config.h" #include "decoder_control.h" #include "pipe.h" +#include "song.h" #include <assert.h> @@ -40,6 +41,8 @@ dc_new(GCond *client_cond) dc->state = DECODE_STATE_STOP; dc->command = DECODE_COMMAND_NONE; + dc->song = NULL; + dc->replay_gain_db = 0; dc->replay_gain_prev_db = 0; dc->mixramp_start = NULL; @@ -52,6 +55,11 @@ dc_new(GCond *client_cond) void dc_free(struct decoder_control *dc) { + dc_clear_error(dc); + + if (dc->song != NULL) + song_free(dc->song); + g_cond_free(dc->cond); g_mutex_free(dc->mutex); g_free(dc->mixramp_start); @@ -79,6 +87,7 @@ static void dc_command(struct decoder_control *dc, enum decoder_command cmd) { decoder_lock(dc); + dc_clear_error(dc); dc_command_locked(dc, cmd); decoder_unlock(dc); } @@ -94,6 +103,27 @@ dc_command_async(struct decoder_control *dc, enum decoder_command cmd) decoder_unlock(dc); } +bool +decoder_is_current_song(const struct decoder_control *dc, + const struct song *song) +{ + assert(dc != NULL); + assert(song != NULL); + + switch (dc->state) { + case DECODE_STATE_STOP: + case DECODE_STATE_ERROR: + return false; + + case DECODE_STATE_START: + case DECODE_STATE_DECODE: + return song_equals(dc->song, song); + } + + assert(false); + return false; +} + void dc_start(struct decoder_control *dc, struct song *song, unsigned start_ms, unsigned end_ms, @@ -104,6 +134,9 @@ dc_start(struct decoder_control *dc, struct song *song, assert(pipe != NULL); assert(music_pipe_empty(pipe)); + if (dc->song != NULL) + song_free(dc->song); + dc->song = song; dc->start_ms = start_ms; dc->end_ms = end_ms; diff --git a/src/decoder_control.h b/src/decoder_control.h index 566b153ee..9ecbde73e 100644 --- a/src/decoder_control.h +++ b/src/decoder_control.h @@ -67,6 +67,14 @@ struct decoder_control { enum decoder_state state; enum decoder_command command; + /** + * The error that occurred in the decoder thread. This + * attribute is only valid if #state is #DECODE_STATE_ERROR. + * The object must be freed when this object transitions to + * any other state (usually #DECODE_STATE_START). + */ + GError *error; + bool quit; bool seek_error; bool seekable; @@ -82,8 +90,11 @@ struct decoder_control { * The song currently being decoded. This attribute is set by * the player thread, when it sends the #DECODE_COMMAND_START * command. + * + * This is a duplicate, and must be freed when this attribute + * is cleared. */ - const struct song *song; + struct song *song; /** * The initial seek position (in milliseconds), e.g. to the @@ -188,6 +199,50 @@ decoder_has_failed(const struct decoder_control *dc) return dc->state == DECODE_STATE_ERROR; } +/** + * Checks whether an error has occurred, and if so, returns a newly + * allocated copy of the #GError object. + * + * Caller must lock the object. + */ +static inline GError * +dc_get_error(const struct decoder_control *dc) +{ + assert(dc != NULL); + assert(dc->command == DECODE_COMMAND_NONE); + assert(dc->state != DECODE_STATE_ERROR || dc->error != NULL); + + return dc->state == DECODE_STATE_ERROR + ? g_error_copy(dc->error) + : NULL; +} + +/** + * Like dc_get_error(), but locks and unlocks the object. + */ +static inline GError * +dc_lock_get_error(struct decoder_control *dc) +{ + decoder_lock(dc); + GError *error = dc_get_error(dc); + decoder_unlock(dc); + return error; +} + +/** + * Clear the error condition and free the #GError object (if any). + * + * Caller must lock the object. + */ +static inline void +dc_clear_error(struct decoder_control *dc) +{ + if (dc->state == DECODE_STATE_ERROR) { + g_error_free(dc->error); + dc->state = DECODE_STATE_STOP; + } +} + static inline bool decoder_lock_is_idle(struct decoder_control *dc) { @@ -224,28 +279,35 @@ decoder_lock_has_failed(struct decoder_control *dc) return ret; } -static inline const struct song * -decoder_current_song(const struct decoder_control *dc) -{ - switch (dc->state) { - case DECODE_STATE_STOP: - case DECODE_STATE_ERROR: - return NULL; - - case DECODE_STATE_START: - case DECODE_STATE_DECODE: - return dc->song; - } +/** + * Check if the specified song is currently being decoded. If the + * decoder is not running currently (or being started), then this + * function returns false in any case. + * + * Caller must lock the object. + */ +gcc_pure +bool +decoder_is_current_song(const struct decoder_control *dc, + const struct song *song); - assert(false); - return NULL; +gcc_pure +static inline bool +decoder_lock_is_current_song(struct decoder_control *dc, + const struct song *song) +{ + decoder_lock(dc); + const bool result = decoder_is_current_song(dc, song); + decoder_unlock(dc); + return result; } /** * Start the decoder. * * @param the decoder - * @param song the song to be decoded + * @param song the song to be decoded; the given instance will be + * owned and freed by the decoder * @param start_ms see #decoder_control * @param end_ms see #decoder_control * @param pipe the pipe which receives the decoded chunks (owned by diff --git a/src/decoder_error.h b/src/decoder_error.h new file mode 100644 index 000000000..a12a31937 --- /dev/null +++ b/src/decoder_error.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_DECODER_ERROR_H +#define MPD_DECODER_ERROR_H + +#include <glib.h> + +/** + * Quark for GError.domain. + */ +G_GNUC_CONST +static inline GQuark +decoder_quark(void) +{ + return g_quark_from_static_string("decoder"); +} + +#endif diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 1440fc272..46349f53b 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -19,6 +19,7 @@ #include "config.h" #include "decoder_thread.h" +#include "decoder_error.h" #include "decoder_control.h" #include "decoder_internal.h" #include "decoder_list.h" @@ -428,12 +429,27 @@ decoder_run_song(struct decoder_control *dc, decoder_lock(dc); - dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR; + if (ret) + dc->state = DECODE_STATE_STOP; + else { + dc->state = DECODE_STATE_ERROR; + + const char *error_uri = song->uri; + char *allocated = uri_remove_auth(error_uri); + if (allocated != NULL) + error_uri = allocated; + + dc->error = g_error_new(decoder_quark(), 0, + "Failed to decode %s", error_uri); + g_free(allocated); + } } static void decoder_run(struct decoder_control *dc) { + dc_clear_error(dc); + const struct song *song = dc->song; char *uri; @@ -446,6 +462,9 @@ decoder_run(struct decoder_control *dc) if (uri == NULL) { dc->state = DECODE_STATE_ERROR; + dc->error = g_error_new(decoder_quark(), 0, + "Failed to map song"); + decoder_command_finished_locked(dc); return; } |