diff options
Diffstat (limited to 'src/pulse-manager.c')
-rw-r--r-- | src/pulse-manager.c | 761 |
1 files changed, 365 insertions, 396 deletions
diff --git a/src/pulse-manager.c b/src/pulse-manager.c index 7323797..a9a47e4 100644 --- a/src/pulse-manager.c +++ b/src/pulse-manager.c @@ -50,7 +50,7 @@ static pa_cvolume construct_mono_volume(const pa_cvolume* vol); /** Future Refactoring notes - - Push all UI updates out through update PA state in the service. + - Push all UI updates out through update PA state in the service. - Collapse 3 update_sink_info into one. The essentially do the same thing from different contexts. **/ @@ -59,18 +59,18 @@ Entry point **/ 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"); - 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); - dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0); - pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); + 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"); + 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); + dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0); + pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); } /** @@ -79,7 +79,7 @@ Needed for testing - bah! **/ pa_context* get_context() { - return pulse_context; + return pulse_context; } /** @@ -88,44 +88,44 @@ Gracefully close our connection with the Pulse async library. **/ void close_pulse_activites() { - if (pulse_context != NULL){ -/* g_debug("freeing the pulse context");*/ - pa_context_unref(pulse_context); - pulse_context = NULL; - } - g_hash_table_destroy(sink_hash); - pa_glib_mainloop_free(pa_main_loop); - pa_main_loop = NULL; -/* g_debug("I just closed communication with Pulse");*/ + if (pulse_context != NULL) { + /* g_debug("freeing the pulse context");*/ + pa_context_unref(pulse_context); + pulse_context = NULL; + } + g_hash_table_destroy(sink_hash); + pa_glib_mainloop_free(pa_main_loop); + pa_main_loop = NULL; + /* g_debug("I just closed communication with Pulse");*/ } -/** +/** reconnect_to_pulse() In the event of Pulseaudio flapping in the wind handle gracefully without memory leaks ! */ static void 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); - dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0); - pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); + // 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); + dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0); + pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); } /** @@ -134,9 +134,9 @@ item destructor method for the sink_info hash **/ static void destroy_sink_info(void *value) { - sink_info *sink = (sink_info*)value; - g_free(sink->name); - g_free(sink); + sink_info *sink = (sink_info*)value; + g_free(sink->name); + g_free(sink); } /* @@ -144,125 +144,122 @@ Controllers & Utilities */ static gboolean determine_sink_availability() { - // Firstly check to see if we have any sinks - // if not get the hell out of here ! - if (g_hash_table_size(sink_hash) < 1){ -/* g_debug("Sink_available returning false because sinks_hash is empty !!!"); */ - DEFAULT_SINK_INDEX = -1; - return FALSE; - } - // Secondly, make sure the default sink index is set - // If the default sink index has not been set - // (via the server or has been reset because default sink has been removed), - // it will attempt to set it to the value of the first - // index in the array of keys from the sink_hash. - GList* keys = g_hash_table_get_keys(sink_hash); - GList* key = g_list_first(keys); - - DEFAULT_SINK_INDEX = (DEFAULT_SINK_INDEX < 0) ? GPOINTER_TO_INT(key->data) : DEFAULT_SINK_INDEX; - - // Thirdly ensure the default sink index does not have the name "auto_null" - sink_info* s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); - // Up until now the most rebust method to test this is to manually remove the available sink device - // kernel module and then reload (rmmod & modprobe). - // TODO: Edge case of dynamic loading and unloading of sinks should be handled also. -/* g_debug("About to test for to see if the available sink is null - s->name = %s", s->name);*/ - gboolean available = g_ascii_strncasecmp("auto_null", s->name, 9) != 0; -/* g_debug("PA_Manager -> determine_sink_availability: %i", available);*/ - return available; + // Firstly check to see if we have any sinks + // if not get the hell out of here ! + if (g_hash_table_size(sink_hash) < 1) { + /* g_debug("Sink_available returning false because sinks_hash is empty !!!"); */ + DEFAULT_SINK_INDEX = -1; + return FALSE; + } + // Secondly, make sure the default sink index is set + // If the default sink index has not been set + // (via the server or has been reset because default sink has been removed), + // it will attempt to set it to the value of the first + // index in the array of keys from the sink_hash. + GList* keys = g_hash_table_get_keys(sink_hash); + GList* key = g_list_first(keys); + + DEFAULT_SINK_INDEX = (DEFAULT_SINK_INDEX < 0) ? GPOINTER_TO_INT(key->data) : DEFAULT_SINK_INDEX; + + // Thirdly ensure the default sink index does not have the name "auto_null" + sink_info* s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); + // Up until now the most rebust method to test this is to manually remove the available sink device + // kernel module and then reload (rmmod & modprobe). + // TODO: Edge case of dynamic loading and unloading of sinks should be handled also. + /* g_debug("About to test for to see if the available sink is null - s->name = %s", s->name);*/ + gboolean available = g_ascii_strncasecmp("auto_null", s->name, 9) != 0; + /* g_debug("PA_Manager -> determine_sink_availability: %i", available);*/ + return available; } static gboolean default_sink_is_muted() { - if(DEFAULT_SINK_INDEX < 0) - return FALSE; - if (g_hash_table_size(sink_hash) < 1) - return FALSE; - sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); - return s->mute; + if (DEFAULT_SINK_INDEX < 0) + return FALSE; + if (g_hash_table_size(sink_hash) < 1) + return FALSE; + sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); + return s->mute; } static void check_sink_input_while_muted_event(gint sink_index) { -/* g_debug("SINKINPUTWHILEMUTED SIGNAL EVENT TO BE SENT FROM PA MANAGER - check trace for value");*/ + /* g_debug("SINKINPUTWHILEMUTED SIGNAL EVENT TO BE SENT FROM PA MANAGER - check trace for value");*/ - if (default_sink_is_muted(sink_index) == TRUE){ - sound_service_dbus_sink_input_while_muted (dbus_service, TRUE); - } - else{ - sound_service_dbus_sink_input_while_muted(dbus_service, FALSE); - } + if (default_sink_is_muted(sink_index) == TRUE) { + sound_service_dbus_sink_input_while_muted (dbus_service, TRUE); + } else { + sound_service_dbus_sink_input_while_muted(dbus_service, FALSE); + } } static gdouble get_default_sink_volume() { - if (DEFAULT_SINK_INDEX < 0) - return 0; - sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); - pa_volume_t vol = pa_cvolume_avg(&s->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; -/* g_debug("software volume = %f", volume_percent);*/ - return volume_percent; + if (DEFAULT_SINK_INDEX < 0) + return 0; + sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); + pa_volume_t vol = pa_cvolume_avg(&s->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + /* g_debug("software volume = %f", volume_percent);*/ + return volume_percent; } static void mute_each_sink(gpointer key, gpointer value, gpointer user_data) { - sink_info *info = (sink_info*)value; - pa_operation_unref(pa_context_set_sink_mute_by_index(pulse_context, info->index, GPOINTER_TO_INT(user_data), context_success_callback, NULL)); - if(GPOINTER_TO_INT(user_data) == 1){ - sound_service_dbus_update_sink_mute(dbus_service, TRUE); - } - else{ - sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume()); - } - -/* g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data));*/ + sink_info *info = (sink_info*)value; + pa_operation_unref(pa_context_set_sink_mute_by_index(pulse_context, info->index, GPOINTER_TO_INT(user_data), context_success_callback, NULL)); + if (GPOINTER_TO_INT(user_data) == 1) { + sound_service_dbus_update_sink_mute(dbus_service, TRUE); + } else { + sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume()); + } + + /* g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data));*/ } void toggle_global_mute(gboolean mute_value) { - g_hash_table_foreach(sink_hash, mute_each_sink, GINT_TO_POINTER(mute_value)); -/* g_debug("in the pulse manager: toggle global mute value %i", mute_value);*/ + g_hash_table_foreach(sink_hash, mute_each_sink, GINT_TO_POINTER(mute_value)); + /* g_debug("in the pulse manager: toggle global mute value %i", mute_value);*/ } /* -Refine the resolution of the slider or binary scale it to achieve a more subtle volume control. -Use the base volume stored in the sink struct to calculate actual linear volumes. +Refine the resolution of the slider or binary scale it to achieve a more subtle volume control. +Use the base volume stored in the sink struct to calculate actual linear volumes. */ void set_sink_volume(gdouble percent) { - if(pa_server_available == FALSE) - return; -/* g_debug("in the pulse manager:set_sink_volume with percent %f", percent);*/ - - if(DEFAULT_SINK_INDEX < 0) - { - g_warning("We have no default sink !!! - returning after not attempting to set any volume of any sink"); - return; - } + if (pa_server_available == FALSE) + return; + /* g_debug("in the pulse manager:set_sink_volume with percent %f", percent);*/ + + if (DEFAULT_SINK_INDEX < 0) { + g_warning("We have no default sink !!! - returning after not attempting to set any volume of any sink"); + return; + } - sink_info *cached_sink = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); + sink_info *cached_sink = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); - pa_cvolume new_volume; - pa_cvolume_init(&new_volume); - new_volume.channels = 1; - pa_volume_t new_volume_value = (pa_volume_t) ((percent * PA_VOLUME_NORM) / 100); - pa_cvolume_set(&new_volume, 1, new_volume_value); - pa_cvolume_set(&cached_sink->volume, cached_sink->channel_map.channels, new_volume_value); - pa_operation_unref(pa_context_set_sink_volume_by_index(pulse_context, DEFAULT_SINK_INDEX, &new_volume, NULL, NULL)); + pa_cvolume new_volume; + pa_cvolume_init(&new_volume); + new_volume.channels = 1; + pa_volume_t new_volume_value = (pa_volume_t) ((percent * PA_VOLUME_NORM) / 100); + pa_cvolume_set(&new_volume, 1, new_volume_value); + pa_cvolume_set(&cached_sink->volume, cached_sink->channel_map.channels, new_volume_value); + pa_operation_unref(pa_context_set_sink_volume_by_index(pulse_context, DEFAULT_SINK_INDEX, &new_volume, NULL, NULL)); } static pa_cvolume construct_mono_volume(const pa_cvolume* vol) { - pa_cvolume new_volume; - pa_cvolume_init(&new_volume); - new_volume.channels = 1; - pa_volume_t max_vol = pa_cvolume_max(vol); - pa_cvolume_set(&new_volume, 1, max_vol); - return new_volume; -} + pa_cvolume new_volume; + pa_cvolume_init(&new_volume); + new_volume.channels = 1; + pa_volume_t max_vol = pa_cvolume_max(vol); + pa_cvolume_set(&new_volume, 1, max_vol); + return new_volume; +} /**********************************************************************************************************************/ // Pulse-Audio asychronous call-backs @@ -270,24 +267,22 @@ static pa_cvolume construct_mono_volume(const pa_cvolume* vol) static void gather_pulse_information(pa_context *c, void *userdata) { - pa_operation *operation; - if(!(operation = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) - { - g_warning("pa_context_get_server_info failed"); - if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) - { - g_warning("pa_context_get_sink_info_list() failed - cannot fetch server or sink info - leaving . . ."); - return; - } + pa_operation *operation; + if (!(operation = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) { + g_warning("pa_context_get_server_info failed"); + if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) { + g_warning("pa_context_get_sink_info_list() failed - cannot fetch server or sink info - leaving . . ."); + return; } - pa_operation_unref(operation); - return; + } + pa_operation_unref(operation); + return; } static void context_success_callback(pa_context *c, int success, void *userdata) { -/* g_debug("Context Success Callback - result = %i", success);*/ + /* g_debug("Context Success Callback - result = %i", success);*/ } /** @@ -298,296 +293,270 @@ Major candidate for refactoring. **/ static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, int eol, void *userdata) { - if (eol > 0) { - - gboolean device_available = determine_sink_availability(); - if(device_available == TRUE) - { - dbus_menu_manager_update_pa_state(TRUE, - device_available, - default_sink_is_muted(), - get_default_sink_volume()); - } - else{ - //Update the indicator to show PA either is not ready or has no available sink - g_warning("Cannot find a suitable default sink ..."); - dbus_menu_manager_update_pa_state(FALSE, device_available, default_sink_is_muted(), get_default_sink_volume()); - } - } - else{ -/* g_debug("About to add an item to our hash");*/ - sink_info *value; - value = g_new0(sink_info, 1); - value->index = sink->index; - value->name = g_strdup(sink->name); - value->mute = !!sink->mute; - value->volume = construct_mono_volume(&sink->volume); - value->base_volume = sink->base_volume; - value->channel_map = sink->channel_map; - g_hash_table_insert(sink_hash, GINT_TO_POINTER(sink->index), value); -/* g_debug("After adding an item to our hash");*/ + if (eol > 0) { + + gboolean device_available = determine_sink_availability(); + if (device_available == TRUE) { + dbus_menu_manager_update_pa_state(TRUE, + device_available, + default_sink_is_muted(), + get_default_sink_volume()); + } else { + //Update the indicator to show PA either is not ready or has no available sink + g_warning("Cannot find a suitable default sink ..."); + dbus_menu_manager_update_pa_state(FALSE, device_available, default_sink_is_muted(), get_default_sink_volume()); } + } else { + /* g_debug("About to add an item to our hash");*/ + sink_info *value; + value = g_new0(sink_info, 1); + value->index = sink->index; + value->name = g_strdup(sink->name); + value->mute = !!sink->mute; + value->volume = construct_mono_volume(&sink->volume); + value->base_volume = sink->base_volume; + value->channel_map = sink->channel_map; + g_hash_table_insert(sink_hash, GINT_TO_POINTER(sink->index), value); + /* g_debug("After adding an item to our hash");*/ + } } 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; -/* g_debug("Just set the default sink index to %i", DEFAULT_SINK_INDEX); */ - GList *keys = g_hash_table_get_keys(sink_hash); - gint position = g_list_index(keys, GINT_TO_POINTER(info->index)); - // Only update sink-list if the index is not in our already fetched list. - if(position < 0) - { - pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL)); - } - else - { - dbus_menu_manager_update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume()); - } + 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; + /* g_debug("Just set the default sink index to %i", DEFAULT_SINK_INDEX); */ + GList *keys = g_hash_table_get_keys(sink_hash); + gint position = g_list_index(keys, GINT_TO_POINTER(info->index)); + // Only update sink-list if the index is not in our already fetched list. + if (position < 0) { + pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL)); + } else { + dbus_menu_manager_update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume()); } + } } -static void pulse_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata){ - if (eol > 0) { - if (pa_context_errno(c) == PA_ERR_NOENTITY) - return; -/* g_warning("Sink INPUT info callback failure");*/ - return; +static void pulse_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata) +{ + if (eol > 0) { + if (pa_context_errno(c) == PA_ERR_NOENTITY) + return; + /* g_warning("Sink INPUT info callback failure");*/ + return; + } else { + if (info == NULL) { + // TODO: watch this carefully - PA async api should not be doing this . . . + /* g_warning("\n Sink input info callback : SINK INPUT INFO IS NULL BUT EOL was not POSITIVE!!!");*/ + return; } - else{ - if (info == NULL) - { - // TODO: watch this carefully - PA async api should not be doing this . . . -/* g_warning("\n Sink input info callback : SINK INPUT INFO IS NULL BUT EOL was not POSITIVE!!!");*/ - return; - } -/* g_debug("\n SINK INPUT INFO sink index : %d \n", info->sink);*/ - check_sink_input_while_muted_event(info->sink); - } + /* g_debug("\n SINK INPUT INFO sink index : %d \n", info->sink);*/ + check_sink_input_while_muted_event(info->sink); + } } static void update_sink_info(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("Sink INPUT info callback failure");*/ - return; - } - gint position = -1; - GList *keys = g_hash_table_get_keys(sink_hash); + if (eol > 0) { + if (pa_context_errno(c) == PA_ERR_NOENTITY) + return; + /* g_warning("Sink INPUT info callback failure");*/ + return; + } + gint position = -1; + GList *keys = g_hash_table_get_keys(sink_hash); + + if (info == NULL) + return; - if(info == NULL) - return; - - position = g_list_index(keys, GINT_TO_POINTER(info->index)); - - if(position >= 0) // => index is within the keys of the hash. - { - sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(info->index)); - s->name = g_strdup(info->name); - gboolean mute_changed = s->mute != !!info->mute; - s->mute = !!info->mute; - gboolean volume_changed = has_volume_changed(info, s); - -/* g_debug("new balance : %i", (int)(pa_cvolume_get_balance(&info->volume, &info->channel_map) * 100));*/ -/* g_debug("cached balance : %i", (int)(pa_cvolume_get_balance(&s->volume, &s->channel_map) * 100));*/ -/* g_debug("update_sink_info: new_volume input : %f", (gdouble)(pa_cvolume_max(&info->volume)));*/ -/* g_debug("update sink info: cached volume is at: %f", (gdouble)(pa_cvolume_max(&s->volume)));*/ -/* g_debug("update sink info : volume changed = %i", volume_changed);*/ -/* g_debug("update sink info : compatibility = %i", pa_cvolume_compatible_with_channel_map(&info->volume, &s->channel_map));*/ - - s->volume = construct_mono_volume(&info->volume); - s->channel_map = info->channel_map; - - if(DEFAULT_SINK_INDEX == s->index) - { - //update the UI - if (volume_changed == TRUE && s->mute == FALSE) - { - pa_volume_t vol = pa_cvolume_max(&s->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; -/* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/ - sound_service_dbus_update_sink_volume(dbus_service, volume_percent); - } - - if (mute_changed == TRUE) - { -/* g_debug("Updating Mute from PA manager with mute = %i", s->mute);*/ - sound_service_dbus_update_sink_mute(dbus_service, s->mute); - dbus_menu_manager_update_mute_ui(s->mute); - if(s->mute == FALSE){ - pa_volume_t vol = pa_cvolume_max(&s->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; -/* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/ - sound_service_dbus_update_sink_volume(dbus_service, volume_percent); - } - } + position = g_list_index(keys, GINT_TO_POINTER(info->index)); + + if (position >= 0) { // => index is within the keys of the hash. + sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(info->index)); + s->name = g_strdup(info->name); + gboolean mute_changed = s->mute != !!info->mute; + s->mute = !!info->mute; + gboolean volume_changed = has_volume_changed(info, s); + + /* g_debug("new balance : %i", (int)(pa_cvolume_get_balance(&info->volume, &info->channel_map) * 100));*/ + /* g_debug("cached balance : %i", (int)(pa_cvolume_get_balance(&s->volume, &s->channel_map) * 100));*/ + /* g_debug("update_sink_info: new_volume input : %f", (gdouble)(pa_cvolume_max(&info->volume)));*/ + /* g_debug("update sink info: cached volume is at: %f", (gdouble)(pa_cvolume_max(&s->volume)));*/ + /* g_debug("update sink info : volume changed = %i", volume_changed);*/ + /* g_debug("update sink info : compatibility = %i", pa_cvolume_compatible_with_channel_map(&info->volume, &s->channel_map));*/ + + s->volume = construct_mono_volume(&info->volume); + s->channel_map = info->channel_map; + + if (DEFAULT_SINK_INDEX == s->index) { + //update the UI + if (volume_changed == TRUE && s->mute == FALSE) { + pa_volume_t vol = pa_cvolume_max(&s->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + /* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/ + sound_service_dbus_update_sink_volume(dbus_service, volume_percent); + } + + if (mute_changed == TRUE) { + /* g_debug("Updating Mute from PA manager with mute = %i", s->mute);*/ + sound_service_dbus_update_sink_mute(dbus_service, s->mute); + dbus_menu_manager_update_mute_ui(s->mute); + if (s->mute == FALSE) { + pa_volume_t vol = pa_cvolume_max(&s->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + /* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/ + sound_service_dbus_update_sink_volume(dbus_service, volume_percent); } + } } - else - { - sink_info *value; - value = g_new0(sink_info, 1); - value->index = info->index; - value->name = g_strdup(info->name); - value->mute = !!info->mute; - value->volume = construct_mono_volume(&info->volume); - value->channel_map = info->channel_map; - value->base_volume = info->base_volume; - g_hash_table_insert(sink_hash, GINT_TO_POINTER(value->index), value); -/* g_debug("pulse-manager:update_sink_info -> After adding a new sink to our hash");*/ - sound_service_dbus_update_sink_availability(dbus_service, TRUE); - } + } else { + sink_info *value; + value = g_new0(sink_info, 1); + value->index = info->index; + value->name = g_strdup(info->name); + value->mute = !!info->mute; + value->volume = construct_mono_volume(&info->volume); + value->channel_map = info->channel_map; + value->base_volume = info->base_volume; + g_hash_table_insert(sink_hash, GINT_TO_POINTER(value->index), value); + /* g_debug("pulse-manager:update_sink_info -> After adding a new sink to our hash");*/ + sound_service_dbus_update_sink_availability(dbus_service, TRUE); + } } static gboolean has_volume_changed(const pa_sink_info* new_sink, sink_info* cached_sink) { - if(pa_cvolume_compatible_with_channel_map(&new_sink->volume, &cached_sink->channel_map) == FALSE) - return FALSE; + if (pa_cvolume_compatible_with_channel_map(&new_sink->volume, &cached_sink->channel_map) == FALSE) + return FALSE; - pa_cvolume new_vol = construct_mono_volume(&new_sink->volume); + pa_cvolume new_vol = construct_mono_volume(&new_sink->volume); - if(pa_cvolume_equal(&new_vol, &(cached_sink->volume)) == TRUE){ -/* g_debug("has_volume_changed: volumes appear to be equal? no change triggered!"); */ - return FALSE; - } - - return TRUE; + if (pa_cvolume_equal(&new_vol, &(cached_sink->volume)) == TRUE) { + /* g_debug("has_volume_changed: volumes appear to be equal? no change triggered!"); */ + return FALSE; + } + + return TRUE; } static void pulse_server_info_callback(pa_context *c, const pa_server_info *info, void *userdata) { -/* g_debug("server info callback");*/ - pa_operation *operation; - if (info == NULL) - { - g_warning("No server - get the hell out of here"); - dbus_menu_manager_update_pa_state(FALSE, FALSE, TRUE, 0); - pa_server_available = FALSE; - return; - } - 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))) - { - g_warning("pa_context_get_sink_info_by_name() failed"); - } - else{ - pa_operation_unref(operation); - return; - } + /* g_debug("server info callback");*/ + pa_operation *operation; + if (info == NULL) { + g_warning("No server - get the hell out of here"); + dbus_menu_manager_update_pa_state(FALSE, FALSE, TRUE, 0); + pa_server_available = FALSE; + return; + } + 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))) { + g_warning("pa_context_get_sink_info_by_name() failed"); + } else { + pa_operation_unref(operation); + return; } - if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) - { - g_warning("pa_context_get_sink_info_list() failed"); - return; - } - pa_operation_unref(operation); + } + if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) { + g_warning("pa_context_get_sink_info_list() failed"); + return; + } + pa_operation_unref(operation); } static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) - { - case PA_SUBSCRIPTION_EVENT_SINK: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) - { - if(index == DEFAULT_SINK_INDEX) - sound_service_dbus_update_sink_availability(dbus_service, FALSE); - -/* g_debug("Subscribed_events_callback - removing sink of index %i from our sink hash - keep the cache tidy !", index);*/ - g_hash_table_remove(sink_hash, GINT_TO_POINTER(index)); - - if(index == DEFAULT_SINK_INDEX){ -/* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK REMOVAL: default sink %i has been removed.", DEFAULT_SINK_INDEX); */ - DEFAULT_SINK_INDEX = -1; - determine_sink_availability(); - } -/* g_debug("subscribed_events_callback - Now what is our default sink : %i", DEFAULT_SINK_INDEX); */ - } - else - { -/* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK: a generic sink event - will trigger an update"); */ - pa_operation_unref(pa_context_get_sink_info_by_index(c, index, update_sink_info, userdata)); - } - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: -/* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK_INPUT event triggered!!");*/ - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) - { - //handle the sink input remove event - not relevant for current design - } - else - { - pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata)); - } - break; - case PA_SUBSCRIPTION_EVENT_SERVER: - g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SERVER change of some description ???"); - pa_operation *o; - if(!(o = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) - { - g_warning("subscribed_events_callback - pa_context_get_server_info() failed"); - return; - } - pa_operation_unref(o); - break; - } + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (index == DEFAULT_SINK_INDEX) + sound_service_dbus_update_sink_availability(dbus_service, FALSE); + + /* g_debug("Subscribed_events_callback - removing sink of index %i from our sink hash - keep the cache tidy !", index);*/ + g_hash_table_remove(sink_hash, GINT_TO_POINTER(index)); + + if (index == DEFAULT_SINK_INDEX) { + /* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK REMOVAL: default sink %i has been removed.", DEFAULT_SINK_INDEX); */ + DEFAULT_SINK_INDEX = -1; + determine_sink_availability(); + } + /* g_debug("subscribed_events_callback - Now what is our default sink : %i", DEFAULT_SINK_INDEX); */ + } else { + /* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK: a generic sink event - will trigger an update"); */ + pa_operation_unref(pa_context_get_sink_info_by_index(c, index, update_sink_info, userdata)); + } + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + /* g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SINK_INPUT event triggered!!");*/ + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + //handle the sink input remove event - not relevant for current design + } else { + pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata)); + } + break; + case PA_SUBSCRIPTION_EVENT_SERVER: + g_debug("subscribed_events_callback - PA_SUBSCRIPTION_EVENT_SERVER change of some description ???"); + pa_operation *o; + if (!(o = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) { + g_warning("subscribed_events_callback - pa_context_get_server_info() failed"); + return; + } + pa_operation_unref(o); + break; + } } -static void context_state_callback(pa_context *c, void *userdata) { - switch (pa_context_get_state(c)) { - case PA_CONTEXT_UNCONNECTED: -/* g_debug("unconnected");*/ - break; - case PA_CONTEXT_CONNECTING: -/* g_debug("connecting - waiting for the server to become available");*/ - break; - case PA_CONTEXT_AUTHORIZING: -/* g_debug("authorizing");*/ - break; - case PA_CONTEXT_SETTING_NAME: -/* g_debug("context setting name");*/ - break; - case PA_CONTEXT_FAILED: - g_warning("FAILED to retrieve context - Is PulseAudio Daemon running ?"); - pa_server_available = FALSE; - reconnect_to_pulse(); - break; - case PA_CONTEXT_TERMINATED: -/* g_debug("context terminated");*/ - break; - case PA_CONTEXT_READY: - g_debug("PA daemon is ready"); - pa_operation *o; - - pa_context_set_subscribe_callback(c, subscribed_events_callback, userdata); - - if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SINK_INPUT| - PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL))) { - g_warning("pa_context_subscribe() failed"); - return; - } - pa_operation_unref(o); - - gather_pulse_information(c, userdata); - - break; +static void context_state_callback(pa_context *c, void *userdata) +{ + switch (pa_context_get_state(c)) { + case PA_CONTEXT_UNCONNECTED: + /* g_debug("unconnected");*/ + break; + case PA_CONTEXT_CONNECTING: + /* g_debug("connecting - waiting for the server to become available");*/ + break; + case PA_CONTEXT_AUTHORIZING: + /* g_debug("authorizing");*/ + break; + case PA_CONTEXT_SETTING_NAME: + /* g_debug("context setting name");*/ + break; + case PA_CONTEXT_FAILED: + g_warning("FAILED to retrieve context - Is PulseAudio Daemon running ?"); + pa_server_available = FALSE; + reconnect_to_pulse(); + break; + case PA_CONTEXT_TERMINATED: + /* g_debug("context terminated");*/ + break; + case PA_CONTEXT_READY: + g_debug("PA daemon is ready"); + pa_operation *o; + + pa_context_set_subscribe_callback(c, subscribed_events_callback, userdata); + + if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK| + PA_SUBSCRIPTION_MASK_SINK_INPUT| + PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL))) { + g_warning("pa_context_subscribe() failed"); + return; } + pa_operation_unref(o); + + gather_pulse_information(c, userdata); + + break; + } } |