diff options
-rw-r--r-- | src/pulse-manager.c | 84 |
1 files changed, 69 insertions, 15 deletions
diff --git a/src/pulse-manager.c b/src/pulse-manager.c index 8779525..1ff1598 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,41 @@ pa_context* get_context() return pulse_context; } +static gboolean +reconnect_to_pulse() +{ + g_debug("Attempt to reconnect to pulse"); + // reset + if (pulse_context != NULL) { + pa_context_unref(pulse_context); + pulse_context = NULL; + } + + if (sink_hash != NULL) { + g_hash_table_destroy(sink_hash); + sink_hash = NULL; + } + 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))); + } + // 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; +} + /** close_pulse_activites() Gracefully close our connection with the Pulse async library. @@ -294,9 +336,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 +455,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 +469,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); @@ -502,16 +546,26 @@ 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, + 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");*/ 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) |