outputThread: optimize Command::OPEN
Try harder to skip steps (reopen filter, reopen output) if the AudioOutput is already open.
This commit is contained in:
@@ -171,6 +171,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
|
||||||
@@ -445,15 +453,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:
|
|||||||
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:
|
|||||||
*/
|
*/
|
||||||
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()
|
|||||||
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 */
|
||||||
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();
|
fail_timer.Update();
|
||||||
}
|
return;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(filter_audio_format.IsValid());
|
if (!open || request.pipe != &pipe.GetPipe())
|
||||||
|
pipe.Init(*request.pipe);
|
||||||
|
|
||||||
const auto audio_format =
|
/* (re)open the filter */
|
||||||
filter_audio_format.WithMask(config_audio_format);
|
|
||||||
bool success = OpenOutputAndConvert(audio_format);
|
if (filter_instance != nullptr &&
|
||||||
if (!success)
|
request.audio_format != in_audio_format)
|
||||||
|
/* the filter must be reopened on all input format
|
||||||
|
changes */
|
||||||
CloseFilter();
|
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
|
bool
|
||||||
@@ -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()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Command::OPEN:
|
case Command::OPEN:
|
||||||
if (open)
|
Open();
|
||||||
Reopen();
|
|
||||||
else
|
|
||||||
Open();
|
|
||||||
CommandFinished();
|
CommandFinished();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user