aboutsummaryrefslogtreecommitdiff
path: root/src/sound-service.c
diff options
context:
space:
mode:
authorConor Curran <conor.curran@canonical.com>2010-01-30 13:41:18 +0000
committerConor Curran <conor.curran@canonical.com>2010-01-30 13:41:18 +0000
commit0b66ce027d9fab70a01ada23f6b77035bbf6719f (patch)
treee9ce0b585878c526055d8ad66492edd790b07893 /src/sound-service.c
parentf3baf71567c1b8840dafcdcbb73a793dd6064c0f (diff)
downloadayatana-indicator-sound-0b66ce027d9fab70a01ada23f6b77035bbf6719f.tar.gz
ayatana-indicator-sound-0b66ce027d9fab70a01ada23f6b77035bbf6719f.tar.bz2
ayatana-indicator-sound-0b66ce027d9fab70a01ada23f6b77035bbf6719f.zip
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
Diffstat (limited to 'src/sound-service.c')
-rw-r--r--src/sound-service.c210
1 files changed, 43 insertions, 167 deletions
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 <http://www.gnu.org/licenses/>.
*/
-
-#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);