diff --git a/src/output/Control.cxx b/src/output/Control.cxx index 81847a1de..39812b165 100644 --- a/src/output/Control.cxx +++ b/src/output/Control.cxx @@ -347,10 +347,22 @@ AudioOutputControl::LockAllowPlay() noexcept void AudioOutputControl::LockRelease() noexcept { - if (always_on) - LockPauseAsync(); + if (output->mixer != nullptr && + (!always_on || !output->SupportsPause())) + /* the device has no pause mode: close the mixer, + unless its "global" flag is set (checked by + mixer_auto_close()) */ + mixer_auto_close(output->mixer); + + const std::lock_guard protect(mutex); + + assert(!open || !fail_timer.IsDefined()); + assert(allow_play); + + if (IsOpen()) + CommandWait(Command::RELEASE); else - LockCloseWait(); + fail_timer.Reset(); } void diff --git a/src/output/Control.hxx b/src/output/Control.hxx index 58924edd5..3a961c57c 100644 --- a/src/output/Control.hxx +++ b/src/output/Control.hxx @@ -131,6 +131,12 @@ class AudioOutputControl { CLOSE, PAUSE, + /** + * Close or pause the device, depending on the + * #always_on setting. + */ + RELEASE, + /** * Drains the internal (hardware) buffers of the device. This * operation may take a while to complete. diff --git a/src/output/Thread.cxx b/src/output/Thread.cxx index 4211cd078..b88eecbad 100644 --- a/src/output/Thread.cxx +++ b/src/output/Thread.cxx @@ -456,6 +456,30 @@ AudioOutputControl::Task() noexcept the new command first */ continue; + case Command::RELEASE: + if (!open) { + /* the output has failed after + the PAUSE command was submitted; bail + out */ + CommandFinished(); + break; + } + + if (always_on) { + /* in "always_on" mode, the output is + paused instead of being closed */ + InternalPause(); + } else { + InternalClose(false); + CommandFinished(); + } + + /* don't "break" here: this might cause + Play() to be called when command==CLOSE + ends the paused state - "continue" checks + the new command first */ + continue; + case Command::DRAIN: if (open) InternalDrain();