diff options
-rw-r--r-- | src/output/alsa_plugin.c | 12 | ||||
-rw-r--r-- | src/output_plugin.h | 12 | ||||
-rw-r--r-- | src/output_thread.c | 24 |
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; |