outputThread: optimize Command::OPEN

Try harder to skip steps (reopen filter, reopen output) if the
AudioOutput is already open.
This commit is contained in:
Max Kellermann 2016-12-24 14:05:11 +01:00
parent ffb8b4fc68
commit f95e404be1
2 changed files with 52 additions and 87 deletions

View File

@ -171,6 +171,14 @@ struct AudioOutput {
*/
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
* is basically config_audio_format (if configured) or
@ -445,15 +453,6 @@ private:
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
* #ConvertFilter.
@ -465,7 +464,6 @@ private:
bool OpenOutputAndConvert(AudioFormat audio_format);
void Close(bool drain);
void Reopen();
/**
* Close the output plugin.
@ -486,8 +484,6 @@ private:
*/
void CloseFilter();
void ReopenFilter();
/**
* Wait until the output's delay reaches zero.
*

View File

@ -133,54 +133,61 @@ AudioOutput::CloseFilter()
inline void
AudioOutput::Open()
{
assert(!open);
assert(request.audio_format.IsValid());
fail_timer.Reset();
/* enable the device (just in case the last enable has failed) */
if (!Enable())
if (!Enable()) {
/* still no luck */
return;
in_audio_format = request.audio_format;
pipe.Init(*request.pipe);
bool success;
{
const ScopeUnlock unlock(mutex);
success = OpenFilterAndOutput();
}
if (success)
open = true;
else
fail_timer.Update();
}
bool
AudioOutput::OpenFilterAndOutput()
{
AudioFormat filter_audio_format;
try {
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;
return;
}
assert(filter_audio_format.IsValid());
if (!open || request.pipe != &pipe.GetPipe())
pipe.Init(*request.pipe);
const auto audio_format =
filter_audio_format.WithMask(config_audio_format);
bool success = OpenOutputAndConvert(audio_format);
if (!success)
/* (re)open the filter */
if (filter_instance != nullptr &&
request.audio_format != in_audio_format)
/* the filter must be reopened on all input format
changes */
CloseFilter();
return success;
if (filter_instance == nullptr) {
/* open the filter */
AudioFormat f;
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;
}
if (open && f != filter_audio_format) {
/* if the filter's output format changes, the
outpuit must be reopened as well */
CloseOutput(true);
open = false;
}
filter_audio_format = f;
}
in_audio_format = request.audio_format;
if (!open) {
if (OpenOutputAndConvert(filter_audio_format)) {
open = true;
} else {
CloseFilter();
fail_timer.Update();
}
}
}
bool
@ -263,41 +270,6 @@ AudioOutput::CloseOutput(bool drain)
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.
*
@ -578,10 +550,7 @@ AudioOutput::Task()
break;
case Command::OPEN:
if (open)
Reopen();
else
Open();
Open();
CommandFinished();
break;