diff --git a/src/output/Control.cxx b/src/output/Control.cxx index 557b7946b..786e6e74d 100644 --- a/src/output/Control.cxx +++ b/src/output/Control.cxx @@ -85,12 +85,6 @@ AudioOutputControl::LockToggleEnabled() noexcept return enabled = !enabled; } -bool -AudioOutputControl::IsOpen() const noexcept -{ - return output->IsOpen(); -} - void AudioOutputControl::WaitForCommand() noexcept { @@ -180,7 +174,7 @@ AudioOutputControl::Open(const AudioFormat audio_format, fail_timer.Reset(); - if (output->open && audio_format == request.audio_format) { + if (open && audio_format == request.audio_format) { assert(request.pipe == &mp || (always_on && pause)); if (!pause) @@ -196,7 +190,7 @@ AudioOutputControl::Open(const AudioFormat audio_format, StartThread(); CommandWait(Command::OPEN); - const bool open2 = output->open; + const bool open2 = open; if (open2 && output->mixer != nullptr) { try { @@ -218,9 +212,9 @@ AudioOutputControl::CloseWait() noexcept if (output->mixer != nullptr) mixer_auto_close(output->mixer); - assert(!output->open || !fail_timer.IsDefined()); + assert(!open || !fail_timer.IsDefined()); - if (output->open) + if (open) CommandWait(Command::CLOSE); else fail_timer.Reset(); @@ -247,7 +241,7 @@ AudioOutputControl::LockUpdate(const AudioFormat audio_format, bool AudioOutputControl::IsChunkConsumed(const MusicChunk &chunk) const noexcept { - if (!output->open) + if (!open) return true; return source.IsChunkConsumed(chunk); @@ -332,7 +326,7 @@ AudioOutputControl::LockRelease() noexcept void AudioOutputControl::LockCloseWait() noexcept { - assert(!output->open || !fail_timer.IsDefined()); + assert(!open || !fail_timer.IsDefined()); const std::lock_guard protect(mutex); CloseWait(); diff --git a/src/output/Control.hxx b/src/output/Control.hxx index 54139f985..1c4cdb4d7 100644 --- a/src/output/Control.hxx +++ b/src/output/Control.hxx @@ -155,6 +155,16 @@ class AudioOutputControl { */ bool really_enabled = false; + /** + * Is the device (already) open and functional? + * + * This attribute may only be modified by the output thread. + * It is protected with #mutex: write accesses inside the + * output thread and read accesses outside of it may only be + * performed while the lock is held. + */ + bool open = false; + /** * Is the device paused? i.e. the output thread is in the * ao_pause() loop. @@ -202,6 +212,7 @@ public: assert(!fail_timer.IsDefined()); assert(!thread.IsDefined()); assert(output == nullptr); + assert(!open); } #endif @@ -240,8 +251,12 @@ public: */ bool LockToggleEnabled() noexcept; - gcc_pure - bool IsOpen() const noexcept; + /** + * Caller must lock the mutex. + */ + bool IsOpen() const noexcept { + return open; + } /** * Caller must lock the mutex. @@ -337,6 +352,11 @@ public: source.SetReplayGainMode(_mode); } + /** + * Throws #std::runtime_error on error. + */ + void InternalOpen2(AudioFormat in_audio_format); + /** * Caller must lock the mutex. */ diff --git a/src/output/Finish.cxx b/src/output/Finish.cxx index 8484b9c5d..ddde8653e 100644 --- a/src/output/Finish.cxx +++ b/src/output/Finish.cxx @@ -27,8 +27,6 @@ AudioOutput::~AudioOutput() { - assert(!open); - if (mixer != nullptr) mixer_free(mixer); @@ -40,7 +38,5 @@ AudioOutput::~AudioOutput() void audio_output_free(AudioOutput *ao) noexcept { - assert(!ao->IsOpen()); - ao_plugin_finish(ao); } diff --git a/src/output/Internal.hxx b/src/output/Internal.hxx index 31221cbcf..f39355192 100644 --- a/src/output/Internal.hxx +++ b/src/output/Internal.hxx @@ -52,16 +52,6 @@ struct AudioOutput { */ Mixer *mixer = nullptr; - /** - * Is the device (already) open and functional? - * - * This attribute may only be modified by the output thread. - * It is protected with #mutex: write accesses inside the - * output thread and read accesses outside of it may only be - * performed while the lock is held. - */ - bool open = false; - /** * The configured audio format. */ @@ -145,13 +135,6 @@ public: return name; } - /** - * Caller must lock the mutex. - */ - bool IsOpen() const { - return open; - } - /** * Throws #std::runtime_error on error. */ @@ -159,14 +142,8 @@ public: void Disable() noexcept; - /** - * Throws #std::runtime_error on error. - */ - void Open(AudioFormat in_audio_format); - void Close(bool drain) noexcept; -private: /** * Invoke OutputPlugin::open() and configure the * #ConvertFilter. @@ -189,7 +166,6 @@ private: */ void CloseFilter() noexcept; -public: void BeginPause() noexcept; bool IteratePause() noexcept; diff --git a/src/output/Thread.cxx b/src/output/Thread.cxx index 1509d3afa..01d13f0e6 100644 --- a/src/output/Thread.cxx +++ b/src/output/Thread.cxx @@ -84,44 +84,47 @@ AudioOutput::CloseFilter() noexcept } inline void -AudioOutput::Open(const AudioFormat in_audio_format) +AudioOutputControl::InternalOpen2(const AudioFormat in_audio_format) { assert(in_audio_format.IsValid()); - if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin)) - software_mixer_set_filter(*mixer, volume_filter.Get()); + if (output->mixer != nullptr && + output->mixer->IsPlugin(software_mixer_plugin)) + software_mixer_set_filter(*output->mixer, + output->volume_filter.Get()); - const auto cf = in_audio_format.WithMask(config_audio_format); + const auto cf = in_audio_format.WithMask(output->config_audio_format); - if (open && cf != filter_audio_format) { + if (open && cf != output->filter_audio_format) { /* if the filter's output format changes, the output must be reopened as well */ - CloseOutput(true); + output->CloseOutput(true); open = false; } - filter_audio_format = cf; + output->filter_audio_format = cf; if (!open) { try { - OpenOutputAndConvert(filter_audio_format); + output->OpenOutputAndConvert(output->filter_audio_format); } catch (...) { - CloseFilter(); + output->CloseFilter(); throw; } open = true; - } else if (in_audio_format != out_audio_format) { + } else if (in_audio_format != output->out_audio_format) { /* reconfigure the final ConvertFilter for its new input AudioFormat */ try { - convert_filter_set(convert_filter.Get(), - out_audio_format); + convert_filter_set(output->convert_filter.Get(), + output->out_audio_format); } catch (const std::runtime_error &e) { - Close(false); + open = false; + output->Close(false); std::throw_with_nested(FormatRuntimeError("Failed to convert for \"%s\" [%s]", - name, plugin.name)); + GetName(), output->plugin.name)); } } } @@ -227,7 +230,7 @@ AudioOutputControl::InternalOpen(const AudioFormat in_audio_format, } try { - output->Open(f); + InternalOpen2(f); } catch (...) { source.Close(); throw; @@ -251,6 +254,7 @@ AudioOutputControl::InternalClose(bool drain) noexcept if (!IsOpen()) return; + open = false; output->Close(drain); source.Close(); } @@ -258,10 +262,6 @@ AudioOutputControl::InternalClose(bool drain) noexcept void AudioOutput::Close(bool drain) noexcept { - assert(open); - - open = false; - const ScopeUnlock unlock(mutex); CloseOutput(drain); @@ -438,9 +438,6 @@ AudioOutput::IteratePause() noexcept success = false; } - if (!success) - Close(false); - return success; } @@ -457,6 +454,8 @@ AudioOutputControl::InternalPause() noexcept break; if (!output->IteratePause()) { + open = false; + output->Close(false); source.Close(); break; } @@ -510,7 +509,7 @@ AudioOutputControl::Task() break; case Command::PAUSE: - if (!output->open) { + if (!open) { /* the output has failed after audio_output_all_pause() has submitted the PAUSE command; bail @@ -527,7 +526,7 @@ AudioOutputControl::Task() continue; case Command::DRAIN: - if (output->open) { + if (open) { const ScopeUnlock unlock(mutex); ao_plugin_drain(*output); } @@ -538,7 +537,7 @@ AudioOutputControl::Task() case Command::CANCEL: source.Cancel(); - if (output->open) { + if (open) { const ScopeUnlock unlock(mutex); ao_plugin_cancel(*output); } @@ -553,7 +552,7 @@ AudioOutputControl::Task() return; } - if (output->open && allow_play && InternalPlay()) + if (open && allow_play && InternalPlay()) /* don't wait for an event if there are more chunks in the pipe */ continue;