output/Internal: move the "open" flag to struct AudioOutputControl

This commit is contained in:
Max Kellermann 2017-06-08 22:25:45 +02:00
parent 5ed5d7fe60
commit 6e2b348758
5 changed files with 53 additions and 68 deletions

View File

@ -85,12 +85,6 @@ AudioOutputControl::LockToggleEnabled() noexcept
return enabled = !enabled; return enabled = !enabled;
} }
bool
AudioOutputControl::IsOpen() const noexcept
{
return output->IsOpen();
}
void void
AudioOutputControl::WaitForCommand() noexcept AudioOutputControl::WaitForCommand() noexcept
{ {
@ -180,7 +174,7 @@ AudioOutputControl::Open(const AudioFormat audio_format,
fail_timer.Reset(); 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)); assert(request.pipe == &mp || (always_on && pause));
if (!pause) if (!pause)
@ -196,7 +190,7 @@ AudioOutputControl::Open(const AudioFormat audio_format,
StartThread(); StartThread();
CommandWait(Command::OPEN); CommandWait(Command::OPEN);
const bool open2 = output->open; const bool open2 = open;
if (open2 && output->mixer != nullptr) { if (open2 && output->mixer != nullptr) {
try { try {
@ -218,9 +212,9 @@ AudioOutputControl::CloseWait() noexcept
if (output->mixer != nullptr) if (output->mixer != nullptr)
mixer_auto_close(output->mixer); mixer_auto_close(output->mixer);
assert(!output->open || !fail_timer.IsDefined()); assert(!open || !fail_timer.IsDefined());
if (output->open) if (open)
CommandWait(Command::CLOSE); CommandWait(Command::CLOSE);
else else
fail_timer.Reset(); fail_timer.Reset();
@ -247,7 +241,7 @@ AudioOutputControl::LockUpdate(const AudioFormat audio_format,
bool bool
AudioOutputControl::IsChunkConsumed(const MusicChunk &chunk) const noexcept AudioOutputControl::IsChunkConsumed(const MusicChunk &chunk) const noexcept
{ {
if (!output->open) if (!open)
return true; return true;
return source.IsChunkConsumed(chunk); return source.IsChunkConsumed(chunk);
@ -332,7 +326,7 @@ AudioOutputControl::LockRelease() noexcept
void void
AudioOutputControl::LockCloseWait() noexcept AudioOutputControl::LockCloseWait() noexcept
{ {
assert(!output->open || !fail_timer.IsDefined()); assert(!open || !fail_timer.IsDefined());
const std::lock_guard<Mutex> protect(mutex); const std::lock_guard<Mutex> protect(mutex);
CloseWait(); CloseWait();

View File

@ -155,6 +155,16 @@ class AudioOutputControl {
*/ */
bool really_enabled = false; 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 * Is the device paused? i.e. the output thread is in the
* ao_pause() loop. * ao_pause() loop.
@ -202,6 +212,7 @@ public:
assert(!fail_timer.IsDefined()); assert(!fail_timer.IsDefined());
assert(!thread.IsDefined()); assert(!thread.IsDefined());
assert(output == nullptr); assert(output == nullptr);
assert(!open);
} }
#endif #endif
@ -240,8 +251,12 @@ public:
*/ */
bool LockToggleEnabled() noexcept; 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. * Caller must lock the mutex.
@ -337,6 +352,11 @@ public:
source.SetReplayGainMode(_mode); source.SetReplayGainMode(_mode);
} }
/**
* Throws #std::runtime_error on error.
*/
void InternalOpen2(AudioFormat in_audio_format);
/** /**
* Caller must lock the mutex. * Caller must lock the mutex.
*/ */

View File

@ -27,8 +27,6 @@
AudioOutput::~AudioOutput() AudioOutput::~AudioOutput()
{ {
assert(!open);
if (mixer != nullptr) if (mixer != nullptr)
mixer_free(mixer); mixer_free(mixer);
@ -40,7 +38,5 @@ AudioOutput::~AudioOutput()
void void
audio_output_free(AudioOutput *ao) noexcept audio_output_free(AudioOutput *ao) noexcept
{ {
assert(!ao->IsOpen());
ao_plugin_finish(ao); ao_plugin_finish(ao);
} }

View File

@ -52,16 +52,6 @@ struct AudioOutput {
*/ */
Mixer *mixer = nullptr; 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. * The configured audio format.
*/ */
@ -145,13 +135,6 @@ public:
return name; return name;
} }
/**
* Caller must lock the mutex.
*/
bool IsOpen() const {
return open;
}
/** /**
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
@ -159,14 +142,8 @@ public:
void Disable() noexcept; void Disable() noexcept;
/**
* Throws #std::runtime_error on error.
*/
void Open(AudioFormat in_audio_format);
void Close(bool drain) noexcept; void Close(bool drain) noexcept;
private:
/** /**
* Invoke OutputPlugin::open() and configure the * Invoke OutputPlugin::open() and configure the
* #ConvertFilter. * #ConvertFilter.
@ -189,7 +166,6 @@ private:
*/ */
void CloseFilter() noexcept; void CloseFilter() noexcept;
public:
void BeginPause() noexcept; void BeginPause() noexcept;
bool IteratePause() noexcept; bool IteratePause() noexcept;

View File

@ -84,44 +84,47 @@ AudioOutput::CloseFilter() noexcept
} }
inline void inline void
AudioOutput::Open(const AudioFormat in_audio_format) AudioOutputControl::InternalOpen2(const AudioFormat in_audio_format)
{ {
assert(in_audio_format.IsValid()); assert(in_audio_format.IsValid());
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin)) if (output->mixer != nullptr &&
software_mixer_set_filter(*mixer, volume_filter.Get()); 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 /* if the filter's output format changes, the output
must be reopened as well */ must be reopened as well */
CloseOutput(true); output->CloseOutput(true);
open = false; open = false;
} }
filter_audio_format = cf; output->filter_audio_format = cf;
if (!open) { if (!open) {
try { try {
OpenOutputAndConvert(filter_audio_format); output->OpenOutputAndConvert(output->filter_audio_format);
} catch (...) { } catch (...) {
CloseFilter(); output->CloseFilter();
throw; throw;
} }
open = true; 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 /* reconfigure the final ConvertFilter for its new
input AudioFormat */ input AudioFormat */
try { try {
convert_filter_set(convert_filter.Get(), convert_filter_set(output->convert_filter.Get(),
out_audio_format); output->out_audio_format);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
Close(false); open = false;
output->Close(false);
std::throw_with_nested(FormatRuntimeError("Failed to convert for \"%s\" [%s]", 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 { try {
output->Open(f); InternalOpen2(f);
} catch (...) { } catch (...) {
source.Close(); source.Close();
throw; throw;
@ -251,6 +254,7 @@ AudioOutputControl::InternalClose(bool drain) noexcept
if (!IsOpen()) if (!IsOpen())
return; return;
open = false;
output->Close(drain); output->Close(drain);
source.Close(); source.Close();
} }
@ -258,10 +262,6 @@ AudioOutputControl::InternalClose(bool drain) noexcept
void void
AudioOutput::Close(bool drain) noexcept AudioOutput::Close(bool drain) noexcept
{ {
assert(open);
open = false;
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
CloseOutput(drain); CloseOutput(drain);
@ -438,9 +438,6 @@ AudioOutput::IteratePause() noexcept
success = false; success = false;
} }
if (!success)
Close(false);
return success; return success;
} }
@ -457,6 +454,8 @@ AudioOutputControl::InternalPause() noexcept
break; break;
if (!output->IteratePause()) { if (!output->IteratePause()) {
open = false;
output->Close(false);
source.Close(); source.Close();
break; break;
} }
@ -510,7 +509,7 @@ AudioOutputControl::Task()
break; break;
case Command::PAUSE: case Command::PAUSE:
if (!output->open) { if (!open) {
/* the output has failed after /* the output has failed after
audio_output_all_pause() has audio_output_all_pause() has
submitted the PAUSE command; bail submitted the PAUSE command; bail
@ -527,7 +526,7 @@ AudioOutputControl::Task()
continue; continue;
case Command::DRAIN: case Command::DRAIN:
if (output->open) { if (open) {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
ao_plugin_drain(*output); ao_plugin_drain(*output);
} }
@ -538,7 +537,7 @@ AudioOutputControl::Task()
case Command::CANCEL: case Command::CANCEL:
source.Cancel(); source.Cancel();
if (output->open) { if (open) {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
ao_plugin_cancel(*output); ao_plugin_cancel(*output);
} }
@ -553,7 +552,7 @@ AudioOutputControl::Task()
return; return;
} }
if (output->open && allow_play && InternalPlay()) if (open && allow_play && InternalPlay())
/* don't wait for an event if there are more /* don't wait for an event if there are more
chunks in the pipe */ chunks in the pipe */
continue; continue;