diff --git a/src/output_all.c b/src/output_all.c index 5b7cc4908..29590abf0 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -495,6 +495,15 @@ audio_output_all_pause(void) audio_output_wait_all(); } +void +audio_output_all_drain(void) +{ + for (unsigned i = 0; i < num_audio_outputs; ++i) + audio_output_drain_async(&audio_outputs[i]); + + audio_output_wait_all(); +} + void audio_output_all_cancel(void) { diff --git a/src/output_all.h b/src/output_all.h index 91b6f3f5d..6ff45fb79 100644 --- a/src/output_all.h +++ b/src/output_all.h @@ -129,6 +129,12 @@ audio_output_all_wait(unsigned threshold); void audio_output_all_pause(void); +/** + * Drain all audio outputs. + */ +void +audio_output_all_drain(void); + /** * Try to cancel data which may still be in the device's buffers. */ diff --git a/src/output_control.c b/src/output_control.c index 842b89030..795d04a8c 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -229,6 +229,15 @@ void audio_output_pause(struct audio_output *ao) g_mutex_unlock(ao->mutex); } +void +audio_output_drain_async(struct audio_output *ao) +{ + g_mutex_lock(ao->mutex); + if (audio_output_is_open(ao)) + ao_command_async(ao, AO_COMMAND_DRAIN); + g_mutex_unlock(ao->mutex); +} + void audio_output_cancel(struct audio_output *ao) { g_mutex_lock(ao->mutex); diff --git a/src/output_control.h b/src/output_control.h index b2e48fa8d..692c11676 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -67,6 +67,9 @@ audio_output_play(struct audio_output *ao); void audio_output_pause(struct audio_output *ao); +void +audio_output_drain_async(struct audio_output *ao); + void audio_output_cancel(struct audio_output *ao); void audio_output_close(struct audio_output *ao); void audio_output_finish(struct audio_output *ao); diff --git a/src/output_internal.h b/src/output_internal.h index 6b81bbc78..de1b15c29 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -40,6 +40,13 @@ enum audio_output_command { AO_COMMAND_CLOSE, AO_COMMAND_PAUSE, + + /** + * Drains the internal (hardware) buffers of the device. This + * operation may take a while to complete. + */ + AO_COMMAND_DRAIN, + AO_COMMAND_CANCEL, AO_COMMAND_KILL }; diff --git a/src/output_thread.c b/src/output_thread.c index 40906d82f..fb1701591 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -450,6 +450,19 @@ static gpointer audio_output_task(gpointer arg) the new command first */ continue; + case AO_COMMAND_DRAIN: + if (ao->open) { + assert(ao->chunk == NULL); + assert(music_pipe_peek(ao->pipe) == NULL); + + g_mutex_unlock(ao->mutex); + ao_plugin_drain(ao->plugin, ao->data); + g_mutex_lock(ao->mutex); + } + + ao_command_finished(ao); + continue; + case AO_COMMAND_CANCEL: ao->chunk = NULL; if (ao->open)