aboutsummaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/pulse-manager.c247
-rw-r--r--src/pulse-manager.h52
-rw-r--r--src/sound-service-dbus.c20
-rw-r--r--src/sound-service-dbus.h8
-rw-r--r--src/sound-service.c210
-rw-r--r--src/sound-service.h36
-rw-r--r--src/sound-service.xml5
8 files changed, 370 insertions, 210 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 916e491..b5c9157 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,6 +47,8 @@ indicator_sound_service_SOURCES = \
common-defs.h \
sound-service.h \
sound-service.c \
+ pulse-manager.h \
+ pulse-manager.c \
sound-service-dbus.h \
sound-service-dbus.c \
sound-service-server.h \
diff --git a/src/pulse-manager.c b/src/pulse-manager.c
new file mode 100644
index 0000000..a65ef7f
--- /dev/null
+++ b/src/pulse-manager.c
@@ -0,0 +1,247 @@
+#include <pulse/glib-mainloop.h>
+#include <pulse/error.h>
+#include <pulse/gccmacro.h>
+
+#include "pulse-manager.h"
+#include "sound-service.h"
+
+
+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 GHashTable *sink_hash = NULL;
+static SoundServiceDbus *dbus_service = NULL;
+
+static void context_state_callback(pa_context *c, void *userdata);
+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);
+
+pa_context* get_context(void)
+{
+ return pulse_context;
+}
+
+void set_sink_volume(gint sink_index, gint percent)
+{
+ g_debug("in the pulse manager:set_sink_volume with index %i and percent %i", sink_index, percent);
+}
+
+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_int_hash, g_int_equal, g_free, g_free);
+ // 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);
+
+}
+
+void close_pulse_activites()
+{
+ if (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;
+}
+
+static void mute_each_sink(gpointer key, gpointer value, gpointer user_data)
+{
+//mute_value == TRUE ? 1 : 0,
+ 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));
+}
+
+void toggle_global_mute(gboolean mute_value)
+{
+ g_hash_table_foreach(sink_hash, mute_each_sink, GINT_TO_POINTER(mute_value));
+}
+
+void set_volume(gint sink_index, gint volume_percent)
+{
+ g_debug("set_volume in the sound-service");
+}
+
+
+static void test_hash(){
+ guint size = 0;
+ size = g_hash_table_size(sink_hash);
+ g_debug("Size of hash = %i", size);
+ gint *key;
+ key = g_new(gint, 1);
+ *key = 0;
+ sink_info *s = g_hash_table_lookup(sink_hash, key);
+ g_debug("and the name of our sink is %s", s->name);
+}
+
+static gboolean sink_available()
+{
+ if (g_hash_table_size(sink_hash) < 1)
+ return FALSE;
+ int *key;
+ key = g_new(gint, 1);
+ *key = 0;
+ sink_info *s = g_hash_table_lookup(sink_hash, key);
+ //int value = g_strcasecmp(s->name, " auto_null ");
+ return ((g_strcasecmp(s->name, " auto_null ") != 0) && s->active_port == TRUE);
+}
+
+// We are assuming the device is 0 for now.
+static gboolean chosen_sink_is_muted()
+{
+ if (g_hash_table_size(sink_hash) < 1)
+ return FALSE;
+ int *key;
+ key = g_new(gint, 1);
+ *key = 0;
+ sink_info *s = g_hash_table_lookup(sink_hash, key);
+ return s->mute;
+}
+
+
+/**********************************************************************************************************************/
+// Pulse-Audio asychronous call-backs
+/**********************************************************************************************************************/
+/*static void pulse_audio_server_info_callback(pa_context *c, const pa_server_info *server_info, void *userdata) */
+/*{*/
+
+/*}*/
+
+static void gather_pulse_information(pa_context *c, void *userdata)
+{
+ pa_operation *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 context_success_callback(pa_context *c, int success, void *userdata)
+{
+ g_debug("Context Success Callback - result = %i", success);
+}
+
+
+static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, int eol, void *userdata)
+{
+ if (eol > 0) {
+ test_hash();
+ update_pa_state(TRUE, sink_available(), chosen_sink_is_muted());
+
+ // 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_warning("Sink info callback failure");
+ return;
+ }
+ else{
+ gint *key;
+ key = g_new(gint, 1);
+ *key = sink->index;
+ sink_info *value;
+ value = g_new(sink_info, 1);
+ value->index = value->device_index = sink->index;
+ value->name = sink->name;
+ value->description = sink->description;
+ value->icon_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME);
+ value->active_port = (sink->active_port != NULL);
+ value->mute = !!sink->mute;
+ g_hash_table_insert(sink_hash, key, value);
+ // VOLUME focus tmrw.
+ //value->volume = sink->volume;
+ //value->channel_map = sink->channel_map;
+ }
+}
+
+
+/*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;
+ }
+}
+
+
+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_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_SOURCE|
+ PA_SUBSCRIPTION_MASK_SINK_INPUT|
+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
+ PA_SUBSCRIPTION_MASK_CLIENT|
+ PA_SUBSCRIPTION_MASK_SERVER|
+ PA_SUBSCRIPTION_MASK_CARD), NULL, NULL))) {
+ g_warning("pa_context_subscribe() failed");
+ return;
+ }
+ pa_operation_unref(o);
+
+ gather_pulse_information(c, userdata);
+
+ break;
+ }
+}
+
diff --git a/src/pulse-manager.h b/src/pulse-manager.h
new file mode 100644
index 0000000..2aacee8
--- /dev/null
+++ b/src/pulse-manager.h
@@ -0,0 +1,52 @@
+#include <pulse/pulseaudio.h>
+#include <glib.h>
+#include "sound-service-dbus.h"
+
+//enum SinkInputType {
+// SINK_INPUT_ALL,
+// SINK_INPUT_CLIENT,
+// SINK_INPUT_VIRTUAL
+//};
+
+//enum SinkType {
+// SINK_ALL,
+// SINK_HARDWARE,
+// SINK_VIRTUAL,
+//};
+
+//enum SourceOutputType {
+// SOURCE_OUTPUT_ALL,
+// SOURCE_OUTPUT_CLIENT,
+// SOURCE_OUTPUT_VIRTUAL
+//};
+
+//enum SourceType {
+// SOURCE_ALL,
+// SOURCE_NO_MONITOR,
+// SOURCE_HARDWARE,
+// SOURCE_VIRTUAL,
+// SOURCE_MONITOR,
+//};
+
+
+typedef struct {
+ const gchar* name;
+ const gchar* description;
+ const gchar* icon_name;
+ gint index;
+ gint device_index;
+// pa_cvolume volume;
+// pa_channel_map channel_map;
+ gboolean mute;
+ gboolean active_port;
+} sink_info;
+
+
+//void set_volume(gint sink_index, gint volume_percent);
+pa_context* get_context(void);
+void establish_pulse_activities(SoundServiceDbus *service);
+void set_sink_volume(gint sink_index, gint percent);
+void toggle_global_mute(gboolean mute_value);
+
+
+
diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c
index 06117eb..286af32 100644
--- a/src/sound-service-dbus.c
+++ b/src/sound-service-dbus.c
@@ -28,7 +28,7 @@
#include "sound-service-server.h"
#include "common-defs.h"
#include "sound-service-marshal.h"
-
+#include "pulse-manager.h"
typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate;
@@ -36,14 +36,17 @@ struct _SoundServiceDbusPrivate
{
DBusGConnection *system_bus;
DBusGConnection *connection;
+ GHashTable *sinks_hash;
};
+
/* Signals */
enum {
SINK_INPUT_WHILE_MUTED,
LAST_SIGNAL
};
+
static guint signals[LAST_SIGNAL] = { 0 };
#define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate))
@@ -85,7 +88,7 @@ DBUS Method Callbacks
**/
gboolean sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const guint volume_percent, GError** gerror)
{
- g_debug("in the set sink volume method in the sound service dbus! Holy Fuck with volume_percent of %i", volume_percent);
+ g_debug("in the set sink volume method in the sound service dbus!, with volume_percent of %i", volume_percent);
/* if (!IS_SOUND_SERVICE_DBUS(service)) {*/
/* g_warning("NO BAD EVIL!");*/
/* return FALSE;*/
@@ -93,6 +96,14 @@ gboolean sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const gui
return TRUE;
}
+GList *
+sound_service_dbus_get_sink_list (SoundServiceDbus *self)
+{
+ SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self);
+
+ return g_hash_table_get_keys (priv->sinks_hash);
+}
+
/**
Utility methods to emit signals from the service into the ether.
@@ -108,6 +119,11 @@ void sound_service_dbus_sink_input_while_muted(SoundServiceDbus* obj, gint sink_
value);
}
+void set_pa_sinks_hash(SoundServiceDbus *self, GHashTable *sinks)
+{
+ SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self);
+ priv->sinks_hash = sinks;
+}
static void
sound_service_dbus_init (SoundServiceDbus *self)
diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h
index 2210eac..784acee 100644
--- a/src/sound-service-dbus.h
+++ b/src/sound-service-dbus.h
@@ -40,10 +40,6 @@ typedef struct _SoundData SoundData;
struct _SoundData
{
- gchar *client_name;
- gint64 sink_index;
- gboolean *muted;
-
SoundServiceDbus *service;
};
@@ -61,11 +57,11 @@ GType sound_service_dbus_get_type (void) G_GNUC_CONST;
// Utility methods to get the messages across into the sound-service-dbus
void sound_service_dbus_sink_input_while_muted (SoundServiceDbus* obj, gint sink_index, gboolean value);
+void set_pa_sinks_hash(SoundServiceDbus *self, GHashTable *sinks);
// DBUS METHODS
gboolean sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const guint volume_percent, GError** gerror);
-
-
+GList *sound_service_dbus_get_sink_list(SoundServiceDbus* service);
G_END_DECLS
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);
diff --git a/src/sound-service.h b/src/sound-service.h
index 7b8f758..744bb56 100644
--- a/src/sound-service.h
+++ b/src/sound-service.h
@@ -37,47 +37,13 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libindicator/indicator-service.h>
-#include <pulse/pulseaudio.h>
-#include <pulse/glib-mainloop.h>
-#include <pulse/error.h>
-#include <pulse/gccmacro.h>
-
#include "dbus-shared-names.h"
-// GTK + DBUS
-static GMainLoop * mainloop = NULL;
-static DbusmenuMenuitem * root_menuitem = NULL;
-static DbusmenuMenuitem * mute_all_menuitem = NULL;
-static SoundServiceDbus * dbus_interface = NULL;
-
-// PULSEAUDIO
-static pa_context *pulse_context = NULL;
-static pa_glib_mainloop *pa_main_loop = NULL;
-static GPtrArray* sink_list = NULL;
-static gboolean sink_available = TRUE;
-
-static void context_state_callback(pa_context *c, void *userdata);
-static gboolean idle_routine (gpointer data);
-static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service);
-
-static gboolean all_muted = FALSE;
-static void set_global_mute();
-//static void set_volume(gint sink_index, gint volume_percent);
-
-typedef struct {
- gchar* name;
- gchar* description;
- gchar* icon_name;
- gint index;
- gint device_index;
- pa_cvolume volume;
- pa_channel_map channel_map;
- gboolean mute;
-} device_info;
// ENTRY AND EXIT POINTS
void service_shutdown(IndicatorService * service, gpointer user_data);
int main (int argc, char ** argv);
+void update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted);
#endif
diff --git a/src/sound-service.xml b/src/sound-service.xml
index 03827d3..d7ec04d 100644
--- a/src/sound-service.xml
+++ b/src/sound-service.xml
@@ -5,6 +5,11 @@
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_set_sink_volume"/>
<arg type='u' name='volume_percent' direction="in"/>
</method>
+ <method name="GetSinkList">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_list"/>
+ <arg name="sinks" direction="out" type="au"/>
+ </method>
+
<!-- Will need to hook up another signal which monitors for volume change
Our respective UI element should listen to this and therefore will be updated with accurate setting-->
<!-- Triggered when a sink is muted but the input has been sent to that sink -->