From f8f95e2dbd73d0d43211136e50a8d640f145872c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 6 Nov 2013 23:47:30 +0100 Subject: OutputControl: reduce the number of OutputThread wakeups Wake up the OutputThread only if it hasn't already been woken up and if it isn't already in the playback loop. --- src/OutputControl.cxx | 5 ++++- src/OutputInit.cxx | 2 ++ src/OutputInternal.hxx | 15 +++++++++++++++ src/OutputThread.cxx | 10 +++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/OutputControl.cxx b/src/OutputControl.cxx index 648705908..553507a2a 100644 --- a/src/OutputControl.cxx +++ b/src/OutputControl.cxx @@ -248,8 +248,11 @@ audio_output_play(struct audio_output *ao) assert(ao->allow_play); - if (audio_output_is_open(ao)) + if (audio_output_is_open(ao) && !ao->in_playback_loop && + !ao->woken_for_play) { + ao->woken_for_play = true; ao->cond.signal(); + } } void audio_output_pause(struct audio_output *ao) diff --git a/src/OutputInit.cxx b/src/OutputInit.cxx index 49b5d68b9..28eba1ab2 100644 --- a/src/OutputInit.cxx +++ b/src/OutputInit.cxx @@ -171,6 +171,8 @@ ao_base_init(struct audio_output *ao, ao->open = false; ao->pause = false; ao->allow_play = true; + ao->in_playback_loop = false; + ao->woken_for_play = false; ao->fail_timer = nullptr; /* set up the filter chain */ diff --git a/src/OutputInternal.hxx b/src/OutputInternal.hxx index 2b3136f94..c07cdf856 100644 --- a/src/OutputInternal.hxx +++ b/src/OutputInternal.hxx @@ -127,6 +127,21 @@ struct audio_output { */ bool allow_play; + /** + * True while the OutputThread is inside ao_play(). This + * means the PlayerThread does not need to wake up the + * OutputThread when new chunks are added to the MusicPipe, + * because the OutputThread is already watching that. + */ + bool in_playback_loop; + + /** + * Has the OutputThread been woken up to play more chunks? + * This is set by audio_output_play() and reset by ao_play() + * to reduce the number of duplicate wakeups. + */ + bool woken_for_play; + /** * If not nullptr, the device has failed, and this timer is used * to estimate how long it should stay disabled (unless diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx index c6f2e4d30..30d3ba30f 100644 --- a/src/OutputThread.cxx +++ b/src/OutputThread.cxx @@ -510,6 +510,9 @@ ao_play(struct audio_output *ao) ao->chunk_finished = false; + assert(!ao->in_playback_loop); + ao->in_playback_loop = true; + while (chunk != nullptr && ao->command == AO_COMMAND_NONE) { assert(!ao->chunk_finished); @@ -525,6 +528,9 @@ ao_play(struct audio_output *ao) chunk = chunk->next; } + assert(ao->in_playback_loop); + ao->in_playback_loop = false; + ao->chunk_finished = true; ao->mutex.unlock(); @@ -656,8 +662,10 @@ audio_output_task(void *arg) chunks in the pipe */ continue; - if (ao->command == AO_COMMAND_NONE) + if (ao->command == AO_COMMAND_NONE) { + ao->woken_for_play = false; ao->cond.wait(ao->mutex); + } } } -- cgit v1.2.3