From 0b66ce027d9fab70a01ada23f6b77035bbf6719f Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Sat, 30 Jan 2010 13:41:18 +0000 Subject: pulse functionality refactored out inot to a separate PA file(s), sink details now stored in hash, complete list of events subscribed to, get sink list method added to the dbus service --- src/sound-service.c | 210 +++++++++++----------------------------------------- 1 file changed, 43 insertions(+), 167 deletions(-) (limited to 'src/sound-service.c') diff --git a/src/sound-service.c b/src/sound-service.c index 27a8248..008e6f8 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -20,151 +20,26 @@ PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ - -#include "sound-service-dbus.h" #include "sound-service.h" +#include "sound-service-dbus.h" +#include "pulse-manager.h" #include "common-defs.h" -/**********************************************************************************************************************/ -// Pulse-Audio asychronous call-backs -/**********************************************************************************************************************/ -static void context_get_sink_info_by_index_callback(pa_context *c, const pa_sink_info *sink, int eol, void *userdata){ - if (eol > 0) { - // TODO follow this pattern for all other async call-backs involving lists - safest/most accurate approach. - if (pa_context_errno(c) == PA_ERR_NOENTITY) - return; - g_debug(_("Sink info callback failure")); - return; - } - else{ - g_debug("\n SINK INFO Name : %s \n", sink->name); - g_debug("\n SINK INFO Muted : %d \n", sink->mute); - if (sink->mute == 1){ - g_debug("HERE is one for the DBUS - sink input while sink is muted"); - sound_service_dbus_sink_input_while_muted(dbus_interface, sink->index, TRUE); - } - else{ - g_debug("Sink input while the device is unmuted - not interested"); - sound_service_dbus_sink_input_while_muted(dbus_interface, sink->index, FALSE); - } - } -} - -static void context_success_callback(pa_context *c, int success, void *userdata){ - g_debug("Context Success Callback - result = %i", success); -} - -// TODO we are not handling multiple sinks appropriately -// Refactor with Colin and Lennarts' approaches in mind. -static void retrieve_complete_sink_list(pa_context *c, const pa_sink_info *sink, int eol, void *userdata){ - if(eol > 0){ - // TODO apparently never returns 0 sinks - Tested and it appears this assumption/prediction is correct. - // i would imagine different behaviour on different machines - watch this space! - // Some fuzzy reasoning might be needed. - if(sink_list->len == 1){ - pa_sink_info* only_sink = (pa_sink_info*)g_ptr_array_index(sink_list, 0); - // TODO: sink is not null but its module is the null-module-sink! - // For now taking the easy route string compare on the name and the active port - // needs more testing - int value = g_strcasecmp(only_sink->name, " auto_null "); - g_debug("comparison outcome with auto_null is %i", value); - sink_available = (value != 0 && only_sink->active_port != NULL); - // Strictly speaking all_muted should only be through if all sinks are muted - // It is more application specific - all_muted = (only_sink->mute == 1); - g_debug("Available sink is named %s", only_sink->name); - g_debug("does Available sink have an active port: %i", only_sink->active_port != NULL); - g_debug("sink_available = %i", sink_available); - } - else{ - sink_available = TRUE; - } - // At this point we can be confident we know enough from PA to draw the UI - rebuild_sound_menu (root_menuitem, dbus_interface); - } - else{ - g_ptr_array_add(sink_list, (gpointer)sink); - } -} - - -static void set_global_mute_callback(pa_context *c, const pa_sink_info *sink, int eol, void *userdata){ - if(eol > 0){ - g_debug("No more sinks to mute ! \n Everything should now be muted/unmuted ?" ); - return; - } - // Otherwise mute/unmute it! - pa_context_set_sink_mute_by_index(pulse_context, sink->index, all_muted == TRUE ? 1 : 0, context_success_callback, NULL); -} - -static void context_get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata){ - if (eol > 0) { - return; - } - else{ - if (info == NULL) - { - // TODO: watch this carefully - PA async api should not be doing this . . . - g_debug("\n Sink input info callback : SINK INPUT INFO IS NULL BUT EOL was not POSITIVE!!!"); - return; - } - g_debug("\n SINK INPUT INFO CALLBACK about to start asking questions...\n"); - g_debug("\n SINK INPUT INFO Name : %s \n", info->name); - g_debug("\n SINK INPUT INFO sink index : %d \n", info->sink); - pa_operation_unref(pa_context_get_sink_info_by_index(c, info->sink, context_get_sink_info_by_index_callback, userdata)); - } -} - -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: - g_debug("Event sink for %i", index); - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - // This will be triggered when the sink receives input from a new stream - // If a playback client is paused and then resumed this will NOT trigger this event. - g_debug("Subscribed_events_callback - type = sink input and index = %i", index); - g_debug("Sink input info query just about to happen"); - pa_operation_unref(pa_context_get_sink_input_info(c, index, context_get_sink_input_info_callback, userdata)); - g_debug("Sink input info query just happened"); - break; - } -} +//TODO: Follow hungarian notation +// GTK + DBUS +static GMainLoop * mainloop = NULL; +static DbusmenuMenuitem * root_menuitem = NULL; +static DbusmenuMenuitem * mute_all_menuitem = NULL; +static SoundServiceDbus * dbus_interface = NULL; -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"); - 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_debug("FAILED to retrieve context"); - break; - case PA_CONTEXT_TERMINATED: - g_debug("context terminated"); - break; - case PA_CONTEXT_READY: - g_debug("PA daemon is ready"); - pa_context_set_subscribe_callback(c, subscribed_events_callback, userdata); - pa_operation_unref(pa_context_get_sink_info_list(c, retrieve_complete_sink_list, NULL)); - pa_operation_unref(pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL)); - pa_operation_unref(pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL)); - break; - } -} +// PULSEAUDIO +static gboolean b_sink_available = FALSE; +static gboolean b_all_muted = FALSE; +static gboolean b_pulse_ready = FALSE; -/*static void set_volume(gint sink_index, gint volume_percent)*/ -/*{*/ -/* g_debug("set_volume in the sound-service");*/ -/*}*/ +static void set_global_mute(); +static gboolean idle_routine (gpointer data); +static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service); /**********************************************************************************************************************/ @@ -185,19 +60,18 @@ static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service { mute_all_menuitem = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(all_muted == FALSE ? "Mute All" : "Unmute")); + dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute")); g_signal_connect(G_OBJECT(mute_all_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(set_global_mute), NULL); //TODO: If no valid sinks are found grey out the item(s) - dbusmenu_menuitem_property_set_bool(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_SENSITIVE, sink_available); + dbusmenu_menuitem_property_set_bool(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_SENSITIVE, b_sink_available); dbusmenu_menuitem_child_append(root, mute_all_menuitem); } static void set_global_mute() { - all_muted = !all_muted; - g_debug("Mute is now = %i", all_muted); - pa_operation_unref(pa_context_get_sink_info_list(pulse_context, set_global_mute_callback, NULL)); - dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(all_muted == FALSE ? "Mute All" : "Unmute")); + b_all_muted = !b_all_muted; + g_debug("Mute is now = %i", b_all_muted); + dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute")); } @@ -210,19 +84,31 @@ service_shutdown (IndicatorService *service, gpointer user_data) if (mainloop != NULL) { -/* g_debug("Service shutdown");*/ -/* if (pulse_context){*/ -/* pa_context_unref(pulse_context);*/ -/* pulse_context = NULL;*/ -/* }*/ -/* g_ptr_array_free(sink_list, TRUE);*/ -/* pa_glib_mainloop_free(pa_main_loop);*/ -/* pa_main_loop = NULL;*/ + g_debug("Service shutdown - but commented out for right now"); +/* close_pulse_activites()*/ /* g_main_loop_quit(mainloop);*/ } return; } +void update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted) +{ + b_sink_available = sink_available; + b_all_muted = sink_muted; + b_pulse_ready = pa_state; + g_debug("update pa state with %i, %i and %i", pa_state, sink_available, sink_muted); + rebuild_sound_menu(root_menuitem, dbus_interface); +} + +/** +Pulsemanager will call this once enough info has been gathered about the PA state +**/ +/*void pa_init_state(GHashTable *sinks)*/ +/*{*/ +/* sinks_hash = sinks;*/ +/* rebuild_sound_menu(root_menuitem, dbus_interface); */ +/*}*/ + /* Main, is well, main. It brings everything up and throws us into the mainloop of no return. Some refactoring needed.*/ @@ -235,7 +121,7 @@ main (int argc, char ** argv) bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); - IndicatorService * service = indicator_service_new_version(INDICATOR_SOUND_DBUS_NAME, + IndicatorService *service = indicator_service_new_version(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_VERSION); g_signal_connect(G_OBJECT(service), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, @@ -246,21 +132,11 @@ main (int argc, char ** argv) g_idle_add(idle_routine, root_menuitem); - sink_list = g_ptr_array_new(); dbus_interface = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL); - DbusmenuServer * server = dbusmenu_server_new(INDICATOR_SOUND_DBUS_OBJECT); + DbusmenuServer *server = dbusmenu_server_new(INDICATOR_SOUND_DBUS_OBJECT); dbusmenu_server_set_root(server, root_menuitem); - - // TODO refactor into separate function - 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); - - // Establish event callback registration - pa_context_set_state_callback(pulse_context, context_state_callback, NULL); - pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); + establish_pulse_activities(dbus_interface); // Run the loop mainloop = g_main_loop_new(NULL, FALSE); -- cgit v1.2.3