Commit 1403172e authored by Max Kellermann's avatar Max Kellermann

output_plugin: added method "drain"

drain() is the opposite of cancel(): it waits until all data in the buffer has finished playing. Instead of implicitly draining in the close() method like the ALSA plugin has been doing it forever, let the output thread decide whether to drain or to cancel.
parent f74ee1a3
......@@ -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,
......
......@@ -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)
......
......@@ -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;
......
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