aboutsummaryrefslogtreecommitdiffstats
path: root/src/output
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2011-09-01 19:19:42 +0200
committerMax Kellermann <max@duempel.org>2011-09-01 19:19:42 +0200
commit6a3008d7ff787164124a43911145f7305c66aa7e (patch)
tree54090ac05037c9ba4c7536747462469744bb2531 /src/output
parent140162191388063e41e33b53d4533e07529df870 (diff)
parent2556449b361c00d9c66cf85beb64d7c6458763ed (diff)
downloadmpd-6a3008d7ff787164124a43911145f7305c66aa7e.tar.gz
mpd-6a3008d7ff787164124a43911145f7305c66aa7e.tar.xz
mpd-6a3008d7ff787164124a43911145f7305c66aa7e.zip
Merge branch 'v0.16.x'
Conflicts: configure.ac src/output_control.c
Diffstat (limited to '')
-rw-r--r--src/output/osx_plugin.c8
-rw-r--r--src/output/pulse_output_plugin.c62
-rw-r--r--src/output_all.c19
-rw-r--r--src/output_control.c30
-rw-r--r--src/output_control.h11
-rw-r--r--src/output_init.c1
-rw-r--r--src/output_internal.h9
-rw-r--r--src/output_thread.c8
8 files changed, 92 insertions, 56 deletions
diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c
index 618cd351f..8091660ab 100644
--- a/src/output/osx_plugin.c
+++ b/src/output/osx_plugin.c
@@ -121,12 +121,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);
@@ -169,8 +163,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;
diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c
index 9fb0b3ade..9825785ee 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/pulse_output_plugin.c
@@ -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.
*
* @return true on success, false on error
@@ -249,28 +287,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,
@@ -540,8 +563,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",
@@ -579,9 +601,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)
diff --git a/src/output_all.c b/src/output_all.c
index bd7c48c92..7f4694a8b 100644
--- a/src/output_all.c
+++ b/src/output_all.c
@@ -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.
*/
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
@@ -531,7 +518,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 22c63b822..7ddcb8b19 100644
--- a/src/output_control.c
+++ b/src/output_control.c
@@ -139,6 +139,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);
@@ -164,10 +166,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;
@@ -205,6 +203,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);
@@ -247,6 +246,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);
@@ -262,6 +263,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);
@@ -271,6 +273,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);
@@ -279,8 +282,24 @@ 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);
+}
+
+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);
}
@@ -310,6 +329,7 @@ void audio_output_finish(struct audio_output *ao)
assert(ao->fail_timer == NULL);
if (ao->thread != NULL) {
+ assert(ao->allow_play);
ao_lock_command(ao, AO_COMMAND_KILL);
g_thread_join(ao->thread);
ao->thread = NULL;
diff --git a/src/output_control.h b/src/output_control.h
index 8711a6566..f58a113e6 100644
--- a/src/output_control.h
+++ b/src/output_control.h
@@ -72,8 +72,19 @@ 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 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);
/**
diff --git a/src/output_init.c b/src/output_init.c
index 107abed41..c52dcc8cd 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -193,6 +193,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 873ec8532..eba3aed91 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -110,6 +110,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
* explicitly reopened with "play").
diff --git a/src/output_thread.c b/src/output_thread.c
index ec5fc5b31..c36ba5f4f 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -649,12 +649,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:
@@ -664,7 +658,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;