filter/FilterInternal: split class Filter, add class PreparedFilter

For easier state management inside filter plugins.
This commit is contained in:
Max Kellermann
2016-06-22 11:15:49 +02:00
parent 5c75096bcd
commit 3a21241248
26 changed files with 615 additions and 388 deletions

View File

@@ -34,9 +34,9 @@ AudioOutput::~AudioOutput()
if (mixer != nullptr)
mixer_free(mixer);
delete replay_gain_filter;
delete other_replay_gain_filter;
delete filter;
delete prepared_replay_gain_filter;
delete prepared_other_replay_gain_filter;
delete prepared_filter;
}
void

View File

@@ -102,7 +102,7 @@ audio_output_mixer_type(const ConfigBlock &block)
"hardware"));
}
static Filter *
static PreparedFilter *
CreateVolumeFilter()
{
return filter_new(&volume_filter_plugin, ConfigBlock(),
@@ -113,12 +113,10 @@ static Mixer *
audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
const ConfigBlock &block,
const MixerPlugin *plugin,
Filter &filter_chain,
PreparedFilter &filter_chain,
MixerListener &listener,
Error &error)
{
assert(ao.volume_filter == nullptr);
Mixer *mixer;
switch (audio_output_mixer_type(block)) {
@@ -144,13 +142,8 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
IgnoreError());
assert(mixer != nullptr);
ao.volume_filter = CreateVolumeFilter();
assert(ao.volume_filter != nullptr);
filter_chain_append(filter_chain, "software_mixer",
ao.volume_filter);
software_mixer_set_filter(*mixer, ao.volume_filter);
ao.volume_filter.Set(CreateVolumeFilter()));
return mixer;
}
@@ -190,23 +183,23 @@ AudioOutput::Configure(const ConfigBlock &block, Error &error)
/* set up the filter chain */
filter = filter_chain_new();
assert(filter != nullptr);
prepared_filter = filter_chain_new();
assert(prepared_filter != nullptr);
/* create the normalization filter (if configured) */
if (config_get_bool(ConfigOption::VOLUME_NORMALIZATION, false)) {
Filter *normalize_filter =
auto *normalize_filter =
filter_new(&normalize_filter_plugin, ConfigBlock(),
IgnoreError());
assert(normalize_filter != nullptr);
filter_chain_append(*filter, "normalize",
filter_chain_append(*prepared_filter, "normalize",
autoconvert_filter_new(normalize_filter));
}
Error filter_error;
filter_chain_parse(*filter,
filter_chain_parse(*prepared_filter,
block.GetBlockValue(AUDIO_FILTERS, ""),
filter_error);
@@ -235,21 +228,21 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
block.GetBlockValue("replay_gain_handler", "software");
if (strcmp(replay_gain_handler, "none") != 0) {
ao.replay_gain_filter = filter_new(&replay_gain_filter_plugin,
block, IgnoreError());
assert(ao.replay_gain_filter != nullptr);
ao.prepared_replay_gain_filter = filter_new(&replay_gain_filter_plugin,
block, IgnoreError());
assert(ao.prepared_replay_gain_filter != nullptr);
ao.replay_gain_serial = 0;
ao.other_replay_gain_filter = filter_new(&replay_gain_filter_plugin,
block,
IgnoreError());
assert(ao.other_replay_gain_filter != nullptr);
ao.prepared_other_replay_gain_filter = filter_new(&replay_gain_filter_plugin,
block,
IgnoreError());
assert(ao.prepared_other_replay_gain_filter != nullptr);
ao.other_replay_gain_serial = 0;
} else {
ao.replay_gain_filter = nullptr;
ao.other_replay_gain_filter = nullptr;
ao.prepared_replay_gain_filter = nullptr;
ao.prepared_other_replay_gain_filter = nullptr;
}
/* set up the mixer */
@@ -257,7 +250,7 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
Error mixer_error;
ao.mixer = audio_output_load_mixer(event_loop, ao, block,
ao.plugin.mixer_plugin,
*ao.filter,
*ao.prepared_filter,
mixer_listener,
mixer_error);
if (ao.mixer == nullptr && mixer_error.IsDefined())
@@ -269,13 +262,13 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
if (strcmp(replay_gain_handler, "mixer") == 0) {
if (ao.mixer != nullptr)
replay_gain_filter_set_mixer(ao.replay_gain_filter,
replay_gain_filter_set_mixer(ao.prepared_replay_gain_filter,
ao.mixer, 100);
else
FormatError(output_domain,
"No such mixer for output '%s'", ao.name);
} else if (strcmp(replay_gain_handler, "software") != 0 &&
ao.replay_gain_filter != nullptr) {
ao.prepared_replay_gain_filter != nullptr) {
error.Set(config_domain,
"Invalid \"replay_gain_handler\" value");
return false;
@@ -283,11 +276,12 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
/* the "convert" filter must be the last one in the chain */
ao.convert_filter = filter_new(&convert_filter_plugin, ConfigBlock(),
IgnoreError());
assert(ao.convert_filter != nullptr);
auto *f = filter_new(&convert_filter_plugin, ConfigBlock(),
IgnoreError());
assert(f != nullptr);
filter_chain_append(*ao.filter, "convert", ao.convert_filter);
filter_chain_append(*ao.prepared_filter, "convert",
ao.convert_filter.Set(f));
return true;
}

View File

@@ -24,12 +24,14 @@
#include "pcm/PcmBuffer.hxx"
#include "pcm/PcmDither.hxx"
#include "ReplayGainInfo.hxx"
#include "filter/Observer.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "thread/Thread.hxx"
#include "system/PeriodClock.hxx"
class Error;
class PreparedFilter;
class Filter;
class MusicPipe;
class EventLoop;
@@ -147,6 +149,8 @@ struct AudioOutput {
*/
bool woken_for_play = false;
ReplayGainMode replay_gain_mode = REPLAY_GAIN_OFF;
/**
* If not nullptr, the device has failed, and this timer is used
* to estimate how long it should stay disabled (unless
@@ -187,19 +191,21 @@ struct AudioOutput {
* The filter object of this audio output. This is an
* instance of chain_filter_plugin.
*/
Filter *filter = nullptr;
PreparedFilter *prepared_filter = nullptr;
Filter *filter_instance;
/**
* The #VolumeFilter instance of this audio output. It is
* used by the #SoftwareMixer.
*/
Filter *volume_filter = nullptr;
FilterObserver volume_filter;
/**
* The replay_gain_filter_plugin instance of this audio
* output.
*/
Filter *replay_gain_filter = nullptr;
PreparedFilter *prepared_replay_gain_filter = nullptr;
Filter *replay_gain_filter_instance;
/**
* The serial number of the last replay gain info. 0 means no
@@ -212,7 +218,8 @@ struct AudioOutput {
* output, to be applied to the second chunk during
* cross-fading.
*/
Filter *other_replay_gain_filter = nullptr;
PreparedFilter *prepared_other_replay_gain_filter = nullptr;
Filter *other_replay_gain_filter_instance;
/**
* The serial number of the last replay gain info by the
@@ -226,7 +233,7 @@ struct AudioOutput {
* for converting the input data into the appropriate format
* for this audio output.
*/
Filter *convert_filter;
FilterObserver convert_filter;
/**
* The thread handle, or nullptr if the output thread isn't
@@ -346,7 +353,9 @@ struct AudioOutput {
*/
void LockRelease();
void SetReplayGainMode(ReplayGainMode mode);
void SetReplayGainMode(ReplayGainMode _mode) {
replay_gain_mode = _mode;
}
/**
* Caller must lock the mutex.

View File

@@ -68,15 +68,6 @@ AudioOutput::LockCommandWait(Command cmd)
CommandWait(cmd);
}
void
AudioOutput::SetReplayGainMode(ReplayGainMode mode)
{
if (replay_gain_filter != nullptr)
replay_gain_filter_set_mode(replay_gain_filter, mode);
if (other_replay_gain_filter != nullptr)
replay_gain_filter_set_mode(other_replay_gain_filter, mode);
}
void
AudioOutput::LockEnableWait()
{

View File

@@ -27,6 +27,8 @@
#include "filter/FilterInternal.hxx"
#include "filter/plugins/ConvertFilterPlugin.hxx"
#include "filter/plugins/ReplayGainFilterPlugin.hxx"
#include "mixer/MixerInternal.hxx"
#include "mixer/plugins/SoftwareMixerPlugin.hxx"
#include "player/Control.hxx"
#include "MusicPipe.hxx"
#include "MusicChunk.hxx"
@@ -94,37 +96,44 @@ AudioOutput::OpenFilter(AudioFormat &format, Error &error_r)
assert(format.IsValid());
/* the replay_gain filter cannot fail here */
if (replay_gain_filter != nullptr &&
!replay_gain_filter->Open(format, error_r).IsDefined())
return AudioFormat::Undefined();
if (prepared_replay_gain_filter != nullptr) {
replay_gain_filter_instance =
prepared_replay_gain_filter->Open(format, error_r);
if (replay_gain_filter_instance == nullptr)
return AudioFormat::Undefined();
}
if (other_replay_gain_filter != nullptr &&
!other_replay_gain_filter->Open(format, error_r).IsDefined()) {
if (replay_gain_filter != nullptr)
replay_gain_filter->Close();
if (prepared_other_replay_gain_filter != nullptr) {
other_replay_gain_filter_instance =
prepared_other_replay_gain_filter->Open(format, error_r);
if (other_replay_gain_filter_instance == nullptr) {
delete replay_gain_filter_instance;
return AudioFormat::Undefined();
}
}
filter_instance = prepared_filter->Open(format, error_r);
if (filter_instance == nullptr) {
delete other_replay_gain_filter_instance;
delete replay_gain_filter_instance;
return AudioFormat::Undefined();
}
const AudioFormat af = filter->Open(format, error_r);
if (!af.IsDefined()) {
if (replay_gain_filter != nullptr)
replay_gain_filter->Close();
if (other_replay_gain_filter != nullptr)
other_replay_gain_filter->Close();
}
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin))
software_mixer_set_filter(*mixer, volume_filter.Get());
return af;
return filter_instance->GetOutAudioFormat();
}
void
AudioOutput::CloseFilter()
{
if (replay_gain_filter != nullptr)
replay_gain_filter->Close();
if (other_replay_gain_filter != nullptr)
other_replay_gain_filter->Close();
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin))
software_mixer_set_filter(*mixer, nullptr);
filter->Close();
delete replay_gain_filter_instance;
delete other_replay_gain_filter_instance;
delete filter_instance;
}
inline void
@@ -186,7 +195,7 @@ AudioOutput::Open()
return;
}
if (!convert_filter_set(convert_filter, out_audio_format,
if (!convert_filter_set(convert_filter.Get(), out_audio_format,
error)) {
FormatError(error, "Failed to convert for \"%s\" [%s]",
name, plugin.name);
@@ -282,7 +291,7 @@ AudioOutput::ReopenFilter()
const AudioFormat filter_audio_format =
OpenFilter(in_audio_format, error);
if (!filter_audio_format.IsDefined() ||
!convert_filter_set(convert_filter, out_audio_format,
!convert_filter_set(convert_filter.Get(), out_audio_format,
error)) {
FormatError(error,
"Failed to open filter for \"%s\" [%s]",
@@ -368,6 +377,9 @@ ao_chunk_data(AudioOutput *ao, const MusicChunk *chunk,
assert(data.size % ao->in_audio_format.GetFrameSize() == 0);
if (!data.IsEmpty() && replay_gain_filter != nullptr) {
replay_gain_filter_set_mode(replay_gain_filter,
ao->replay_gain_mode);
if (chunk->replay_gain_serial != *replay_gain_serial_p) {
replay_gain_filter_set_info(replay_gain_filter,
chunk->replay_gain_serial != 0
@@ -390,7 +402,7 @@ static ConstBuffer<void>
ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
{
ConstBuffer<void> data =
ao_chunk_data(ao, chunk, ao->replay_gain_filter,
ao_chunk_data(ao, chunk, ao->replay_gain_filter_instance,
&ao->replay_gain_serial);
if (data.IsEmpty())
return data;
@@ -400,7 +412,7 @@ ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
if (chunk->other != nullptr) {
ConstBuffer<void> other_data =
ao_chunk_data(ao, chunk->other,
ao->other_replay_gain_filter,
ao->other_replay_gain_filter_instance,
&ao->other_replay_gain_serial);
if (other_data.IsNull())
return nullptr;
@@ -443,7 +455,7 @@ ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
/* apply filter chain */
Error error;
data = ao->filter->FilterPCM(data, error);
data = ao->filter_instance->FilterPCM(data, error);
if (data.IsNull()) {
FormatError(error, "\"%s\" [%s] failed to filter",
ao->name, ao->plugin.name);
@@ -456,7 +468,7 @@ ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
inline bool
AudioOutput::PlayChunk(const MusicChunk *chunk)
{
assert(filter != nullptr);
assert(filter_instance != nullptr);
if (tags && gcc_unlikely(chunk->tag != nullptr)) {
mutex.unlock();