From f12fa7e20a1e3a352faf401ea9ef2020ff105db2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 8 Nov 2016 15:40:19 +0100 Subject: [PATCH] output/shout: migrate from class Error to C++ exceptions --- src/output/plugins/ShoutOutputPlugin.cxx | 273 ++++++++--------------- 1 file changed, 99 insertions(+), 174 deletions(-) diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx index c12d81d8c..0d62b7e43 100644 --- a/src/output/plugins/ShoutOutputPlugin.cxx +++ b/src/output/plugins/ShoutOutputPlugin.cxx @@ -24,10 +24,8 @@ #include "encoder/EncoderInterface.hxx" #include "encoder/EncoderPlugin.hxx" #include "encoder/EncoderList.hxx" -#include "config/ConfigError.hxx" -#include "util/Error.hxx" +#include "util/RuntimeError.hxx" #include "util/Domain.hxx" -#include "system/FatalError.hxx" #include "Log.hxx" #include @@ -57,18 +55,9 @@ struct ShoutOutput final { uint8_t buffer[32768]; - ShoutOutput() - :base(shout_output_plugin), - shout_conn(shout_new()), - shout_meta(shout_metadata_new()) {} - + explicit ShoutOutput(const ConfigBlock &block); ~ShoutOutput(); - bool Initialize(const ConfigBlock &block, Error &error) { - return base.Configure(block, error); - } - - bool Configure(const ConfigBlock &block, Error &error); static ShoutOutput *Create(const ConfigBlock &block, Error &error); bool Open(AudioFormat &audio_format, Error &error); @@ -85,18 +74,16 @@ static int shout_init_count; static constexpr Domain shout_output_domain("shout_output"); -ShoutOutput::~ShoutOutput() +gcc_pure +static const char * +require_block_string(const ConfigBlock &block, const char *name) { - if (shout_meta != nullptr) - shout_metadata_free(shout_meta); - if (shout_conn != nullptr) - shout_free(shout_conn); + const char *value = block.GetBlockValue(name); + if (value == nullptr) + throw FormatRuntimeError("no \"%s\" defined for shout device defined " + "at line %d\n", name, block.line); - shout_init_count--; - if (shout_init_count == 0) - shout_shutdown(); - - delete prepared_encoder; + return value; } static const EncoderPlugin * @@ -110,36 +97,20 @@ shout_encoder_plugin_get(const char *name) return encoder_plugin_get(name); } -gcc_pure -static const char * -require_block_string(const ConfigBlock &block, const char *name) +ShoutOutput::ShoutOutput(const ConfigBlock &block) + :base(shout_output_plugin, block), + shout_conn(shout_new()), + shout_meta(shout_metadata_new()) { - const char *value = block.GetBlockValue(name); - if (value == nullptr) - FormatFatalError("no \"%s\" defined for shout device defined " - "at line %d\n", name, block.line); - - return value; -} - -inline bool -ShoutOutput::Configure(const ConfigBlock &block, Error &error) -{ - const AudioFormat audio_format = base.config_audio_format; - if (!audio_format.IsFullyDefined()) { - error.Set(config_domain, - "Need full audio format specification"); - return false; - } + if (!audio_format.IsFullyDefined()) + throw std::runtime_error("Need full audio format specification"); const char *host = require_block_string(block, "host"); const char *mount = require_block_string(block, "mount"); unsigned port = block.GetBlockValue("port", 0u); - if (port == 0) { - error.Set(config_domain, "shout port must be configured"); - return false; - } + if (port == 0) + throw std::runtime_error("shout port must be configured"); const char *passwd = require_block_string(block, "password"); const char *name = require_block_string(block, "name"); @@ -153,48 +124,33 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error) char *test; quality = strtod(value, &test); - if (*test != '\0' || quality < -1.0 || quality > 10.0) { - error.Format(config_domain, - "shout quality \"%s\" is not a number in the " - "range -1 to 10", - value); - return false; - } + if (*test != '\0' || quality < -1.0 || quality > 10.0) + throw FormatRuntimeError("shout 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 { 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"); char *test; bitrate = strtol(value, &test, 10); - if (*test != '\0' || bitrate <= 0) { - error.Set(config_domain, - "bitrate must be a positive integer"); - return false; - } + if (*test != '\0' || bitrate <= 0) + throw std::runtime_error("bitrate must be a positive integer"); } const char *encoding = block.GetBlockValue("encoder", nullptr); if (encoding == nullptr) encoding = block.GetBlockValue("encoding", "vorbis"); const auto encoder_plugin = shout_encoder_plugin_get(encoding); - if (encoder_plugin == nullptr) { - error.Format(config_domain, - "couldn't find shout encoder plugin \"%s\"", - encoding); - return false; - } + if (encoder_plugin == nullptr) + throw FormatRuntimeError("couldn't find shout encoder plugin \"%s\"", + encoding); prepared_encoder = encoder_init(*encoder_plugin, block); @@ -208,24 +164,19 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error) value = block.GetBlockValue("protocol"); if (value != nullptr) { if (0 == strcmp(value, "shoutcast") && - 0 != strcmp(encoding, "mp3")) { - error.Format(config_domain, - "you cannot stream \"%s\" to shoutcast, use mp3", - encoding); - return false; - } else if (0 == strcmp(value, "shoutcast")) + 0 != strcmp(encoding, "mp3")) + throw FormatRuntimeError("you cannot stream \"%s\" to shoutcast, use mp3", + encoding); + else if (0 == strcmp(value, "shoutcast")) protocol = SHOUT_PROTOCOL_ICY; else if (0 == strcmp(value, "icecast1")) protocol = SHOUT_PROTOCOL_XAUDIOCAST; else if (0 == strcmp(value, "icecast2")) protocol = SHOUT_PROTOCOL_HTTP; - else { - error.Format(config_domain, - "shout protocol \"%s\" is not \"shoutcast\" or " - "\"icecast1\"or \"icecast2\"", - value); - return false; - } + else + throw FormatRuntimeError("shout protocol \"%s\" is not \"shoutcast\" or " + "\"icecast1\"or \"icecast2\"", + value); } else { protocol = SHOUT_PROTOCOL_HTTP; } @@ -240,31 +191,23 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error) shout_set_format(shout_conn, shout_format) != SHOUTERR_SUCCESS || shout_set_protocol(shout_conn, protocol) != SHOUTERR_SUCCESS || - shout_set_agent(shout_conn, "MPD") != SHOUTERR_SUCCESS) { - error.Set(shout_output_domain, shout_get_error(shout_conn)); - return false; - } + shout_set_agent(shout_conn, "MPD") != SHOUTERR_SUCCESS) + throw std::runtime_error(shout_get_error(shout_conn)); /* optional paramters */ timeout = block.GetBlockValue("timeout", DEFAULT_CONN_TIMEOUT); value = block.GetBlockValue("genre"); - if (value != nullptr && shout_set_genre(shout_conn, value)) { - error.Set(shout_output_domain, shout_get_error(shout_conn)); - return false; - } + if (value != nullptr && shout_set_genre(shout_conn, value)) + throw std::runtime_error(shout_get_error(shout_conn)); value = block.GetBlockValue("description"); - if (value != nullptr && shout_set_description(shout_conn, value)) { - error.Set(shout_output_domain, shout_get_error(shout_conn)); - return false; - } + if (value != nullptr && shout_set_description(shout_conn, value)) + throw std::runtime_error(shout_get_error(shout_conn)); value = block.GetBlockValue("url"); - if (value != nullptr && shout_set_url(shout_conn, value)) { - error.Set(shout_output_domain, shout_get_error(shout_conn)); - return false; - } + if (value != nullptr && shout_set_url(shout_conn, value)) + throw std::runtime_error(shout_get_error(shout_conn)); { char temp[11]; @@ -286,39 +229,35 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error) temp); } } +} - return true; +ShoutOutput::~ShoutOutput() +{ + if (shout_meta != nullptr) + shout_metadata_free(shout_meta); + if (shout_conn != nullptr) + shout_free(shout_conn); + + shout_init_count--; + if (shout_init_count == 0) + shout_shutdown(); + + delete prepared_encoder; } ShoutOutput * -ShoutOutput::Create(const ConfigBlock &block, Error &error) +ShoutOutput::Create(const ConfigBlock &block, Error &) { if (shout_init_count == 0) shout_init(); shout_init_count++; - ShoutOutput *sd = new ShoutOutput(); - if (!sd->Initialize(block, error)) { - delete sd; - return nullptr; - } - - try { - if (!sd->Configure(block, error)) { - delete sd; - return nullptr; - } - } catch (...) { - delete sd; - throw; - } - - return sd; + return new ShoutOutput(block); } -static bool -handle_shout_error(ShoutOutput *sd, int err, Error &error) +static void +handle_shout_error(ShoutOutput *sd, int err) { switch (err) { case SHOUTERR_SUCCESS: @@ -326,27 +265,21 @@ handle_shout_error(ShoutOutput *sd, int err, Error &error) case SHOUTERR_UNCONNECTED: case SHOUTERR_SOCKET: - error.Format(shout_output_domain, err, - "Lost shout connection to %s:%i: %s", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - shout_get_error(sd->shout_conn)); - return false; + throw FormatRuntimeError("Lost shout connection to %s:%i: %s", + shout_get_host(sd->shout_conn), + shout_get_port(sd->shout_conn), + shout_get_error(sd->shout_conn)); default: - error.Format(shout_output_domain, err, - "connection to %s:%i error: %s", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - shout_get_error(sd->shout_conn)); - return false; + throw FormatRuntimeError("connection to %s:%i error: %s", + shout_get_host(sd->shout_conn), + shout_get_port(sd->shout_conn), + shout_get_error(sd->shout_conn)); } - - return true; } static bool -write_page(ShoutOutput *sd, Error &error) +write_page(ShoutOutput *sd) { assert(sd->encoder != nullptr); @@ -357,8 +290,7 @@ write_page(ShoutOutput *sd, Error &error) return true; int err = shout_send(sd->shout_conn, sd->buffer, nbytes); - if (!handle_shout_error(sd, err, error)) - return false; + handle_shout_error(sd, err); } return true; @@ -370,7 +302,7 @@ ShoutOutput::Close() if (encoder != nullptr) { try { encoder->End(); - write_page(this, IgnoreError()); + write_page(this); } catch (const std::runtime_error &) { /* ignore */ } @@ -392,39 +324,32 @@ ShoutOutput::Cancel() /* needs to be implemented for shout */ } -static bool -shout_connect(ShoutOutput *sd, Error &error) +static void +shout_connect(ShoutOutput *sd) { switch (shout_open(sd->shout_conn)) { case SHOUTERR_SUCCESS: case SHOUTERR_CONNECTED: - return true; + break; default: - error.Format(shout_output_domain, - "problem opening connection to shout server %s:%i: %s", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - shout_get_error(sd->shout_conn)); - return false; + throw FormatRuntimeError("problem opening connection to shout server %s:%i: %s", + shout_get_host(sd->shout_conn), + shout_get_port(sd->shout_conn), + shout_get_error(sd->shout_conn)); } } bool -ShoutOutput::Open(AudioFormat &audio_format, Error &error) +ShoutOutput::Open(AudioFormat &audio_format, Error &) { - if (!shout_connect(this, error)) - return false; + shout_connect(this); try { encoder = prepared_encoder->Open(audio_format); try { - if (!write_page(this, error)) { - delete encoder; - shout_close(shout_conn); - return false; - } + write_page(this); } catch (const std::runtime_error &) { delete encoder; throw; @@ -448,12 +373,11 @@ ShoutOutput::Delay() const } size_t -ShoutOutput::Play(const void *chunk, size_t size, Error &error) +ShoutOutput::Play(const void *chunk, size_t size, Error &) { encoder->Write(chunk, size); - return write_page(this, error) - ? size - : 0; + write_page(this); + return size; } bool @@ -461,7 +385,14 @@ ShoutOutput::Pause() { static char silence[1020]; - return Play(silence, sizeof(silence), IgnoreError()); + try { + encoder->Write(silence, sizeof(silence)); + write_page(this); + } catch (const std::runtime_error &) { + return false; + } + + return true; } static void @@ -497,13 +428,7 @@ ShoutOutput::SendTag(const Tag &tag) /* encoder plugin supports stream tags */ encoder->PreTag(); - - Error error; - if (!write_page(this, error)) { - LogError(error); - return; - } - + write_page(this); encoder->SendTag(tag); } else { /* no stream tag support: fall back to icy-metadata */ @@ -518,7 +443,7 @@ ShoutOutput::SendTag(const Tag &tag) } } - write_page(this, IgnoreError()); + write_page(this); } typedef AudioOutputWrapper Wrapper;