Filter/Internal: migrate from class Error to C++ exceptions
This commit is contained in:
parent
28c6975732
commit
13c32111a0
@ -54,13 +54,15 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Filters a block of PCM data.
|
* Filters a block of PCM data.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param src the input buffer
|
* @param src the input buffer
|
||||||
* @param error location to store the error occurring
|
* @param error location to store the error occurring
|
||||||
* @return the destination buffer on success (will be
|
* @return the destination buffer on success (will be
|
||||||
* invalidated by deleting this object or the next FilterPCM()
|
* invalidated by deleting this object or the next FilterPCM()
|
||||||
* call), nullptr on error
|
* call)
|
||||||
*/
|
*/
|
||||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, Error &error) = 0;
|
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedFilter {
|
class PreparedFilter {
|
||||||
@ -70,12 +72,13 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Opens the filter, preparing it for FilterPCM().
|
* Opens the filter, preparing it for FilterPCM().
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param af the audio format of incoming data; the
|
* @param af the audio format of incoming data; the
|
||||||
* plugin may modify the object to enforce another input
|
* plugin may modify the object to enforce another input
|
||||||
* format
|
* format
|
||||||
* @param error location to store the error occurring
|
|
||||||
*/
|
*/
|
||||||
virtual Filter *Open(AudioFormat &af, Error &error) = 0;
|
virtual Filter *Open(AudioFormat &af) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
|
|
||||||
Filter *Get();
|
Filter *Get();
|
||||||
|
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilterObserver::Proxy final : public Filter {
|
class FilterObserver::Proxy final : public Filter {
|
||||||
@ -73,9 +73,8 @@ public:
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
|
||||||
Error &error) override {
|
return filter->FilterPCM(src);
|
||||||
return filter->FilterPCM(src, error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,14 +87,11 @@ FilterObserver::PreparedProxy::Get()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
FilterObserver::PreparedProxy::Open(AudioFormat &af, Error &error)
|
FilterObserver::PreparedProxy::Open(AudioFormat &af)
|
||||||
{
|
{
|
||||||
assert(child == nullptr);
|
assert(child == nullptr);
|
||||||
|
|
||||||
Filter *f = prepared_filter->Open(af, error);
|
Filter *f = prepared_filter->Open(af);
|
||||||
if (f == nullptr)
|
|
||||||
return f;
|
|
||||||
|
|
||||||
return child = new Proxy(*this, f);
|
return child = new Proxy(*this, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ public:
|
|||||||
std::unique_ptr<Filter> &&_convert)
|
std::unique_ptr<Filter> &&_convert)
|
||||||
:filter(std::move(_filter)), convert(std::move(_convert)) {}
|
:filter(std::move(_filter)), convert(std::move(_convert)) {}
|
||||||
|
|
||||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedAutoConvertFilter final : public PreparedFilter {
|
class PreparedAutoConvertFilter final : public PreparedFilter {
|
||||||
@ -63,20 +62,18 @@ public:
|
|||||||
delete filter;
|
delete filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
|
PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format)
|
||||||
{
|
{
|
||||||
assert(in_audio_format.IsValid());
|
assert(in_audio_format.IsValid());
|
||||||
|
|
||||||
/* open the "real" filter */
|
/* open the "real" filter */
|
||||||
|
|
||||||
AudioFormat child_audio_format = in_audio_format;
|
AudioFormat child_audio_format = in_audio_format;
|
||||||
std::unique_ptr<Filter> new_filter(filter->Open(child_audio_format, error));
|
std::unique_ptr<Filter> new_filter(filter->Open(child_audio_format));
|
||||||
if (!new_filter)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
/* need to convert? */
|
/* need to convert? */
|
||||||
|
|
||||||
@ -85,10 +82,7 @@ PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
|
|||||||
/* yes - create a convert_filter */
|
/* yes - create a convert_filter */
|
||||||
|
|
||||||
convert.reset(convert_filter_new(in_audio_format,
|
convert.reset(convert_filter_new(in_audio_format,
|
||||||
child_audio_format,
|
child_audio_format));
|
||||||
error));
|
|
||||||
if (!convert)
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AutoConvertFilter(std::move(new_filter),
|
return new AutoConvertFilter(std::move(new_filter),
|
||||||
@ -96,15 +90,15 @@ PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
AutoConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
|
AutoConvertFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
if (convert != nullptr) {
|
if (convert != nullptr) {
|
||||||
src = convert->FilterPCM(src, error);
|
src = convert->FilterPCM(src);
|
||||||
if (src.IsNull())
|
if (src.IsNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filter->FilterPCM(src, error);
|
return filter->FilterPCM(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparedFilter *
|
PreparedFilter *
|
||||||
|
@ -23,9 +23,8 @@
|
|||||||
#include "filter/FilterInternal.hxx"
|
#include "filter/FilterInternal.hxx"
|
||||||
#include "filter/FilterRegistry.hxx"
|
#include "filter/FilterRegistry.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -62,8 +61,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedChainFilter final : public PreparedFilter {
|
class PreparedChainFilter final : public PreparedFilter {
|
||||||
@ -80,8 +78,7 @@ class PreparedChainFilter final : public PreparedFilter {
|
|||||||
Child(const Child &) = delete;
|
Child(const Child &) = delete;
|
||||||
Child &operator=(const Child &) = delete;
|
Child &operator=(const Child &) = delete;
|
||||||
|
|
||||||
Filter *Open(const AudioFormat &prev_audio_format,
|
Filter *Open(const AudioFormat &prev_audio_format);
|
||||||
Error &error);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::list<Child> children;
|
std::list<Child> children;
|
||||||
@ -92,11 +89,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class PreparedFilter */
|
/* virtual methods from class PreparedFilter */
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain chain_filter_domain("chain_filter");
|
|
||||||
|
|
||||||
static PreparedFilter *
|
static PreparedFilter *
|
||||||
chain_filter_init(gcc_unused const ConfigBlock &block,
|
chain_filter_init(gcc_unused const ConfigBlock &block,
|
||||||
gcc_unused Error &error)
|
gcc_unused Error &error)
|
||||||
@ -105,39 +100,31 @@ chain_filter_init(gcc_unused const ConfigBlock &block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedChainFilter::Child::Open(const AudioFormat &prev_audio_format,
|
PreparedChainFilter::Child::Open(const AudioFormat &prev_audio_format)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
AudioFormat conv_audio_format = prev_audio_format;
|
AudioFormat conv_audio_format = prev_audio_format;
|
||||||
Filter *new_filter = filter->Open(conv_audio_format, error);
|
Filter *new_filter = filter->Open(conv_audio_format);
|
||||||
if (new_filter == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (conv_audio_format != prev_audio_format) {
|
if (conv_audio_format != prev_audio_format) {
|
||||||
delete new_filter;
|
delete new_filter;
|
||||||
|
|
||||||
struct audio_format_string s;
|
struct audio_format_string s;
|
||||||
error.Format(chain_filter_domain,
|
throw FormatRuntimeError("Audio format not supported by filter '%s': %s",
|
||||||
"Audio format not supported by filter '%s': %s",
|
name,
|
||||||
name,
|
audio_format_to_string(prev_audio_format, &s));
|
||||||
audio_format_to_string(prev_audio_format, &s));
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_filter;
|
return new_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedChainFilter::Open(AudioFormat &in_audio_format, Error &error)
|
PreparedChainFilter::Open(AudioFormat &in_audio_format)
|
||||||
{
|
{
|
||||||
std::unique_ptr<ChainFilter> chain(new ChainFilter(in_audio_format));
|
std::unique_ptr<ChainFilter> chain(new ChainFilter(in_audio_format));
|
||||||
|
|
||||||
for (auto &child : children) {
|
for (auto &child : children) {
|
||||||
AudioFormat audio_format = chain->GetOutAudioFormat();
|
AudioFormat audio_format = chain->GetOutAudioFormat();
|
||||||
auto *filter = child.Open(audio_format, error);
|
auto *filter = child.Open(audio_format);
|
||||||
if (filter == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
chain->Append(child.name, filter);
|
chain->Append(child.name, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,14 +132,12 @@ PreparedChainFilter::Open(AudioFormat &in_audio_format, Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
ChainFilter::FilterPCM(ConstBuffer<void> src, Error &error)
|
ChainFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
for (auto &child : children) {
|
for (auto &child : children) {
|
||||||
/* feed the output of the previous filter as input
|
/* feed the output of the previous filter as input
|
||||||
into the current one */
|
into the current one */
|
||||||
src = child.filter->FilterPCM(src, error);
|
src = child.filter->FilterPCM(src);
|
||||||
if (src.IsNull())
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the output of the last filter */
|
/* return the output of the last filter */
|
||||||
|
@ -25,9 +25,13 @@
|
|||||||
#include "pcm/PcmConvert.hxx"
|
#include "pcm/PcmConvert.hxx"
|
||||||
#include "util/Manual.hxx"
|
#include "util/Manual.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
#include "util/Error.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "poison.h"
|
#include "poison.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
class ConvertFilter final : public Filter {
|
class ConvertFilter final : public Filter {
|
||||||
@ -47,17 +51,16 @@ public:
|
|||||||
ConvertFilter(const AudioFormat &audio_format);
|
ConvertFilter(const AudioFormat &audio_format);
|
||||||
~ConvertFilter();
|
~ConvertFilter();
|
||||||
|
|
||||||
bool Set(const AudioFormat &_out_audio_format, Error &error);
|
void Set(const AudioFormat &_out_audio_format);
|
||||||
|
|
||||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedConvertFilter final : public PreparedFilter {
|
class PreparedConvertFilter final : public PreparedFilter {
|
||||||
public:
|
public:
|
||||||
bool Set(const AudioFormat &_out_audio_format, Error &error);
|
void Set(const AudioFormat &_out_audio_format);
|
||||||
|
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PreparedFilter *
|
static PreparedFilter *
|
||||||
@ -67,15 +70,15 @@ convert_filter_init(gcc_unused const ConfigBlock &block,
|
|||||||
return new PreparedConvertFilter();
|
return new PreparedConvertFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ConvertFilter::Set(const AudioFormat &_out_audio_format, Error &error)
|
ConvertFilter::Set(const AudioFormat &_out_audio_format)
|
||||||
{
|
{
|
||||||
assert(in_audio_format.IsValid());
|
assert(in_audio_format.IsValid());
|
||||||
assert(_out_audio_format.IsValid());
|
assert(_out_audio_format.IsValid());
|
||||||
|
|
||||||
if (_out_audio_format == out_audio_format)
|
if (_out_audio_format == out_audio_format)
|
||||||
/* no change */
|
/* no change */
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
if (out_audio_format != in_audio_format) {
|
if (out_audio_format != in_audio_format) {
|
||||||
out_audio_format = in_audio_format;
|
out_audio_format = in_audio_format;
|
||||||
@ -84,13 +87,13 @@ ConvertFilter::Set(const AudioFormat &_out_audio_format, Error &error)
|
|||||||
|
|
||||||
if (_out_audio_format == in_audio_format)
|
if (_out_audio_format == in_audio_format)
|
||||||
/* optimized special case: no-op */
|
/* optimized special case: no-op */
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
|
Error error;
|
||||||
if (!state.Open(in_audio_format, _out_audio_format, error))
|
if (!state.Open(in_audio_format, _out_audio_format, error))
|
||||||
return false;
|
throw std::runtime_error(error.GetMessage());
|
||||||
|
|
||||||
out_audio_format = _out_audio_format;
|
out_audio_format = _out_audio_format;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertFilter::ConvertFilter(const AudioFormat &audio_format)
|
ConvertFilter::ConvertFilter(const AudioFormat &audio_format)
|
||||||
@ -99,7 +102,7 @@ ConvertFilter::ConvertFilter(const AudioFormat &audio_format)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedConvertFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
|
PreparedConvertFilter::Open(AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ ConvertFilter::~ConvertFilter()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
ConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
|
ConvertFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
assert(in_audio_format.IsValid());
|
assert(in_audio_format.IsValid());
|
||||||
|
|
||||||
@ -123,7 +126,12 @@ ConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
|
|||||||
/* optimized special case: no-op */
|
/* optimized special case: no-op */
|
||||||
return src;
|
return src;
|
||||||
|
|
||||||
return state.Convert(src, error);
|
Error error;
|
||||||
|
auto result = state.Convert(src, error);
|
||||||
|
if (result.IsNull())
|
||||||
|
throw std::runtime_error(error.GetMessage());
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct filter_plugin convert_filter_plugin = {
|
const struct filter_plugin convert_filter_plugin = {
|
||||||
@ -133,23 +141,17 @@ const struct filter_plugin convert_filter_plugin = {
|
|||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
convert_filter_new(const AudioFormat in_audio_format,
|
convert_filter_new(const AudioFormat in_audio_format,
|
||||||
const AudioFormat out_audio_format,
|
const AudioFormat out_audio_format)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
auto *filter = new ConvertFilter(in_audio_format);
|
std::unique_ptr<ConvertFilter> filter(new ConvertFilter(in_audio_format));
|
||||||
if (!filter->Set(out_audio_format, error)) {
|
filter->Set(out_audio_format);
|
||||||
delete filter;
|
return filter.release();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
convert_filter_set(Filter *_filter, AudioFormat out_audio_format,
|
convert_filter_set(Filter *_filter, AudioFormat out_audio_format)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
ConvertFilter *filter = (ConvertFilter *)_filter;
|
ConvertFilter *filter = (ConvertFilter *)_filter;
|
||||||
|
|
||||||
return filter->Set(out_audio_format, error);
|
filter->Set(out_audio_format);
|
||||||
}
|
}
|
||||||
|
@ -26,17 +26,17 @@ struct AudioFormat;
|
|||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
convert_filter_new(AudioFormat in_audio_format,
|
convert_filter_new(AudioFormat in_audio_format,
|
||||||
AudioFormat out_audio_format,
|
AudioFormat out_audio_format);
|
||||||
Error &error);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the output audio format for the specified filter. You must
|
* Sets the output audio format for the specified filter. You must
|
||||||
* call this after the filter has been opened. Since this audio
|
* call this after the filter has been opened. Since this audio
|
||||||
* format switch is a violation of the filter API, this filter must be
|
* format switch is a violation of the filter API, this filter must be
|
||||||
* the last in a chain.
|
* the last in a chain.
|
||||||
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
bool
|
void
|
||||||
convert_filter_set(Filter *filter, AudioFormat out_audio_format,
|
convert_filter_set(Filter *filter, AudioFormat out_audio_format);
|
||||||
Error &error);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,14 +43,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedNormalizeFilter final : public PreparedFilter {
|
class PreparedNormalizeFilter final : public PreparedFilter {
|
||||||
public:
|
public:
|
||||||
/* virtual methods from class PreparedFilter */
|
/* virtual methods from class PreparedFilter */
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PreparedFilter *
|
static PreparedFilter *
|
||||||
@ -61,7 +60,7 @@ normalize_filter_init(gcc_unused const ConfigBlock &block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedNormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
|
PreparedNormalizeFilter::Open(AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
audio_format.format = SampleFormat::S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ PreparedNormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
NormalizeFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
|
NormalizeFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
int16_t *dest = (int16_t *)buffer.Get(src.size);
|
int16_t *dest = (int16_t *)buffer.Get(src.size);
|
||||||
memcpy(dest, src.data, src.size);
|
memcpy(dest, src.data, src.size);
|
||||||
|
@ -36,16 +36,14 @@ class NullFilter final : public Filter {
|
|||||||
public:
|
public:
|
||||||
explicit NullFilter(const AudioFormat &af):Filter(af) {}
|
explicit NullFilter(const AudioFormat &af):Filter(af) {}
|
||||||
|
|
||||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
|
||||||
gcc_unused Error &error) override {
|
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedNullFilter final : public PreparedFilter {
|
class PreparedNullFilter final : public PreparedFilter {
|
||||||
public:
|
public:
|
||||||
virtual Filter *Open(AudioFormat &af,
|
virtual Filter *Open(AudioFormat &af) override {
|
||||||
gcc_unused Error &error) override {
|
|
||||||
return new NullFilter(af);
|
return new NullFilter(af);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static constexpr Domain replay_gain_domain("replay_gain");
|
static constexpr Domain replay_gain_domain("replay_gain");
|
||||||
@ -73,10 +75,10 @@ public:
|
|||||||
:Filter(audio_format),
|
:Filter(audio_format),
|
||||||
mixer(_mixer), base(_base), mode(REPLAY_GAIN_OFF) {
|
mixer(_mixer), base(_base), mode(REPLAY_GAIN_OFF) {
|
||||||
info.Clear();
|
info.Clear();
|
||||||
}
|
|
||||||
|
|
||||||
bool Open(Error &error) {
|
Error error;
|
||||||
return pv.Open(out_audio_format.format, error);
|
if (!pv.Open(out_audio_format.format, error))
|
||||||
|
throw std::runtime_error(error.GetMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInfo(const ReplayGainInfo *_info) {
|
void SetInfo(const ReplayGainInfo *_info) {
|
||||||
@ -108,8 +110,7 @@ public:
|
|||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedReplayGainFilter final : public PreparedFilter {
|
class PreparedReplayGainFilter final : public PreparedFilter {
|
||||||
@ -134,7 +135,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -174,19 +175,13 @@ replay_gain_filter_init(gcc_unused const ConfigBlock &block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedReplayGainFilter::Open(AudioFormat &af, gcc_unused Error &error)
|
PreparedReplayGainFilter::Open(AudioFormat &af)
|
||||||
{
|
{
|
||||||
auto *filter = new ReplayGainFilter(af, mixer, base);
|
return new ReplayGainFilter(af, mixer, base);
|
||||||
if (!filter->Open(error)) {
|
|
||||||
delete filter;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
ReplayGainFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
|
ReplayGainFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
return mixer != nullptr
|
return mixer != nullptr
|
||||||
? src
|
? src
|
||||||
|
@ -96,8 +96,7 @@ public:
|
|||||||
const std::array<int8_t, MAX_CHANNELS> &_sources);
|
const std::array<int8_t, MAX_CHANNELS> &_sources);
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedRouteFilter final : public PreparedFilter {
|
class PreparedRouteFilter final : public PreparedFilter {
|
||||||
@ -136,7 +135,7 @@ public:
|
|||||||
bool Configure(const ConfigBlock &block, Error &error);
|
bool Configure(const ConfigBlock &block, Error &error);
|
||||||
|
|
||||||
/* virtual methods from class PreparedFilter */
|
/* virtual methods from class PreparedFilter */
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -243,13 +242,13 @@ RouteFilter::RouteFilter(const AudioFormat &audio_format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedRouteFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
|
PreparedRouteFilter::Open(AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
return new RouteFilter(audio_format, min_output_channels, sources);
|
return new RouteFilter(audio_format, min_output_channels, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
RouteFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
|
RouteFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
size_t number_of_frames = src.size / input_frame_size;
|
size_t number_of_frames = src.size / input_frame_size;
|
||||||
|
|
||||||
|
@ -25,16 +25,19 @@
|
|||||||
#include "pcm/Volume.hxx"
|
#include "pcm/Volume.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
#include "util/Error.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
class VolumeFilter final : public Filter {
|
class VolumeFilter final : public Filter {
|
||||||
PcmVolume pv;
|
PcmVolume pv;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VolumeFilter(const AudioFormat &audio_format)
|
explicit VolumeFilter(const AudioFormat &audio_format)
|
||||||
:Filter(audio_format) {}
|
:Filter(audio_format) {
|
||||||
|
Error error;
|
||||||
bool Open(Error &error) {
|
if (!pv.Open(out_audio_format.format, error))
|
||||||
return pv.Open(out_audio_format.format, error);
|
throw std::runtime_error(error.GetMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned GetVolume() const {
|
unsigned GetVolume() const {
|
||||||
@ -46,8 +49,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
Error &error) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedVolumeFilter final : public PreparedFilter {
|
class PreparedVolumeFilter final : public PreparedFilter {
|
||||||
@ -55,7 +57,7 @@ class PreparedVolumeFilter final : public PreparedFilter {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
Filter *Open(AudioFormat &af, Error &error) override;
|
Filter *Open(AudioFormat &af) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PreparedFilter *
|
static PreparedFilter *
|
||||||
@ -66,19 +68,13 @@ volume_filter_init(gcc_unused const ConfigBlock &block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Filter *
|
Filter *
|
||||||
PreparedVolumeFilter::Open(AudioFormat &audio_format, Error &error)
|
PreparedVolumeFilter::Open(AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
auto *filter = new VolumeFilter(audio_format);
|
return new VolumeFilter(audio_format);
|
||||||
if (!filter->Open(error)) {
|
|
||||||
delete filter;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
VolumeFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
|
VolumeFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
return pv.Apply(src);
|
return pv.Apply(src);
|
||||||
}
|
}
|
||||||
|
@ -404,7 +404,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
void CloseOutput(bool drain);
|
void CloseOutput(bool drain);
|
||||||
|
|
||||||
AudioFormat OpenFilter(AudioFormat &format, Error &error_r);
|
/**
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*/
|
||||||
|
AudioFormat OpenFilter(AudioFormat &format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutex must not be locked.
|
* Mutex must not be locked.
|
||||||
|
@ -93,38 +93,28 @@ AudioOutput::Disable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline AudioFormat
|
inline AudioFormat
|
||||||
AudioOutput::OpenFilter(AudioFormat &format, Error &error_r)
|
AudioOutput::OpenFilter(AudioFormat &format)
|
||||||
{
|
try {
|
||||||
assert(format.IsValid());
|
assert(format.IsValid());
|
||||||
|
|
||||||
/* the replay_gain filter cannot fail here */
|
/* the replay_gain filter cannot fail here */
|
||||||
if (prepared_replay_gain_filter != nullptr) {
|
if (prepared_replay_gain_filter != nullptr)
|
||||||
replay_gain_filter_instance =
|
replay_gain_filter_instance =
|
||||||
prepared_replay_gain_filter->Open(format, error_r);
|
prepared_replay_gain_filter->Open(format);
|
||||||
if (replay_gain_filter_instance == nullptr)
|
|
||||||
return AudioFormat::Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prepared_other_replay_gain_filter != nullptr) {
|
if (prepared_other_replay_gain_filter != nullptr)
|
||||||
other_replay_gain_filter_instance =
|
other_replay_gain_filter_instance =
|
||||||
prepared_other_replay_gain_filter->Open(format, error_r);
|
prepared_other_replay_gain_filter->Open(format);
|
||||||
if (other_replay_gain_filter_instance == nullptr) {
|
|
||||||
delete replay_gain_filter_instance;
|
|
||||||
return AudioFormat::Undefined();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_instance = prepared_filter->Open(format, error_r);
|
filter_instance = prepared_filter->Open(format);
|
||||||
if (filter_instance == nullptr) {
|
|
||||||
delete other_replay_gain_filter_instance;
|
|
||||||
delete replay_gain_filter_instance;
|
|
||||||
return AudioFormat::Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin))
|
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin))
|
||||||
software_mixer_set_filter(*mixer, volume_filter.Get());
|
software_mixer_set_filter(*mixer, volume_filter.Get());
|
||||||
|
|
||||||
return filter_instance->GetOutAudioFormat();
|
return filter_instance->GetOutAudioFormat();
|
||||||
|
} catch (...) {
|
||||||
|
CloseFilter();
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -165,10 +155,11 @@ AudioOutput::Open()
|
|||||||
|
|
||||||
/* open the filter */
|
/* open the filter */
|
||||||
|
|
||||||
const AudioFormat filter_audio_format =
|
AudioFormat filter_audio_format;
|
||||||
OpenFilter(in_audio_format, error);
|
try {
|
||||||
if (!filter_audio_format.IsDefined()) {
|
filter_audio_format = OpenFilter(in_audio_format);
|
||||||
FormatError(error, "Failed to open filter for \"%s\" [%s]",
|
} catch (const std::runtime_error &e) {
|
||||||
|
FormatError(e, "Failed to open filter for \"%s\" [%s]",
|
||||||
name, plugin.name);
|
name, plugin.name);
|
||||||
|
|
||||||
fail_timer.Update();
|
fail_timer.Update();
|
||||||
@ -202,9 +193,10 @@ AudioOutput::Open()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!convert_filter_set(convert_filter.Get(), out_audio_format,
|
try {
|
||||||
error)) {
|
convert_filter_set(convert_filter.Get(), out_audio_format);
|
||||||
FormatError(error, "Failed to convert for \"%s\" [%s]",
|
} catch (const std::runtime_error &e) {
|
||||||
|
FormatError(e, "Failed to convert for \"%s\" [%s]",
|
||||||
name, plugin.name);
|
name, plugin.name);
|
||||||
|
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
@ -295,12 +287,12 @@ AudioOutput::ReopenFilter()
|
|||||||
CloseFilter();
|
CloseFilter();
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
|
||||||
const AudioFormat filter_audio_format =
|
AudioFormat filter_audio_format;
|
||||||
OpenFilter(in_audio_format, error);
|
try {
|
||||||
if (!filter_audio_format.IsDefined() ||
|
filter_audio_format = OpenFilter(in_audio_format);
|
||||||
!convert_filter_set(convert_filter.Get(), out_audio_format,
|
convert_filter_set(convert_filter.Get(), out_audio_format);
|
||||||
error)) {
|
} catch (const std::runtime_error &e) {
|
||||||
FormatError(error,
|
FormatError(e,
|
||||||
"Failed to open filter for \"%s\" [%s]",
|
"Failed to open filter for \"%s\" [%s]",
|
||||||
name, plugin.name);
|
name, plugin.name);
|
||||||
|
|
||||||
@ -383,11 +375,13 @@ ao_chunk_data(AudioOutput *ao, const MusicChunk *chunk,
|
|||||||
*replay_gain_serial_p = chunk->replay_gain_serial;
|
*replay_gain_serial_p = chunk->replay_gain_serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
data = replay_gain_filter->FilterPCM(data, error);
|
data = replay_gain_filter->FilterPCM(data);
|
||||||
if (data.IsNull())
|
} catch (const std::runtime_error &e) {
|
||||||
FormatError(error, "\"%s\" [%s] failed to filter",
|
FormatError(e, "\"%s\" [%s] failed to filter",
|
||||||
ao->name, ao->plugin.name);
|
ao->name, ao->plugin.name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -449,15 +443,13 @@ ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
|
|||||||
|
|
||||||
/* apply filter chain */
|
/* apply filter chain */
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
data = ao->filter_instance->FilterPCM(data, error);
|
return ao->filter_instance->FilterPCM(data);
|
||||||
if (data.IsNull()) {
|
} catch (const std::runtime_error &e) {
|
||||||
FormatError(error, "\"%s\" [%s] failed to filter",
|
FormatError(e, "\"%s\" [%s] failed to filter",
|
||||||
ao->name, ao->plugin.name);
|
ao->name, ao->plugin.name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -105,13 +105,7 @@ try {
|
|||||||
|
|
||||||
/* open the filter */
|
/* open the filter */
|
||||||
|
|
||||||
Error error;
|
std::unique_ptr<Filter> filter(prepared_filter->Open(audio_format));
|
||||||
std::unique_ptr<Filter> filter(prepared_filter->Open(audio_format,
|
|
||||||
error));
|
|
||||||
if (!filter) {
|
|
||||||
LogError(error, "Failed to open filter");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AudioFormat out_audio_format = filter->GetOutAudioFormat();
|
const AudioFormat out_audio_format = filter->GetOutAudioFormat();
|
||||||
|
|
||||||
@ -127,12 +121,7 @@ try {
|
|||||||
if (nbytes <= 0)
|
if (nbytes <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes},
|
auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes});
|
||||||
error);
|
|
||||||
if (dest.IsNull()) {
|
|
||||||
LogError(error, "filter/Filter failed");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = write(1, dest.data, dest.size);
|
nbytes = write(1, dest.data, dest.size);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
@ -147,7 +136,7 @@ try {
|
|||||||
config_global_finish();
|
config_global_finish();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LogError(e);
|
LogError(e);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user