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) if (filter_instance == nullptr) {
open = true; /* open the filter */
else AudioFormat f;
fail_timer.Update(); try {
} f = OpenFilter(request.audio_format)
.WithMask(config_audio_format);
} catch (const std::runtime_error &e) {
FormatError(e, "Failed to open filter for \"%s\" [%s]",
name, plugin.name);
fail_timer.Update();
return;
}
bool if (open && f != filter_audio_format) {
AudioOutput::OpenFilterAndOutput() /* if the filter's output format changes, the
{ outpuit must be reopened as well */
AudioFormat filter_audio_format; CloseOutput(true);
try { open = false;
filter_audio_format = OpenFilter(in_audio_format); }
} catch (const std::runtime_error &e) {
FormatError(e, "Failed to open filter for \"%s\" [%s]",
name, plugin.name);
return false;
}
assert(filter_audio_format.IsValid()); filter_audio_format = f;
}
const auto audio_format = in_audio_format = request.audio_format;
filter_audio_format.WithMask(config_audio_format);
bool success = OpenOutputAndConvert(audio_format);
if (!success)
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,10 +550,7 @@ AudioOutput::Task() ...@@ -578,10 +550,7 @@ AudioOutput::Task()
break; break;
case Command::OPEN: case Command::OPEN:
if (open) Open();
Reopen();
else
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