refactor(pulseaudio): Use index instead of name to track sinks

This commit is contained in:
NBonaparte 2017-09-17 16:46:51 -07:00
parent 23ee9afb6f
commit 916c7b6852
2 changed files with 26 additions and 40 deletions

View file

@ -66,11 +66,9 @@ class pulseaudio {
// specified sink name // specified sink name
string spec_s_name; string spec_s_name;
// sink currently in use
string s_name;
// default sink name // default sink name
string def_s_name; string def_s_name;
uint32_t s_index{0}; uint32_t m_index{0};
}; };
POLYBAR_NS_END POLYBAR_NS_END

View file

@ -2,7 +2,6 @@
// TODO possibly move all the callback functions to lambda functions // TODO possibly move all the callback functions to lambda functions
// create base volume backend class (mixer/control, pulseaudio inherits from base class) // create base volume backend class (mixer/control, pulseaudio inherits from base class)
// use index instead of name internally?
POLYBAR_NS POLYBAR_NS
/* Multichannel volumes: /* Multichannel volumes:
@ -58,17 +57,14 @@ pulseaudio::pulseaudio(string&& sink_name) : spec_s_name(sink_name) {
pa_operation* op = pa_context_get_sink_info_by_name(m_context, sink_name.c_str(), sink_info_callback, this); pa_operation* op = pa_context_get_sink_info_by_name(m_context, sink_name.c_str(), sink_info_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
if (exists) if (!exists) {
s_name = sink_name;
else {
op = pa_context_get_server_info(m_context, get_default_sink_callback, this); op = pa_context_get_server_info(m_context, get_default_sink_callback, this);
if (!op) { if (!op) {
throw pulseaudio_error("Failed to get pulseaudio server info."); throw pulseaudio_error("Failed to get pulseaudio server info.");
} }
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
s_name = def_s_name;
// get the sink index // get the sink index
op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), sink_info_callback, this); op = pa_context_get_sink_info_by_name(m_context, def_s_name.c_str(), sink_info_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
} }
@ -95,7 +91,7 @@ pulseaudio::~pulseaudio() {
* Get sink name * Get sink name
*/ */
const string& pulseaudio::get_name() { const string& pulseaudio::get_name() {
return s_name; return spec_s_name;
} }
/** /**
@ -119,21 +115,20 @@ int pulseaudio::process_events() {
switch (m_events.front()) { switch (m_events.front()) {
// try to get specified sink // try to get specified sink
case evtype::NEW: case evtype::NEW:
// redundant if already using specified sink
o = pa_context_get_sink_info_by_name(m_context, spec_s_name.c_str(), sink_info_callback, this); o = pa_context_get_sink_info_by_name(m_context, spec_s_name.c_str(), sink_info_callback, this);
wait_loop(o, m_mainloop); wait_loop(o, m_mainloop);
if (exists)
s_name = spec_s_name;
break; break;
// get volume // get volume
case evtype::CHANGE: case evtype::CHANGE:
o = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); o = pa_context_get_sink_info_by_index(m_context, m_index, get_sink_volume_callback, this);
wait_loop(o, m_mainloop); wait_loop(o, m_mainloop);
break; break;
// get default sink // get default sink
case evtype::REMOVE: case evtype::REMOVE:
o = pa_context_get_server_info(m_context, get_default_sink_callback, this); o = pa_context_get_server_info(m_context, get_default_sink_callback, this);
wait_loop(o, m_mainloop); wait_loop(o, m_mainloop);
o = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), sink_info_callback, this); o = pa_context_get_sink_info_by_name(m_context, def_s_name.c_str(), sink_info_callback, this);
wait_loop(o, m_mainloop); wait_loop(o, m_mainloop);
break; break;
} }
@ -148,11 +143,11 @@ int pulseaudio::process_events() {
*/ */
int pulseaudio::get_volume() { int pulseaudio::get_volume() {
pa_threaded_mainloop_lock(m_mainloop); pa_threaded_mainloop_lock(m_mainloop);
pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); pa_operation *op = pa_context_get_sink_info_by_index(m_context, m_index, get_sink_volume_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_unlock(m_mainloop);
// alternatively, user pa_cvolume_avg_mask() to average selected channels // alternatively, user pa_cvolume_avg_mask() to average selected channels
return math_util::percentage(pa_cvolume_max(&cv), PA_VOLUME_MUTED, PA_VOLUME_NORM); return static_cast<int>(pa_cvolume_max(&cv) * 100.0f / PA_VOLUME_NORM + 0.5f);
} }
/** /**
@ -160,11 +155,11 @@ int pulseaudio::get_volume() {
*/ */
void pulseaudio::set_volume(float percentage) { void pulseaudio::set_volume(float percentage) {
pa_threaded_mainloop_lock(m_mainloop); pa_threaded_mainloop_lock(m_mainloop);
pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); pa_operation *op = pa_context_get_sink_info_by_index(m_context, m_index, get_sink_volume_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_volume_t vol = math_util::percentage_to_value<pa_volume_t>(percentage, PA_VOLUME_MUTED, PA_VOLUME_NORM); pa_volume_t vol = math_util::percentage_to_value<pa_volume_t>(percentage, PA_VOLUME_MUTED, PA_VOLUME_NORM);
pa_cvolume_scale(&cv, vol); pa_cvolume_scale(&cv, vol);
op = pa_context_set_sink_volume_by_name(m_context, s_name.c_str(), &cv, simple_callback, this); op = pa_context_set_sink_volume_by_index(m_context, m_index, &cv, simple_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_unlock(m_mainloop);
} }
@ -173,15 +168,16 @@ void pulseaudio::set_volume(float percentage) {
* Increment or decrement volume by given percentage (prevents accumulation of rounding errors from get_volume) * Increment or decrement volume by given percentage (prevents accumulation of rounding errors from get_volume)
*/ */
void pulseaudio::inc_volume(int delta_perc) { void pulseaudio::inc_volume(int delta_perc) {
// set max value?
pa_threaded_mainloop_lock(m_mainloop); pa_threaded_mainloop_lock(m_mainloop);
pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); pa_operation *op = pa_context_get_sink_info_by_index(m_context, m_index, get_sink_volume_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_volume_t vol = math_util::percentage_to_value<pa_volume_t>(abs(delta_perc), PA_VOLUME_MUTED, PA_VOLUME_NORM); pa_volume_t vol = math_util::percentage_to_value<pa_volume_t>(abs(delta_perc), PA_VOLUME_NORM);
if (delta_perc > 0) if (delta_perc > 0)
pa_cvolume_inc(&cv, vol); pa_cvolume_inc(&cv, vol);
else else
pa_cvolume_dec(&cv, vol); pa_cvolume_dec(&cv, vol);
op = pa_context_set_sink_volume_by_name(m_context, s_name.c_str(), &cv, simple_callback, this); op = pa_context_set_sink_volume_by_index(m_context, m_index, &cv, simple_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_unlock(m_mainloop);
} }
@ -191,7 +187,7 @@ void pulseaudio::inc_volume(int delta_perc) {
*/ */
void pulseaudio::set_mute(bool mode) { void pulseaudio::set_mute(bool mode) {
pa_threaded_mainloop_lock(m_mainloop); pa_threaded_mainloop_lock(m_mainloop);
pa_operation *op = pa_context_set_sink_mute_by_name(m_context, s_name.c_str(), mode, simple_callback, this); pa_operation *op = pa_context_set_sink_mute_by_index(m_context, m_index, mode, simple_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_unlock(m_mainloop);
} }
@ -208,7 +204,7 @@ void pulseaudio::toggle_mute() {
*/ */
bool pulseaudio::is_muted() { bool pulseaudio::is_muted() {
pa_threaded_mainloop_lock(m_mainloop); pa_threaded_mainloop_lock(m_mainloop);
pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), check_mute_callback, this); pa_operation *op = pa_context_get_sink_info_by_index(m_context, m_index, check_mute_callback, this);
wait_loop(op, m_mainloop); wait_loop(op, m_mainloop);
pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_unlock(m_mainloop);
return muted; return muted;
@ -250,26 +246,26 @@ void pulseaudio::get_sink_volume_callback(pa_context *context, const pa_sink_inf
*/ */
void pulseaudio::subscribe_callback(pa_context* context, pa_subscription_event_type_t t, uint32_t idx, void* userdata) { void pulseaudio::subscribe_callback(pa_context* context, pa_subscription_event_type_t t, uint32_t idx, void* userdata) {
pulseaudio *This = static_cast<pulseaudio *>(userdata); pulseaudio *This = static_cast<pulseaudio *>(userdata);
if (idx == PA_INVALID_INDEX)
throw pulseaudio_error("Invalid index given: " + string{pa_strerror(pa_context_errno(context))});
switch(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { switch(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
case PA_SUBSCRIPTION_EVENT_SINK: case PA_SUBSCRIPTION_EVENT_SINK:
switch(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { switch(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
case PA_SUBSCRIPTION_EVENT_NEW: case PA_SUBSCRIPTION_EVENT_NEW:
// if using the default sink, check if the new sink matches our specified sink // if using the default sink, check if the new sink matches our specified sink
if (This->s_name == This->def_s_name && This->spec_s_name != This->def_s_name) { //if (This->s_name == This->def_s_name && This->spec_s_name != This->def_s_name) {
printf("NEW\n"); printf("NEW\n");
This->m_events.emplace(evtype::NEW); This->m_events.emplace(evtype::NEW);
} //}
break; break;
case PA_SUBSCRIPTION_EVENT_CHANGE: case PA_SUBSCRIPTION_EVENT_CHANGE:
if (idx == PA_INVALID_INDEX) { if (idx == This->m_index) {
throw pulseaudio_error("Invalid index given: " + string{pa_strerror(pa_context_errno(context))});
} else if (idx == This->s_index) {
printf("CHANGE\n"); printf("CHANGE\n");
This->m_events.emplace(evtype::CHANGE); This->m_events.emplace(evtype::CHANGE);
} }
break; break;
case PA_SUBSCRIPTION_EVENT_REMOVE: case PA_SUBSCRIPTION_EVENT_REMOVE:
if (idx == This->s_index) { if (idx == This->m_index) {
printf("REMOVE\n"); printf("REMOVE\n");
This->m_events.emplace(evtype::REMOVE); This->m_events.emplace(evtype::REMOVE);
} }
@ -298,7 +294,6 @@ void pulseaudio::get_default_sink_callback(pa_context *context, const pa_server_
if (!info) { if (!info) {
throw pulseaudio_error("Failed to get server information: %s" + string{pa_strerror(pa_context_errno(context))}); throw pulseaudio_error("Failed to get server information: %s" + string{pa_strerror(pa_context_errno(context))});
} else { } else {
This->s_name = info->default_sink_name;
This->def_s_name = info->default_sink_name; This->def_s_name = info->default_sink_name;
} }
pa_threaded_mainloop_signal(This->m_mainloop, 0); pa_threaded_mainloop_signal(This->m_mainloop, 0);
@ -310,19 +305,11 @@ void pulseaudio::get_default_sink_callback(pa_context *context, const pa_server_
void pulseaudio::sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *userdata) { void pulseaudio::sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *userdata) {
(void) context; (void) context;
pulseaudio *This = static_cast<pulseaudio *>(userdata); pulseaudio *This = static_cast<pulseaudio *>(userdata);
if (eol < 0) { if (eol || !info) {
//throw pulseaudio_error("Failed to get server information: " + string{pa_strerror(pa_context_errno(context))});
This->exists = false;
pa_threaded_mainloop_signal(This->m_mainloop, 0);
return;
}
if (eol)
return;
if (!info) {
This->exists = false; This->exists = false;
} else { } else {
This->exists = true; This->exists = true;
This->s_index = info->index; This->m_index = info->index;
} }
pa_threaded_mainloop_signal(This->m_mainloop, 0); pa_threaded_mainloop_signal(This->m_mainloop, 0);
} }
@ -352,4 +339,5 @@ inline void pulseaudio::wait_loop(pa_operation *op, pa_threaded_mainloop *loop)
pa_threaded_mainloop_wait(loop); pa_threaded_mainloop_wait(loop);
pa_operation_unref(op); pa_operation_unref(op);
} }
POLYBAR_NS_END POLYBAR_NS_END