filter/FilterInternal: split class Filter, add class PreparedFilter
For easier state management inside filter plugins.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user