diff options
author | Chris Robinson <[email protected]> | 2019-05-04 20:35:24 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-05-04 20:35:24 -0700 |
commit | 31c29f1ea85e9edf0061721082f6f39d8e862922 (patch) | |
tree | b4600f9b8a6fa2eb231bfd762e9188940ed70a8a | |
parent | 95d19be36bf1d8b08fdb9cd09d94bc37658deea6 (diff) |
Use exceptions when opening and reseting the PulseAudio backend
-rw-r--r-- | Alc/backends/pulseaudio.cpp | 199 |
1 files changed, 82 insertions, 117 deletions
diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index f3d5d453..cc65e5fc 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -38,6 +38,7 @@ #include "alu.h" #include "alconfig.h" #include "compat.h" +#include "alexcpt.h" #include <pulse/pulseaudio.h> @@ -264,7 +265,7 @@ void wait_for_operation(pa_operation *op, std::unique_lock<std::mutex> &plock) } -pa_context *connect_context(std::unique_lock<std::mutex> &plock, ALboolean silent) +pa_context *connect_context(std::unique_lock<std::mutex> &plock) { const char *name{"OpenAL Soft"}; @@ -280,11 +281,7 @@ pa_context *connect_context(std::unique_lock<std::mutex> &plock, ALboolean silen } pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; - if(!context) - { - ERR("pa_context_new() failed\n"); - return nullptr; - } + if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"}; pa_context_set_state_callback(context, context_state_callback, nullptr); @@ -308,25 +305,15 @@ pa_context *connect_context(std::unique_lock<std::mutex> &plock, ALboolean silen if(err < 0) { - if(!silent) - ERR("Context did not connect: %s\n", pa_strerror(err)); pa_context_unref(context); - context = nullptr; + throw al::backend_exception{ALC_INVALID_VALUE, "Context did not connect (%s)", + pa_strerror(err)}; } return context; } -pa_context *pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) -{ - std::unique_lock<std::mutex> plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(LIKELY(context)) - pa_context_set_state_callback(context, state_cb, ptr); - return context; -} - void pulse_close(pa_context *context, pa_stream *stream) { std::lock_guard<std::mutex> _{pulse_lock}; @@ -366,13 +353,11 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock<std::m pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, BackendType type) { - pa_stream *stream{pa_stream_new(context, - (type==BackendType::Playback) ? "Playback Stream" : "Capture Stream", spec, chanmap)}; + const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"}; + pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)}; if(!stream) - { - ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); - return nullptr; - } + throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_stream_new() failed (%s)", + pa_strerror(pa_context_errno(context))}; pa_stream_set_state_callback(stream, stream_state_callback, nullptr); @@ -381,9 +366,9 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock<std::m pa_stream_connect_record(stream, device_name, attr, flags)}; if(err < 0) { - ERR("Stream did not connect: %s\n", pa_strerror(err)); pa_stream_unref(stream); - return nullptr; + throw al::backend_exception{ALC_INVALID_VALUE, "%s did not connect (%s)", stream_id, + pa_strerror(err)}; } pa_stream_state_t state; @@ -391,9 +376,10 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock<std::m { if(!PA_STREAM_IS_GOOD(state)) { - ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + int err{pa_context_errno(context)}; pa_stream_unref(stream); - return nullptr; + throw al::backend_exception{ALC_INVALID_VALUE, "%s did not get ready (%s)", stream_id, + pa_strerror(err)}; } pulse_condvar.wait(plock); @@ -440,23 +426,21 @@ void probePlaybackDevices() { PlaybackDevices.clear(); - std::unique_lock<std::mutex> plock{pulse_lock}; + try { + std::unique_lock<std::mutex> plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(!context) return; + pa_context *context{connect_context(plock)}; - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | - PA_STREAM_DONT_MOVE}; + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Playback)}; - if(stream) - { + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, + nullptr, BackendType::Playback)}; pa_operation *op{pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; wait_for_operation(op, plock); @@ -464,13 +448,16 @@ void probePlaybackDevices() pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - } - pa_operation *op{pa_context_get_sink_info_list(context, device_sink_callback, nullptr)}; - wait_for_operation(op, plock); + op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr); + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } } @@ -510,23 +497,21 @@ void probeCaptureDevices() { CaptureDevices.clear(); - std::unique_lock<std::mutex> plock{pulse_lock}; + try { + std::unique_lock<std::mutex> plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(!context) return; + pa_context *context{connect_context(plock)}; - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | - PA_STREAM_DONT_MOVE}; + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Capture)}; - if(stream) - { + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Capture)}; pa_operation *op{pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), device_source_callback, nullptr)}; wait_for_operation(op, plock); @@ -534,13 +519,16 @@ void probeCaptureDevices() pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - } - pa_operation *op{pa_context_get_source_info_list(context, device_source_callback, nullptr)}; - wait_for_operation(op, plock); + op = pa_context_get_source_info_list(context, device_source_callback, nullptr); + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } } @@ -763,16 +751,16 @@ ALCenum PulsePlayback::open(const ALCchar *name) { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; pulse_name = iter->device_name.c_str(); dev_name = iter->name.c_str(); } - mContext = pulse_open(&PulsePlayback::contextStateCallbackC, this); - if(!mContext) return ALC_INVALID_VALUE; - std::unique_lock<std::mutex> plock{pulse_lock}; + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this); + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; @@ -782,21 +770,15 @@ ALCenum PulsePlayback::open(const ALCchar *name) spec.rate = 44100; spec.channels = 2; - TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); if(!pulse_name) { pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); if(pulse_name && !pulse_name[0]) pulse_name = nullptr; } + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, BackendType::Playback); - if(!mStream) - { - plock.unlock(); - pulse_close(mContext, mStream); - mContext = nullptr; - return ALC_INVALID_VALUE; - } + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); @@ -877,10 +859,7 @@ ALCboolean PulsePlayback::reset() mSpec.channels = mDevice->channelsFromFmt(); if(pa_sample_spec_valid(&mSpec) == 0) - { - ERR("Invalid sample format\n"); - return ALC_FALSE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; const char *mapname{nullptr}; pa_channel_map chanmap; @@ -912,10 +891,8 @@ ALCboolean PulsePlayback::reset() break; } if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_FALSE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", + DevFmtChannelsString(mDevice->FmtChans)}; SetDefaultWFXChannelOrder(mDevice); mAttr.maxlength = -1; @@ -926,7 +903,6 @@ ALCboolean PulsePlayback::reset() mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); - if(!mStream) return ALC_FALSE; pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); @@ -1152,16 +1128,16 @@ ALCenum PulseCapture::open(const ALCchar *name) { return entry.name == name; } ); if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; pulse_name = iter->device_name.c_str(); mDevice->DeviceName = iter->name; } - mContext = pulse_open(&PulseCapture::contextStateCallbackC, this); - if(!mContext) return ALC_INVALID_VALUE; - std::unique_lock<std::mutex> plock{pulse_lock}; + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); + switch(mDevice->FmtType) { case DevFmtUByte: @@ -1179,8 +1155,8 @@ ALCenum PulseCapture::open(const ALCchar *name) case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } const char *mapname{nullptr}; @@ -1209,29 +1185,18 @@ ALCenum PulseCapture::open(const ALCchar *name) mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; break; case DevFmtAmbi3D: - ERR("%s capture samples not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", + DevFmtChannelsString(mDevice->FmtChans)}; mSpec.rate = mDevice->Frequency; mSpec.channels = mDevice->channelsFromFmt(); if(pa_sample_spec_valid(&mSpec) == 0) - { - ERR("Invalid sample format\n"); - return ALC_INVALID_VALUE; - } - - if(!pa_channel_map_init_auto(&chanmap, mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) - { - ERR("Couldn't build map for channel count (%d)!\n", mSpec.channels); - return ALC_INVALID_VALUE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; ALuint samples{mDevice->BufferSize}; samples = maxu(samples, 100 * mDevice->Frequency / 1000); @@ -1249,7 +1214,6 @@ ALCenum PulseCapture::open(const ALCchar *name) TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Capture); - if(!mStream) return ALC_INVALID_VALUE; pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); @@ -1437,15 +1401,16 @@ bool PulseBackendFactory::init() if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - std::unique_lock<std::mutex> plock{pulse_lock}; - - pa_context *context{connect_context(plock, AL_TRUE)}; - if(!context) return false; - - pa_context_disconnect(context); - pa_context_unref(context); - - return true; + try { + std::unique_lock<std::mutex> plock{pulse_lock}; + pa_context *context{connect_context(plock)}; + pa_context_disconnect(context); + pa_context_unref(context); + return true; + } + catch(...) { + return false; + } } bool PulseBackendFactory::querySupport(BackendType type) |