diff options
author | Max Kellermann <max@musicpd.org> | 2016-11-02 10:43:25 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2016-11-02 11:01:22 +0100 |
commit | 6ead9750f40e5ce72c4f07c2d78135e61c68bf85 (patch) | |
tree | 3d88d4ddb8b4a04d0e87622e38c71f9dd24f9247 | |
parent | 6532c7e089fdddbfe7182d4becb4923272f2b863 (diff) |
output/pulse: migrate from class Error to C++ exceptions
-rw-r--r-- | src/lib/pulse/Error.cxx | 9 | ||||
-rw-r--r-- | src/lib/pulse/Error.hxx | 7 | ||||
-rw-r--r-- | src/output/plugins/PulseOutputPlugin.cxx | 248 |
3 files changed, 108 insertions, 156 deletions
diff --git a/src/lib/pulse/Error.cxx b/src/lib/pulse/Error.cxx index a9a909e1d..37f03ab78 100644 --- a/src/lib/pulse/Error.cxx +++ b/src/lib/pulse/Error.cxx @@ -19,15 +19,14 @@ #include "config.h" #include "Error.hxx" -#include "Domain.hxx" -#include "util/Error.hxx" +#include "util/RuntimeError.hxx" #include <pulse/context.h> #include <pulse/error.h> -void -SetPulseError(Error &error, pa_context *context, const char *prefix) +std::runtime_error +MakePulseError(pa_context *context, const char *prefix) { const int e = pa_context_errno(context); - error.Format(pulse_domain, e, "%s: %s", prefix, pa_strerror(e)); + return FormatRuntimeError("%s: %s", prefix, pa_strerror(e)); } diff --git a/src/lib/pulse/Error.hxx b/src/lib/pulse/Error.hxx index db40fb120..4b2836ba8 100644 --- a/src/lib/pulse/Error.hxx +++ b/src/lib/pulse/Error.hxx @@ -20,10 +20,11 @@ #ifndef MPD_PULSE_ERROR_HXX #define MPD_PULSE_ERROR_HXX -class Error; +#include <stdexcept> + struct pa_context; -void -SetPulseError(Error &error, pa_context *context, const char *prefix); +std::runtime_error +MakePulseError(pa_context *context, const char *prefix); #endif diff --git a/src/output/plugins/PulseOutputPlugin.cxx b/src/output/plugins/PulseOutputPlugin.cxx index 20564cba1..541ff1e11 100644 --- a/src/output/plugins/PulseOutputPlugin.cxx +++ b/src/output/plugins/PulseOutputPlugin.cxx @@ -27,7 +27,6 @@ #include "../Wrapper.hxx" #include "mixer/MixerList.hxx" #include "mixer/plugins/PulseMixerPlugin.hxx" -#include "util/Error.hxx" #include "Log.hxx" #include <pulse/thread-mainloop.h> @@ -62,8 +61,7 @@ class PulseOutput { size_t writable; - PulseOutput() - :base(pulse_output_plugin) {} + explicit PulseOutput(const ConfigBlock &block); public: void SetMixer(PulseMixer &_mixer); @@ -95,7 +93,6 @@ public: gcc_const static bool TestDefaultDevice(); - bool Configure(const ConfigBlock &block, Error &error); static PulseOutput *Create(const ConfigBlock &block, Error &error); bool Enable(Error &error); @@ -113,18 +110,18 @@ private: /** * Attempt to connect asynchronously to the PulseAudio server. * - * @return true on success, false on error + * Throws #std::runtime_error on error. */ - bool Connect(Error &error); + void Connect(); /** * Create, set up and connect a context. * * Caller must lock the main loop. * - * @return true on success, false on error + * Throws #std::runtime_error on error. */ - bool SetupContext(Error &error); + void SetupContext(); /** * Frees and clears the context. @@ -144,18 +141,18 @@ private: * * Caller must lock the main loop. * - * @return true on success, false on error + * Throws #std::runtime_error on error. */ - bool WaitConnection(Error &error); + void WaitConnection(); /** * Create, set up and connect a context. * * Caller must lock the main loop. * - * @return true on success, false on error + * Throws #std::runtime_error on error. */ - bool SetupStream(const pa_sample_spec &ss, Error &error); + void SetupStream(const pa_sample_spec &ss); /** * Frees and clears the stream. @@ -167,16 +164,28 @@ private: * not. The mainloop must be locked before calling this * function. * - * @return true on success, false on error + * Throws #std::runtime_error on error. */ - bool WaitStream(Error &error); + void WaitStream(); /** * Sets cork mode on the stream. + * + * Throws #std::runtime_error on error. */ - bool StreamPause(bool pause, Error &error); + void StreamPause(bool pause); }; +PulseOutput::PulseOutput(const ConfigBlock &block) + :base(pulse_output_plugin, block), + name(block.GetBlockValue("name", "mpd_pulse")), + server(block.GetBlockValue("server")), + sink(block.GetBlockValue("sink")) +{ + setenv("PULSE_PROP_media.role", "music", true); + setenv("PULSE_PROP_application.icon_name", "mpd", true); +} + struct pa_threaded_mainloop * pulse_output_get_mainloop(PulseOutput &po) { @@ -343,19 +352,15 @@ pulse_output_subscribe_cb(gcc_unused pa_context *context, po.OnServerLayoutChanged(t, idx); } -inline bool -PulseOutput::Connect(Error &error) +inline void +PulseOutput::Connect() { assert(context != nullptr); if (pa_context_connect(context, server, - (pa_context_flags_t)0, nullptr) < 0) { - SetPulseError(error, context, - "pa_context_connect() has failed"); - return false; - } - - return true; + (pa_context_flags_t)0, nullptr) < 0) + throw MakePulseError(context, + "pa_context_connect() has failed"); } void @@ -386,72 +391,45 @@ PulseOutput::DeleteContext() context = nullptr; } -bool -PulseOutput::SetupContext(Error &error) +void +PulseOutput::SetupContext() { assert(mainloop != nullptr); context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), MPD_PULSE_NAME); - if (context == nullptr) { - error.Set(pulse_domain, "pa_context_new() has failed"); - return false; - } + if (context == nullptr) + throw std::runtime_error("pa_context_new() has failed"); pa_context_set_state_callback(context, pulse_output_context_state_cb, this); pa_context_set_subscribe_callback(context, pulse_output_subscribe_cb, this); - if (!Connect(error)) { + try { + Connect(); + } catch (...) { DeleteContext(); - return false; + throw; } - - return true; -} - -inline bool -PulseOutput::Configure(const ConfigBlock &block, Error &error) -{ - if (!base.Configure(block, error)) - return false; - - name = block.GetBlockValue("name", "mpd_pulse"); - server = block.GetBlockValue("server"); - sink = block.GetBlockValue("sink"); - - return true; } PulseOutput * -PulseOutput::Create(const ConfigBlock &block, Error &error) +PulseOutput::Create(const ConfigBlock &block, gcc_unused Error &error) { - setenv("PULSE_PROP_media.role", "music", true); - setenv("PULSE_PROP_application.icon_name", "mpd", true); - - auto *po = new PulseOutput(); - if (!po->Configure(block, error)) { - delete po; - return nullptr; - } - - return po; + return new PulseOutput(block); } inline bool -PulseOutput::Enable(Error &error) +PulseOutput::Enable(gcc_unused Error &error) { assert(mainloop == nullptr); /* create the libpulse mainloop and start the thread */ mainloop = pa_threaded_mainloop_new(); - if (mainloop == nullptr) { - error.Set(pulse_domain, - "pa_threaded_mainloop_new() has failed"); - return false; - } + if (mainloop == nullptr) + throw std::runtime_error("pa_threaded_mainloop_new() has failed"); pa_threaded_mainloop_lock(mainloop); @@ -460,19 +438,19 @@ PulseOutput::Enable(Error &error) pa_threaded_mainloop_free(mainloop); mainloop = nullptr; - error.Set(pulse_domain, - "pa_threaded_mainloop_start() has failed"); - return false; + throw std::runtime_error("pa_threaded_mainloop_start() has failed"); } /* create the libpulse context and connect it */ - if (!SetupContext(error)) { + try { + SetupContext(); + } catch (...) { pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_stop(mainloop); pa_threaded_mainloop_free(mainloop); mainloop = nullptr; - return false; + throw; } pa_threaded_mainloop_unlock(mainloop); @@ -492,30 +470,33 @@ PulseOutput::Disable() mainloop = nullptr; } -bool -PulseOutput::WaitConnection(Error &error) +void +PulseOutput::WaitConnection() { assert(mainloop != nullptr); pa_context_state_t state; - if (context == nullptr && !SetupContext(error)) - return false; + if (context == nullptr) + SetupContext(); while (true) { state = pa_context_get_state(context); switch (state) { case PA_CONTEXT_READY: /* nothing to do */ - return true; + return; case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: /* failure */ - SetPulseError(error, context, "failed to connect"); - DeleteContext(); - return false; + { + auto e = MakePulseError(context, + "failed to connect"); + DeleteContext(); + throw e; + } case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: @@ -602,8 +583,8 @@ pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes, return po.OnStreamWrite(nbytes); } -inline bool -PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error) +inline void +PulseOutput::SetupStream(const pa_sample_spec &ss) { assert(context != nullptr); @@ -612,11 +593,9 @@ PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error) pa_channel_map_init_auto(&chan_map, ss.channels, PA_CHANNEL_MAP_WAVEEX); stream = pa_stream_new(context, name, &ss, &chan_map); - if (stream == nullptr) { - SetPulseError(error, context, - "pa_stream_new() has failed"); - return false; - } + if (stream == nullptr) + throw MakePulseError(context, + "pa_stream_new() has failed"); pa_stream_set_suspended_callback(stream, pulse_output_stream_suspended_cb, @@ -626,12 +605,10 @@ PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error) pulse_output_stream_state_cb, this); pa_stream_set_write_callback(stream, pulse_output_stream_write_cb, this); - - return true; } inline bool -PulseOutput::Open(AudioFormat &audio_format, Error &error) +PulseOutput::Open(AudioFormat &audio_format, gcc_unused Error &error) { assert(mainloop != nullptr); @@ -656,8 +633,7 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error) } } - if (!WaitConnection(error)) - return false; + WaitConnection(); /* Use the sample formats that our version of PulseAudio and MPD have in common, otherwise force MPD to send 16 bit */ @@ -688,8 +664,7 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error) /* create a stream .. */ - if (!SetupStream(ss, error)) - return false; + SetupStream(ss); /* .. and connect it (asynchronously) */ @@ -698,9 +673,8 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error) nullptr, nullptr) < 0) { DeleteStream(); - SetPulseError(error, context, - "pa_stream_connect_playback() has failed"); - return false; + throw MakePulseError(context, + "pa_stream_connect_playback() has failed"); } return true; @@ -731,20 +705,19 @@ PulseOutput::Close() DeleteContext(); } -bool -PulseOutput::WaitStream(Error &error) +void +PulseOutput::WaitStream() { while (true) { switch (pa_stream_get_state(stream)) { case PA_STREAM_READY: - return true; + return; case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: case PA_STREAM_UNCONNECTED: - SetPulseError(error, context, - "failed to connect the stream"); - return false; + throw MakePulseError(context, + "failed to connect the stream"); case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); @@ -753,8 +726,8 @@ PulseOutput::WaitStream(Error &error) } } -bool -PulseOutput::StreamPause(bool pause, Error &error) +void +PulseOutput::StreamPause(bool pause) { assert(mainloop != nullptr); assert(context != nullptr); @@ -762,19 +735,13 @@ PulseOutput::StreamPause(bool pause, Error &error) pa_operation *o = pa_stream_cork(stream, pause, pulse_output_stream_success_cb, this); - if (o == nullptr) { - SetPulseError(error, context, - "pa_stream_cork() has failed"); - return false; - } - - if (!pulse_wait_for_operation(mainloop, o)) { - SetPulseError(error, context, - "pa_stream_cork() has failed"); - return false; - } + if (o == nullptr) + throw MakePulseError(context, + "pa_stream_cork() has failed"); - return true; + if (!pulse_wait_for_operation(mainloop, o)) + throw MakePulseError(context, + "pa_stream_cork() has failed"); } inline unsigned @@ -792,7 +759,7 @@ PulseOutput::Delay() } inline size_t -PulseOutput::Play(const void *chunk, size_t size, Error &error) +PulseOutput::Play(const void *chunk, size_t size, gcc_unused Error &error) { assert(mainloop != nullptr); assert(stream != nullptr); @@ -801,30 +768,25 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error) /* check if the stream is (already) connected */ - if (!WaitStream(error)) - return 0; + WaitStream(); assert(context != nullptr); /* unpause if previously paused */ - if (pa_stream_is_corked(stream) && !StreamPause(false, error)) - return 0; + if (pa_stream_is_corked(stream)) + StreamPause(false); /* wait until the server allows us to write */ while (writable == 0) { - if (pa_stream_is_suspended(stream)) { - error.Set(pulse_domain, "suspended"); - return 0; - } + if (pa_stream_is_suspended(stream)) + throw std::runtime_error("suspended"); pa_threaded_mainloop_wait(mainloop); - if (pa_stream_get_state(stream) != PA_STREAM_READY) { - error.Set(pulse_domain, "disconnected"); - return 0; - } + if (pa_stream_get_state(stream) != PA_STREAM_READY) + throw std::runtime_error("disconnected"); } /* now write */ @@ -837,10 +799,8 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error) int result = pa_stream_write(stream, chunk, size, nullptr, 0, PA_SEEK_RELATIVE); - if (result < 0) { - SetPulseError(error, context, "pa_stream_write() failed"); - return 0; - } + if (result < 0) + throw MakePulseError(context, "pa_stream_write() failed"); return size; } @@ -882,35 +842,27 @@ PulseOutput::Pause() /* check if the stream is (already/still) connected */ - Error error; - if (!WaitStream(error)) { - LogError(error); - return false; - } + WaitStream(); assert(context != nullptr); /* cork the stream */ - if (!pa_stream_is_corked(stream) && !StreamPause(true, error)) { - LogError(error); - return false; - } + if (!pa_stream_is_corked(stream)) + StreamPause(true); return true; } inline bool PulseOutput::TestDefaultDevice() -{ +try { const ConfigBlock empty; - PulseOutput *po = PulseOutput::Create(empty, IgnoreError()); - if (po == nullptr) - return false; - - bool success = po->WaitConnection(IgnoreError()); - delete po; - return success; + PulseOutput po(empty); + po.WaitConnection(); + return true; +} catch (const std::runtime_error &e) { + return false; } static bool |