diff --git a/src/encoder/EncoderInterface.hxx b/src/encoder/EncoderInterface.hxx index fccb5dff2..47f05c07d 100644 --- a/src/encoder/EncoderInterface.hxx +++ b/src/encoder/EncoderInterface.hxx @@ -28,7 +28,6 @@ struct AudioFormat; struct Tag; -class Error; class Encoder { const bool implements_tag; @@ -51,20 +50,18 @@ public: * usable for more data, and only Read() and Close() can be * called. * - * @return true on success + * Throws #std::runtime_error on error. */ - virtual bool End(gcc_unused Error &error) { - return true; + virtual void End() { } /** * Flushes an encoder object, make everything which might * currently be buffered available by Read(). * - * @return true on success + * Throws #std::runtime_error on error. */ - virtual bool Flush(gcc_unused Error &error) { - return true; + virtual void Flush() { } /** @@ -72,10 +69,9 @@ public: * some encoders to flush the previous sub-stream, in * preparation to begin a new one. * - * @return true on success + * Throws #std::runtime_error on error. */ - virtual bool PreTag(gcc_unused Error &error) { - return true; + virtual void PreTag() { } /** @@ -84,23 +80,22 @@ public: * Instructions: call PreTag(); then obtain flushed data with * Read(); finally call Tag(). * + * Throws #std::runtime_error on error. + * * @param tag the tag object - * @return true on success */ - virtual bool SendTag(gcc_unused const Tag &tag, - gcc_unused Error &error) { - return true; + virtual void SendTag(gcc_unused const Tag &tag) { } /** * Writes raw PCM data to the encoder. * + * Throws #std::runtime_error on error. + * * @param data the buffer containing PCM samples * @param length the length of the buffer in bytes - * @return true on success */ - virtual bool Write(const void *data, size_t length, - Error &error) = 0; + virtual void Write(const void *data, size_t length) = 0; /** * Reads encoded data from the encoder. @@ -127,11 +122,12 @@ public: * first encoder_write() call, you should invoke * encoder_read() to obtain the file header. * + * Throws #std::runtime_error on error. + * * @param audio_format the encoder's input audio format; the plugin * may modify the struct to adapt it to its abilities - * @return true on success */ - virtual Encoder *Open(AudioFormat &audio_format, Error &error) = 0; + virtual Encoder *Open(AudioFormat &audio_format) = 0; /** * Get mime type of encoded content. diff --git a/src/encoder/plugins/FlacEncoderPlugin.cxx b/src/encoder/plugins/FlacEncoderPlugin.cxx index 7f5b3a889..7d58d9166 100644 --- a/src/encoder/plugins/FlacEncoderPlugin.cxx +++ b/src/encoder/plugins/FlacEncoderPlugin.cxx @@ -24,8 +24,7 @@ #include "pcm/PcmBuffer.hxx" #include "config/ConfigError.hxx" #include "util/DynamicFifoBuffer.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" +#include "util/RuntimeError.hxx" #include @@ -47,29 +46,22 @@ class FlacEncoder final : public Encoder { DynamicFifoBuffer output_buffer; public: - FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse) - :Encoder(false), - audio_format(_audio_format), fse(_fse), - output_buffer(8192) {} + FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse); ~FlacEncoder() override { FLAC__stream_encoder_delete(fse); } - bool Init(Error &error); - /* virtual methods from class Encoder */ - bool End(Error &) override { + void End() override { (void) FLAC__stream_encoder_finish(fse); - return true; } - bool Flush(Error &) override { + void Flush() override { (void) FLAC__stream_encoder_finish(fse); - return true; } - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override { return output_buffer.Read((uint8_t *)dest, length); @@ -95,15 +87,13 @@ public: PreparedFlacEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/flac"; } }; -static constexpr Domain flac_encoder_domain("vorbis_encoder"); - PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block) :compression(block.GetBlockValue("compression", 5u)) { @@ -115,45 +105,32 @@ flac_encoder_init(const ConfigBlock &block) return new PreparedFlacEncoder(block); } -static bool +static void flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression, - const AudioFormat &audio_format, unsigned bits_per_sample, - Error &error) + const AudioFormat &audio_format, unsigned bits_per_sample) { - if (!FLAC__stream_encoder_set_compression_level(fse, compression)) { - error.Format(config_domain, - "error setting flac compression to %d", - compression); - return false; - } + if (!FLAC__stream_encoder_set_compression_level(fse, compression)) + throw FormatRuntimeError("error setting flac compression to %d", + compression); - if (!FLAC__stream_encoder_set_channels(fse, audio_format.channels)) { - error.Format(config_domain, - "error setting flac channels num to %d", - audio_format.channels); - return false; - } + if (!FLAC__stream_encoder_set_channels(fse, audio_format.channels)) + throw FormatRuntimeError("error setting flac channels num to %d", + audio_format.channels); - if (!FLAC__stream_encoder_set_bits_per_sample(fse, bits_per_sample)) { - error.Format(config_domain, - "error setting flac bit format to %d", - bits_per_sample); - return false; - } + if (!FLAC__stream_encoder_set_bits_per_sample(fse, bits_per_sample)) + throw FormatRuntimeError("error setting flac bit format to %d", + bits_per_sample); if (!FLAC__stream_encoder_set_sample_rate(fse, - audio_format.sample_rate)) { - error.Format(config_domain, - "error setting flac sample rate to %d", - audio_format.sample_rate); - return false; - } - - return true; + audio_format.sample_rate)) + throw FormatRuntimeError("error setting flac sample rate to %d", + audio_format.sample_rate); } -bool -FlacEncoder::Init(Error &error) +FlacEncoder::FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse) + :Encoder(false), + audio_format(_audio_format), fse(_fse), + output_buffer(8192) { /* this immediately outputs data through callback */ @@ -163,18 +140,13 @@ FlacEncoder::Init(Error &error) nullptr, nullptr, nullptr, this); - if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { - error.Format(flac_encoder_domain, - "failed to initialize encoder: %s\n", - FLAC__StreamEncoderInitStatusString[init_status]); - return false; - } - - return true; + if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) + throw FormatRuntimeError("failed to initialize encoder: %s\n", + FLAC__StreamEncoderInitStatusString[init_status]); } Encoder * -PreparedFlacEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedFlacEncoder::Open(AudioFormat &audio_format) { unsigned bits_per_sample; @@ -199,24 +171,18 @@ PreparedFlacEncoder::Open(AudioFormat &audio_format, Error &error) /* allocate the encoder */ auto fse = FLAC__stream_encoder_new(); - if (fse == nullptr) { - error.Set(flac_encoder_domain, "FLAC__stream_encoder_new() failed"); - return nullptr; - } + if (fse == nullptr) + throw std::runtime_error("FLAC__stream_encoder_new() failed"); - if (!flac_encoder_setup(fse, compression, - audio_format, bits_per_sample, error)) { + try { + flac_encoder_setup(fse, compression, + audio_format, bits_per_sample); + } catch (...) { FLAC__stream_encoder_delete(fse); - return nullptr; + throw; } - auto *e = new FlacEncoder(audio_format, fse); - if (!e->Init(error)) { - delete e; - return nullptr; - } - - return e; + return new FlacEncoder(audio_format, fse); } static inline void @@ -237,8 +203,8 @@ pcm16_to_flac(int32_t *out, const int16_t *in, unsigned num_samples) } } -bool -FlacEncoder::Write(const void *data, size_t length, Error &error) +void +FlacEncoder::Write(const void *data, size_t length) { void *exbuffer; const void *buffer = nullptr; @@ -278,12 +244,8 @@ FlacEncoder::Write(const void *data, size_t length, Error &error) if (!FLAC__stream_encoder_process_interleaved(fse, (const FLAC__int32 *)buffer, - num_frames)) { - error.Set(flac_encoder_domain, "flac encoder process failed"); - return false; - } - - return true; + num_frames)) + throw std::runtime_error("flac encoder process failed"); } const EncoderPlugin flac_encoder_plugin = { diff --git a/src/encoder/plugins/LameEncoderPlugin.cxx b/src/encoder/plugins/LameEncoderPlugin.cxx index 781672d06..82fd5849f 100644 --- a/src/encoder/plugins/LameEncoderPlugin.cxx +++ b/src/encoder/plugins/LameEncoderPlugin.cxx @@ -25,11 +25,11 @@ #include "util/NumberParser.hxx" #include "util/ReusableArray.hxx" #include "util/RuntimeError.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" #include +#include + #include #include @@ -50,7 +50,7 @@ public: ~LameEncoder() override; /* virtual methods from class Encoder */ - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override; }; @@ -62,15 +62,13 @@ public: PreparedLameEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/mpeg"; } }; -static constexpr Domain lame_encoder_domain("lame_encoder"); - PreparedLameEncoder::PreparedLameEncoder(const ConfigBlock &block) { const char *value; @@ -110,76 +108,53 @@ lame_encoder_init(const ConfigBlock &block) return new PreparedLameEncoder(block); } -static bool +static void lame_encoder_setup(lame_global_flags *gfp, float quality, int bitrate, - const AudioFormat &audio_format, Error &error) + const AudioFormat &audio_format) { if (quality >= -1.0) { /* a quality was configured (VBR) */ - if (0 != lame_set_VBR(gfp, vbr_rh)) { - error.Set(lame_encoder_domain, - "error setting lame VBR mode"); - return false; - } - if (0 != lame_set_VBR_q(gfp, quality)) { - error.Set(lame_encoder_domain, - "error setting lame VBR quality"); - return false; - } + if (0 != lame_set_VBR(gfp, vbr_rh)) + throw std::runtime_error("error setting lame VBR mode"); + + if (0 != lame_set_VBR_q(gfp, quality)) + throw std::runtime_error("error setting lame VBR quality"); } else { /* a bit rate was configured */ - if (0 != lame_set_brate(gfp, bitrate)) { - error.Set(lame_encoder_domain, - "error setting lame bitrate"); - return false; - } + if (0 != lame_set_brate(gfp, bitrate)) + throw std::runtime_error("error setting lame bitrate"); } - if (0 != lame_set_num_channels(gfp, audio_format.channels)) { - error.Set(lame_encoder_domain, - "error setting lame num channels"); - return false; - } + if (0 != lame_set_num_channels(gfp, audio_format.channels)) + throw std::runtime_error("error setting lame num channels"); - if (0 != lame_set_in_samplerate(gfp, audio_format.sample_rate)) { - error.Set(lame_encoder_domain, - "error setting lame sample rate"); - return false; - } + if (0 != lame_set_in_samplerate(gfp, audio_format.sample_rate)) + throw std::runtime_error("error setting lame sample rate"); - if (0 != lame_set_out_samplerate(gfp, audio_format.sample_rate)) { - error.Set(lame_encoder_domain, - "error setting lame out sample rate"); - return false; - } + if (0 != lame_set_out_samplerate(gfp, audio_format.sample_rate)) + throw std::runtime_error("error setting lame out sample rate"); - if (0 > lame_init_params(gfp)) { - error.Set(lame_encoder_domain, - "error initializing lame params"); - return false; - } - - return true; + if (0 > lame_init_params(gfp)) + throw std::runtime_error("error initializing lame params"); } Encoder * -PreparedLameEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedLameEncoder::Open(AudioFormat &audio_format) { audio_format.format = SampleFormat::S16; audio_format.channels = 2; auto gfp = lame_init(); - if (gfp == nullptr) { - error.Set(lame_encoder_domain, "lame_init() failed"); - return nullptr; - } + if (gfp == nullptr) + throw std::runtime_error("lame_init() failed"); - if (!lame_encoder_setup(gfp, quality, bitrate, - audio_format, error)) { + try { + lame_encoder_setup(gfp, quality, bitrate, audio_format); + } catch (...) { lame_close(gfp); - return nullptr; + throw; } return new LameEncoder(audio_format, gfp); @@ -190,9 +165,8 @@ LameEncoder::~LameEncoder() lame_close(gfp); } -bool -LameEncoder::Write(const void *data, size_t length, - gcc_unused Error &error) +void +LameEncoder::Write(const void *data, size_t length) { const int16_t *src = (const int16_t*)data; @@ -212,14 +186,11 @@ LameEncoder::Write(const void *data, size_t length, num_frames, dest, output_buffer_size); - if (bytes_out < 0) { - error.Set(lame_encoder_domain, "lame encoder failed"); - return false; - } + if (bytes_out < 0) + throw std::runtime_error("lame encoder failed"); output_begin = dest; output_end = dest + bytes_out; - return true; } size_t diff --git a/src/encoder/plugins/NullEncoderPlugin.cxx b/src/encoder/plugins/NullEncoderPlugin.cxx index aa12d8b06..3229ee160 100644 --- a/src/encoder/plugins/NullEncoderPlugin.cxx +++ b/src/encoder/plugins/NullEncoderPlugin.cxx @@ -32,9 +32,8 @@ public: buffer(8192) {} /* virtual methods from class Encoder */ - bool Write(const void *data, size_t length, Error &) override { + void Write(const void *data, size_t length) override { buffer.Append((const uint8_t *)data, length); - return true; } size_t Read(void *dest, size_t length) override { @@ -45,7 +44,7 @@ public: class PreparedNullEncoder final : public PreparedEncoder { public: /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &, Error &) override { + Encoder *Open(AudioFormat &) override { return new NullEncoder(); } }; diff --git a/src/encoder/plugins/OggEncoder.hxx b/src/encoder/plugins/OggEncoder.hxx index 8749aaf87..8134a05e1 100644 --- a/src/encoder/plugins/OggEncoder.hxx +++ b/src/encoder/plugins/OggEncoder.hxx @@ -47,9 +47,8 @@ public: } /* virtual methods from class Encoder */ - bool Flush(Error &) override { - Flush(); - return true; + void Flush() final { + flush = true; } size_t Read(void *dest, size_t length) override { @@ -67,11 +66,6 @@ public: return ReadPage(page, dest, length); } - -protected: - void Flush() { - flush = true; - } }; #endif diff --git a/src/encoder/plugins/OpusEncoderPlugin.cxx b/src/encoder/plugins/OpusEncoderPlugin.cxx index 8c1469509..8a84327ed 100644 --- a/src/encoder/plugins/OpusEncoderPlugin.cxx +++ b/src/encoder/plugins/OpusEncoderPlugin.cxx @@ -23,8 +23,6 @@ #include "AudioFormat.hxx" #include "config/ConfigError.hxx" #include "util/Alloc.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" #include "system/ByteOrder.hxx" #include @@ -61,14 +59,14 @@ public: ~OpusEncoder() override; /* virtual methods from class Encoder */ - bool End(Error &) override; - bool Write(const void *data, size_t length, Error &) override; + void End() override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override; private: - bool DoEncode(bool eos, Error &error); - bool WriteSilence(unsigned fill_frames, Error &error); + void DoEncode(bool eos); + void WriteSilence(unsigned fill_frames); void GenerateHead(); void GenerateTags(); @@ -83,15 +81,13 @@ public: PreparedOpusEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/ogg"; } }; -static constexpr Domain opus_encoder_domain("opus_encoder"); - PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block) { const char *value = block.GetBlockValue("bitrate", "auto"); @@ -141,7 +137,7 @@ OpusEncoder::OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc) } Encoder * -PreparedOpusEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedOpusEncoder::Open(AudioFormat &audio_format) { /* libopus supports only 48 kHz */ audio_format.sample_rate = 48000; @@ -168,11 +164,8 @@ PreparedOpusEncoder::Open(AudioFormat &audio_format, Error &error) audio_format.channels, OPUS_APPLICATION_AUDIO, &error_code); - if (enc == nullptr) { - error.Set(opus_encoder_domain, error_code, - opus_strerror(error_code)); - return nullptr; - } + if (enc == nullptr) + throw std::runtime_error(opus_strerror(error_code)); opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); @@ -187,8 +180,8 @@ OpusEncoder::~OpusEncoder() opus_encoder_destroy(enc); } -bool -OpusEncoder::DoEncode(bool eos, Error &error) +void +OpusEncoder::DoEncode(bool eos) { assert(buffer_position == buffer_size); @@ -204,10 +197,8 @@ OpusEncoder::DoEncode(bool eos, Error &error) buffer_frames, buffer2, sizeof(buffer2)); - if (result < 0) { - error.Set(opus_encoder_domain, "Opus encoder error"); - return false; - } + if (result < 0) + throw std::runtime_error("Opus encoder error"); granulepos += buffer_frames; @@ -221,12 +212,10 @@ OpusEncoder::DoEncode(bool eos, Error &error) stream.PacketIn(packet); buffer_position = 0; - - return true; } -bool -OpusEncoder::End(Error &error) +void +OpusEncoder::End() { Flush(); @@ -234,11 +223,11 @@ OpusEncoder::End(Error &error) buffer_size - buffer_position); buffer_position = buffer_size; - return DoEncode(true, error); + DoEncode(true); } -bool -OpusEncoder::WriteSilence(unsigned fill_frames, Error &error) +void +OpusEncoder::WriteSilence(unsigned fill_frames) { size_t fill_bytes = fill_frames * frame_size; @@ -251,16 +240,13 @@ OpusEncoder::WriteSilence(unsigned fill_frames, Error &error) buffer_position += nbytes; fill_bytes -= nbytes; - if (buffer_position == buffer_size && - !DoEncode(false, error)) - return false; + if (buffer_position == buffer_size) + DoEncode(false); } - - return true; } -bool -OpusEncoder::Write(const void *_data, size_t length, Error &error) +void +OpusEncoder::Write(const void *_data, size_t length) { const uint8_t *data = (const uint8_t *)_data; @@ -270,9 +256,7 @@ OpusEncoder::Write(const void *_data, size_t length, Error &error) assert(buffer_position == 0); - if (!WriteSilence(lookahead, error)) - return false; - + WriteSilence(lookahead); lookahead = 0; } @@ -286,12 +270,9 @@ OpusEncoder::Write(const void *_data, size_t length, Error &error) length -= nbytes; buffer_position += nbytes; - if (buffer_position == buffer_size && - !DoEncode(false, error)) - return false; + if (buffer_position == buffer_size) + DoEncode(false); } - - return true; } void diff --git a/src/encoder/plugins/ShineEncoderPlugin.cxx b/src/encoder/plugins/ShineEncoderPlugin.cxx index b05de32f6..8d2d4b774 100644 --- a/src/encoder/plugins/ShineEncoderPlugin.cxx +++ b/src/encoder/plugins/ShineEncoderPlugin.cxx @@ -23,7 +23,7 @@ #include "AudioFormat.hxx" #include "config/ConfigError.hxx" #include "util/DynamicFifoBuffer.hxx" -#include "util/Error.hxx" +#include "util/RuntimeError.hxx" extern "C" { @@ -71,13 +71,13 @@ public: bool WriteChunk(bool flush); /* virtual methods from class Encoder */ - bool End(Error &error) override { - return Flush(error); + void End() override { + return Flush(); } - bool Flush(Error &) override; + void Flush() override; - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override { return output_buffer.Read((uint8_t *)dest, length); @@ -91,7 +91,7 @@ public: PreparedShineEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/mpeg"; @@ -111,8 +111,7 @@ shine_encoder_init(const ConfigBlock &block) } static shine_t -SetupShine(shine_config_t config, AudioFormat &audio_format, - Error &error) +SetupShine(shine_config_t config, AudioFormat &audio_format) { audio_format.format = SampleFormat::S16; audio_format.channels = CHANNELS; @@ -122,32 +121,24 @@ SetupShine(shine_config_t config, AudioFormat &audio_format, config.wave.channels = audio_format.channels == 2 ? PCM_STEREO : PCM_MONO; - if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) { - error.Format(config_domain, - "error configuring shine. " - "samplerate %d and bitrate %d configuration" - " not supported.", - config.wave.samplerate, - config.mpeg.bitr); - - return nullptr; - } + if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) + throw FormatRuntimeError("error configuring shine. " + "samplerate %d and bitrate %d configuration" + " not supported.", + config.wave.samplerate, + config.mpeg.bitr); auto shine = shine_initialise(&config); if (!shine) - error.Format(config_domain, - "error initializing shine."); + throw std::runtime_error("error initializing shine"); return shine; } Encoder * -PreparedShineEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedShineEncoder::Open(AudioFormat &audio_format) { - auto shine = SetupShine(config, audio_format, error); - if (!shine) - return nullptr; - + auto shine = SetupShine(config, audio_format); return new ShineEncoder(audio_format, shine); } @@ -175,8 +166,8 @@ ShineEncoder::WriteChunk(bool flush) return true; } -bool -ShineEncoder::Write(const void *_data, size_t length, gcc_unused Error &error) +void +ShineEncoder::Write(const void *_data, size_t length) { const int16_t *data = (const int16_t*)_data; length /= sizeof(*data) * audio_format.channels; @@ -198,12 +189,10 @@ ShineEncoder::Write(const void *_data, size_t length, gcc_unused Error &error) /* write if chunk is filled */ WriteChunk(false); } - - return true; } -bool -ShineEncoder::Flush(gcc_unused Error &error) +void +ShineEncoder::Flush() { /* flush buffers and flush shine */ WriteChunk(true); @@ -213,8 +202,6 @@ ShineEncoder::Flush(gcc_unused Error &error) if (written > 0) output_buffer.Append(data, written); - - return true; } const EncoderPlugin shine_encoder_plugin = { diff --git a/src/encoder/plugins/TwolameEncoderPlugin.cxx b/src/encoder/plugins/TwolameEncoderPlugin.cxx index ba980b05c..c49501524 100644 --- a/src/encoder/plugins/TwolameEncoderPlugin.cxx +++ b/src/encoder/plugins/TwolameEncoderPlugin.cxx @@ -24,12 +24,13 @@ #include "config/ConfigError.hxx" #include "util/NumberParser.hxx" #include "util/RuntimeError.hxx" -#include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" #include +#include + #include #include @@ -59,17 +60,15 @@ public: /* virtual methods from class Encoder */ - bool End(Error &) override { + void End() override { flush = true; - return true; } - bool Flush(Error &) override { + void Flush() override { flush = true; - return true; } - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override; }; @@ -81,7 +80,7 @@ public: PreparedTwolameEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/mpeg"; @@ -132,71 +131,52 @@ twolame_encoder_init(const ConfigBlock &block) return new PreparedTwolameEncoder(block); } -static bool +static void twolame_encoder_setup(twolame_options *options, float quality, int bitrate, - const AudioFormat &audio_format, Error &error) + const AudioFormat &audio_format) { if (quality >= -1.0) { /* a quality was configured (VBR) */ - if (0 != twolame_set_VBR(options, true)) { - error.Set(twolame_encoder_domain, - "error setting twolame VBR mode"); - return false; - } - if (0 != twolame_set_VBR_q(options, quality)) { - error.Set(twolame_encoder_domain, - "error setting twolame VBR quality"); - return false; - } + if (0 != twolame_set_VBR(options, true)) + throw std::runtime_error("error setting twolame VBR mode"); + + if (0 != twolame_set_VBR_q(options, quality)) + throw std::runtime_error("error setting twolame VBR quality"); } else { /* a bit rate was configured */ - if (0 != twolame_set_brate(options, bitrate)) { - error.Set(twolame_encoder_domain, - "error setting twolame bitrate"); - return false; - } + if (0 != twolame_set_brate(options, bitrate)) + throw std::runtime_error("error setting twolame bitrate"); } - if (0 != twolame_set_num_channels(options, audio_format.channels)) { - error.Set(twolame_encoder_domain, - "error setting twolame num channels"); - return false; - } + if (0 != twolame_set_num_channels(options, audio_format.channels)) + throw std::runtime_error("error setting twolame num channels"); if (0 != twolame_set_in_samplerate(options, - audio_format.sample_rate)) { - error.Set(twolame_encoder_domain, - "error setting twolame sample rate"); - return false; - } + audio_format.sample_rate)) + throw std::runtime_error("error setting twolame sample rate"); - if (0 > twolame_init_params(options)) { - error.Set(twolame_encoder_domain, - "error initializing twolame params"); - return false; - } - - return true; + if (0 > twolame_init_params(options)) + throw std::runtime_error("error initializing twolame params"); } Encoder * -PreparedTwolameEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedTwolameEncoder::Open(AudioFormat &audio_format) { audio_format.format = SampleFormat::S16; audio_format.channels = 2; auto options = twolame_init(); - if (options == nullptr) { - error.Set(twolame_encoder_domain, "twolame_init() failed"); - return nullptr; - } + if (options == nullptr) + throw std::runtime_error("twolame_init() failed"); - if (!twolame_encoder_setup(options, quality, bitrate, - audio_format, error)) { + try { + twolame_encoder_setup(options, quality, bitrate, + audio_format); + } catch (...) { twolame_close(&options); - return nullptr; + throw; } return new TwolameEncoder(audio_format, options); @@ -207,9 +187,8 @@ TwolameEncoder::~TwolameEncoder() twolame_close(&options); } -bool -TwolameEncoder::Write(const void *data, size_t length, - gcc_unused Error &error) +void +TwolameEncoder::Write(const void *data, size_t length) { const int16_t *src = (const int16_t*)data; @@ -221,14 +200,11 @@ TwolameEncoder::Write(const void *data, size_t length, src, num_frames, output_buffer, sizeof(output_buffer)); - if (bytes_out < 0) { - error.Set(twolame_encoder_domain, "twolame encoder failed"); - return false; - } + if (bytes_out < 0) + throw std::runtime_error("twolame encoder failed"); output_buffer_length = (size_t)bytes_out; output_buffer_position = 0; - return true; } size_t diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx index 94c7ff80b..74b80c572 100644 --- a/src/encoder/plugins/VorbisEncoderPlugin.cxx +++ b/src/encoder/plugins/VorbisEncoderPlugin.cxx @@ -26,8 +26,6 @@ #include "util/StringUtil.hxx" #include "util/NumberParser.hxx" #include "util/RuntimeError.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" #include @@ -39,10 +37,7 @@ class VorbisEncoder final : public OggEncoder { vorbis_info vi; public: - VorbisEncoder() - :OggEncoder(true) { - vorbis_info_init(&vi); - } + VorbisEncoder(float quality, int bitrate, AudioFormat &_audio_format); virtual ~VorbisEncoder() { vorbis_block_clear(&vb); @@ -50,18 +45,15 @@ public: vorbis_info_clear(&vi); } - bool Open(float quality, int bitrate, AudioFormat &audio_format, - Error &error); - /* virtual methods from class Encoder */ - bool End(Error &error) override { - return PreTag(error); + void End() override { + PreTag(); } - bool PreTag(Error &error) override; - bool SendTag(const Tag &tag, Error &error) override; + void PreTag() override; + void SendTag(const Tag &tag) override; - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; private: void HeaderOut(vorbis_comment &vc); @@ -77,15 +69,13 @@ public: PreparedVorbisEncoder(const ConfigBlock &block); /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override; + Encoder *Open(AudioFormat &audio_format) override; const char *GetMimeType() const override { return "audio/ogg"; } }; -static constexpr Domain vorbis_encoder_domain("vorbis_encoder"); - PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block) { const char *value = block.GetBlockValue("quality"); @@ -124,10 +114,12 @@ vorbis_encoder_init(const ConfigBlock &block) return new PreparedVorbisEncoder(block); } -bool -VorbisEncoder::Open(float quality, int bitrate, AudioFormat &_audio_format, - Error &error) +VorbisEncoder::VorbisEncoder(float quality, int bitrate, + AudioFormat &_audio_format) + :OggEncoder(true) { + vorbis_info_init(&vi); + _audio_format.format = SampleFormat::FLOAT; audio_format = _audio_format; @@ -138,9 +130,8 @@ VorbisEncoder::Open(float quality, int bitrate, AudioFormat &_audio_format, audio_format.channels, audio_format.sample_rate, quality * 0.1)) { - error.Set(vorbis_encoder_domain, - "error initializing vorbis vbr"); - return false; + vorbis_info_clear(&vi); + throw std::runtime_error("error initializing vorbis vbr"); } } else { /* a bit rate was configured */ @@ -149,9 +140,8 @@ VorbisEncoder::Open(float quality, int bitrate, AudioFormat &_audio_format, audio_format.channels, audio_format.sample_rate, -1.0, bitrate * 1000, -1.0)) { - error.Set(vorbis_encoder_domain, - "error initializing vorbis encoder"); - return false; + vorbis_info_clear(&vi); + throw std::runtime_error("error initializing vorbis encoder"); } } @@ -159,8 +149,6 @@ VorbisEncoder::Open(float quality, int bitrate, AudioFormat &_audio_format, vorbis_block_init(&vd, &vb); SendHeader(); - - return true; } void @@ -184,15 +172,9 @@ VorbisEncoder::SendHeader() } Encoder * -PreparedVorbisEncoder::Open(AudioFormat &audio_format, Error &error) +PreparedVorbisEncoder::Open(AudioFormat &audio_format) { - auto *e = new VorbisEncoder(); - if (!e->Open(quality, bitrate, audio_format, error)) { - delete e; - return nullptr; - } - - return e; + return new VorbisEncoder(quality, bitrate, audio_format); } void @@ -208,8 +190,8 @@ VorbisEncoder::BlockOut() } } -bool -VorbisEncoder::PreTag(gcc_unused Error &error) +void +VorbisEncoder::PreTag() { vorbis_analysis_wrote(&vd, 0); BlockOut(); @@ -222,7 +204,6 @@ VorbisEncoder::PreTag(gcc_unused Error &error) vorbis_block_init(&vd, &vb); Flush(); - return true; } static void @@ -235,8 +216,8 @@ copy_tag_to_vorbis_comment(VorbisComment &vc, const Tag &tag) } } -bool -VorbisEncoder::SendTag(const Tag &tag, gcc_unused Error &error) +void +VorbisEncoder::SendTag(const Tag &tag) { /* write the vorbis_comment object */ @@ -250,8 +231,6 @@ VorbisEncoder::SendTag(const Tag &tag, gcc_unused Error &error) /* send that vorbis_comment to the ogg_stream_state */ HeaderOut(comment); - - return true; } static void @@ -263,8 +242,8 @@ interleaved_to_vorbis_buffer(float **dest, const float *src, dest[j][i] = *src++; } -bool -VorbisEncoder::Write(const void *data, size_t length, gcc_unused Error &error) +void +VorbisEncoder::Write(const void *data, size_t length) { unsigned num_frames = length / audio_format.GetFrameSize(); @@ -277,7 +256,6 @@ VorbisEncoder::Write(const void *data, size_t length, gcc_unused Error &error) vorbis_analysis_wrote(&vd, num_frames); BlockOut(); - return true; } const EncoderPlugin vorbis_encoder_plugin = { diff --git a/src/encoder/plugins/WaveEncoderPlugin.cxx b/src/encoder/plugins/WaveEncoderPlugin.cxx index 90be1d296..7ea4e1298 100644 --- a/src/encoder/plugins/WaveEncoderPlugin.cxx +++ b/src/encoder/plugins/WaveEncoderPlugin.cxx @@ -37,7 +37,7 @@ public: WaveEncoder(AudioFormat &audio_format); /* virtual methods from class Encoder */ - bool Write(const void *data, size_t length, Error &) override; + void Write(const void *data, size_t length) override; size_t Read(void *dest, size_t length) override { return buffer.Read((uint8_t *)dest, length); @@ -46,7 +46,7 @@ public: class PreparedWaveEncoder final : public PreparedEncoder { /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format, Error &) override { + Encoder *Open(AudioFormat &audio_format) override { return new WaveEncoder(audio_format); } @@ -186,9 +186,8 @@ pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) return (dst8 - dst_old); } -bool -WaveEncoder::Write(const void *src, size_t length, - gcc_unused Error &error) +void +WaveEncoder::Write(const void *src, size_t length) { uint8_t *dst = buffer.Write(length); @@ -223,7 +222,6 @@ WaveEncoder::Write(const void *src, size_t length, } buffer.Append(length); - return true; } const EncoderPlugin wave_encoder_plugin = { diff --git a/src/output/plugins/RecorderOutputPlugin.cxx b/src/output/plugins/RecorderOutputPlugin.cxx index 9ee8cb5a4..dc6685d13 100644 --- a/src/output/plugins/RecorderOutputPlugin.cxx +++ b/src/output/plugins/RecorderOutputPlugin.cxx @@ -110,8 +110,10 @@ private: /** * Finish the encoder and commit the file. + * + * Throws #std::runtime_error on error. */ - bool Commit(Error &error); + void Commit(); void FinishFormat(); bool ReopenFormat(AllocatedPath &&new_path, Error &error); @@ -209,10 +211,11 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error) /* open the encoder */ - encoder = prepared_encoder->Open(audio_format, error); - if (encoder == nullptr) { + try { + encoder = prepared_encoder->Open(audio_format); + } catch (const std::runtime_error &) { delete file; - return false; + throw; } if (!HasDynamicPath()) { @@ -235,39 +238,33 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error) return true; } -inline bool -RecorderOutput::Commit(Error &error) +inline void +RecorderOutput::Commit() { assert(!path.IsNull()); /* flush the encoder and write the rest to the file */ - bool success = encoder->End(error); - if (success) { - try { - EncoderToFile(); - } catch (...) { - delete encoder; - throw; - } + try { + encoder->End(); + EncoderToFile(); + } catch (...) { + delete encoder; + throw; } /* now really close everything */ delete encoder; - if (success) { - try { - file->Commit(); - } catch (...) { - delete file; - throw; - } + try { + file->Commit(); + } catch (...) { + delete file; + throw; } delete file; - - return success; } inline void @@ -282,9 +279,7 @@ RecorderOutput::Close() } try { - Error error; - if (!Commit(error)) - LogError(error); + Commit(); } catch (const std::exception &e) { LogError(e); } @@ -304,9 +299,7 @@ RecorderOutput::FinishFormat() return; try { - Error error; - if (!Commit(error)) - LogError(error); + Commit(); } catch (const std::exception &e) { LogError(e); } @@ -331,10 +324,12 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error) } AudioFormat new_audio_format = effective_audio_format; - encoder = prepared_encoder->Open(new_audio_format, error); - if (encoder == nullptr) { + + try { + encoder = prepared_encoder->Open(new_audio_format); + } catch (...) { delete new_file; - return false; + throw; } /* reopening the encoder must always result in the same @@ -395,21 +390,9 @@ RecorderOutput::SendTag(const Tag &tag) } } - Error error; - if (!encoder->PreTag(error)) { - LogError(error); - return; - } - - try { - EncoderToFile(); - } catch (const std::exception &e) { - LogError(e); - return; - } - - if (!encoder->SendTag(tag, error)) - LogError(error); + encoder->PreTag(); + EncoderToFile(); + encoder->SendTag(tag); } inline size_t @@ -423,8 +406,7 @@ RecorderOutput::Play(const void *chunk, size_t size, Error &error) return size; } - if (!encoder->Write(chunk, size, error)) - return 0; + encoder->Write(chunk, size); try { EncoderToFile(); diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx index 43f79f6f7..c12d81d8c 100644 --- a/src/output/plugins/ShoutOutputPlugin.cxx +++ b/src/output/plugins/ShoutOutputPlugin.cxx @@ -32,6 +32,8 @@ #include +#include + #include #include #include @@ -366,8 +368,12 @@ void ShoutOutput::Close() { if (encoder != nullptr) { - if (encoder->End(IgnoreError())) + try { + encoder->End(); write_page(this, IgnoreError()); + } catch (const std::runtime_error &) { + /* ignore */ + } delete encoder; } @@ -410,16 +416,22 @@ ShoutOutput::Open(AudioFormat &audio_format, Error &error) if (!shout_connect(this, error)) return false; - encoder = prepared_encoder->Open(audio_format, error); - if (encoder == nullptr) { - shout_close(shout_conn); - return false; - } + try { + encoder = prepared_encoder->Open(audio_format); - if (!write_page(this, error)) { - delete encoder; + try { + if (!write_page(this, error)) { + delete encoder; + shout_close(shout_conn); + return false; + } + } catch (const std::runtime_error &) { + delete encoder; + throw; + } + } catch (const std::runtime_error &) { shout_close(shout_conn); - return false; + throw; } return true; @@ -438,8 +450,8 @@ ShoutOutput::Delay() const size_t ShoutOutput::Play(const void *chunk, size_t size, Error &error) { - return encoder->Write(chunk, size, error) && - write_page(this, error) + encoder->Write(chunk, size); + return write_page(this, error) ? size : 0; } @@ -484,13 +496,15 @@ ShoutOutput::SendTag(const Tag &tag) if (encoder->ImplementsTag()) { /* encoder plugin supports stream tags */ + encoder->PreTag(); + Error error; - if (!encoder->PreTag(error) || - !write_page(this, error) || - !encoder->SendTag(tag, error)) { + if (!write_page(this, error)) { LogError(error); return; } + + encoder->SendTag(tag); } else { /* no stream tag support: fall back to icy-metadata */ char song[1024]; diff --git a/src/output/plugins/httpd/HttpdInternal.hxx b/src/output/plugins/httpd/HttpdInternal.hxx index 757df5ecd..bec26711b 100644 --- a/src/output/plugins/httpd/HttpdInternal.hxx +++ b/src/output/plugins/httpd/HttpdInternal.hxx @@ -171,8 +171,10 @@ public: /** * Caller must lock the mutex. + * + * Throws #std::runtime_error on error. */ - bool OpenEncoder(AudioFormat &audio_format, Error &error); + void OpenEncoder(AudioFormat &audio_format); /** * Caller must lock the mutex. @@ -237,7 +239,10 @@ public: */ void BroadcastFromEncoder(); - bool EncodeAndPlay(const void *chunk, size_t size, Error &error); + /** + * Throws #std::runtime_error on error. + */ + void EncodeAndPlay(const void *chunk, size_t size); void SendTag(const Tag &tag); diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.cxx b/src/output/plugins/httpd/HttpdOutputPlugin.cxx index a46432843..a90a88ac1 100644 --- a/src/output/plugins/httpd/HttpdOutputPlugin.cxx +++ b/src/output/plugins/httpd/HttpdOutputPlugin.cxx @@ -221,7 +221,12 @@ HttpdOutput::ReadPage() /* we have fed a lot of input into the encoder, but it didn't give anything back yet - flush now to avoid buffer underruns */ - encoder->Flush(IgnoreError()); + try { + encoder->Flush(); + } catch (const std::runtime_error &) { + /* ignore */ + } + unflushed_input = 0; } @@ -260,12 +265,10 @@ httpd_output_disable(AudioOutput *ao) httpd->Unbind(); } -inline bool -HttpdOutput::OpenEncoder(AudioFormat &audio_format, Error &error) +inline void +HttpdOutput::OpenEncoder(AudioFormat &audio_format) { - encoder = prepared_encoder->Open(audio_format, error); - if (encoder == nullptr) - return false; + encoder = prepared_encoder->Open(audio_format); /* we have to remember the encoder header, i.e. the first bytes of encoder output after opening it, because it has to @@ -273,20 +276,15 @@ HttpdOutput::OpenEncoder(AudioFormat &audio_format, Error &error) header = ReadPage(); unflushed_input = 0; - - return true; } inline bool -HttpdOutput::Open(AudioFormat &audio_format, Error &error) +HttpdOutput::Open(AudioFormat &audio_format, Error &) { assert(!open); assert(clients.empty()); - /* open the encoder */ - - if (!OpenEncoder(audio_format, error)) - return false; + OpenEncoder(audio_format); /* initialize other attributes */ @@ -410,25 +408,21 @@ HttpdOutput::BroadcastFromEncoder() DeferredMonitor::Schedule(); } -inline bool -HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, Error &error) +inline void +HttpdOutput::EncodeAndPlay(const void *chunk, size_t size) { - if (!encoder->Write(chunk, size, error)) - return false; + encoder->Write(chunk, size); unflushed_input += size; BroadcastFromEncoder(); - return true; } inline size_t -HttpdOutput::Play(const void *chunk, size_t size, Error &error) +HttpdOutput::Play(const void *chunk, size_t size, Error &) { - if (LockHasClients()) { - if (!EncodeAndPlay(chunk, size, error)) - return 0; - } + if (LockHasClients()) + EncodeAndPlay(chunk, size); if (!timer->IsStarted()) timer->Start(); @@ -468,13 +462,22 @@ HttpdOutput::SendTag(const Tag &tag) /* flush the current stream, and end it */ - encoder->PreTag(IgnoreError()); + try { + encoder->PreTag(); + } catch (const std::runtime_error &) { + /* ignore */ + } + BroadcastFromEncoder(); /* send the tag to the encoder - which starts a new stream now */ - encoder->SendTag(tag, IgnoreError()); + try { + encoder->SendTag(tag); + } catch (const std::runtime_error &) { + /* ignore */ + } /* the first page generated by the encoder will now be used as the new "header" page, which is sent to all diff --git a/test/run_encoder.cxx b/test/run_encoder.cxx index 78dd093eb..6c5fd272f 100644 --- a/test/run_encoder.cxx +++ b/test/run_encoder.cxx @@ -26,7 +26,6 @@ #include "AudioParser.hxx" #include "config/Block.hxx" #include "fs/io/StdioOutputStream.hxx" -#include "util/Error.hxx" #include "Log.hxx" #include @@ -66,7 +65,6 @@ int main(int argc, char **argv) block.AddBlockParam("quality", "5.0", -1); try { - Error error; std::unique_ptr p_encoder(encoder_init(*plugin, block)); /* open the encoder */ @@ -75,11 +73,7 @@ int main(int argc, char **argv) if (argc > 2) audio_format = ParseAudioFormat(argv[2], false); - std::unique_ptr encoder(p_encoder->Open(audio_format, error)); - if (encoder == nullptr) { - LogError(error, "Failed to open encoder"); - return EXIT_FAILURE; - } + std::unique_ptr encoder(p_encoder->Open(audio_format)); StdioOutputStream os(stdout); @@ -89,19 +83,11 @@ int main(int argc, char **argv) ssize_t nbytes; while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) { - if (!encoder->Write(buffer, nbytes, error)) { - LogError(error, "encoder_write() failed"); - return EXIT_FAILURE; - } - + encoder->Write(buffer, nbytes); EncoderToOutputStream(os, *encoder); } - if (!encoder->End(error)) { - LogError(error, "encoder_flush() failed"); - return EXIT_FAILURE; - } - + encoder->End(); EncoderToOutputStream(os, *encoder); return EXIT_SUCCESS; diff --git a/test/test_vorbis_encoder.cxx b/test/test_vorbis_encoder.cxx index 054700c2e..71366460e 100644 --- a/test/test_vorbis_encoder.cxx +++ b/test/test_vorbis_encoder.cxx @@ -27,7 +27,6 @@ #include "fs/io/StdioOutputStream.hxx" #include "tag/Tag.hxx" #include "tag/TagBuilder.hxx" -#include "util/Error.hxx" #include "Log.hxx" #include @@ -40,8 +39,6 @@ static uint8_t zero[256]; int main(gcc_unused int argc, gcc_unused char **argv) try { - gcc_unused bool success; - /* create the encoder */ const auto plugin = encoder_plugin_get("vorbis"); @@ -56,8 +53,7 @@ try { /* open the encoder */ AudioFormat audio_format(44100, SampleFormat::S16, 2); - std::unique_ptr encoder(p_encoder->Open(audio_format, - IgnoreError())); + std::unique_ptr encoder(p_encoder->Open(audio_format)); assert(encoder != nullptr); StdioOutputStream os(stdout); @@ -66,15 +62,13 @@ try { /* write a block of data */ - success = encoder->Write(zero, sizeof(zero), IgnoreError()); - assert(success); + encoder->Write(zero, sizeof(zero)); EncoderToOutputStream(os, *encoder); /* write a tag */ - success = encoder->PreTag(IgnoreError()); - assert(success); + encoder->PreTag(); EncoderToOutputStream(os, *encoder); @@ -87,21 +81,17 @@ try { tag_builder.Commit(tag); } - success = encoder->SendTag(tag, IgnoreError()); - assert(success); + encoder->SendTag(tag); EncoderToOutputStream(os, *encoder); /* write another block of data */ - success = encoder->Write(zero, sizeof(zero), IgnoreError()); - assert(success); + encoder->Write(zero, sizeof(zero)); /* finish */ - success = encoder->End(IgnoreError()); - assert(success); - + encoder->End(); EncoderToOutputStream(os, *encoder); return EXIT_SUCCESS;