aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/output/alsa_plugin.c12
-rw-r--r--src/output_plugin.h12
-rw-r--r--src/output_thread.c24
3 files changed, 34 insertions, 14 deletions
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c
index 89ed6058e..870115998 100644
--- a/src/output/alsa_plugin.c
+++ b/src/output/alsa_plugin.c
@@ -496,6 +496,14 @@ alsa_recover(struct alsa_data *ad, int err)
}
static void
+alsa_drain(void *data)
+{
+ struct alsa_data *ad = data;
+
+ snd_pcm_drain(ad->pcm);
+}
+
+static void
alsa_cancel(void *data)
{
struct alsa_data *ad = data;
@@ -508,9 +516,6 @@ alsa_close(void *data)
{
struct alsa_data *ad = data;
- if (snd_pcm_state(ad->pcm) == SND_PCM_STATE_RUNNING)
- snd_pcm_drain(ad->pcm);
-
snd_pcm_close(ad->pcm);
}
@@ -542,6 +547,7 @@ const struct audio_output_plugin alsaPlugin = {
.finish = alsa_finish,
.open = alsa_open,
.play = alsa_play,
+ .drain = alsa_drain,
.cancel = alsa_cancel,
.close = alsa_close,
diff --git a/src/output_plugin.h b/src/output_plugin.h
index 3a9748d46..ee7f7c73d 100644
--- a/src/output_plugin.h
+++ b/src/output_plugin.h
@@ -117,6 +117,11 @@ struct audio_output_plugin {
GError **error);
/**
+ * Wait until the device has finished playing.
+ */
+ void (*drain)(void *data);
+
+ /**
* Try to cancel data which may still be in the device's
* buffers.
*/
@@ -214,6 +219,13 @@ ao_plugin_play(const struct audio_output_plugin *plugin,
}
static inline void
+ao_plugin_drain(const struct audio_output_plugin *plugin, void *data)
+{
+ if (plugin->drain != NULL)
+ plugin->drain(data);
+}
+
+static inline void
ao_plugin_cancel(const struct audio_output_plugin *plugin, void *data)
{
if (plugin->cancel != NULL)
diff --git a/src/output_thread.c b/src/output_thread.c
index f1af81a37..9d25d4758 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -62,13 +62,13 @@ ao_enable(struct audio_output *ao)
}
static void
-ao_close(struct audio_output *ao);
+ao_close(struct audio_output *ao, bool drain);
static void
ao_disable(struct audio_output *ao)
{
if (ao->open)
- ao_close(ao);
+ ao_close(ao, false);
if (ao->really_enabled) {
ao->really_enabled = false;
@@ -151,7 +151,7 @@ ao_open(struct audio_output *ao)
}
static void
-ao_close(struct audio_output *ao)
+ao_close(struct audio_output *ao, bool drain)
{
assert(ao->open);
@@ -162,6 +162,11 @@ ao_close(struct audio_output *ao)
ao->open = false;
g_mutex_unlock(ao->mutex);
+ if (drain)
+ ao_plugin_drain(ao->plugin, ao->data);
+ else
+ ao_plugin_cancel(ao->plugin, ao->data);
+
ao_plugin_close(ao->plugin, ao->data);
filter_close(ao->filter);
@@ -208,7 +213,7 @@ ao_reopen(struct audio_output *ao)
if (!audio_format_fully_defined(&ao->config_audio_format)) {
if (ao->open) {
const struct music_pipe *mp = ao->pipe;
- ao_close(ao);
+ ao_close(ao, true);
ao->pipe = mp;
}
@@ -253,8 +258,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
ao->name, ao->plugin->name, error->message);
g_error_free(error);
- ao_plugin_cancel(ao->plugin, ao->data);
- ao_close(ao);
+ ao_close(ao, false);
/* don't automatically reopen this device for 10
seconds */
@@ -273,8 +277,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
ao->name, ao->plugin->name, error->message);
g_error_free(error);
- ao_plugin_cancel(ao->plugin, ao->data);
- ao_close(ao);
+ ao_close(ao, false);
/* don't automatically reopen this device for
10 seconds */
@@ -344,7 +347,7 @@ static void ao_pause(struct audio_output *ao)
do {
ret = ao_plugin_pause(ao->plugin, ao->data);
if (!ret) {
- ao_close(ao);
+ ao_close(ao, false);
break;
}
} while (ao->command == AO_COMMAND_NONE);
@@ -385,8 +388,7 @@ static gpointer audio_output_task(gpointer arg)
assert(ao->open);
assert(ao->pipe != NULL);
- ao_plugin_cancel(ao->plugin, ao->data);
- ao_close(ao);
+ ao_close(ao, false);
ao_command_finished(ao);
break;