diff --git a/src/encoder/EncoderInterface.hxx b/src/encoder/EncoderInterface.hxx index 791752f85..fccb5dff2 100644 --- a/src/encoder/EncoderInterface.hxx +++ b/src/encoder/EncoderInterface.hxx @@ -28,6 +28,7 @@ struct AudioFormat; struct Tag; +class Error; class Encoder { const bool implements_tag; diff --git a/src/encoder/EncoderPlugin.hxx b/src/encoder/EncoderPlugin.hxx index 83792f3a7..d404de44e 100644 --- a/src/encoder/EncoderPlugin.hxx +++ b/src/encoder/EncoderPlugin.hxx @@ -22,27 +22,27 @@ class PreparedEncoder; struct ConfigBlock; -class Error; struct EncoderPlugin { const char *name; - PreparedEncoder *(*init)(const ConfigBlock &block, - Error &error); + /** + * Throws #std::runtime_error on error. + */ + PreparedEncoder *(*init)(const ConfigBlock &block); }; /** * Creates a new encoder object. * + * Throws #std::runtime_error on error. + * * @param plugin the encoder plugin - * @param error location to store the error occurring, or nullptr to ignore errors. - * @return an encoder object on success, nullptr on failure */ static inline PreparedEncoder * -encoder_init(const EncoderPlugin &plugin, const ConfigBlock &block, - Error &error) +encoder_init(const EncoderPlugin &plugin, const ConfigBlock &block) { - return plugin.init(block, error); + return plugin.init(block); } #endif diff --git a/src/encoder/plugins/FlacEncoderPlugin.cxx b/src/encoder/plugins/FlacEncoderPlugin.cxx index f26efd8e0..7f5b3a889 100644 --- a/src/encoder/plugins/FlacEncoderPlugin.cxx +++ b/src/encoder/plugins/FlacEncoderPlugin.cxx @@ -89,10 +89,10 @@ private: }; class PreparedFlacEncoder final : public PreparedEncoder { - unsigned compression; + const unsigned compression; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedFlacEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -104,26 +104,15 @@ public: static constexpr Domain flac_encoder_domain("vorbis_encoder"); -bool -PreparedFlacEncoder::Configure(const ConfigBlock &block, Error &) +PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block) + :compression(block.GetBlockValue("compression", 5u)) { - compression = block.GetBlockValue("compression", 5u); - return true; } static PreparedEncoder * -flac_encoder_init(const ConfigBlock &block, Error &error) +flac_encoder_init(const ConfigBlock &block) { - auto *encoder = new PreparedFlacEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedFlacEncoder(block); } static bool diff --git a/src/encoder/plugins/LameEncoderPlugin.cxx b/src/encoder/plugins/LameEncoderPlugin.cxx index 8d4c0b2bf..781672d06 100644 --- a/src/encoder/plugins/LameEncoderPlugin.cxx +++ b/src/encoder/plugins/LameEncoderPlugin.cxx @@ -24,6 +24,7 @@ #include "config/ConfigError.hxx" #include "util/NumberParser.hxx" #include "util/ReusableArray.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" @@ -58,7 +59,7 @@ class PreparedLameEncoder final : public PreparedEncoder { int bitrate; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedLameEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -70,8 +71,7 @@ public: static constexpr Domain lame_encoder_domain("lame_encoder"); -bool -PreparedLameEncoder::Configure(const ConfigBlock &block, Error &error) +PreparedLameEncoder::PreparedLameEncoder(const ConfigBlock &block) { const char *value; char *endptr; @@ -82,55 +82,32 @@ PreparedLameEncoder::Configure(const ConfigBlock &block, Error &error) quality = ParseDouble(value, &endptr); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) { - error.Format(config_domain, - "quality \"%s\" is not a number in the " - "range -1 to 10", - value); - return false; - } + if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + throw FormatRuntimeError("quality \"%s\" is not a number in the " + "range -1 to 10", + value); - if (block.GetBlockValue("bitrate") != nullptr) { - error.Set(config_domain, - "quality and bitrate are both defined"); - return false; - } + if (block.GetBlockValue("bitrate") != nullptr) + throw std::runtime_error("quality and bitrate are both defined"); } else { /* a bit rate was configured */ value = block.GetBlockValue("bitrate"); - if (value == nullptr) { - error.Set(config_domain, - "neither bitrate nor quality defined"); - return false; - } + if (value == nullptr) + throw std::runtime_error("neither bitrate nor quality defined"); quality = -2.0; bitrate = ParseInt(value, &endptr); - if (*endptr != '\0' || bitrate <= 0) { - error.Set(config_domain, - "bitrate should be a positive integer"); - return false; - } + if (*endptr != '\0' || bitrate <= 0) + throw std::runtime_error("bitrate should be a positive integer"); } - - return true; } static PreparedEncoder * -lame_encoder_init(const ConfigBlock &block, Error &error) +lame_encoder_init(const ConfigBlock &block) { - auto *encoder = new PreparedLameEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedLameEncoder(block); } static bool diff --git a/src/encoder/plugins/NullEncoderPlugin.cxx b/src/encoder/plugins/NullEncoderPlugin.cxx index 7f64effbe..aa12d8b06 100644 --- a/src/encoder/plugins/NullEncoderPlugin.cxx +++ b/src/encoder/plugins/NullEncoderPlugin.cxx @@ -51,8 +51,7 @@ public: }; static PreparedEncoder * -null_encoder_init(gcc_unused const ConfigBlock &block, - gcc_unused Error &error) +null_encoder_init(gcc_unused const ConfigBlock &block) { return new PreparedNullEncoder(); } diff --git a/src/encoder/plugins/OpusEncoderPlugin.cxx b/src/encoder/plugins/OpusEncoderPlugin.cxx index 63fcf557d..8c1469509 100644 --- a/src/encoder/plugins/OpusEncoderPlugin.cxx +++ b/src/encoder/plugins/OpusEncoderPlugin.cxx @@ -30,6 +30,8 @@ #include #include +#include + #include #include @@ -78,7 +80,7 @@ class PreparedOpusEncoder final : public PreparedEncoder { int signal; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedOpusEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -90,8 +92,7 @@ public: static constexpr Domain opus_encoder_domain("opus_encoder"); -bool -PreparedOpusEncoder::Configure(const ConfigBlock &block, Error &error) +PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block) { const char *value = block.GetBlockValue("bitrate", "auto"); if (strcmp(value, "auto") == 0) @@ -102,17 +103,13 @@ PreparedOpusEncoder::Configure(const ConfigBlock &block, Error &error) char *endptr; bitrate = strtoul(value, &endptr, 10); if (endptr == value || *endptr != 0 || - bitrate < 500 || bitrate > 512000) { - error.Set(config_domain, "Invalid bit rate"); - return false; - } + bitrate < 500 || bitrate > 512000) + throw std::runtime_error("Invalid bit rate"); } complexity = block.GetBlockValue("complexity", 10u); - if (complexity > 10) { - error.Format(config_domain, "Invalid complexity"); - return false; - } + if (complexity > 10) + throw std::runtime_error("Invalid complexity"); value = block.GetBlockValue("signal", "auto"); if (strcmp(value, "auto") == 0) @@ -121,27 +118,14 @@ PreparedOpusEncoder::Configure(const ConfigBlock &block, Error &error) signal = OPUS_SIGNAL_VOICE; else if (strcmp(value, "music") == 0) signal = OPUS_SIGNAL_MUSIC; - else { - error.Format(config_domain, "Invalid signal"); - return false; - } - - return true; + else + throw std::runtime_error("Invalid signal"); } static PreparedEncoder * -opus_encoder_init(const ConfigBlock &block, Error &error) +opus_encoder_init(const ConfigBlock &block) { - auto *encoder = new PreparedOpusEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedOpusEncoder(block); } OpusEncoder::OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc) diff --git a/src/encoder/plugins/ShineEncoderPlugin.cxx b/src/encoder/plugins/ShineEncoderPlugin.cxx index 39f30d060..b05de32f6 100644 --- a/src/encoder/plugins/ShineEncoderPlugin.cxx +++ b/src/encoder/plugins/ShineEncoderPlugin.cxx @@ -88,7 +88,7 @@ class PreparedShineEncoder final : public PreparedEncoder { shine_config_t config; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedShineEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -98,28 +98,16 @@ public: } }; -inline bool -PreparedShineEncoder::Configure(const ConfigBlock &block, Error &) +PreparedShineEncoder::PreparedShineEncoder(const ConfigBlock &block) { shine_set_config_mpeg_defaults(&config.mpeg); config.mpeg.bitr = block.GetBlockValue("bitrate", 128); - - return true; } static PreparedEncoder * -shine_encoder_init(const ConfigBlock &block, Error &error) +shine_encoder_init(const ConfigBlock &block) { - auto *encoder = new PreparedShineEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedShineEncoder(block); } static shine_t diff --git a/src/encoder/plugins/TwolameEncoderPlugin.cxx b/src/encoder/plugins/TwolameEncoderPlugin.cxx index 7ef02addb..ba980b05c 100644 --- a/src/encoder/plugins/TwolameEncoderPlugin.cxx +++ b/src/encoder/plugins/TwolameEncoderPlugin.cxx @@ -23,6 +23,7 @@ #include "AudioFormat.hxx" #include "config/ConfigError.hxx" #include "util/NumberParser.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -77,7 +78,7 @@ class PreparedTwolameEncoder final : public PreparedEncoder { int bitrate; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedTwolameEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -89,8 +90,7 @@ public: static constexpr Domain twolame_encoder_domain("twolame_encoder"); -bool -PreparedTwolameEncoder::Configure(const ConfigBlock &block, Error &error) +PreparedTwolameEncoder::PreparedTwolameEncoder(const ConfigBlock &block) { const char *value; char *endptr; @@ -101,58 +101,35 @@ PreparedTwolameEncoder::Configure(const ConfigBlock &block, Error &error) quality = ParseDouble(value, &endptr); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) { - error.Format(config_domain, - "quality \"%s\" is not a number in the " - "range -1 to 10", - value); - return false; - } + if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + throw FormatRuntimeError("quality \"%s\" is not a number in the " + "range -1 to 10", + value); - if (block.GetBlockValue("bitrate") != nullptr) { - error.Set(config_domain, - "quality and bitrate are both defined"); - return false; - } + if (block.GetBlockValue("bitrate") != nullptr) + throw std::runtime_error("quality and bitrate are both defined"); } else { /* a bit rate was configured */ value = block.GetBlockValue("bitrate"); - if (value == nullptr) { - error.Set(config_domain, - "neither bitrate nor quality defined"); - return false; - } + if (value == nullptr) + throw std::runtime_error("neither bitrate nor quality defined"); quality = -2.0; bitrate = ParseInt(value, &endptr); - if (*endptr != '\0' || bitrate <= 0) { - error.Set(config_domain, - "bitrate should be a positive integer"); - return false; - } + if (*endptr != '\0' || bitrate <= 0) + throw std::runtime_error("bitrate should be a positive integer"); } - - return true; } static PreparedEncoder * -twolame_encoder_init(const ConfigBlock &block, Error &error_r) +twolame_encoder_init(const ConfigBlock &block) { FormatDebug(twolame_encoder_domain, "libtwolame version %s", get_twolame_version()); - auto *encoder = new PreparedTwolameEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error_r)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedTwolameEncoder(block); } static bool diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx index 5ca2346a0..94c7ff80b 100644 --- a/src/encoder/plugins/VorbisEncoderPlugin.cxx +++ b/src/encoder/plugins/VorbisEncoderPlugin.cxx @@ -25,6 +25,7 @@ #include "config/ConfigError.hxx" #include "util/StringUtil.hxx" #include "util/NumberParser.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" @@ -73,7 +74,7 @@ class PreparedVorbisEncoder final : public PreparedEncoder { int bitrate; public: - bool Configure(const ConfigBlock &block, Error &error); + PreparedVorbisEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ Encoder *Open(AudioFormat &audio_format, Error &) override; @@ -85,8 +86,7 @@ public: static constexpr Domain vorbis_encoder_domain("vorbis_encoder"); -bool -PreparedVorbisEncoder::Configure(const ConfigBlock &block, Error &error) +PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block) { const char *value = block.GetBlockValue("quality"); if (value != nullptr) { @@ -95,56 +95,33 @@ PreparedVorbisEncoder::Configure(const ConfigBlock &block, Error &error) char *endptr; quality = ParseDouble(value, &endptr); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) { - error.Format(config_domain, - "quality \"%s\" is not a number in the " - "range -1 to 10", - value); - return false; - } + if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + throw FormatRuntimeError("quality \"%s\" is not a number in the " + "range -1 to 10", + value); - if (block.GetBlockValue("bitrate") != nullptr) { - error.Set(config_domain, - "quality and bitrate are both defined"); - return false; - } + if (block.GetBlockValue("bitrate") != nullptr) + throw std::runtime_error("quality and bitrate are both defined"); } else { /* a bit rate was configured */ value = block.GetBlockValue("bitrate"); - if (value == nullptr) { - error.Set(config_domain, - "neither bitrate nor quality defined"); - return false; - } + if (value == nullptr) + throw std::runtime_error("neither bitrate nor quality defined"); quality = -2.0; char *endptr; bitrate = ParseInt(value, &endptr); - if (*endptr != '\0' || bitrate <= 0) { - error.Set(config_domain, - "bitrate should be a positive integer"); - return false; - } + if (*endptr != '\0' || bitrate <= 0) + throw std::runtime_error("bitrate should be a positive integer"); } - - return true; } static PreparedEncoder * -vorbis_encoder_init(const ConfigBlock &block, Error &error) +vorbis_encoder_init(const ConfigBlock &block) { - auto *encoder = new PreparedVorbisEncoder(); - - /* load configuration from "block" */ - if (!encoder->Configure(block, error)) { - /* configuration has failed, roll back and return error */ - delete encoder; - return nullptr; - } - - return encoder; + return new PreparedVorbisEncoder(block); } bool diff --git a/src/encoder/plugins/WaveEncoderPlugin.cxx b/src/encoder/plugins/WaveEncoderPlugin.cxx index 140266984..90be1d296 100644 --- a/src/encoder/plugins/WaveEncoderPlugin.cxx +++ b/src/encoder/plugins/WaveEncoderPlugin.cxx @@ -98,8 +98,7 @@ fill_wave_header(WaveHeader *header, int channels, int bits, } static PreparedEncoder * -wave_encoder_init(gcc_unused const ConfigBlock &block, - gcc_unused Error &error) +wave_encoder_init(gcc_unused const ConfigBlock &block) { return new PreparedWaveEncoder(); } diff --git a/src/output/plugins/RecorderOutputPlugin.cxx b/src/output/plugins/RecorderOutputPlugin.cxx index da03668ca..6cf3af624 100644 --- a/src/output/plugins/RecorderOutputPlugin.cxx +++ b/src/output/plugins/RecorderOutputPlugin.cxx @@ -148,9 +148,7 @@ RecorderOutput::Configure(const ConfigBlock &block, Error &error) /* initialize encoder */ - prepared_encoder = encoder_init(*encoder_plugin, block, error); - if (prepared_encoder == nullptr) - return false; + prepared_encoder = encoder_init(*encoder_plugin, block); return true; } @@ -160,14 +158,19 @@ RecorderOutput::Create(const ConfigBlock &block, Error &error) { RecorderOutput *recorder = new RecorderOutput(); - if (!recorder->Initialize(block, error)) { - delete recorder; - return nullptr; - } + try { + if (!recorder->Initialize(block, error)) { + delete recorder; + return nullptr; + } - if (!recorder->Configure(block, error)) { + if (!recorder->Configure(block, error)) { + delete recorder; + return nullptr; + } + } catch (...) { delete recorder; - return nullptr; + throw; } return recorder; diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx index a36444ef9..43f79f6f7 100644 --- a/src/output/plugins/ShoutOutputPlugin.cxx +++ b/src/output/plugins/ShoutOutputPlugin.cxx @@ -194,9 +194,7 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error) return false; } - prepared_encoder = encoder_init(*encoder_plugin, block, error); - if (prepared_encoder == nullptr) - return false; + prepared_encoder = encoder_init(*encoder_plugin, block); unsigned shout_format; if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0) @@ -304,9 +302,14 @@ ShoutOutput::Create(const ConfigBlock &block, Error &error) return nullptr; } - if (!sd->Configure(block, error)) { + try { + if (!sd->Configure(block, error)) { + delete sd; + return nullptr; + } + } catch (...) { delete sd; - return nullptr; + throw; } return sd; diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.cxx b/src/output/plugins/httpd/HttpdOutputPlugin.cxx index 15115bb2b..bacc350bc 100644 --- a/src/output/plugins/httpd/HttpdOutputPlugin.cxx +++ b/src/output/plugins/httpd/HttpdOutputPlugin.cxx @@ -117,9 +117,7 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error) /* initialize encoder */ - prepared_encoder = encoder_init(*encoder_plugin, block, error); - if (prepared_encoder == nullptr) - return false; + prepared_encoder = encoder_init(*encoder_plugin, block); /* determine content type */ content_type = prepared_encoder->GetMimeType(); diff --git a/test/run_encoder.cxx b/test/run_encoder.cxx index 52857c2e8..5775a9b25 100644 --- a/test/run_encoder.cxx +++ b/test/run_encoder.cxx @@ -67,11 +67,7 @@ int main(int argc, char **argv) try { Error error; - std::unique_ptr p_encoder(encoder_init(*plugin, block, error)); - if (p_encoder == nullptr) { - LogError(error, "Failed to initialize encoder"); - return EXIT_FAILURE; - } + std::unique_ptr p_encoder(encoder_init(*plugin, block)); /* open the encoder */ diff --git a/test/test_vorbis_encoder.cxx b/test/test_vorbis_encoder.cxx index fb4a619dd..054700c2e 100644 --- a/test/test_vorbis_encoder.cxx +++ b/test/test_vorbis_encoder.cxx @@ -39,7 +39,7 @@ static uint8_t zero[256]; int main(gcc_unused int argc, gcc_unused char **argv) -{ +try { gcc_unused bool success; /* create the encoder */ @@ -50,65 +50,62 @@ main(gcc_unused int argc, gcc_unused char **argv) ConfigBlock block; block.AddBlockParam("quality", "5.0", -1); - std::unique_ptr p_encoder(encoder_init(*plugin, block, - IgnoreError())); + std::unique_ptr p_encoder(encoder_init(*plugin, block)); assert(p_encoder != nullptr); - try { - /* open the encoder */ + /* open the encoder */ - AudioFormat audio_format(44100, SampleFormat::S16, 2); - std::unique_ptr encoder(p_encoder->Open(audio_format, - IgnoreError())); - assert(encoder != nullptr); + AudioFormat audio_format(44100, SampleFormat::S16, 2); + std::unique_ptr encoder(p_encoder->Open(audio_format, + IgnoreError())); + assert(encoder != nullptr); - StdioOutputStream os(stdout); + StdioOutputStream os(stdout); - EncoderToOutputStream(os, *encoder); + EncoderToOutputStream(os, *encoder); - /* write a block of data */ + /* write a block of data */ - success = encoder->Write(zero, sizeof(zero), IgnoreError()); - assert(success); + success = encoder->Write(zero, sizeof(zero), IgnoreError()); + assert(success); - EncoderToOutputStream(os, *encoder); + EncoderToOutputStream(os, *encoder); - /* write a tag */ + /* write a tag */ - success = encoder->PreTag(IgnoreError()); - assert(success); + success = encoder->PreTag(IgnoreError()); + assert(success); - EncoderToOutputStream(os, *encoder); + EncoderToOutputStream(os, *encoder); - Tag tag; + Tag tag; - { - TagBuilder tag_builder; - tag_builder.AddItem(TAG_ARTIST, "Foo"); - tag_builder.AddItem(TAG_TITLE, "Bar"); - tag_builder.Commit(tag); - } - - success = encoder->SendTag(tag, IgnoreError()); - assert(success); - - EncoderToOutputStream(os, *encoder); - - /* write another block of data */ - - success = encoder->Write(zero, sizeof(zero), IgnoreError()); - assert(success); - - /* finish */ - - success = encoder->End(IgnoreError()); - assert(success); - - EncoderToOutputStream(os, *encoder); - - return EXIT_SUCCESS; - } catch (const std::exception &e) { - LogError(e); - return EXIT_FAILURE; + { + TagBuilder tag_builder; + tag_builder.AddItem(TAG_ARTIST, "Foo"); + tag_builder.AddItem(TAG_TITLE, "Bar"); + tag_builder.Commit(tag); } + + success = encoder->SendTag(tag, IgnoreError()); + assert(success); + + EncoderToOutputStream(os, *encoder); + + /* write another block of data */ + + success = encoder->Write(zero, sizeof(zero), IgnoreError()); + assert(success); + + /* finish */ + + success = encoder->End(IgnoreError()); + assert(success); + + EncoderToOutputStream(os, *encoder); + + return EXIT_SUCCESS; +} catch (const std::exception &e) { + LogError(e); + return EXIT_FAILURE; }