Commit f95e404b authored by Max Kellermann's avatar Max Kellermann

outputThread: optimize Command::OPEN

Try harder to skip steps (reopen filter, reopen output) if the AudioOutput is already open.
parent ffb8b4fc
...@@ -172,6 +172,14 @@ struct AudioOutput { ...@@ -172,6 +172,14 @@ struct AudioOutput {
AudioFormat in_audio_format; AudioFormat in_audio_format;
/** /**
* The #AudioFormat which is emitted by the #Filter, with
* #config_audio_format already applied. This is used to
* decide whether this object needs to be closed and reopened
* upon #AudioFormat changes.
*/
AudioFormat filter_audio_format;
/**
* The audio_format which is really sent to the device. This * The audio_format which is really sent to the device. This
* is basically config_audio_format (if configured) or * is basically config_audio_format (if configured) or
* in_audio_format, but may have been modified by * in_audio_format, but may have been modified by
...@@ -446,15 +454,6 @@ private: ...@@ -446,15 +454,6 @@ private:
void Open(); void Open();
/** /**
* Open the #ChainFilter and call OpenOutputAndConvert().
*
* Caller must not lock the mutex.
*
* @return true on success
*/
bool OpenFilterAndOutput();
/**
* Invoke OutputPlugin::open() and configure the * Invoke OutputPlugin::open() and configure the
* #ConvertFilter. * #ConvertFilter.
* *
...@@ -465,7 +464,6 @@ private: ...@@ -465,7 +464,6 @@ private:
bool OpenOutputAndConvert(AudioFormat audio_format); bool OpenOutputAndConvert(AudioFormat audio_format);
void Close(bool drain); void Close(bool drain);
void Reopen();
/** /**
* Close the output plugin. * Close the output plugin.
...@@ -486,8 +484,6 @@ private: ...@@ -486,8 +484,6 @@ private:
*/ */
void CloseFilter(); void CloseFilter();
void ReopenFilter();
/** /**
* Wait until the output's delay reaches zero. * Wait until the output's delay reaches zero.
* *
......
...@@ -133,54 +133,61 @@ AudioOutput::CloseFilter() ...@@ -133,54 +133,61 @@ AudioOutput::CloseFilter()
inline void inline void
AudioOutput::Open() AudioOutput::Open()
{ {
assert(!open);
assert(request.audio_format.IsValid()); assert(request.audio_format.IsValid());
fail_timer.Reset(); fail_timer.Reset();
/* enable the device (just in case the last enable has failed) */ /* enable the device (just in case the last enable has failed) */
if (!Enable()) {
if (!Enable())
/* still no luck */ /* still no luck */
fail_timer.Update();
return; return;
}
in_audio_format = request.audio_format; if (!open || request.pipe != &pipe.GetPipe())
pipe.Init(*request.pipe); pipe.Init(*request.pipe);
bool success; /* (re)open the filter */
{ if (filter_instance != nullptr &&
const ScopeUnlock unlock(mutex); request.audio_format != in_audio_format)
success = OpenFilterAndOutput(); /* the filter must be reopened on all input format
} changes */
CloseFilter();
if (success)
open = true;
else
fail_timer.Update();
}
bool if (filter_instance == nullptr) {
AudioOutput::OpenFilterAndOutput() /* open the filter */
{ AudioFormat f;
AudioFormat filter_audio_format;
try { try {
filter_audio_format = OpenFilter(in_audio_format); f = OpenFilter(request.audio_format)
.WithMask(config_audio_format);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
FormatError(e, "Failed to open filter for \"%s\" [%s]", FormatError(e, "Failed to open filter for \"%s\" [%s]",
name, plugin.name); name, plugin.name);
return false; fail_timer.Update();
return;
} }
assert(filter_audio_format.IsValid()); if (open && f != filter_audio_format) {
/* if the filter's output format changes, the
outpuit must be reopened as well */
CloseOutput(true);
open = false;
}
const auto audio_format = filter_audio_format = f;
filter_audio_format.WithMask(config_audio_format); }
bool success = OpenOutputAndConvert(audio_format);
if (!success) in_audio_format = request.audio_format;
CloseFilter();
return success; if (!open) {
if (OpenOutputAndConvert(filter_audio_format)) {
open = true;
} else {
CloseFilter();
fail_timer.Update();
}
}
} }
bool bool
...@@ -263,41 +270,6 @@ AudioOutput::CloseOutput(bool drain) ...@@ -263,41 +270,6 @@ AudioOutput::CloseOutput(bool drain)
ao_plugin_close(this); ao_plugin_close(this);
} }
void
AudioOutput::ReopenFilter()
{
try {
const ScopeUnlock unlock(mutex);
CloseFilter();
OpenFilter(in_audio_format);
convert_filter_set(convert_filter.Get(), out_audio_format);
} catch (const std::runtime_error &e) {
FormatError(e,
"Failed to open filter for \"%s\" [%s]",
name, plugin.name);
Close(false);
}
}
void
AudioOutput::Reopen()
{
assert(open);
if ((request.audio_format != in_audio_format &&
!config_audio_format.IsFullyDefined()) ||
request.pipe != &pipe.GetPipe()) {
Close(true);
Open();
} else {
/* the audio format has changed, and all filters have
to be reconfigured */
in_audio_format = request.audio_format;
ReopenFilter();
}
}
/** /**
* Wait until the output's delay reaches zero. * Wait until the output's delay reaches zero.
* *
...@@ -578,9 +550,6 @@ AudioOutput::Task() ...@@ -578,9 +550,6 @@ AudioOutput::Task()
break; break;
case Command::OPEN: case Command::OPEN:
if (open)
Reopen();
else
Open(); Open();
CommandFinished(); CommandFinished();
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment