Skip to content

Commit

Permalink
pai dis/connect methods and error handling
Browse files Browse the repository at this point in the history
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
  • Loading branch information
patroclos committed Aug 9, 2016
1 parent d89e02e commit a6953ac
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 42 deletions.
5 changes: 5 additions & 0 deletions include/painterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<uint32_t, InputInfo> &getInputInfo();
Expand Down
95 changes: 58 additions & 37 deletions src/painterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 13 additions & 5 deletions src/pamix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand Down

0 comments on commit a6953ac

Please sign in to comment.