Commit 6a3008d7 authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.16.x'

Conflicts: configure.ac src/output_control.c
parents 14016219 2556449b
...@@ -11,6 +11,7 @@ noinst_LIBRARIES = ...@@ -11,6 +11,7 @@ noinst_LIBRARIES =
src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS) src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS)
src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
$(AVAHI_CFLAGS) \
$(LIBWRAP_CFLAGS) \ $(LIBWRAP_CFLAGS) \
$(SQLITE_CFLAGS) \ $(SQLITE_CFLAGS) \
$(ARCHIVE_CFLAGS) \ $(ARCHIVE_CFLAGS) \
...@@ -21,6 +22,7 @@ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \ ...@@ -21,6 +22,7 @@ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
$(FILTER_CFLAGS) \ $(FILTER_CFLAGS) \
$(OUTPUT_CFLAGS) $(OUTPUT_CFLAGS)
src_mpd_LDADD = $(MPD_LIBS) \ src_mpd_LDADD = $(MPD_LIBS) \
$(AVAHI_LIBS) \
$(LIBWRAP_LDFLAGS) \ $(LIBWRAP_LDFLAGS) \
$(SQLITE_LIBS) \ $(SQLITE_LIBS) \
$(ARCHIVE_LIBS) \ $(ARCHIVE_LIBS) \
......
...@@ -21,11 +21,15 @@ ver 0.17 (2011/??/??) ...@@ -21,11 +21,15 @@ ver 0.17 (2011/??/??)
ver 0.16.4 (2011/??/??) ver 0.16.4 (2011/??/??)
* don't abort configure when avahi is not found
* auto-detect libmad without pkg-config
* fix memory leaks * fix memory leaks
* don't resume playback when seeking to another song while paused * don't resume playback when seeking to another song while paused
* apply follow_inside_symlinks to absolute symlinks * apply follow_inside_symlinks to absolute symlinks
* fix playback discontinuation after seeking
* input: * input:
- curl: limit the receive buffer size - curl: limit the receive buffer size
- curl: implement a hard-coded timeout of 10 seconds
* decoder: * decoder:
- ffmpeg: workaround for semantic API change in recent ffmpeg versions - ffmpeg: workaround for semantic API change in recent ffmpeg versions
- flac: validate the sample rate when scanning the tag - flac: validate the sample rate when scanning the tag
...@@ -35,6 +39,7 @@ ver 0.16.4 (2011/??/??) ...@@ -35,6 +39,7 @@ ver 0.16.4 (2011/??/??)
* output: * output:
- alsa: fix SIGFPE when alsa announces a period size of 0 - alsa: fix SIGFPE when alsa announces a period size of 0
- httpd: don't warn on client disconnect - 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 resuming the stream
- pulse: fix deadlock when the stream was suspended - pulse: fix deadlock when the stream was suspended
......
...@@ -186,9 +186,9 @@ AC_ARG_ENABLE(fifo, ...@@ -186,9 +186,9 @@ AC_ARG_ENABLE(fifo,
enable_fifo=yes) enable_fifo=yes)
AC_ARG_ENABLE(flac, AC_ARG_ENABLE(flac,
AS_HELP_STRING([--disable-flac], AS_HELP_STRING([--enable-flac],
[disable flac support (default: enable)]),, [enable FLAC decoder]),,
enable_flac=yes) enable_flac=auto)
AC_ARG_ENABLE(fluidsynth, AC_ARG_ENABLE(fluidsynth,
AS_HELP_STRING([--enable-fluidsynth], AS_HELP_STRING([--enable-fluidsynth],
...@@ -216,9 +216,9 @@ AC_ARG_ENABLE(raop-output, ...@@ -216,9 +216,9 @@ AC_ARG_ENABLE(raop-output,
[enable_raop_output=auto]) [enable_raop_output=auto])
AC_ARG_ENABLE(id3, AC_ARG_ENABLE(id3,
AS_HELP_STRING([--disable-id3], AS_HELP_STRING([--enable-id3],
[disable id3 support (default: enable)]),, [disable id3 support]),,
enable_id3=yes) enable_id3=auto)
AC_ARG_ENABLE(inotify, AC_ARG_ENABLE(inotify,
AS_HELP_STRING([--disable-inotify], AS_HELP_STRING([--disable-inotify],
...@@ -378,9 +378,9 @@ AC_ARG_ENABLE(un, ...@@ -378,9 +378,9 @@ AC_ARG_ENABLE(un,
[enable_un=yes]) [enable_un=yes])
AC_ARG_ENABLE(vorbis, AC_ARG_ENABLE(vorbis,
AS_HELP_STRING([--disable-vorbis], AS_HELP_STRING([--enable-vorbis],
[disable Ogg Vorbis support (default: enable)]),, [enable Ogg Vorbis decoder]),,
enable_vorbis=yes) enable_vorbis=auto)
AC_ARG_ENABLE(vorbis-encoder, AC_ARG_ENABLE(vorbis-encoder,
AS_HELP_STRING([--enable-vorbis-encoder], AS_HELP_STRING([--enable-vorbis-encoder],
...@@ -535,13 +535,8 @@ fi ...@@ -535,13 +535,8 @@ fi
AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes) AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes)
dnl -------------------------------- libid3tag -------------------------------- dnl -------------------------------- libid3tag --------------------------------
if test x$enable_id3 = xyes; then MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [],
PKG_CHECK_MODULES([ID3TAG], [id3tag],, [id3tag], [libid3tag not found])
AC_CHECK_LIB(id3tag, id3_file_open,
[ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""],
enable_id3=no))
fi
if test x$enable_id3 = xyes; then if test x$enable_id3 = xyes; then
AC_DEFINE(HAVE_ID3TAG, 1, [Define to use id3tag]) AC_DEFINE(HAVE_ID3TAG, 1, [Define to use id3tag])
fi fi
...@@ -555,28 +550,31 @@ dnl --------------------------------------------------------------------------- ...@@ -555,28 +550,31 @@ dnl ---------------------------------------------------------------------------
dnl --------------------------------- zeroconf -------------------------------- dnl --------------------------------- zeroconf --------------------------------
case $with_zeroconf in case $with_zeroconf in
no|avahi|bonjour) no|bonjour)
enable_avahi=no
;; ;;
avahi)
enable_avahi=yes
;;
*) *)
with_zeroconf=auto with_zeroconf=auto
enable_avahi=auto
;; ;;
esac esac
enable_avahi=no MPD_AUTO_PKG(avahi, AVAHI, [avahi-client avahi-glib],
enable_bounjour=no [avahi client library], [avahi client+glib not found])
if test x$with_zeroconf != xno; then if test x$enable_avahi = xyes; then
if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])
PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib], with_zeroconf=avahi
[enable_avahi=yes;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])] fi
MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS")
fi
if test x$enable_avahi = xyes; then AM_CONDITIONAL(HAVE_AVAHI, test x$enable_avahi = xyes)
with_zeroconf=avahi
elif test x$with_zeroconf = xavahi; then
AC_MSG_ERROR([Avahi support requested but not found])
fi
enable_bounjour=no
if test x$with_zeroconf != xno; then
if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then
AC_CHECK_HEADER(dns_sd.h, AC_CHECK_HEADER(dns_sd.h,
[enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])]) [enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])])
...@@ -599,7 +597,6 @@ if test x$with_zeroconf != xno; then ...@@ -599,7 +597,6 @@ if test x$with_zeroconf != xno; then
fi fi
AM_CONDITIONAL(HAVE_ZEROCONF, test x$with_zeroconf != xno) 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) AM_CONDITIONAL(HAVE_BONJOUR, test x$with_zeroconf = xbonjour)
dnl --------------------------------------------------------------------------- dnl ---------------------------------------------------------------------------
...@@ -686,11 +683,6 @@ fi ...@@ -686,11 +683,6 @@ fi
AM_CONDITIONAL(ENABLE_CDIO_PARANOIA, test x$enable_cdio_paranoia = xyes) AM_CONDITIONAL(ENABLE_CDIO_PARANOIA, test x$enable_cdio_paranoia = 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 --------------------------------- dnl ---------------------------------- libmms ---------------------------------
MPD_AUTO_PKG(mms, MMS, [libmms >= 0.4], MPD_AUTO_PKG(mms, MMS, [libmms >= 0.4],
[libmms mms:// protocol support], [libmms not found]) [libmms mms:// protocol support], [libmms not found])
...@@ -794,10 +786,12 @@ fi ...@@ -794,10 +786,12 @@ fi
AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes) AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes)
dnl ----------------------------------- FLAC ---------------------------------- dnl ----------------------------------- FLAC ----------------------------------
MPD_AUTO_PKG(flac, FLAC, [flac >= 1.1],
[FLAC decoder], [libFLAC not found])
if test x$enable_flac = xyes; then if test x$enable_flac = xyes; then
PKG_CHECK_MODULES(FLAC, [flac >= 1.1], AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support])
AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support]),
enable_flac=no)
oldcflags="$CFLAGS" oldcflags="$CFLAGS"
oldlibs="$LIBS" oldlibs="$LIBS"
...@@ -812,12 +806,10 @@ if test x$enable_flac = xyes; then ...@@ -812,12 +806,10 @@ if test x$enable_flac = xyes; then
LIBS="$oldlibs" LIBS="$oldlibs"
if test x$enable_oggflac = xflac; then if test x$enable_oggflac = xflac; then
if test x$enable_ogg = xyes; then PKG_CHECK_MODULES(OGG, [ogg],
FLAC_LIBS="${FLAC_LIBS} -logg" [FLAC_LIBS="${FLAC_LIBS} ${OGG_LIBS}" FLAC_CFLAGS="${FLAC_CFLAGS} ${OGG_CFLAGS}"],
else [enable_oggflac=yes;
enable_oggflac=yes AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")])
AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")
fi
fi fi
fi fi
...@@ -843,7 +835,8 @@ if test x$enable_gme = xyes; then ...@@ -843,7 +835,8 @@ if test x$enable_gme = xyes; then
fi fi
dnl ---------------------------------- libmad --------------------------------- 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]) [libmad MP3 decoder plugin], [libmad not found])
if test x$enable_mad = xyes; then if test x$enable_mad = xyes; then
AC_DEFINE(HAVE_MAD, 1, [Define to use libmad]) AC_DEFINE(HAVE_MAD, 1, [Define to use libmad])
...@@ -984,7 +977,7 @@ fi ...@@ -984,7 +977,7 @@ fi
if test x$enable_tremor = xyes; then if test x$enable_tremor = xyes; then
AC_DEFINE(HAVE_TREMOR,1, AC_DEFINE(HAVE_TREMOR,1,
[Define to use tremor (libvorbisidec) for ogg support]) [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 else
TREMOR_CFLAGS= TREMOR_CFLAGS=
TREMOR_LIBS= TREMOR_LIBS=
...@@ -1013,18 +1006,18 @@ fi ...@@ -1013,18 +1006,18 @@ fi
AM_CONDITIONAL(HAVE_OGGFLAC, test x$enable_oggflac = xyes) AM_CONDITIONAL(HAVE_OGGFLAC, test x$enable_oggflac = xyes)
dnl -------------------------------- Ogg Vorbis ------------------------------- 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."]) 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 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 fi
AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes) AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes)
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
Some example code: Some example code:
</para> </para>
<programlisting lang="C">static inline bool <programlisting lang="C">static inline int
foo(const char *abc, int xyz) foo(const char *abc, int xyz)
{ {
if (abc == NULL) { if (abc == NULL) {
......
...@@ -63,3 +63,18 @@ AC_DEFUN([MPD_AUTO_PKG], [ ...@@ -63,3 +63,18 @@ AC_DEFUN([MPD_AUTO_PKG], [
MPD_AUTO_RESULT([$1], [$4], [$5]) 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])
])
...@@ -3,7 +3,7 @@ PWD=`pwd` ...@@ -3,7 +3,7 @@ PWD=`pwd`
## If we're not in the scripts directory ## If we're not in the scripts directory
## assume the base directory. ## assume the base directory.
if test "`basename $PWD`" == "scripts"; then if test "`basename $PWD`" = "scripts"; then
cd ../ cd ../
else else
MYOLDPWD=`pwd` MYOLDPWD=`pwd`
...@@ -18,7 +18,7 @@ fi ...@@ -18,7 +18,7 @@ fi
make make
make dist make dist
if test "`basename $PWD`" == "scripts"; then if test "`basename $PWD`" = "scripts"; then
cd contrib/ cd contrib/
else else
cd $MYOLDPWD cd $MYOLDPWD
......
...@@ -1124,6 +1124,9 @@ input_curl_easy_init(struct input_curl *c, GError **error_r) ...@@ -1124,6 +1124,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_MAXREDIRS, 5);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true); curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error); 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) if (proxy != NULL)
curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy); curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy);
......
...@@ -121,12 +121,6 @@ static void osx_output_close(void *data) ...@@ -121,12 +121,6 @@ static void osx_output_close(void *data)
{ {
struct osx_output *od = 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); AudioOutputUnitStop(od->au);
AudioUnitUninitialize(od->au); AudioUnitUninitialize(od->au);
CloseComponent(od->au); CloseComponent(od->au);
...@@ -169,8 +163,8 @@ osx_render(void *vdata, ...@@ -169,8 +163,8 @@ osx_render(void *vdata,
if (od->pos >= od->buffer_size) if (od->pos >= od->buffer_size)
od->pos = 0; od->pos = 0;
g_mutex_unlock(od->mutex);
g_cond_signal(od->condition); g_cond_signal(od->condition);
g_mutex_unlock(od->mutex);
buffer->mDataByteSize = buffer_size; buffer->mDataByteSize = buffer_size;
......
...@@ -225,6 +225,44 @@ pulse_output_connect(struct pulse_output *po, GError **error_r) ...@@ -225,6 +225,44 @@ pulse_output_connect(struct pulse_output *po, GError **error_r)
} }
/** /**
* Frees and clears the stream.
*/
static void
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;
}
/**
* Frees and clears the context.
*/
static void
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;
}
/**
* Create, set up and connect a context. * Create, set up and connect a context.
* *
* @return true on success, false on error * @return true on success, false on error
...@@ -249,28 +287,13 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r) ...@@ -249,28 +287,13 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r)
pulse_output_subscribe_cb, po); pulse_output_subscribe_cb, po);
if (!pulse_output_connect(po, error_r)) { if (!pulse_output_connect(po, error_r)) {
pa_context_unref(po->context); pulse_output_delete_context(po);
po->context = NULL;
return false; return false;
} }
return true; 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 * static void *
pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
const struct config_param *param, const struct config_param *param,
...@@ -540,8 +563,7 @@ pulse_output_open(void *data, struct audio_format *audio_format, ...@@ -540,8 +563,7 @@ pulse_output_open(void *data, struct audio_format *audio_format,
error = pa_stream_connect_playback(po->stream, po->sink, error = pa_stream_connect_playback(po->stream, po->sink,
NULL, 0, NULL, NULL); NULL, 0, NULL, NULL);
if (error < 0) { if (error < 0) {
pa_stream_unref(po->stream); pulse_output_delete_stream(po);
po->stream = NULL;
g_set_error(error_r, pulse_output_quark(), 0, g_set_error(error_r, pulse_output_quark(), 0,
"pa_stream_connect_playback() has failed: %s", "pa_stream_connect_playback() has failed: %s",
...@@ -579,9 +601,7 @@ pulse_output_close(void *data) ...@@ -579,9 +601,7 @@ pulse_output_close(void *data)
pulse_wait_for_operation(po->mainloop, o); pulse_wait_for_operation(po->mainloop, o);
} }
pa_stream_disconnect(po->stream); pulse_output_delete_stream(po);
pa_stream_unref(po->stream);
po->stream = NULL;
if (po->context != NULL && if (po->context != NULL &&
pa_context_get_state(po->context) != PA_CONTEXT_READY) pa_context_get_state(po->context) != PA_CONTEXT_READY)
......
...@@ -207,26 +207,13 @@ static void audio_output_wait_all(void) ...@@ -207,26 +207,13 @@ static void audio_output_wait_all(void)
} }
/** /**
* Signals the audio output if it is open. This function locks the
* mutex.
*/
static void
audio_output_lock_signal(struct audio_output *ao)
{
g_mutex_lock(ao->mutex);
if (audio_output_is_open(ao))
g_cond_signal(ao->cond);
g_mutex_unlock(ao->mutex);
}
/**
* Signals all audio outputs which are open. * Signals all audio outputs which are open.
*/ */
static void static void
audio_output_signal_all(void) audio_output_allow_play_all(void)
{ {
for (unsigned i = 0; i < num_audio_outputs; ++i) 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 static void
...@@ -531,7 +518,7 @@ audio_output_all_cancel(void) ...@@ -531,7 +518,7 @@ audio_output_all_cancel(void)
/* the audio outputs are now waiting for a signal, to /* the audio outputs are now waiting for a signal, to
synchronize the cleared music pipe */ synchronize the cleared music pipe */
audio_output_signal_all(); audio_output_allow_play_all();
/* invalidate elapsed_time */ /* invalidate elapsed_time */
......
...@@ -139,6 +139,8 @@ audio_output_open(struct audio_output *ao, ...@@ -139,6 +139,8 @@ audio_output_open(struct audio_output *ao,
{ {
bool open; bool open;
assert(ao != NULL);
assert(ao->allow_play);
assert(audio_format_valid(audio_format)); assert(audio_format_valid(audio_format));
assert(mp != NULL); assert(mp != NULL);
...@@ -164,10 +166,6 @@ audio_output_open(struct audio_output *ao, ...@@ -164,10 +166,6 @@ audio_output_open(struct audio_output *ao,
/* we're not using audio_output_cancel() here, /* we're not using audio_output_cancel() here,
because that function is asynchronous */ because that function is asynchronous */
ao_command(ao, AO_COMMAND_CANCEL); 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; return true;
...@@ -205,6 +203,7 @@ static void ...@@ -205,6 +203,7 @@ static void
audio_output_close_locked(struct audio_output *ao) audio_output_close_locked(struct audio_output *ao)
{ {
assert(ao != NULL); assert(ao != NULL);
assert(ao->allow_play);
if (ao->mixer != NULL) if (ao->mixer != NULL)
mixer_auto_close(ao->mixer); mixer_auto_close(ao->mixer);
...@@ -247,6 +246,8 @@ audio_output_play(struct audio_output *ao) ...@@ -247,6 +246,8 @@ audio_output_play(struct audio_output *ao)
{ {
g_mutex_lock(ao->mutex); g_mutex_lock(ao->mutex);
assert(ao->allow_play);
if (audio_output_is_open(ao)) if (audio_output_is_open(ao))
g_cond_signal(ao->cond); g_cond_signal(ao->cond);
...@@ -262,6 +263,7 @@ void audio_output_pause(struct audio_output *ao) ...@@ -262,6 +263,7 @@ void audio_output_pause(struct audio_output *ao)
mixer_auto_close(ao->mixer); mixer_auto_close(ao->mixer);
g_mutex_lock(ao->mutex); g_mutex_lock(ao->mutex);
assert(ao->allow_play);
if (audio_output_is_open(ao)) if (audio_output_is_open(ao))
ao_command_async(ao, AO_COMMAND_PAUSE); ao_command_async(ao, AO_COMMAND_PAUSE);
g_mutex_unlock(ao->mutex); g_mutex_unlock(ao->mutex);
...@@ -271,6 +273,7 @@ void ...@@ -271,6 +273,7 @@ void
audio_output_drain_async(struct audio_output *ao) audio_output_drain_async(struct audio_output *ao)
{ {
g_mutex_lock(ao->mutex); g_mutex_lock(ao->mutex);
assert(ao->allow_play);
if (audio_output_is_open(ao)) if (audio_output_is_open(ao))
ao_command_async(ao, AO_COMMAND_DRAIN); ao_command_async(ao, AO_COMMAND_DRAIN);
g_mutex_unlock(ao->mutex); g_mutex_unlock(ao->mutex);
...@@ -279,8 +282,24 @@ audio_output_drain_async(struct audio_output *ao) ...@@ -279,8 +282,24 @@ audio_output_drain_async(struct audio_output *ao)
void audio_output_cancel(struct audio_output *ao) void audio_output_cancel(struct audio_output *ao)
{ {
g_mutex_lock(ao->mutex); 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); ao_command_async(ao, AO_COMMAND_CANCEL);
}
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); g_mutex_unlock(ao->mutex);
} }
...@@ -310,6 +329,7 @@ void audio_output_finish(struct audio_output *ao) ...@@ -310,6 +329,7 @@ void audio_output_finish(struct audio_output *ao)
assert(ao->fail_timer == NULL); assert(ao->fail_timer == NULL);
if (ao->thread != NULL) { if (ao->thread != NULL) {
assert(ao->allow_play);
ao_lock_command(ao, AO_COMMAND_KILL); ao_lock_command(ao, AO_COMMAND_KILL);
g_thread_join(ao->thread); g_thread_join(ao->thread);
ao->thread = NULL; ao->thread = NULL;
......
...@@ -72,8 +72,19 @@ void audio_output_pause(struct audio_output *ao); ...@@ -72,8 +72,19 @@ void audio_output_pause(struct audio_output *ao);
void void
audio_output_drain_async(struct audio_output *ao); 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 call
* audio_output_allow_play().
*/
void audio_output_cancel(struct audio_output *ao); 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); void audio_output_close(struct audio_output *ao);
/** /**
......
...@@ -193,6 +193,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ...@@ -193,6 +193,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
ao->really_enabled = false; ao->really_enabled = false;
ao->open = false; ao->open = false;
ao->pause = false; ao->pause = false;
ao->allow_play = true;
ao->fail_timer = NULL; ao->fail_timer = NULL;
pcm_buffer_init(&ao->cross_fade_buffer); pcm_buffer_init(&ao->cross_fade_buffer);
......
...@@ -110,6 +110,15 @@ struct audio_output { ...@@ -110,6 +110,15 @@ struct audio_output {
bool pause; 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 * If not NULL, the device has failed, and this timer is used
* to estimate how long it should stay disabled (unless * to estimate how long it should stay disabled (unless
* explicitly reopened with "play"). * explicitly reopened with "play").
......
...@@ -649,12 +649,6 @@ static gpointer audio_output_task(gpointer arg) ...@@ -649,12 +649,6 @@ static gpointer audio_output_task(gpointer arg)
} }
ao_command_finished(ao); 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; continue;
case AO_COMMAND_KILL: case AO_COMMAND_KILL:
...@@ -664,7 +658,7 @@ static gpointer audio_output_task(gpointer arg) ...@@ -664,7 +658,7 @@ static gpointer audio_output_task(gpointer arg)
return NULL; 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 /* don't wait for an event if there are more
chunks in the pipe */ chunks in the pipe */
continue; continue;
......
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