From e2950a7e4d9bdc36a207023fc55ec03dfae0d7af Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Sat, 4 Jun 2011 07:37:33 -0700 Subject: [PATCH 01/21] mpd version 0.16.3 --- NEWS | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index f56e2e872..31169a85c 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.16.3 (2011/??/??) +ver 0.16.3 (2011/06/04) * fix assertion failure in audio format mask parser * fix NULL pointer dereference in playlist parser * fix playlist files in base music directory diff --git a/configure.ac b/configure.ac index 184f0dcb0..0aed23bf2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.16.3~git, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.16.3, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects]) AM_CONFIG_HEADER(config.h) From 3c4f4793b517a3bf8803d39818a94ac727b5f5a1 Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Sat, 4 Jun 2011 07:37:34 -0700 Subject: [PATCH 02/21] Modify version string to post-release version 0.16.4~git --- NEWS | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 31169a85c..f38358a83 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +ver 0.16.4 (2010/??/??) + + ver 0.16.3 (2011/06/04) * fix assertion failure in audio format mask parser * fix NULL pointer dereference in playlist parser diff --git a/configure.ac b/configure.ac index 0aed23bf2..0618bd413 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.16.3, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.16.4~git, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects]) AM_CONFIG_HEADER(config.h) From 52b8e0f9ecdc15c90266d6a50a5ebd9a1038ebdb Mon Sep 17 00:00:00 2001 From: Tony Miller Date: Sun, 26 Jun 2011 15:00:48 -0700 Subject: [PATCH 03/21] doc/user: Typo in playlist plugin documentation, 'playlist plugin' not 'filter'. This patch fixes a typo in doc/user about playlist plugins. Its in the top commit in my repository in a branch called 'doc_fix': git://github.com/mcfiredrill/mpd.git --- doc/user.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user.xml b/doc/user.xml index 17bbdf91f..6a9871007 100644 --- a/doc/user.xml +++ b/doc/user.xml @@ -446,7 +446,7 @@ cd mpd-version - To configure a filter, add a + To configure a playlist plugin, add a playlist_plugin block to mpd.conf: From 8d1c7ca2065444dfe2da432a30c95782e3ead48d Mon Sep 17 00:00:00 2001 From: oblique Date: Sun, 3 Jul 2011 14:54:56 +0200 Subject: [PATCH 04/21] ffmpeg: workaround for semantic API change in recent ffmpeg versions --- NEWS | 2 ++ src/decoder/ffmpeg_decoder_plugin.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index f38358a83..208ba1069 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.16.4 (2010/??/??) +* decoder: + - ffmpeg: workaround for semantic API change in recent ffmpeg versions ver 0.16.3 (2011/06/04) diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c index 6d794db49..156853faf 100644 --- a/src/decoder/ffmpeg_decoder_plugin.c +++ b/src/decoder/ffmpeg_decoder_plugin.c @@ -321,7 +321,7 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) } //ffmpeg works with ours "fileops" helper - AVFormatContext *format_context; + AVFormatContext *format_context = NULL; if (av_open_input_stream(&format_context, stream->io, input->uri, input_format, NULL) != 0) { g_warning("Open failed\n"); @@ -470,7 +470,7 @@ ffmpeg_stream_tag(struct input_stream *is) if (stream == NULL) return NULL; - AVFormatContext *f; + AVFormatContext *f = NULL; if (av_open_input_stream(&f, stream->io, is->uri, input_format, NULL) != 0) { mpd_ffmpeg_stream_close(stream); From 6aa6a9c2727c863239d6396a40a781e98e922565 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 3 Jul 2011 14:57:56 +0200 Subject: [PATCH 05/21] decoder/flac: validate the sample rate when scanning the tag Don't calculate the song duration when the sample rate is 0 (division by zero crash). --- NEWS | 1 + src/decoder/flac_metadata.c | 3 ++- src/decoder/flac_metadata.h | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 208ba1069..138630967 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.16.4 (2010/??/??) * decoder: - ffmpeg: workaround for semantic API change in recent ffmpeg versions + - flac: validate the sample rate when scanning the tag ver 0.16.3 (2011/06/04) diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c index f2f2f954d..5b94fd426 100644 --- a/src/decoder/flac_metadata.c +++ b/src/decoder/flac_metadata.c @@ -224,7 +224,8 @@ flac_tag_apply_metadata(struct tag *tag, const char *track, break; case FLAC__METADATA_TYPE_STREAMINFO: - tag->time = flac_duration(&block->data.stream_info); + if (block->data.stream_info.sample_rate > 0) + tag->time = flac_duration(&block->data.stream_info); break; default: diff --git a/src/decoder/flac_metadata.h b/src/decoder/flac_metadata.h index 06e691d1d..e52b0fb82 100644 --- a/src/decoder/flac_metadata.h +++ b/src/decoder/flac_metadata.h @@ -20,6 +20,7 @@ #ifndef MPD_FLAC_METADATA_H #define MPD_FLAC_METADATA_H +#include #include #include @@ -29,6 +30,8 @@ struct replay_gain_info; static inline unsigned flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info) { + assert(stream_info->sample_rate > 0); + return (stream_info->total_samples + stream_info->sample_rate - 1) / stream_info->sample_rate; } From 3680a6bbbb6c2ae26d5c9bf361bc2feea362b553 Mon Sep 17 00:00:00 2001 From: Jonathan Ballet Date: Sun, 3 Jul 2011 15:05:04 +0200 Subject: [PATCH 06/21] doc/protocol: add some missing specifications --- doc/protocol.xml | 134 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 7 deletions(-) diff --git a/doc/protocol.xml b/doc/protocol.xml index 3eb5aa932..0b4f0d175 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -8,18 +8,54 @@ General protocol syntax
- Requests + Protocol overview - If arguments contain spaces, they should be surrounded by double quotation - marks. + The MPD command protocol exchanges line-based text records + between client and server over TCP. Once the client is + connected to the server, they conduct a conversation until the + client closes the connection. The conversation flow is always + initiated by the client. + + The client transmits a command sequence, terminated by the + newline character \n. The server will + respond with one or more lines, the last of which will be a + completion code. + + + + When the client connects to the server, the server will answer + with the following line: + + OK MPD version + + where version is a version identifier such as + 0.12.2. This version identifier is the version of the protocol + spoken, not the real version of the daemon. (There is no way to + retrieve this real version identifier from the connection.) + +
+ +
+ Requests + COMMAND ARG + + If arguments contain spaces, they should be surrounded by double + quotation marks. + + + + Argument strings are separated from the command and any other + arguments by linear white-space (' ' or '\t'). + + All data between the client and the server is encoded in UTF-8. (Note: In UTF-8 all standard ansi characters, 0-127 are @@ -38,13 +74,97 @@ Responses - A command returns OK on completion - or ACK some error on failure. - These denote the end of command execution. + A command returns OK on completion or + ACK some error on failure. These + denote the end of command execution. + +
+ Failure responses + + + The nature of the error can be gleaned from the information + that follows the ACK. + ACK lines are of the form: + + ACK [error@command_listNum] {current_command} message_text\n + + These responses are generated by a call to + commandError. They contain four separate + terms. Let's look at each of them: + + + + + error: numeric value of one + of the ACK_ERROR constants defined + in ack.h. + + + + + command_listNum: + offset of the command that caused the error in a Command List. + An error will always cause a command list to terminate + at the command that causes the error. + + + + + current_command: + name of the command, in a Command List, + that was executing when the error occurred. + + + + + message_text: + some (hopefully) informative text that describes the + nature of the error. + + + + + + + foo + + An example might help. Consider the following sequence + sent from the client to the server. + + + command_list_begin + volume 86 + play 10240 + status + command_list_end + + + + + The server responds with: + + + ACK [50@1] {play} song doesn't exist: "10240" + + + + + This tells us that the play command, which was the + second in the list (the first or only command is + numbered 0), failed with error 50. The number 50 + translates to ACK_ERROR_NO_EXIST--the + song doesn't exist. This is reiterated by the message text + which also tells us which song doesn't exist. + + + +
-
+
Command lists From dca405a746e0b86e37659bdb112358324fc48d28 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 3 Jul 2011 15:20:28 +0200 Subject: [PATCH 07/21] test/read_conf: fix -Wunused-but-set-variable --- test/read_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/read_conf.c b/test/read_conf.c index 4f43e6a2e..e96bd9046 100644 --- a/test/read_conf.c +++ b/test/read_conf.c @@ -70,5 +70,5 @@ int main(int argc, char **argv) } config_global_finish(); - return 0; + return ret; } From 52e2fa91c4c322bc0d8a12a825370f91aa7fecc6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 3 Jul 2011 15:20:39 +0200 Subject: [PATCH 08/21] test/read_conf: make variables more local --- test/read_conf.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/read_conf.c b/test/read_conf.c index e96bd9046..f1b38cafe 100644 --- a/test/read_conf.c +++ b/test/read_conf.c @@ -37,30 +37,28 @@ my_log_func(G_GNUC_UNUSED const gchar *log_domain, int main(int argc, char **argv) { - const char *path, *name, *value; - GError *error = NULL; - bool success; - int ret; - if (argc != 3) { g_printerr("Usage: read_conf FILE SETTING\n"); return 1; } - path = argv[1]; - name = argv[2]; + const char *path = argv[1]; + const char *name = argv[2]; g_log_set_default_handler(my_log_func, NULL); config_global_init(); - success = config_read_file(path, &error); + + GError *error = NULL; + bool success = config_read_file(path, &error); if (!success) { g_printerr("%s:", error->message); g_error_free(error); return 1; } - value = config_get_string(name, NULL); + const char *value = config_get_string(name, NULL); + int ret; if (value != NULL) { g_print("%s\n", value); ret = 0; From cca2c2f4ca42f1c6a15d16bd2e8384971dad811d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 3 Jul 2011 15:21:40 +0200 Subject: [PATCH 09/21] test/run_filter: remove unused variable "frame_size" --- test/run_filter.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/run_filter.c b/test/run_filter.c index ee2445eac..3758eb5bb 100644 --- a/test/run_filter.c +++ b/test/run_filter.c @@ -106,7 +106,6 @@ int main(int argc, char **argv) struct filter *filter; const struct audio_format *out_audio_format; char buffer[4096]; - size_t frame_size; if (argc < 3 || argc > 4) { g_printerr("Usage: run_filter CONFIG NAME [FORMAT] Date: Sun, 3 Jul 2011 15:42:22 +0200 Subject: [PATCH 10/21] configure: correct avahi/bonjour state on result page Was always displayed as "no", even if one was found. --- configure.ac | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 0618bd413..b362592cf 100644 --- a/configure.ac +++ b/configure.ac @@ -537,15 +537,16 @@ no|avahi|bonjour) ;; esac +enable_avahi=no +enable_bounjour=no if test x$with_zeroconf != xno; then if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib], - [found_avahi=1;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])] - MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS", - [found_avahi=0]) + [enable_avahi=yes;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])] + MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS") fi - if test x$found_avahi = x1; then + if test x$enable_avahi = xyes; then with_zeroconf=avahi elif test x$with_zeroconf = xavahi; then AC_MSG_ERROR([Avahi support requested but not found]) @@ -553,13 +554,12 @@ if test x$with_zeroconf != xno; then if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then AC_CHECK_HEADER(dns_sd.h, - [found_bonjour=1;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])], - [found_bonjour=0]) + [enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])]) AC_CHECK_LIB(dns_sd, DNSServiceRegister, MPD_LIBS="$MPD_LIBS -ldns_sd") fi - if test x$found_bonjour = x1; then + if test x$enable_bonjour = xyes; then with_zeroconf=bonjour elif test x$with_zeroconf = xbonjour; then AC_MSG_ERROR([Bonjour support requested but not found]) From affb4bd923492913ffebb71c4f977a6bbf9ed257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 12:37:25 +0200 Subject: [PATCH 11/21] ape: add missing g_free in error path --- src/ape.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ape.c b/src/ape.c index 5fca98e28..5f4da3f2e 100644 --- a/src/ape.c +++ b/src/ape.c @@ -60,8 +60,10 @@ ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx) assert(remaining > 10); char *buffer = g_malloc(remaining); - if (fread(buffer, 1, remaining, fp) != remaining) + if (fread(buffer, 1, remaining, fp) != remaining) { + g_free(buffer); return false; + } /* read tags */ unsigned n = GUINT32_FROM_LE(footer.count); From d5684f74440fec77b3bc7c80a8396c79e4e489ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 12:47:06 +0200 Subject: [PATCH 12/21] sticker: fix a memory leak --- src/sticker.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sticker.c b/src/sticker.c index c59cdd078..f6cd04346 100644 --- a/src/sticker.c +++ b/src/sticker.c @@ -579,8 +579,10 @@ sticker_load(const char *type, const char *uri) bool success; success = sticker_list_values(sticker->table, type, uri); - if (!success) + if (!success) { + sticker_free(sticker); return NULL; + } if (g_hash_table_size(sticker->table) == 0) { /* don't return empty sticker objects */ From c49c69d6ea0b7670f70066f0735fcffc69966d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 12:38:43 +0200 Subject: [PATCH 13/21] conf: add missing fclose in error path This patch seems a bit ugly, maybe it would be a bit cleaner with gotos. --- src/conf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/conf.c b/src/conf.c index 705942085..14dac93a6 100644 --- a/src/conf.c +++ b/src/conf.c @@ -367,6 +367,7 @@ config_read_file(const char *file, GError **error_r) assert(*line != 0); g_propagate_prefixed_error(error_r, error, "line %i: ", count); + fclose(fp); return false; } @@ -378,6 +379,7 @@ config_read_file(const char *file, GError **error_r) g_set_error(error_r, config_quark(), 0, "unrecognized parameter in config file at " "line %i: %s\n", count, name); + fclose(fp); return false; } @@ -387,6 +389,7 @@ config_read_file(const char *file, GError **error_r) "config parameter \"%s\" is first defined " "on line %i and redefined on line %i\n", name, param->line, count); + fclose(fp); return false; } @@ -398,6 +401,7 @@ config_read_file(const char *file, GError **error_r) if (*line != '{') { g_set_error(error_r, config_quark(), 0, "line %i: '{' expected", count); + fclose(fp); return false; } @@ -406,12 +410,15 @@ config_read_file(const char *file, GError **error_r) g_set_error(error_r, config_quark(), 0, "line %i: Unknown tokens after '{'", count); + fclose(fp); return false; } param = config_read_block(fp, &count, string, error_r); - if (param == NULL) + if (param == NULL) { + fclose(fp); return false; + } } else { /* a string value */ @@ -428,6 +435,7 @@ config_read_file(const char *file, GError **error_r) g_error_free(error); } + fclose(fp); return false; } @@ -435,6 +443,7 @@ config_read_file(const char *file, GError **error_r) g_set_error(error_r, config_quark(), 0, "line %i: Unknown tokens after value", count); + fclose(fp); return false; } From 36aa8ce3c9f34d41aa7fd94d90f23ba62f5caafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 13:38:46 +0200 Subject: [PATCH 14/21] output/ao: add missing g_free in error path --- src/output/ao_plugin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c index 6fedbc6e2..42ece5a3a 100644 --- a/src/output/ao_plugin.c +++ b/src/output/ao_plugin.c @@ -106,12 +106,14 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, g_set_error(error, ao_output_quark(), 0, "\"%s\" is not a valid ao driver", value); + g_free(ad); return NULL; } if ((ai = ao_driver_info(ad->driver)) == NULL) { g_set_error(error, ao_output_quark(), 0, "problems getting driver info"); + g_free(ad); return NULL; } @@ -129,6 +131,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, g_set_error(error, ao_output_quark(), 0, "problems parsing options \"%s\"", options[i]); + g_free(ad); return NULL; } From 296085ff23f3992f0f45fc0325c5bdbab953e114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 14:35:04 +0200 Subject: [PATCH 15/21] output/httpd: add missing g_free in error path --- src/output/httpd_output_plugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c index 6650d89e3..b82dc0599 100644 --- a/src/output/httpd_output_plugin.c +++ b/src/output/httpd_output_plugin.c @@ -103,6 +103,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, if (encoder_plugin == NULL) { g_set_error(error, httpd_output_quark(), 0, "No such encoder: %s", encoder_name); + g_free(httpd); return NULL; } From a6a8bdffc35c3b592ca9eb908ef010a27ddbb3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 15:39:19 +0200 Subject: [PATCH 16/21] output/recorder: fix a memory leak --- src/output/recorder_output_plugin.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index c01d927c4..10d64106c 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -79,23 +79,27 @@ recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, if (encoder_plugin == NULL) { g_set_error(error_r, recorder_output_quark(), 0, "No such encoder: %s", encoder_name); - return NULL; + goto failure; } recorder->path = config_get_block_string(param, "path", NULL); if (recorder->path == NULL) { g_set_error(error_r, recorder_output_quark(), 0, "'path' not configured"); - return NULL; + goto failure; } /* initialize encoder */ recorder->encoder = encoder_init(encoder_plugin, param, error_r); if (recorder->encoder == NULL) - return NULL; + goto failure; return recorder; + +failure: + g_free(recorder); + return NULL; } static void From 7d6a605a859139dd1e22b6e7e91479b644d5f398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 18 Jul 2011 15:58:02 +0200 Subject: [PATCH 17/21] output/shout: fix a memory leak --- src/output/shout_plugin.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c index baaeccf92..5e1ef762a 100644 --- a/src/output/shout_plugin.c +++ b/src/output/shout_plugin.c @@ -152,7 +152,7 @@ my_shout_init_driver(const struct audio_format *audio_format, if (port == 0) { g_set_error(error, shout_output_quark(), 0, "shout port must be configured"); - return NULL; + goto failure; } check_block_param("password"); @@ -174,21 +174,21 @@ my_shout_init_driver(const struct audio_format *audio_format, "shout quality \"%s\" is not a number in the " "range -1 to 10, line %i", value, param->line); - return NULL; + goto failure; } if (config_get_block_string(param, "bitrate", NULL) != NULL) { g_set_error(error, shout_output_quark(), 0, "quality and bitrate are " "both defined"); - return NULL; + goto failure; } } else { value = config_get_block_string(param, "bitrate", NULL); if (value == NULL) { g_set_error(error, shout_output_quark(), 0, "neither bitrate nor quality defined"); - return NULL; + goto failure; } sd->bitrate = strtol(value, &test, 10); @@ -196,7 +196,7 @@ my_shout_init_driver(const struct audio_format *audio_format, if (*test != '\0' || sd->bitrate <= 0) { g_set_error(error, shout_output_quark(), 0, "bitrate must be a positive integer"); - return NULL; + goto failure; } } @@ -206,12 +206,12 @@ my_shout_init_driver(const struct audio_format *audio_format, g_set_error(error, shout_output_quark(), 0, "couldn't find shout encoder plugin \"%s\"", encoding); - return NULL; + goto failure; } sd->encoder = encoder_init(encoder_plugin, param, error); if (sd->encoder == NULL) - return NULL; + goto failure; if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0) shout_format = SHOUT_FORMAT_MP3; @@ -225,7 +225,7 @@ my_shout_init_driver(const struct audio_format *audio_format, g_set_error(error, shout_output_quark(), 0, "you cannot stream \"%s\" to shoutcast, use mp3", encoding); - return NULL; + goto failure; } else if (0 == strcmp(value, "shoutcast")) protocol = SHOUT_PROTOCOL_ICY; else if (0 == strcmp(value, "icecast1")) @@ -237,7 +237,7 @@ my_shout_init_driver(const struct audio_format *audio_format, "shout protocol \"%s\" is not \"shoutcast\" or " "\"icecast1\"or \"icecast2\"", value); - return NULL; + goto failure; } } else { protocol = SHOUT_PROTOCOL_HTTP; @@ -256,7 +256,7 @@ my_shout_init_driver(const struct audio_format *audio_format, shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) { g_set_error(error, shout_output_quark(), 0, "%s", shout_get_error(sd->shout_conn)); - return NULL; + goto failure; } /* optional paramters */ @@ -267,14 +267,14 @@ my_shout_init_driver(const struct audio_format *audio_format, if (value != NULL && shout_set_genre(sd->shout_conn, value)) { g_set_error(error, shout_output_quark(), 0, "%s", shout_get_error(sd->shout_conn)); - return NULL; + goto failure; } value = config_get_block_string(param, "description", NULL); if (value != NULL && shout_set_description(sd->shout_conn, value)) { g_set_error(error, shout_output_quark(), 0, "%s", shout_get_error(sd->shout_conn)); - return NULL; + goto failure; } { @@ -300,6 +300,10 @@ my_shout_init_driver(const struct audio_format *audio_format, } return sd; + +failure: + free_shout_data(sd); + return NULL; } static bool From 73f9e1795156fc7fd5e41de45f3acce24c71d874 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 18 Jul 2011 22:47:51 +0200 Subject: [PATCH 18/21] NEWS: fix memory leaks --- NEWS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 138630967..4756b64f6 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,5 @@ -ver 0.16.4 (2010/??/??) +ver 0.16.4 (2011/??/??) +* fix memory leaks * decoder: - ffmpeg: workaround for semantic API change in recent ffmpeg versions - flac: validate the sample rate when scanning the tag From 762712c756fe3041cc60cc4084ef505e56acf57c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 8 Jul 2011 21:20:38 +0200 Subject: [PATCH 19/21] database: require X_OK on parent directory, not R_OK For accessing the child of a directory, one needs X_OK on the directory. --- src/database.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database.c b/src/database.c index f255d6ca5..9f29f95e1 100644 --- a/src/database.c +++ b/src/database.c @@ -180,7 +180,7 @@ db_check(void) } /* Check if we can write to the directory */ - if (access(dirPath, R_OK | W_OK)) { + if (access(dirPath, X_OK | W_OK)) { g_warning("Can't create db file in \"%s\": %s", dirPath, strerror(errno)); g_free(dirPath); From 6592ca9f8805c3cf5154626087a01a183c38b6d5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 18 Jul 2011 23:29:42 +0200 Subject: [PATCH 20/21] decoder: use AVDictionary instead of AVMetadata AVMetadata has been deprecated. --- src/decoder/ffmpeg_decoder_plugin.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c index 156853faf..15ea77f70 100644 --- a/src/decoder/ffmpeg_decoder_plugin.c +++ b/src/decoder/ffmpeg_decoder_plugin.c @@ -446,13 +446,26 @@ static const ffmpeg_tag_map ffmpeg_tag_maps[] = { }; static bool -ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m, +ffmpeg_copy_metadata(struct tag *tag, +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0) + AVDictionary *m, +#else + AVMetadata *m, +#endif const ffmpeg_tag_map tag_map) { +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0) + AVDictionaryEntry *mt = NULL; + + while ((mt = av_dict_get(m, tag_map.name, mt, 0)) != NULL) + tag_add_item(tag, tag_map.type, mt->value); +#else AVMetadataTag *mt = NULL; while ((mt = av_metadata_get(m, tag_map.name, mt, 0)) != NULL) tag_add_item(tag, tag_map.type, mt->value); +#endif + return mt != NULL; } From 736fd0e29326548152e91e4e3fb8c0ea9c1b50ac Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 18 Jul 2011 23:31:47 +0200 Subject: [PATCH 21/21] decoder/ffmpeg: use avformat_open_input() if available av_open_input_stream() has been deprecated. --- src/decoder/ffmpeg_decoder_plugin.c | 39 ++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c index 15ea77f70..70628df9d 100644 --- a/src/decoder/ffmpeg_decoder_plugin.c +++ b/src/decoder/ffmpeg_decoder_plugin.c @@ -89,7 +89,11 @@ struct mpd_ffmpeg_stream { struct decoder *decoder; struct input_stream *input; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0) + AVIOContext *io; +#else ByteIOContext *io; +#endif unsigned char buffer[8192]; }; @@ -135,6 +139,33 @@ mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input) return stream; } +/** + * API compatibility wrapper for av_open_input_stream() and + * avformat_open_input(). + */ +static int +mpd_ffmpeg_open_input(AVFormatContext **ic_ptr, +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0) + AVIOContext *pb, +#else + ByteIOContext *pb, +#endif + const char *filename, + AVInputFormat *fmt) +{ +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,1,3) + AVFormatContext *context = avformat_alloc_context(); + if (context == NULL) + return AVERROR(ENOMEM); + + context->pb = pb; + *ic_ptr = context; + return avformat_open_input(ic_ptr, filename, fmt, NULL); +#else + return av_open_input_stream(ic_ptr, pb, filename, fmt, NULL); +#endif +} + static void mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream) { @@ -322,8 +353,8 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) //ffmpeg works with ours "fileops" helper AVFormatContext *format_context = NULL; - if (av_open_input_stream(&format_context, stream->io, input->uri, - input_format, NULL) != 0) { + if (mpd_ffmpeg_open_input(&format_context, stream->io, input->uri, + input_format) != 0) { g_warning("Open failed\n"); mpd_ffmpeg_stream_close(stream); return; @@ -484,8 +515,8 @@ ffmpeg_stream_tag(struct input_stream *is) return NULL; AVFormatContext *f = NULL; - if (av_open_input_stream(&f, stream->io, is->uri, - input_format, NULL) != 0) { + if (mpd_ffmpeg_open_input(&f, stream->io, is->uri, + input_format) != 0) { mpd_ffmpeg_stream_close(stream); return NULL; }