Filter/Internal: migrate from class Error to C++ exceptions

This commit is contained in:
Max Kellermann 2016-09-04 14:32:09 +02:00
parent 28c6975732
commit 13c32111a0
14 changed files with 142 additions and 191 deletions

View File

@ -54,13 +54,15 @@ public:
/**
* Filters a block of PCM data.
*
* Throws std::runtime_error on error.
*
* @param src the input buffer
* @param error location to store the error occurring
* @return the destination buffer on success (will be
* 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 {
@ -70,12 +72,13 @@ public:
/**
* Opens the filter, preparing it for FilterPCM().
*
* Throws std::runtime_error on error.
*
* @param af the audio format of incoming data; the
* plugin may modify the object to enforce another input
* format
* @param error location to store the error occurring
*/
virtual Filter *Open(AudioFormat &af, Error &error) = 0;
virtual Filter *Open(AudioFormat &af) = 0;
};
#endif

View File

@ -51,7 +51,7 @@ public:
Filter *Get();
Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
class FilterObserver::Proxy final : public Filter {
@ -73,9 +73,8 @@ public:
return filter;
}
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override {
return filter->FilterPCM(src, error);
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
return filter->FilterPCM(src);
}
};
@ -88,14 +87,11 @@ FilterObserver::PreparedProxy::Get()
}
Filter *
FilterObserver::PreparedProxy::Open(AudioFormat &af, Error &error)
FilterObserver::PreparedProxy::Open(AudioFormat &af)
{
assert(child == nullptr);
Filter *f = prepared_filter->Open(af, error);
if (f == nullptr)
return f;
Filter *f = prepared_filter->Open(af);
return child = new Proxy(*this, f);
}

View File

@ -47,8 +47,7 @@ public:
std::unique_ptr<Filter> &&_convert)
:filter(std::move(_filter)), convert(std::move(_convert)) {}
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedAutoConvertFilter final : public PreparedFilter {
@ -63,20 +62,18 @@ public:
delete filter;
}
virtual Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
Filter *
PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format)
{
assert(in_audio_format.IsValid());
/* open the "real" filter */
AudioFormat child_audio_format = in_audio_format;
std::unique_ptr<Filter> new_filter(filter->Open(child_audio_format, error));
if (!new_filter)
return nullptr;
std::unique_ptr<Filter> new_filter(filter->Open(child_audio_format));
/* need to convert? */
@ -85,10 +82,7 @@ PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
/* yes - create a convert_filter */
convert.reset(convert_filter_new(in_audio_format,
child_audio_format,
error));
if (!convert)
return nullptr;
child_audio_format));
}
return new AutoConvertFilter(std::move(new_filter),
@ -96,15 +90,15 @@ PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
}
ConstBuffer<void>
AutoConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
AutoConvertFilter::FilterPCM(ConstBuffer<void> src)
{
if (convert != nullptr) {
src = convert->FilterPCM(src, error);
src = convert->FilterPCM(src);
if (src.IsNull())
return nullptr;
}
return filter->FilterPCM(src, error);
return filter->FilterPCM(src);
}
PreparedFilter *

View File

@ -23,9 +23,8 @@
#include "filter/FilterInternal.hxx"
#include "filter/FilterRegistry.hxx"
#include "AudioFormat.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/ConstBuffer.hxx"
#include "util/RuntimeError.hxx"
#include <memory>
#include <list>
@ -62,8 +61,7 @@ public:
}
/* virtual methods from class Filter */
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedChainFilter final : public PreparedFilter {
@ -80,8 +78,7 @@ class PreparedChainFilter final : public PreparedFilter {
Child(const Child &) = delete;
Child &operator=(const Child &) = delete;
Filter *Open(const AudioFormat &prev_audio_format,
Error &error);
Filter *Open(const AudioFormat &prev_audio_format);
};
std::list<Child> children;
@ -92,11 +89,9 @@ public:
}
/* 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 *
chain_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
@ -105,39 +100,31 @@ chain_filter_init(gcc_unused const ConfigBlock &block,
}
Filter *
PreparedChainFilter::Child::Open(const AudioFormat &prev_audio_format,
Error &error)
PreparedChainFilter::Child::Open(const AudioFormat &prev_audio_format)
{
AudioFormat conv_audio_format = prev_audio_format;
Filter *new_filter = filter->Open(conv_audio_format, error);
if (new_filter == nullptr)
return nullptr;
Filter *new_filter = filter->Open(conv_audio_format);
if (conv_audio_format != prev_audio_format) {
delete new_filter;
struct audio_format_string s;
error.Format(chain_filter_domain,
"Audio format not supported by filter '%s': %s",
name,
audio_format_to_string(prev_audio_format, &s));
return nullptr;
throw FormatRuntimeError("Audio format not supported by filter '%s': %s",
name,
audio_format_to_string(prev_audio_format, &s));
}
return new_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));
for (auto &child : children) {
AudioFormat audio_format = chain->GetOutAudioFormat();
auto *filter = child.Open(audio_format, error);
if (filter == nullptr)
return nullptr;
auto *filter = child.Open(audio_format);
chain->Append(child.name, filter);
}
@ -145,14 +132,12 @@ PreparedChainFilter::Open(AudioFormat &in_audio_format, Error &error)
}
ConstBuffer<void>
ChainFilter::FilterPCM(ConstBuffer<void> src, Error &error)
ChainFilter::FilterPCM(ConstBuffer<void> src)
{
for (auto &child : children) {
/* feed the output of the previous filter as input
into the current one */
src = child.filter->FilterPCM(src, error);
if (src.IsNull())
return nullptr;
src = child.filter->FilterPCM(src);
}
/* return the output of the last filter */

View File

@ -25,9 +25,13 @@
#include "pcm/PcmConvert.hxx"
#include "util/Manual.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "AudioFormat.hxx"
#include "poison.h"
#include <stdexcept>
#include <memory>
#include <assert.h>
class ConvertFilter final : public Filter {
@ -47,17 +51,16 @@ public:
ConvertFilter(const AudioFormat &audio_format);
~ConvertFilter();
bool Set(const AudioFormat &_out_audio_format, Error &error);
void Set(const AudioFormat &_out_audio_format);
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedConvertFilter final : public PreparedFilter {
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 *
@ -67,15 +70,15 @@ convert_filter_init(gcc_unused const ConfigBlock &block,
return new PreparedConvertFilter();
}
bool
ConvertFilter::Set(const AudioFormat &_out_audio_format, Error &error)
void
ConvertFilter::Set(const AudioFormat &_out_audio_format)
{
assert(in_audio_format.IsValid());
assert(_out_audio_format.IsValid());
if (_out_audio_format == out_audio_format)
/* no change */
return true;
return;
if (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)
/* optimized special case: no-op */
return true;
return;
Error 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;
return true;
}
ConvertFilter::ConvertFilter(const AudioFormat &audio_format)
@ -99,7 +102,7 @@ ConvertFilter::ConvertFilter(const AudioFormat &audio_format)
}
Filter *
PreparedConvertFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
PreparedConvertFilter::Open(AudioFormat &audio_format)
{
assert(audio_format.IsValid());
@ -115,7 +118,7 @@ ConvertFilter::~ConvertFilter()
}
ConstBuffer<void>
ConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
ConvertFilter::FilterPCM(ConstBuffer<void> src)
{
assert(in_audio_format.IsValid());
@ -123,7 +126,12 @@ ConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error)
/* optimized special case: no-op */
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 = {
@ -133,23 +141,17 @@ const struct filter_plugin convert_filter_plugin = {
Filter *
convert_filter_new(const AudioFormat in_audio_format,
const AudioFormat out_audio_format,
Error &error)
const AudioFormat out_audio_format)
{
auto *filter = new ConvertFilter(in_audio_format);
if (!filter->Set(out_audio_format, error)) {
delete filter;
return nullptr;
}
return filter;
std::unique_ptr<ConvertFilter> filter(new ConvertFilter(in_audio_format));
filter->Set(out_audio_format);
return filter.release();
}
bool
convert_filter_set(Filter *_filter, AudioFormat out_audio_format,
Error &error)
void
convert_filter_set(Filter *_filter, AudioFormat out_audio_format)
{
ConvertFilter *filter = (ConvertFilter *)_filter;
return filter->Set(out_audio_format, error);
filter->Set(out_audio_format);
}

View File

@ -26,17 +26,17 @@ struct AudioFormat;
Filter *
convert_filter_new(AudioFormat in_audio_format,
AudioFormat out_audio_format,
Error &error);
AudioFormat out_audio_format);
/**
* Sets the output audio format for the specified filter. You must
* call this after the filter has been opened. Since this audio
* format switch is a violation of the filter API, this filter must be
* the last in a chain.
*
* Throws std::runtime_error on error.
*/
bool
convert_filter_set(Filter *filter, AudioFormat out_audio_format,
Error &error);
void
convert_filter_set(Filter *filter, AudioFormat out_audio_format);
#endif

View File

@ -43,14 +43,13 @@ public:
}
/* virtual methods from class Filter */
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedNormalizeFilter final : public PreparedFilter {
public:
/* virtual methods from class PreparedFilter */
Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
static PreparedFilter *
@ -61,7 +60,7 @@ normalize_filter_init(gcc_unused const ConfigBlock &block,
}
Filter *
PreparedNormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
PreparedNormalizeFilter::Open(AudioFormat &audio_format)
{
audio_format.format = SampleFormat::S16;
@ -69,7 +68,7 @@ PreparedNormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error
}
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);
memcpy(dest, src.data, src.size);

View File

@ -36,16 +36,14 @@ class NullFilter final : public Filter {
public:
explicit NullFilter(const AudioFormat &af):Filter(af) {}
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
gcc_unused Error &error) override {
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
return src;
}
};
class PreparedNullFilter final : public PreparedFilter {
public:
virtual Filter *Open(AudioFormat &af,
gcc_unused Error &error) override {
virtual Filter *Open(AudioFormat &af) override {
return new NullFilter(af);
}
};

View File

@ -32,6 +32,8 @@
#include "util/Domain.hxx"
#include "Log.hxx"
#include <stdexcept>
#include <assert.h>
static constexpr Domain replay_gain_domain("replay_gain");
@ -73,10 +75,10 @@ public:
:Filter(audio_format),
mixer(_mixer), base(_base), mode(REPLAY_GAIN_OFF) {
info.Clear();
}
bool Open(Error &error) {
return pv.Open(out_audio_format.format, error);
Error error;
if (!pv.Open(out_audio_format.format, error))
throw std::runtime_error(error.GetMessage());
}
void SetInfo(const ReplayGainInfo *_info) {
@ -108,8 +110,7 @@ public:
void Update();
/* virtual methods from class Filter */
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedReplayGainFilter final : public PreparedFilter {
@ -134,7 +135,7 @@ public:
}
/* virtual methods from class Filter */
Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
void
@ -174,19 +175,13 @@ replay_gain_filter_init(gcc_unused const ConfigBlock &block,
}
Filter *
PreparedReplayGainFilter::Open(AudioFormat &af, gcc_unused Error &error)
PreparedReplayGainFilter::Open(AudioFormat &af)
{
auto *filter = new ReplayGainFilter(af, mixer, base);
if (!filter->Open(error)) {
delete filter;
return nullptr;
}
return filter;
return new ReplayGainFilter(af, mixer, base);
}
ConstBuffer<void>
ReplayGainFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
ReplayGainFilter::FilterPCM(ConstBuffer<void> src)
{
return mixer != nullptr
? src

View File

@ -96,8 +96,7 @@ public:
const std::array<int8_t, MAX_CHANNELS> &_sources);
/* virtual methods from class Filter */
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedRouteFilter final : public PreparedFilter {
@ -136,7 +135,7 @@ public:
bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class PreparedFilter */
Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
bool
@ -243,13 +242,13 @@ RouteFilter::RouteFilter(const AudioFormat &audio_format,
}
Filter *
PreparedRouteFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
PreparedRouteFilter::Open(AudioFormat &audio_format)
{
return new RouteFilter(audio_format, min_output_channels, sources);
}
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;

View File

@ -25,16 +25,19 @@
#include "pcm/Volume.hxx"
#include "AudioFormat.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include <stdexcept>
class VolumeFilter final : public Filter {
PcmVolume pv;
public:
explicit VolumeFilter(const AudioFormat &audio_format)
:Filter(audio_format) {}
bool Open(Error &error) {
return pv.Open(out_audio_format.format, error);
:Filter(audio_format) {
Error error;
if (!pv.Open(out_audio_format.format, error))
throw std::runtime_error(error.GetMessage());
}
unsigned GetVolume() const {
@ -46,8 +49,7 @@ public:
}
/* virtual methods from class Filter */
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
};
class PreparedVolumeFilter final : public PreparedFilter {
@ -55,7 +57,7 @@ class PreparedVolumeFilter final : public PreparedFilter {
public:
/* virtual methods from class Filter */
Filter *Open(AudioFormat &af, Error &error) override;
Filter *Open(AudioFormat &af) override;
};
static PreparedFilter *
@ -66,19 +68,13 @@ volume_filter_init(gcc_unused const ConfigBlock &block,
}
Filter *
PreparedVolumeFilter::Open(AudioFormat &audio_format, Error &error)
PreparedVolumeFilter::Open(AudioFormat &audio_format)
{
auto *filter = new VolumeFilter(audio_format);
if (!filter->Open(error)) {
delete filter;
return nullptr;
}
return filter;
return new VolumeFilter(audio_format);
}
ConstBuffer<void>
VolumeFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error)
VolumeFilter::FilterPCM(ConstBuffer<void> src)
{
return pv.Apply(src);
}

View File

@ -404,7 +404,10 @@ private:
*/
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.

View File

@ -93,38 +93,28 @@ AudioOutput::Disable()
}
inline AudioFormat
AudioOutput::OpenFilter(AudioFormat &format, Error &error_r)
{
AudioOutput::OpenFilter(AudioFormat &format)
try {
assert(format.IsValid());
/* the replay_gain filter cannot fail here */
if (prepared_replay_gain_filter != nullptr) {
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();
}
prepared_replay_gain_filter->Open(format);
if (prepared_other_replay_gain_filter != nullptr) {
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();
}
}
prepared_other_replay_gain_filter->Open(format);
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();
}
filter_instance = prepared_filter->Open(format);
if (mixer != nullptr && mixer->IsPlugin(software_mixer_plugin))
software_mixer_set_filter(*mixer, volume_filter.Get());
return filter_instance->GetOutAudioFormat();
} catch (...) {
CloseFilter();
throw;
}
void
@ -165,10 +155,11 @@ AudioOutput::Open()
/* open the filter */
const AudioFormat filter_audio_format =
OpenFilter(in_audio_format, error);
if (!filter_audio_format.IsDefined()) {
FormatError(error, "Failed to open filter for \"%s\" [%s]",
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);
fail_timer.Update();
@ -202,9 +193,10 @@ AudioOutput::Open()
return;
}
if (!convert_filter_set(convert_filter.Get(), out_audio_format,
error)) {
FormatError(error, "Failed to convert for \"%s\" [%s]",
try {
convert_filter_set(convert_filter.Get(), out_audio_format);
} catch (const std::runtime_error &e) {
FormatError(e, "Failed to convert for \"%s\" [%s]",
name, plugin.name);
mutex.unlock();
@ -295,12 +287,12 @@ AudioOutput::ReopenFilter()
CloseFilter();
mutex.lock();
const AudioFormat filter_audio_format =
OpenFilter(in_audio_format, error);
if (!filter_audio_format.IsDefined() ||
!convert_filter_set(convert_filter.Get(), out_audio_format,
error)) {
FormatError(error,
AudioFormat filter_audio_format;
try {
filter_audio_format = 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);
@ -383,11 +375,13 @@ ao_chunk_data(AudioOutput *ao, const MusicChunk *chunk,
*replay_gain_serial_p = chunk->replay_gain_serial;
}
Error error;
data = replay_gain_filter->FilterPCM(data, error);
if (data.IsNull())
FormatError(error, "\"%s\" [%s] failed to filter",
try {
data = replay_gain_filter->FilterPCM(data);
} catch (const std::runtime_error &e) {
FormatError(e, "\"%s\" [%s] failed to filter",
ao->name, ao->plugin.name);
return nullptr;
}
}
return data;
@ -449,15 +443,13 @@ ao_filter_chunk(AudioOutput *ao, const MusicChunk *chunk)
/* apply filter chain */
Error error;
data = ao->filter_instance->FilterPCM(data, error);
if (data.IsNull()) {
FormatError(error, "\"%s\" [%s] failed to filter",
try {
return ao->filter_instance->FilterPCM(data);
} catch (const std::runtime_error &e) {
FormatError(e, "\"%s\" [%s] failed to filter",
ao->name, ao->plugin.name);
return nullptr;
}
return data;
}
inline bool

View File

@ -105,13 +105,7 @@ try {
/* open the filter */
Error error;
std::unique_ptr<Filter> filter(prepared_filter->Open(audio_format,
error));
if (!filter) {
LogError(error, "Failed to open filter");
return EXIT_FAILURE;
}
std::unique_ptr<Filter> filter(prepared_filter->Open(audio_format));
const AudioFormat out_audio_format = filter->GetOutAudioFormat();
@ -127,12 +121,7 @@ try {
if (nbytes <= 0)
break;
auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes},
error);
if (dest.IsNull()) {
LogError(error, "filter/Filter failed");
return EXIT_FAILURE;
}
auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes});
nbytes = write(1, dest.data, dest.size);
if (nbytes < 0) {
@ -147,7 +136,7 @@ try {
config_global_finish();
return EXIT_SUCCESS;
} catch (const std::exception &e) {
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
}
}