From 916c7b6852df4d3f2dd3a090d04943c1fa4a3d47 Mon Sep 17 00:00:00 2001
From: NBonaparte <nbonaparte@protonmail.com>
Date: Sun, 17 Sep 2017 16:46:51 -0700
Subject: [PATCH] refactor(pulseaudio): Use index instead of name to track
 sinks

---
 include/adapters/pulseaudio.hpp |  4 +--
 src/adapters/pulseaudio.cpp     | 62 +++++++++++++--------------------
 2 files changed, 26 insertions(+), 40 deletions(-)

diff --git a/include/adapters/pulseaudio.hpp b/include/adapters/pulseaudio.hpp
index 1e3e7f47..28411b4c 100644
--- a/include/adapters/pulseaudio.hpp
+++ b/include/adapters/pulseaudio.hpp
@@ -66,11 +66,9 @@ class pulseaudio {
 
     // specified sink name
     string spec_s_name;
-    // sink currently in use
-    string s_name;
     // default sink name
     string def_s_name;
-    uint32_t s_index{0};
+    uint32_t m_index{0};
 };
 
 POLYBAR_NS_END
diff --git a/src/adapters/pulseaudio.cpp b/src/adapters/pulseaudio.cpp
index 625794fa..0a3601d7 100644
--- a/src/adapters/pulseaudio.cpp
+++ b/src/adapters/pulseaudio.cpp
@@ -2,7 +2,6 @@
 
 // TODO possibly move all the callback functions to lambda functions
 // create base volume backend class (mixer/control, pulseaudio inherits from base class)
-// use index instead of name internally?
 POLYBAR_NS
 
 /* 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);
   wait_loop(op, m_mainloop);
-  if (exists)
-    s_name = sink_name;
-  else {
+  if (!exists) {
     op = pa_context_get_server_info(m_context, get_default_sink_callback, this);
     if (!op) {
       throw pulseaudio_error("Failed to get pulseaudio server info.");
     }
     wait_loop(op, m_mainloop);
-    s_name = def_s_name;
     // 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);
   }
 
@@ -95,7 +91,7 @@ pulseaudio::~pulseaudio() {
  * Get sink 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()) {
       // try to get specified sink
       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);
         wait_loop(o, m_mainloop);
-        if (exists)
-          s_name = spec_s_name;
         break;
       // get volume
       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);
         break;
       // get default sink 
       case evtype::REMOVE:
         o = pa_context_get_server_info(m_context, get_default_sink_callback, this);
         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);
         break;
     }
@@ -148,11 +143,11 @@ int pulseaudio::process_events() {
  */
 int pulseaudio::get_volume() {
   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);
   pa_threaded_mainloop_unlock(m_mainloop);
   // 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) {
   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);
   pa_volume_t vol = math_util::percentage_to_value<pa_volume_t>(percentage, PA_VOLUME_MUTED, PA_VOLUME_NORM);
   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);
   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)
  */
 void pulseaudio::inc_volume(int delta_perc) {
+  // set max value?
   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);
-  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)
     pa_cvolume_inc(&cv, vol);
   else
     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);
   pa_threaded_mainloop_unlock(m_mainloop);
 }
@@ -191,7 +187,7 @@ void pulseaudio::inc_volume(int delta_perc) {
  */
 void pulseaudio::set_mute(bool mode) {
   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);
   pa_threaded_mainloop_unlock(m_mainloop);
 }
@@ -208,7 +204,7 @@ void pulseaudio::toggle_mute() {
  */
 bool pulseaudio::is_muted() {
   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);
   pa_threaded_mainloop_unlock(m_mainloop);
   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) {
   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) {
     case PA_SUBSCRIPTION_EVENT_SINK:
       switch(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
         case PA_SUBSCRIPTION_EVENT_NEW:
 	  // 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");
             This->m_events.emplace(evtype::NEW);
-          }
+          //}
 	  break;
         case PA_SUBSCRIPTION_EVENT_CHANGE:
-          if (idx == PA_INVALID_INDEX) {
-            throw pulseaudio_error("Invalid index given: " + string{pa_strerror(pa_context_errno(context))});
-          } else if (idx == This->s_index) {
+          if (idx == This->m_index) {
 	  printf("CHANGE\n");
             This->m_events.emplace(evtype::CHANGE);
           }
           break;
         case PA_SUBSCRIPTION_EVENT_REMOVE:
-          if (idx == This->s_index) {
+          if (idx == This->m_index) {
 	  printf("REMOVE\n");
             This->m_events.emplace(evtype::REMOVE);
           }
@@ -298,7 +294,6 @@ void pulseaudio::get_default_sink_callback(pa_context *context, const pa_server_
   if (!info) {
     throw pulseaudio_error("Failed to get server information: %s" + string{pa_strerror(pa_context_errno(context))});
   } else {
-    This->s_name = info->default_sink_name; 
     This->def_s_name = info->default_sink_name; 
   }
   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) context;
   pulseaudio *This = static_cast<pulseaudio *>(userdata);
-  if (eol < 0) {
-    //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) {
+  if (eol || !info) {
     This->exists = false;
   } else {
     This->exists = true;
-    This->s_index = info->index;
+    This->m_index = info->index;
   }
   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_operation_unref(op);
 }
+
 POLYBAR_NS_END