output/Internal: move the "open" flag to struct AudioOutputControl
This commit is contained in:
parent
5ed5d7fe60
commit
6e2b348758
@ -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();
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user