From db28882a5f0de835bc81d075f6ff35348736ec77 Mon Sep 17 00:00:00 2001
From: Conor Curran <conor.curran@canonical.com>
Date: Mon, 25 Oct 2010 15:44:47 -0400
Subject: reconnect bug hopefully fixed for good

---
 src/pulse-manager.c | 77 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 12 deletions(-)

(limited to 'src')

diff --git a/src/pulse-manager.c b/src/pulse-manager.c
index 8779525..353c297 100644
--- a/src/pulse-manager.c
+++ b/src/pulse-manager.c
@@ -20,7 +20,6 @@ You should have received a copy of the GNU General Public License along
 with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 #include <pulse/glib-mainloop.h>
 #include <pulse/error.h>
 #include <pulse/gccmacro.h>
@@ -28,14 +27,18 @@ with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "pulse-manager.h"
 #include "dbus-menu-manager.h"
 
+#define RECONNECT_DELAY 5
+
 static GHashTable *sink_hash = NULL;
 static SoundServiceDbus *dbus_service = NULL;
 static gint DEFAULT_SINK_INDEX = -1;
 static gboolean pa_server_available = FALSE;
-// PA related
+static gint reconnect_idle_id = 0;
 static pa_context *pulse_context = NULL;
 static pa_glib_mainloop *pa_main_loop = NULL;
+
 static void context_state_callback(pa_context *c, void *userdata);
+static gboolean reconnect_to_pulse();
 static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink_info, int eol, void *userdata);
 static void context_success_callback(pa_context *c, int success, void *userdata);
 static void pulse_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata);
@@ -61,15 +64,19 @@ void establish_pulse_activities(SoundServiceDbus *service)
   dbus_service = service;
   pa_main_loop = pa_glib_mainloop_new(g_main_context_default());
   g_assert(pa_main_loop);
-  pulse_context = pa_context_new(pa_glib_mainloop_get_api(pa_main_loop), "ayatana.indicator.sound");
+  pulse_context = pa_context_new(pa_glib_mainloop_get_api(pa_main_loop),
+                                 "ayatana.indicator.sound");
   g_assert(pulse_context);
 
-  sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_sink_info);
+  sink_hash = g_hash_table_new_full(g_direct_hash,
+                                    g_direct_equal,
+                                    NULL,
+                                    destroy_sink_info);
 
   // Establish event callback registration
-  pa_context_set_state_callback(pulse_context, context_state_callback, NULL);
-  dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0);
-  pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);
+  pa_context_set_state_callback (pulse_context, context_state_callback, NULL);
+  dbus_menu_manager_update_pa_state (FALSE, FALSE, FALSE, 0);
+  pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);
 }
 
 /**
@@ -81,6 +88,39 @@ pa_context* get_context()
   return pulse_context;
 }
 
+static gboolean
+reconnect_to_pulse()
+{
+  // reset
+  if (pulse_context != NULL) {
+    g_debug("freeing the pulse context");
+    pa_context_unref(pulse_context);
+    pulse_context = NULL;
+  }
+
+  if (sink_hash != NULL) {
+   g_hash_table_destroy(sink_hash);
+    sink_hash = NULL;
+  }
+
+  // reconnect
+  pulse_context = pa_context_new(pa_glib_mainloop_get_api(pa_main_loop),
+                                 "ayatana.indicator.sound");
+  g_assert(pulse_context);
+  sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                    NULL,
+                                    destroy_sink_info);
+  // Establish event callback registration
+  pa_context_set_state_callback (pulse_context, context_state_callback, NULL);
+  int result = pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);
+  if (result < 0) {
+    g_warning ("Failed to connect context: %s",
+               pa_strerror (pa_context_errno (pulse_context)));
+  }
+  reconnect_idle_id = 0;  
+  return FALSE;
+}
+
 /**
 close_pulse_activites()
 Gracefully close our connection with the Pulse async library.
@@ -294,9 +334,6 @@ static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, in
 static void pulse_default_sink_info_callback(pa_context *c, const pa_sink_info *info, int eol, void *userdata)
 {
   if (eol > 0) {
-    if (pa_context_errno(c) == PA_ERR_NOENTITY)
-      return;
-    g_warning("Default Sink info callback failure");
     return;
   } else {
     DEFAULT_SINK_INDEX = info->index;
@@ -416,7 +453,9 @@ static gboolean has_volume_changed(const pa_sink_info* new_sink, sink_info* cach
 }
 
 
-static void pulse_server_info_callback(pa_context *c, const pa_server_info *info, void *userdata)
+static void pulse_server_info_callback(pa_context *c,
+                                       const pa_server_info *info,
+                                       void *userdata)
 {
   /*    g_debug("server info callback");*/
   pa_operation *operation;
@@ -428,7 +467,10 @@ static void pulse_server_info_callback(pa_context *c, const pa_server_info *info
   }
   pa_server_available = TRUE;
   if (info->default_sink_name != NULL) {
-    if (!(operation = pa_context_get_sink_info_by_name(c, info->default_sink_name, pulse_default_sink_info_callback, userdata))) {
+    if (!(operation = pa_context_get_sink_info_by_name(c,
+                                                       info->default_sink_name,
+                                                       pulse_default_sink_info_callback,
+                                                       userdata))) {
       g_warning("pa_context_get_sink_info_by_name() failed");
     } else {
       pa_operation_unref(operation);
@@ -504,6 +546,17 @@ static void context_state_callback(pa_context *c, void *userdata)
   case PA_CONTEXT_FAILED:
     g_warning("FAILED to retrieve context - Is PulseAudio Daemon running ?");
     pa_server_available = FALSE;
+    dbus_menu_manager_update_pa_state(TRUE,
+                                      pa_server_available,
+                                      default_sink_is_muted(),
+                                      get_default_sink_volume());
+      
+    if (reconnect_idle_id == 0){
+      reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY,
+                                                 reconnect_to_pulse,
+                                                 NULL);      
+                                                
+    }     
     break;
   case PA_CONTEXT_TERMINATED:
     /*			g_debug("context terminated");*/
-- 
cgit v1.2.3


From fbf5ac2d80a9bc536bb0ab10dc54121301c4b7c4 Mon Sep 17 00:00:00 2001
From: Conor Curran <conor.curran@canonical.com>
Date: Wed, 3 Nov 2010 16:27:56 +0000
Subject: tidy up

---
 src/pulse-manager.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

(limited to 'src')

diff --git a/src/pulse-manager.c b/src/pulse-manager.c
index 353c297..1ff1598 100644
--- a/src/pulse-manager.c
+++ b/src/pulse-manager.c
@@ -91,9 +91,9 @@ pa_context* get_context()
 static gboolean
 reconnect_to_pulse()
 {
+  g_debug("Attempt to reconnect to pulse");
   // reset
   if (pulse_context != NULL) {
-    g_debug("freeing the pulse context");
     pa_context_unref(pulse_context);
     pulse_context = NULL;
   }
@@ -102,21 +102,23 @@ reconnect_to_pulse()
    g_hash_table_destroy(sink_hash);
     sink_hash = NULL;
   }
-
-  // reconnect
-  pulse_context = pa_context_new(pa_glib_mainloop_get_api(pa_main_loop),
-                                 "ayatana.indicator.sound");
+  pulse_context = pa_context_new( pa_glib_mainloop_get_api( pa_main_loop ),
+                                  "ayatana.indicator.sound" );
   g_assert(pulse_context);
-  sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-                                    NULL,
-                                    destroy_sink_info);
+  sink_hash = g_hash_table_new_full( g_direct_hash, g_direct_equal,
+                                     NULL,
+                                     destroy_sink_info );
   // Establish event callback registration
   pa_context_set_state_callback (pulse_context, context_state_callback, NULL);
   int result = pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);
+
   if (result < 0) {
     g_warning ("Failed to connect context: %s",
                pa_strerror (pa_context_errno (pulse_context)));
   }
+  // we always want to cancel any continious callbacks with the existing timeout
+  // if the connection failed the new context created above will catch any updates
+  // to do with the state of pulse and thus take care of business.
   reconnect_idle_id = 0;  
   return FALSE;
 }
@@ -544,7 +546,7 @@ static void context_state_callback(pa_context *c, void *userdata)
     /*			g_debug("context setting name");*/
     break;
   case PA_CONTEXT_FAILED:
-    g_warning("FAILED to retrieve context - Is PulseAudio Daemon running ?");
+    g_warning("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?");
     pa_server_available = FALSE;
     dbus_menu_manager_update_pa_state(TRUE,
                                       pa_server_available,
@@ -554,17 +556,16 @@ static void context_state_callback(pa_context *c, void *userdata)
     if (reconnect_idle_id == 0){
       reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY,
                                                  reconnect_to_pulse,
-                                                 NULL);      
-                                                
+                                                 NULL);                                                      
     }     
     break;
   case PA_CONTEXT_TERMINATED:
     /*			g_debug("context terminated");*/
     break;
   case PA_CONTEXT_READY:
-    g_debug("PA daemon is ready");
+    g_debug("PA_CONTEXT_READY");
     pa_operation *o;
-
+            
     pa_context_set_subscribe_callback(c, subscribed_events_callback, userdata);
 
     if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
-- 
cgit v1.2.3