From 11626e48bfb1dbf265e7eba3777c77d5ab6bd72b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 26 Aug 2011 19:28:09 +0200 Subject: [PATCH 01/16] input/curl: implement a hard-coded timeout of 10 seconds Be sure to stop the operation at some point when the server isn't responding. --- NEWS | 1 + src/input/curl_input_plugin.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index b23c4a087..0bf08d0ab 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.16.4 (2011/??/??) * apply follow_inside_symlinks to absolute symlinks * input: - curl: limit the receive buffer size + - curl: implement a hard-coded timeout of 10 seconds * decoder: - ffmpeg: workaround for semantic API change in recent ffmpeg versions - flac: validate the sample rate when scanning the tag diff --git a/src/input/curl_input_plugin.c b/src/input/curl_input_plugin.c index d6424c2c6..2c4ac2ff8 100644 --- a/src/input/curl_input_plugin.c +++ b/src/input/curl_input_plugin.c @@ -680,6 +680,9 @@ input_curl_easy_init(struct input_curl *c, GError **error_r) curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5); curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true); curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error); + curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l); + curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l); + curl_easy_setopt(c->easy, CURLOPT_CONNECTTIMEOUT, 10l); if (proxy != NULL) curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy); From 87593f95d43e1e113d3ed55d2dc038e3f846cc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sun, 17 Jul 2011 21:09:52 +0200 Subject: [PATCH 02/16] scripts/makedist.sh: fix test usage Checkbashisms (part of the Debian devscripts) pionted this out. --- scripts/makedist.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/makedist.sh b/scripts/makedist.sh index d342cea3a..7f8624d8f 100755 --- a/scripts/makedist.sh +++ b/scripts/makedist.sh @@ -3,7 +3,7 @@ PWD=`pwd` ## If we're not in the scripts directory ## assume the base directory. -if test "`basename $PWD`" == "scripts"; then +if test "`basename $PWD`" = "scripts"; then cd ../ else MYOLDPWD=`pwd` @@ -18,7 +18,7 @@ fi make make dist -if test "`basename $PWD`" == "scripts"; then +if test "`basename $PWD`" = "scripts"; then cd contrib/ else cd $MYOLDPWD From 3d12d7de624c734112741bdbe55bcdf818df19ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Wed, 24 Aug 2011 22:41:31 +0200 Subject: [PATCH 03/16] doc/developer.xml: change the coing style example return type to int --- doc/developer.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer.xml b/doc/developer.xml index c63e2c265..010b85064 100644 --- a/doc/developer.xml +++ b/doc/developer.xml @@ -57,7 +57,7 @@ Some example code: - static inline bool + static inline int foo(const char *abc, int xyz) { if (abc == NULL) { From 042c1abc6e1b0023a9f2964573102a332e598237 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 31 Aug 2011 20:58:36 +0200 Subject: [PATCH 04/16] output/pulse: use _delete_context() Eliminate duplicate code. --- src/output/pulse_output_plugin.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index babb8e221..c09b6a6af 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -224,6 +224,20 @@ pulse_output_connect(struct pulse_output *po, GError **error_r) return true; } +/** + * Frees and clears the context. + */ +static void +pulse_output_delete_context(struct pulse_output *po) +{ + assert(po != NULL); + assert(po->context != NULL); + + pa_context_disconnect(po->context); + pa_context_unref(po->context); + po->context = NULL; +} + /** * Create, set up and connect a context. * @@ -249,28 +263,13 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r) pulse_output_subscribe_cb, po); if (!pulse_output_connect(po, error_r)) { - pa_context_unref(po->context); - po->context = NULL; + pulse_output_delete_context(po); return false; } return true; } -/** - * Frees and clears the context. - */ -static void -pulse_output_delete_context(struct pulse_output *po) -{ - assert(po != NULL); - assert(po->context != NULL); - - pa_context_disconnect(po->context); - pa_context_unref(po->context); - po->context = NULL; -} - static void * pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, const struct config_param *param, From e76c752987e0b943e0ee01d6e062e86befd9e8c5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 31 Aug 2011 21:00:55 +0200 Subject: [PATCH 05/16] output/pulse: add function _delete_stream() Merge common code. --- src/output/pulse_output_plugin.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index c09b6a6af..8fcf26992 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -224,6 +224,20 @@ pulse_output_connect(struct pulse_output *po, GError **error_r) return true; } +/** + * Frees and clears the stream. + */ +static void +pulse_output_delete_stream(struct pulse_output *po) +{ + assert(po != NULL); + assert(po->stream != NULL); + + pa_stream_disconnect(po->stream); + pa_stream_unref(po->stream); + po->stream = NULL; +} + /** * Frees and clears the context. */ @@ -539,8 +553,7 @@ pulse_output_open(void *data, struct audio_format *audio_format, error = pa_stream_connect_playback(po->stream, po->sink, NULL, 0, NULL, NULL); if (error < 0) { - pa_stream_unref(po->stream); - po->stream = NULL; + pulse_output_delete_stream(po); g_set_error(error_r, pulse_output_quark(), 0, "pa_stream_connect_playback() has failed: %s", @@ -578,9 +591,7 @@ pulse_output_close(void *data) pulse_wait_for_operation(po->mainloop, o); } - pa_stream_disconnect(po->stream); - pa_stream_unref(po->stream); - po->stream = NULL; + pulse_output_delete_stream(po); if (po->context != NULL && pa_context_get_state(po->context) != PA_CONTEXT_READY) From 60f7ff3de594ef6b54a61b6ad630819ce026c760 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 31 Aug 2011 20:55:49 +0200 Subject: [PATCH 06/16] output/pulse: reset callbacks before closing stream/context Fixes assertion failure when a stream callback is invoked too late after a format change. --- src/output/pulse_output_plugin.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index 8fcf26992..34d736546 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -233,6 +233,13 @@ pulse_output_delete_stream(struct pulse_output *po) assert(po != NULL); assert(po->stream != NULL); +#if PA_CHECK_VERSION(0,9,8) + pa_stream_set_suspended_callback(po->stream, NULL, NULL); +#endif + + pa_stream_set_state_callback(po->stream, NULL, NULL); + pa_stream_set_write_callback(po->stream, NULL, NULL); + pa_stream_disconnect(po->stream); pa_stream_unref(po->stream); po->stream = NULL; @@ -247,6 +254,9 @@ pulse_output_delete_context(struct pulse_output *po) assert(po != NULL); assert(po->context != NULL); + pa_context_set_state_callback(po->context, NULL, NULL); + pa_context_set_subscribe_callback(po->context, NULL, NULL); + pa_context_disconnect(po->context); pa_context_unref(po->context); po->context = NULL; From 8b0b4ff0860ea93850c2f44e72e8a8a5de05e13b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 07:13:21 +0200 Subject: [PATCH 07/16] output_thread: reimplement CANCEL synchronization The output thread could hang indefinitely after finishing CANCEL, because it could have missed the signal while the output was not unlocked in ao_command_finished(). This patch removes the wait() call after CANCEL, and adds the flag "allow_play" instead. While this flag is set, playback is skipped. With this flag, there will not be any excess wait() call after the pipe has been cleared. This patch fixes a bug that causes mpd to discontinue playback after seeking, due to the race condition described above. --- NEWS | 1 + src/output_all.c | 7 +++++-- src/output_control.c | 18 +++++++++++++----- src/output_control.h | 5 +++++ src/output_init.c | 1 + src/output_internal.h | 9 +++++++++ src/output_thread.c | 8 +------- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 0bf08d0ab..56a846582 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ ver 0.16.4 (2011/??/??) * fix memory leaks * don't resume playback when seeking to another song while paused * apply follow_inside_symlinks to absolute symlinks +* fix playback discontinuation after seeking * input: - curl: limit the receive buffer size - curl: implement a hard-coded timeout of 10 seconds diff --git a/src/output_all.c b/src/output_all.c index 19c0f0166..551736a41 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -206,15 +206,18 @@ static void audio_output_wait_all(void) } /** - * Signals the audio output if it is open. This function locks the - * mutex. + * Signal the audio output if it is open, and set the "allow_play" + * flag. This function locks the mutex. */ static void audio_output_lock_signal(struct audio_output *ao) { g_mutex_lock(ao->mutex); + + ao->allow_play = true; if (audio_output_is_open(ao)) g_cond_signal(ao->cond); + g_mutex_unlock(ao->mutex); } diff --git a/src/output_control.c b/src/output_control.c index 0823b667b..14976dbfb 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -115,6 +115,8 @@ audio_output_open(struct audio_output *ao, { bool open; + assert(ao != NULL); + assert(ao->allow_play); assert(audio_format_valid(audio_format)); assert(mp != NULL); @@ -140,10 +142,6 @@ 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); - - /* the audio output is now waiting for a - signal; wake it up immediately */ - g_cond_signal(ao->cond); } return true; @@ -181,6 +179,7 @@ static void audio_output_close_locked(struct audio_output *ao) { assert(ao != NULL); + assert(ao->allow_play); if (ao->mixer != NULL) mixer_auto_close(ao->mixer); @@ -223,6 +222,8 @@ audio_output_play(struct audio_output *ao) { g_mutex_lock(ao->mutex); + assert(ao->allow_play); + if (audio_output_is_open(ao)) g_cond_signal(ao->cond); @@ -238,6 +239,7 @@ void audio_output_pause(struct audio_output *ao) mixer_auto_close(ao->mixer); g_mutex_lock(ao->mutex); + assert(ao->allow_play); if (audio_output_is_open(ao)) ao_command_async(ao, AO_COMMAND_PAUSE); g_mutex_unlock(ao->mutex); @@ -247,6 +249,7 @@ void audio_output_drain_async(struct audio_output *ao) { g_mutex_lock(ao->mutex); + assert(ao->allow_play); if (audio_output_is_open(ao)) ao_command_async(ao, AO_COMMAND_DRAIN); g_mutex_unlock(ao->mutex); @@ -255,8 +258,12 @@ audio_output_drain_async(struct audio_output *ao) void audio_output_cancel(struct audio_output *ao) { g_mutex_lock(ao->mutex); - if (audio_output_is_open(ao)) + + if (audio_output_is_open(ao)) { + ao->allow_play = false; ao_command_async(ao, AO_COMMAND_CANCEL); + } + g_mutex_unlock(ao->mutex); } @@ -287,6 +294,7 @@ void audio_output_finish(struct audio_output *ao) if (ao->thread != NULL) { g_mutex_lock(ao->mutex); + assert(ao->allow_play); ao_command(ao, AO_COMMAND_KILL); g_mutex_unlock(ao->mutex); g_thread_join(ao->thread); diff --git a/src/output_control.h b/src/output_control.h index 7f4f4a53c..2b88d4103 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -70,6 +70,11 @@ void audio_output_pause(struct audio_output *ao); void audio_output_drain_async(struct audio_output *ao); +/** + * Clear the "allow_play" flag and send the "CANCEL" command + * asynchronously. To finish the operation, the caller has to set the + * "allow_play" flag and signal the thread. + */ void audio_output_cancel(struct audio_output *ao); void audio_output_close(struct audio_output *ao); diff --git a/src/output_init.c b/src/output_init.c index f4700dfb2..96f87f512 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -189,6 +189,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ao->really_enabled = false; ao->open = false; ao->pause = false; + ao->allow_play = true; ao->fail_timer = NULL; pcm_buffer_init(&ao->cross_fade_buffer); diff --git a/src/output_internal.h b/src/output_internal.h index 18d431352..7102ea5cd 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -109,6 +109,15 @@ struct audio_output { */ bool pause; + /** + * When this flag is set, the output thread will not do any + * playback. It will wait until the flag is cleared. + * + * This is used to synchronize the "clear" operation on the + * shared music pipe during the CANCEL command. + */ + bool allow_play; + /** * If not NULL, the device has failed, and this timer is used * to estimate how long it should stay disabled (unless diff --git a/src/output_thread.c b/src/output_thread.c index 2c2b8d116..bf56ca971 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -648,12 +648,6 @@ static gpointer audio_output_task(gpointer arg) } ao_command_finished(ao); - - /* the player thread will now clear our music - pipe - wait for a notify, to give it some - time */ - if (ao->command == AO_COMMAND_NONE) - g_cond_wait(ao->cond, ao->mutex); continue; case AO_COMMAND_KILL: @@ -663,7 +657,7 @@ static gpointer audio_output_task(gpointer arg) return NULL; } - if (ao->open && ao_play(ao)) + if (ao->open && ao->allow_play && ao_play(ao)) /* don't wait for an event if there are more chunks in the pipe */ continue; From 2be6184c8d274a5b99cc2c8c86a7aebe46187320 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 07:53:42 +0200 Subject: [PATCH 08/16] output_all: move _lock_signal() to output_control.c Better name, better documentation. --- src/output_all.c | 22 +++------------------- src/output_control.c | 12 ++++++++++++ src/output_control.h | 10 ++++++++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/output_all.c b/src/output_all.c index 551736a41..4e0b2eb22 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -205,30 +205,14 @@ static void audio_output_wait_all(void) notify_wait(&audio_output_client_notify); } -/** - * Signal the audio output if it is open, and set the "allow_play" - * flag. This function locks the mutex. - */ -static void -audio_output_lock_signal(struct audio_output *ao) -{ - g_mutex_lock(ao->mutex); - - ao->allow_play = true; - if (audio_output_is_open(ao)) - g_cond_signal(ao->cond); - - g_mutex_unlock(ao->mutex); -} - /** * Signals all audio outputs which are open. */ static void -audio_output_signal_all(void) +audio_output_allow_play_all(void) { for (unsigned i = 0; i < num_audio_outputs; ++i) - audio_output_lock_signal(&audio_outputs[i]); + audio_output_allow_play(&audio_outputs[i]); } static void @@ -533,7 +517,7 @@ audio_output_all_cancel(void) /* the audio outputs are now waiting for a signal, to synchronize the cleared music pipe */ - audio_output_signal_all(); + audio_output_allow_play_all(); /* invalidate elapsed_time */ diff --git a/src/output_control.c b/src/output_control.c index 14976dbfb..f8c5cd873 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -267,6 +267,18 @@ void audio_output_cancel(struct audio_output *ao) g_mutex_unlock(ao->mutex); } +void +audio_output_allow_play(struct audio_output *ao) +{ + g_mutex_lock(ao->mutex); + + ao->allow_play = true; + if (audio_output_is_open(ao)) + g_cond_signal(ao->cond); + + g_mutex_unlock(ao->mutex); +} + void audio_output_release(struct audio_output *ao) { diff --git a/src/output_control.h b/src/output_control.h index 2b88d4103..f0e317d6e 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -72,11 +72,17 @@ audio_output_drain_async(struct audio_output *ao); /** * Clear the "allow_play" flag and send the "CANCEL" command - * asynchronously. To finish the operation, the caller has to set the - * "allow_play" flag and signal the thread. + * asynchronously. To finish the operation, the caller has to call + * audio_output_allow_play(). */ void audio_output_cancel(struct audio_output *ao); +/** + * Set the "allow_play" and signal the thread. + */ +void +audio_output_allow_play(struct audio_output *ao); + void audio_output_close(struct audio_output *ao); /** From 53ac72a8783c54467f7462cf536d637e058da0fd Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 10:09:46 +0200 Subject: [PATCH 09/16] Makefile.am: use AVAHI_CFLAGS, AVAHI_LIBS Don't add those to MPD_CFLAGS / MPD_LIBS. --- Makefile.am | 2 ++ configure.ac | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 88eebe60f..b3620bdeb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,7 @@ noinst_LIBRARIES = src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS) src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \ + $(AVAHI_CFLAGS) \ $(LIBWRAP_CFLAGS) \ $(SQLITE_CFLAGS) \ $(ARCHIVE_CFLAGS) \ @@ -21,6 +22,7 @@ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \ $(FILTER_CFLAGS) \ $(OUTPUT_CFLAGS) src_mpd_LDADD = $(MPD_LIBS) \ + $(AVAHI_LIBS) \ $(LIBWRAP_LDFLAGS) \ $(SQLITE_LIBS) \ $(ARCHIVE_LIBS) \ diff --git a/configure.ac b/configure.ac index b362592cf..cf992eb9d 100644 --- a/configure.ac +++ b/configure.ac @@ -542,8 +542,7 @@ 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], - [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") + [enable_avahi=yes;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]) fi if test x$enable_avahi = xyes; then From e635d479129fe3a6ea4cff13b682be6cc97db81c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 10:07:58 +0200 Subject: [PATCH 10/16] configure.ac: use MPD_AUTO_PKG to detect avahi Don't abort the configure script when avahi could not be auto-detected. It previously did, because there was no custom "fail" action for PKG_CHECK_MODULES. --- NEWS | 1 + configure.ac | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 56a846582..e0c376ec9 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,5 @@ ver 0.16.4 (2011/??/??) +* don't abort configure when avahi is not found * fix memory leaks * don't resume playback when seeking to another song while paused * apply follow_inside_symlinks to absolute symlinks diff --git a/configure.ac b/configure.ac index cf992eb9d..4de63dac9 100644 --- a/configure.ac +++ b/configure.ac @@ -530,27 +530,31 @@ dnl --------------------------------------------------------------------------- dnl --------------------------------- zeroconf -------------------------------- case $with_zeroconf in -no|avahi|bonjour) +no|bonjour) + enable_avahi=no ;; + +avahi) + enable_avahi=yes + ;; + *) with_zeroconf=auto + enable_avahi=auto ;; esac -enable_avahi=no +MPD_AUTO_PKG(avahi, AVAHI, [avahi-client avahi-glib], + [avahi client library], [avahi client+glib not found]) +if test x$enable_avahi = xyes; then + AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support]) + with_zeroconf=avahi +fi + +AM_CONDITIONAL(HAVE_AVAHI, test x$enable_avahi = xyes) + 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], - [enable_avahi=yes;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]) - fi - - 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]) - fi - if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then AC_CHECK_HEADER(dns_sd.h, [enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])]) @@ -573,7 +577,6 @@ if test x$with_zeroconf != xno; then fi AM_CONDITIONAL(HAVE_ZEROCONF, test x$with_zeroconf != xno) -AM_CONDITIONAL(HAVE_AVAHI, test x$with_zeroconf = xavahi) AM_CONDITIONAL(HAVE_BONJOUR, test x$with_zeroconf = xbonjour) dnl --------------------------------------------------------------------------- From a1b880642244b9f732d327e1d93162652838bb06 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 09:18:16 +0200 Subject: [PATCH 11/16] configure.ac: fail if libid3tag was enabled explicitly, but not found Add M4 function MPD_AUTO_PKG_LIB for pkg-config with AC_CHECK_LIB fallback. --- configure.ac | 15 +++++---------- m4/mpd_auto.m4 | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 4de63dac9..74aef61de 100644 --- a/configure.ac +++ b/configure.ac @@ -196,9 +196,9 @@ AC_ARG_ENABLE(httpd-output, [enable_httpd_output=auto]) AC_ARG_ENABLE(id3, - AS_HELP_STRING([--disable-id3], - [disable id3 support (default: enable)]),, - enable_id3=yes) + AS_HELP_STRING([--enable-id3], + [disable id3 support]),, + enable_id3=auto) AC_ARG_ENABLE(inotify, AS_HELP_STRING([--disable-inotify], @@ -510,13 +510,8 @@ fi AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes) dnl -------------------------------- libid3tag -------------------------------- -if test x$enable_id3 = xyes; then - PKG_CHECK_MODULES([ID3TAG], [id3tag],, - AC_CHECK_LIB(id3tag, id3_file_open, - [ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""], - enable_id3=no)) -fi - +MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [], + [id3tag], [libid3tag not found]) if test x$enable_id3 = xyes; then AC_DEFINE(HAVE_ID3TAG, 1, [Define to use id3tag]) fi diff --git a/m4/mpd_auto.m4 b/m4/mpd_auto.m4 index 3f233938f..23713d5b7 100644 --- a/m4/mpd_auto.m4 +++ b/m4/mpd_auto.m4 @@ -63,3 +63,18 @@ AC_DEFUN([MPD_AUTO_PKG], [ MPD_AUTO_RESULT([$1], [$4], [$5]) ]) + +dnl Check with pkg-config first, fall back to AC_CHECK_LIB. +dnl +dnl Parameters: varname1, varname2, pkgname, libname, symname, libs, cflags, description, errmsg +AC_DEFUN([MPD_AUTO_PKG_LIB], [ + if eval "test x`echo '$'enable_$1` != xno"; then + PKG_CHECK_MODULES([$2], [$3], + [eval "found_$1=yes"], + AC_CHECK_LIB($4, $5, + [eval "found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'"], + [eval "found_$1=no"])) + fi + + MPD_AUTO_RESULT([$1], [$8], [$9]) +]) From 13cdc9a9f8944d124da3f6a25dfc93cd9f11997b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 09:22:18 +0200 Subject: [PATCH 12/16] configure.ac: auto-detect libmad without pkg-config The pkg-config file was added by the Debian package maintainers, and unfortunately, the rest of the world doesn't have it. --- NEWS | 1 + configure.ac | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e0c376ec9..9a6764d9b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.16.4 (2011/??/??) * don't abort configure when avahi is not found +* auto-detect libmad without pkg-config * fix memory leaks * don't resume playback when seeking to another song while paused * apply follow_inside_symlinks to absolute symlinks diff --git a/configure.ac b/configure.ac index 74aef61de..4d855a70b 100644 --- a/configure.ac +++ b/configure.ac @@ -799,7 +799,8 @@ if test x$enable_gme = xyes; then fi dnl ---------------------------------- libmad --------------------------------- -MPD_AUTO_PKG(mad, MAD, [mad], +MPD_AUTO_PKG_LIB(mad, MAD, [mad], + mad, mad_stream_init, [-lmad], [], [libmad MP3 decoder plugin], [libmad not found]) if test x$enable_mad = xyes; then AC_DEFINE(HAVE_MAD, 1, [Define to use libmad]) From e7abdab58dd566d9b80fb5caf5dee867f184d913 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 18:21:40 +0200 Subject: [PATCH 13/16] output/osx: signal the GCond while mutex is locked --- src/output/osx_plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c index ce82656bd..2c150fc41 100644 --- a/src/output/osx_plugin.c +++ b/src/output/osx_plugin.c @@ -143,8 +143,8 @@ osx_render(void *vdata, if (od->pos >= od->buffer_size) od->pos = 0; - g_mutex_unlock(od->mutex); g_cond_signal(od->condition); + g_mutex_unlock(od->mutex); buffer->mDataByteSize = buffer_size; From 596f36bb78425c8bd6aa4e9a81c796cb78b011c0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 18:13:05 +0200 Subject: [PATCH 14/16] output/osx: don't drain the buffer when closing Eliminate an unnecessary source of deadlocks. --- NEWS | 1 + src/output/osx_plugin.c | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 9a6764d9b..e580192f9 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ ver 0.16.4 (2011/??/??) * output: - alsa: fix SIGFPE when alsa announces a period size of 0 - httpd: don't warn on client disconnect + - osx: don't drain the buffer when closing - pulse: fix deadlock when resuming the stream - pulse: fix deadlock when the stream was suspended diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c index 2c150fc41..7639f3bd9 100644 --- a/src/output/osx_plugin.c +++ b/src/output/osx_plugin.c @@ -95,12 +95,6 @@ static void osx_output_close(void *data) { struct osx_output *od = data; - g_mutex_lock(od->mutex); - while (od->len) { - g_cond_wait(od->condition, od->mutex); - } - g_mutex_unlock(od->mutex); - AudioOutputUnitStop(od->au); AudioUnitUninitialize(od->au); CloseComponent(od->au); From 446f9973cc020490b649c3b40feae2fa9ca98c0d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 18:37:40 +0200 Subject: [PATCH 15/16] configure.ac: fail if FLAC was enabled explicitly, but not found --- configure.ac | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 4d855a70b..508775c09 100644 --- a/configure.ac +++ b/configure.ac @@ -171,9 +171,9 @@ AC_ARG_ENABLE(fifo, enable_fifo=yes) AC_ARG_ENABLE(flac, - AS_HELP_STRING([--disable-flac], - [disable flac support (default: enable)]),, - enable_flac=yes) + AS_HELP_STRING([--enable-flac], + [enable FLAC decoder]),, + enable_flac=auto) AC_ARG_ENABLE(fluidsynth, AS_HELP_STRING([--enable-fluidsynth], @@ -750,10 +750,12 @@ fi AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes) dnl ----------------------------------- FLAC ---------------------------------- + +MPD_AUTO_PKG(flac, FLAC, [flac >= 1.1], + [FLAC decoder], [libFLAC not found]) + if test x$enable_flac = xyes; then - PKG_CHECK_MODULES(FLAC, [flac >= 1.1], - AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support]), - enable_flac=no) + AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support]) oldcflags="$CFLAGS" oldlibs="$LIBS" From 2556449b361c00d9c66cf85beb64d7c6458763ed Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 1 Sep 2011 18:42:17 +0200 Subject: [PATCH 16/16] configure.ac: fail if Vorbis was enabled explicitly, but not found .. and a minor tweak for libFLAC+libogg detection. --- configure.ac | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 508775c09..502560110 100644 --- a/configure.ac +++ b/configure.ac @@ -353,9 +353,9 @@ AC_ARG_ENABLE(un, [enable_un=yes]) AC_ARG_ENABLE(vorbis, - AS_HELP_STRING([--disable-vorbis], - [disable Ogg Vorbis support (default: enable)]),, - enable_vorbis=yes) + AS_HELP_STRING([--enable-vorbis], + [enable Ogg Vorbis decoder]),, + enable_vorbis=auto) AC_ARG_ENABLE(vorbis-encoder, AS_HELP_STRING([--enable-vorbis-encoder], @@ -631,11 +631,6 @@ if test x$enable_lastfm = xyes; then fi AM_CONDITIONAL(ENABLE_LASTFM, test x$enable_lastfm = xyes) -dnl ---------------------------------- libogg --------------------------------- -if test x$with_tremor = xno || test -z $with_tremor; then - PKG_CHECK_MODULES(OGG, [ogg], enable_ogg=yes, enable_ogg=no) -fi - dnl ---------------------------------- libmms --------------------------------- MPD_AUTO_PKG(mms, MMS, [libmms >= 0.4], [libmms mms:// protocol support], [libmms not found]) @@ -770,12 +765,10 @@ if test x$enable_flac = xyes; then LIBS="$oldlibs" if test x$enable_oggflac = xflac; then - if test x$enable_ogg = xyes; then - FLAC_LIBS="${FLAC_LIBS} -logg" - else - enable_oggflac=yes - AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.") - fi + PKG_CHECK_MODULES(OGG, [ogg], + [FLAC_LIBS="${FLAC_LIBS} ${OGG_LIBS}" FLAC_CFLAGS="${FLAC_CFLAGS} ${OGG_CFLAGS}"], + [enable_oggflac=yes; + AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")]) fi fi @@ -943,7 +936,7 @@ fi if test x$enable_tremor = xyes; then AC_DEFINE(HAVE_TREMOR,1, [Define to use tremor (libvorbisidec) for ogg support]) - AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]), + AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]) else TREMOR_CFLAGS= TREMOR_LIBS= @@ -972,18 +965,18 @@ fi AM_CONDITIONAL(HAVE_OGGFLAC, test x$enable_oggflac = xyes) dnl -------------------------------- Ogg Vorbis ------------------------------- -if test x$enable_vorbis = xyes; then - if test x$enable_tremor = xyes; then + +if test x$enable_tremor = xyes; then + if test x$enable_vorbis = xyes; then AC_MSG_WARN(["OggTremor detected, could not enable Vorbis."]) - enable_vorbis=no - elif test x$enable_ogg = xyes; then - PKG_CHECK_MODULES(VORBIS, [vorbis vorbisfile], - AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]), - enable_vorbis=no) - else - AC_MSG_WARN(["Ogg not detected, could not enable Vorbis."]) - enable_vorbis=no fi + enable_vorbis=no +fi + +MPD_AUTO_PKG(vorbis, VORBIS, [vorbis vorbisfile ogg], + [Ogg Vorbis decoder], [libvorbis not found]) +if test x$enable_vorbis = xyes; then + AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]) fi AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes)