From a6953ac70ed67dbc2ed3ce480e413fd461f98803 Mon Sep 17 00:00:00 2001 From: Joshua Jensch Date: Tue, 9 Aug 2016 18:10:47 +0200 Subject: [PATCH] pai dis/connect methods and error handling PAInterface got the following new methods: connect() closes open connection and opens a new one disconnect() closes open connection isConnected() If pamix cant establish a connection on program start, it will exit with an error message --- include/painterface.h | 5 +++ src/painterface.cpp | 95 ++++++++++++++++++++++++++----------------- src/pamix.cpp | 18 +++++--- 3 files changed, 76 insertions(+), 42 deletions(-) diff --git a/include/painterface.h b/include/painterface.h index 245f507..e4b847b 100644 --- a/include/painterface.h +++ b/include/painterface.h @@ -61,6 +61,7 @@ typedef void (*pai_subscription_cb)(PAInterface *, const pai_subscription_type_t class PAInterface { private: + const char * m_ContextName; pa_threaded_mainloop *m_Mainloop; pa_mainloop_api * m_MainloopApi; pa_context * m_Context; @@ -98,6 +99,10 @@ class PAInterface PAInterface(const char *context_name); ~PAInterface(); + bool connect(); + void disconnect(); + bool isConnected(); + void subscribe(pai_subscription_cb callback); std::map &getInputInfo(); diff --git a/src/painterface.cpp b/src/painterface.cpp index 565c8ce..af2f736 100644 --- a/src/painterface.cpp +++ b/src/painterface.cpp @@ -50,48 +50,13 @@ SinkInfo::SinkInfo(const pa_sink_info *info) } PAInterface::PAInterface(const char *context_name) + : m_ContextName(context_name), m_Mainloop(0), m_MainloopApi(0), m_Context(0) { - m_Subscription_callback = nullptr; - m_Mainloop = pa_threaded_mainloop_new(); - - assert(m_Mainloop); - - m_MainloopApi = pa_threaded_mainloop_get_api(m_Mainloop); - m_Context = pa_context_new(m_MainloopApi, context_name); - assert(m_Context); - - pa_context_set_state_callback(m_Context, &PAInterface::cb_context_state, this); - pa_threaded_mainloop_lock(m_Mainloop); - - assert(pa_threaded_mainloop_start(m_Mainloop) == 0); - assert(pa_context_connect(m_Context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) == 0); - - for (;;) - { - pa_context_state_t state = pa_context_get_state(m_Context); - assert(PA_CONTEXT_IS_GOOD(state)); - if (state == PA_CONTEXT_READY) - break; - pa_threaded_mainloop_wait(m_Mainloop); - } - - pa_context_set_subscribe_callback(m_Context, &PAInterface::cb_subscription_event, this); - pa_operation *subscrop = pa_context_subscribe(m_Context, PA_SUBSCRIPTION_MASK_ALL, &PAInterface::cb_success, this); - - while (pa_operation_get_state(subscrop) == PA_OPERATION_RUNNING) - pa_threaded_mainloop_wait(m_Mainloop); - pa_operation_unref(subscrop); - - pa_threaded_mainloop_unlock(m_Mainloop); - updateSinks(); - updateInputs(); } PAInterface::~PAInterface() { - pa_context_disconnect(m_Context); - pa_threaded_mainloop_stop(m_Mainloop); - pa_threaded_mainloop_free(m_Mainloop); + disconnect(); } void PAInterface::signal_mainloop(void *interface) @@ -248,6 +213,62 @@ void PAInterface::_updateSinks(PAInterface *interface) pa_operation_unref(infooper); } +bool PAInterface::connect() +{ + m_Mainloop = pa_threaded_mainloop_new(); + + assert(m_Mainloop); + + m_MainloopApi = pa_threaded_mainloop_get_api(m_Mainloop); + m_Context = pa_context_new(m_MainloopApi, m_ContextName); + assert(m_Context); + + pa_context_set_state_callback(m_Context, &PAInterface::cb_context_state, this); + pa_threaded_mainloop_lock(m_Mainloop); + + if (pa_threaded_mainloop_start(m_Mainloop)) + return false; + if (pa_context_connect(m_Context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) + return false; + + for (;;) + { + pa_context_state_t state = pa_context_get_state(m_Context); + assert(PA_CONTEXT_IS_GOOD(state)); + if (state == PA_CONTEXT_READY) + break; + pa_threaded_mainloop_wait(m_Mainloop); + } + + pa_context_set_subscribe_callback(m_Context, &PAInterface::cb_subscription_event, this); + pa_operation *subscrop = pa_context_subscribe(m_Context, PA_SUBSCRIPTION_MASK_ALL, &PAInterface::cb_success, this); + + while (pa_operation_get_state(subscrop) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(m_Mainloop); + pa_operation_unref(subscrop); + + pa_threaded_mainloop_unlock(m_Mainloop); + updateSinks(); + updateInputs(); + return true; +} + +void PAInterface::disconnect() +{ + if (m_Context) + pa_context_disconnect(m_Context); + if (m_Mainloop) + { + pa_threaded_mainloop_stop(m_Mainloop); + pa_threaded_mainloop_free(m_Mainloop); + } +} + +bool PAInterface::isConnected() +{ + return m_Context ? pa_context_get_state(m_Context) == PA_CONTEXT_READY : false; +} + void PAInterface::updateInputs() { PAInterface::_updateInputs(this); diff --git a/src/pamix.cpp b/src/pamix.cpp index 14d6c27..c093bf9 100644 --- a/src/pamix.cpp +++ b/src/pamix.cpp @@ -393,18 +393,30 @@ void init_colors() init_pair(3, COLOR_RED, 0); } +void sig_handle_abort(int sig) +{ + endwin(); +} + int main(int argc, char **argv) { setlocale(LC_ALL, ""); initscr(); init_colors(); - curs_set(0); // make cursor invisible + curs_set(0); noecho(); + signal(SIGABRT, sig_handle_abort); signal(SIGWINCH, sig_handle_resize); PAInterface pai("pamix"); pai.subscribe(pai_subscription); + if(!pai.connect()) + { + endwin(); + fprintf(stderr, "Failed to connect to PulseAudio.\n"); + exit(1); + } updatesinks(&pai); std::thread inputT(inputThread, &pai); @@ -416,13 +428,9 @@ int main(int argc, char **argv) cv.wait(lk, [] { return !updateDataQ.empty(); }); if (updateDataQ.front().redrawAll) - { updatesinks(&pai); - } else - { updateMonitors(&pai); - } updateDataQ.pop(); } endwin();