From 9eef471b5d0f8cbfa298e607c2ddf8300623a06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 13:58:21 +0100 Subject: added libnotify build dependency --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 13e323c..f36c9e2 100644 --- a/configure.ac +++ b/configure.ac @@ -35,11 +35,13 @@ PULSE_AUDIO_REQUIRED_VERSION=0.9.19 INDICATOR_DISPLAY_OBJECTS=0.1.11 DBUSMENUGLIB_REQUIRED_VERSION=0.3.9 GIO_2_0_REQUIRED_VERSION=2.25.13 +LIBNOTIFY_REQUIRED_VERSION=0.5.0 PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION indicator >= $INDICATOR_REQUIRED_VERSION dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION - libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS) + libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS + libnotify >= $LIBNOTIFY_REQUIRED_VERSION) AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) -- cgit v1.2.3 From 411333bed0e020e1725e3dd48afdc57e41fd1b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 14:10:10 +0100 Subject: use update_state_from_volume instead of determine_state_from_volume And make determine_state_from_volume return the state for the selected value --- src/indicator-sound.c | 23 ++++++++++++++++------- src/indicator-sound.h | 2 +- src/volume-widget.c | 6 +++--- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 3867f27..d1bcc33 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -115,6 +115,7 @@ static void get_sink_availability_cb ( GObject *object, /****Volume States 'members' ***/ static void update_state(const gint state); +static const gint STATE_INVALID = -1; static const gint STATE_MUTED = 0; static const gint STATE_ZERO = 1; static const gint STATE_LOW = 2; @@ -452,7 +453,7 @@ static void fetch_state (IndicatorSound* self) IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); if(priv->volume_widget != NULL){ - determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); + update_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); } g_dbus_proxy_call ( priv->dbus_proxy, @@ -631,12 +632,11 @@ update_state(const gint state) indicator_image_helper_update(speaker_image, image_name); } - -void +static gint determine_state_from_volume(gdouble volume_percent) { if (device_available == FALSE) - return; + return STATE_INVALID; gint state = previous_state; if (volume_percent < 30.0 && volume_percent > 0) { state = STATE_LOW; @@ -647,9 +647,18 @@ determine_state_from_volume(gdouble volume_percent) } else if (volume_percent == 0.0) { state = STATE_ZERO; } - update_state(state); + return state; } +void +update_state_from_volume(gdouble volume_percent) +{ + gint state = determine_state_from_volume(volume_percent); + if (state == STATE_INVALID) + return; + + update_state(state); +} static gboolean start_animation() @@ -753,7 +762,7 @@ react_to_signal_sink_mute_update(gboolean mute_value, IndicatorSound* self) GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); gtk_widget_set_sensitive(slider_widget, !mute_value); if(mute_value == FALSE){ - determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); + update_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); } } @@ -768,7 +777,7 @@ react_to_signal_sink_availability_update(gboolean available_value, IndicatorSoun } IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); + update_state_from_volume (volume_widget_get_current_volume(priv->volume_widget)); //g_debug("signal caught - sink availability update with value: %i", available_value); } diff --git a/src/indicator-sound.h b/src/indicator-sound.h index 9f829bb..7bf69b6 100644 --- a/src/indicator-sound.h +++ b/src/indicator-sound.h @@ -53,7 +53,7 @@ struct _IndicatorSound { GType indicator_sound_get_type (void); void prepare_state_machine(); -extern void determine_state_from_volume(gdouble volume_percent); +extern void update_state_from_volume(gdouble volume_percent); gint get_state(); gchar* get_state_image_name(gint state); void prepare_for_tests(IndicatorObject * io); diff --git a/src/volume-widget.c b/src/volume-widget.c index 38dc9bb..9fa1395 100644 --- a/src/volume-widget.c +++ b/src/volume-widget.c @@ -137,7 +137,7 @@ volume_widget_property_update( DbusmenuMenuitem* item, gchar* property, gdouble update = g_variant_get_double (value); //g_debug("volume-widget - update level with value %f", update); gtk_range_set_value(range, update); - determine_state_from_volume(update); + update_state_from_volume(update); } } } @@ -157,7 +157,7 @@ volume_widget_set_twin_item(VolumeWidget* self, GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); GtkRange *range = (GtkRange*)slider; gtk_range_set_value(range, initial_level); - determine_state_from_volume(initial_level); + update_state_from_volume(initial_level); } static gboolean @@ -169,7 +169,7 @@ volume_widget_change_value_cb (GtkRange *range, g_return_val_if_fail (IS_VOLUME_WIDGET (user_data), FALSE); VolumeWidget* mitem = VOLUME_WIDGET(user_data); volume_widget_update(mitem, new_value); - determine_state_from_volume(new_value); + update_state_from_volume(new_value); return FALSE; } -- cgit v1.2.3 From 463c714aac4835bcdfda3c523122c13fac1586f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 17:01:01 +0100 Subject: Show a value notify-osd notification (if supported) when scrolling To improve the indicator usability, show a notify-osd bubble with the volume value when changing the value level using the scrolling-wheel over the indicator icon. --- src/indicator-sound.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/indicator-sound.h | 2 ++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index d1bcc33..aa7c43e 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -30,6 +30,8 @@ with this program. If not, see . #include +#include + #include "indicator-sound.h" #include "transport-widget.h" #include "metadata-widget.h" @@ -47,7 +49,8 @@ struct _IndicatorSoundPrivate { GtkWidget* volume_widget; GList* transport_widgets_list; - GDBusProxy *dbus_proxy; + GDBusProxy *dbus_proxy; + NotifyNotification* notification; }; #define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate)) @@ -69,6 +72,10 @@ static GtkImage * get_icon (IndicatorObject * io); static GtkMenu * get_menu (IndicatorObject * io); static void indicator_sound_scroll (IndicatorObject* io, gint delta, IndicatorScrollDirection direction); +//Notification +static void indicator_sound_notification_init (IndicatorSound *self); +static void indicator_sound_notification_show (IndicatorSound *self, double value); + //Slider related static gboolean new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); @@ -183,6 +190,10 @@ indicator_sound_init (IndicatorSound *self) priv->dbus_proxy = NULL; GList* t_list = NULL; priv->transport_widgets_list = t_list; + priv->notification = NULL; + + priv->notification = NULL; + indicator_sound_notification_init (self); g_signal_connect(G_OBJECT(self->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, @@ -206,6 +217,10 @@ indicator_sound_dispose (GObject *object) g_list_free ( priv->transport_widgets_list ); + if (priv->notification) { + notify_uninit(); + } + G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object); return; } @@ -349,6 +364,9 @@ new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); priv->volume_widget = volume_widget; + if (priv->notification) + notify_notification_attach_to_widget(priv->notification, volume_widget); + GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); g_signal_connect(ido_slider_widget, "style-set", G_CALLBACK(style_changed_cb), NULL); @@ -366,6 +384,28 @@ new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, return TRUE; } +static void indicator_sound_notification_init (IndicatorSound *self) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + + if (notify_init(PACKAGE_NAME)) { + GList* caps = notify_get_server_caps(); + gboolean has_notify_osd = FALSE; + + if (caps) { + if (g_list_find_custom(caps, "x-canonical-private-synchronous", (GCompareFunc) g_strcmp0)) { + has_notify_osd = TRUE; + } + g_list_foreach(caps, (GFunc) g_free, NULL); + g_list_free(caps); + } + + if (has_notify_osd) { + priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL, NULL); + notify_notification_set_hint_string(priv->notification, "x-canonical-private-synchronous", ""); + } + } +} static void connection_changed (IndicatorServiceManager * sm, @@ -950,6 +990,41 @@ style_changed_cb(GtkWidget *widget, gpointer user_data) prepare_blocked_animation(); } +static void +indicator_sound_notification_show(IndicatorSound *self, double value) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + + if (priv->notification == NULL) + return; + + char *icon; + const int notify_value = CLAMP((int)value, -1, 101); + gint state = determine_state_from_volume (CLAMP(value, 0, 100)); + + if (state == STATE_ZERO) { + GtkIconTheme *theme = gtk_icon_theme_get_default(); + if (gtk_icon_theme_has_icon(theme, "audio-volume-off")) { + // Not available in all the themes + icon = "audio-volume-off"; + } else { + icon = "audio-volume-muted"; + } + } else if (state == STATE_LOW) { + icon = "audio-volume-low"; + } else if (state == STATE_MEDIUM) { + icon = "audio-volume-medium"; + } else if (state == STATE_HIGH) { + icon = "audio-volume-high"; + } else { + icon = "audio-volume-muted"; + } + + notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); + notify_notification_set_hint_int32(priv->notification, "value", notify_value); + notify_notification_show(priv->notification, NULL); +} + static void indicator_sound_scroll (IndicatorObject *io, gint delta, IndicatorScrollDirection direction) { @@ -973,5 +1048,7 @@ indicator_sound_scroll (IndicatorObject *io, gint delta, IndicatorScrollDirectio value -= adj->step_increment; } //g_debug("indicator-sound-scroll - update slider with value %f", value); - volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value); + volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value); + + indicator_sound_notification_show(INDICATOR_SOUND (io), value); } diff --git a/src/indicator-sound.h b/src/indicator-sound.h index 7bf69b6..276136d 100644 --- a/src/indicator-sound.h +++ b/src/indicator-sound.h @@ -23,6 +23,8 @@ 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 "config.h" + #include #include #include -- cgit v1.2.3 From 9c765ddc17fefb9d0839b75c66551ed72e187bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 17:18:52 +0100 Subject: indentation fixes --- src/indicator-sound.c | 81 ++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index aa7c43e..15c8cb0 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -388,23 +388,26 @@ static void indicator_sound_notification_init (IndicatorSound *self) { IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - if (notify_init(PACKAGE_NAME)) { - GList* caps = notify_get_server_caps(); - gboolean has_notify_osd = FALSE; + if (!notify_init(PACKAGE_NAME)) + return; - if (caps) { - if (g_list_find_custom(caps, "x-canonical-private-synchronous", (GCompareFunc) g_strcmp0)) { - has_notify_osd = TRUE; - } - g_list_foreach(caps, (GFunc) g_free, NULL); - g_list_free(caps); - } + GList* caps = notify_get_server_caps(); + gboolean has_notify_osd = FALSE; - if (has_notify_osd) { - priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL, NULL); - notify_notification_set_hint_string(priv->notification, "x-canonical-private-synchronous", ""); + if (caps) { + if (g_list_find_custom(caps, "x-canonical-private-synchronous", + (GCompareFunc) g_strcmp0)) { + has_notify_osd = TRUE; } - } + g_list_foreach(caps, (GFunc) g_free, NULL); + g_list_free(caps); + } + + if (has_notify_osd) { + priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL, NULL); + notify_notification_set_hint_string(priv->notification, + "x-canonical-private-synchronous", ""); + } } static void @@ -998,31 +1001,31 @@ indicator_sound_notification_show(IndicatorSound *self, double value) if (priv->notification == NULL) return; - char *icon; - const int notify_value = CLAMP((int)value, -1, 101); - gint state = determine_state_from_volume (CLAMP(value, 0, 100)); - - if (state == STATE_ZERO) { - GtkIconTheme *theme = gtk_icon_theme_get_default(); - if (gtk_icon_theme_has_icon(theme, "audio-volume-off")) { - // Not available in all the themes - icon = "audio-volume-off"; - } else { - icon = "audio-volume-muted"; - } - } else if (state == STATE_LOW) { - icon = "audio-volume-low"; - } else if (state == STATE_MEDIUM) { - icon = "audio-volume-medium"; - } else if (state == STATE_HIGH) { - icon = "audio-volume-high"; - } else { - icon = "audio-volume-muted"; - } - - notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); - notify_notification_set_hint_int32(priv->notification, "value", notify_value); - notify_notification_show(priv->notification, NULL); + char *icon; + const int notify_value = CLAMP((int)value, -1, 101); + gint state = determine_state_from_volume (CLAMP(value, 0, 100)); + + if (state == STATE_ZERO) { + GtkIconTheme *theme = gtk_icon_theme_get_default(); + if (gtk_icon_theme_has_icon(theme, "audio-volume-off")) { + // Not available in all the themes + icon = "audio-volume-off"; + } else { + icon = "audio-volume-muted"; + } + } else if (state == STATE_LOW) { + icon = "audio-volume-low"; + } else if (state == STATE_MEDIUM) { + icon = "audio-volume-medium"; + } else if (state == STATE_HIGH) { + icon = "audio-volume-high"; + } else { + icon = "audio-volume-muted"; + } + + notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); + notify_notification_set_hint_int32(priv->notification, "value", notify_value); + notify_notification_show(priv->notification, NULL); } static void -- cgit v1.2.3 From 826144b11815fb1f475dcdab0fd235e4f34df9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 17:22:55 +0100 Subject: Ops, indentation: one space left! :P --- src/indicator-sound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 15c8cb0..4022422 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -1014,7 +1014,7 @@ indicator_sound_notification_show(IndicatorSound *self, double value) icon = "audio-volume-muted"; } } else if (state == STATE_LOW) { - icon = "audio-volume-low"; + icon = "audio-volume-low"; } else if (state == STATE_MEDIUM) { icon = "audio-volume-medium"; } else if (state == STATE_HIGH) { -- cgit v1.2.3 From 41fb49c27538a2c6044a7170e855baea0f11b2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 17:23:58 +0100 Subject: gtk_icon_theme_has_icon() doesn't seem to work here... When no "audio-volume-off" icon is provided by any theme, the notification is not shown, so notify-osd-icons package is reccomanded here. --- src/indicator-sound.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 4022422..e94526b 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -1006,13 +1006,8 @@ indicator_sound_notification_show(IndicatorSound *self, double value) gint state = determine_state_from_volume (CLAMP(value, 0, 100)); if (state == STATE_ZERO) { - GtkIconTheme *theme = gtk_icon_theme_get_default(); - if (gtk_icon_theme_has_icon(theme, "audio-volume-off")) { - // Not available in all the themes - icon = "audio-volume-off"; - } else { - icon = "audio-volume-muted"; - } + // Not available for all the themes + icon = "audio-volume-off"; } else if (state == STATE_LOW) { icon = "audio-volume-low"; } else if (state == STATE_MEDIUM) { -- cgit v1.2.3 From b0babf1fab9b3e74f32de4635dd9eed78cccfc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sun, 23 Jan 2011 18:37:25 +0100 Subject: more indentation fixes... --- src/indicator-sound.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index e94526b..8e86f8b 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -698,9 +698,9 @@ update_state_from_volume(gdouble volume_percent) { gint state = determine_state_from_volume(volume_percent); if (state == STATE_INVALID) - return; + return; - update_state(state); + update_state(state); } static gboolean -- cgit v1.2.3 From 21cf01130cd686a9e4c1d4e90dbd3e01f8d0b7b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 27 Jan 2011 16:49:23 +0100 Subject: merge: reset indicator-sound.h values --- src/indicator-sound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/indicator-sound.h b/src/indicator-sound.h index a7468fb..c52a62a 100644 --- a/src/indicator-sound.h +++ b/src/indicator-sound.h @@ -54,7 +54,7 @@ struct _IndicatorSound { GType indicator_sound_get_type (void); void prepare_state_machine(); -extern void update_state_from_volume(gdouble volume_percent); +extern void determine_state_from_volume(gdouble volume_percent); gint get_state(); gchar* get_state_image_name(gint state); void prepare_for_tests(IndicatorObject * io); -- cgit v1.2.3 From d834013cb980c93b88d2f09aec69bce9d5f95148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 27 Jan 2011 18:25:15 +0100 Subject: Added show-notify-osd-on-scroll gsettings parameter This parameter (ON, by default) allows to enable/disable the notify-osd bubble on volume-change by mouse scroll. --- data/com.canonical.indicators.sound.gschema.xml | 9 +++++++++ src/indicator-sound.c | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/data/com.canonical.indicators.sound.gschema.xml b/data/com.canonical.indicators.sound.gschema.xml index 3850f65..1e08269 100644 --- a/data/com.canonical.indicators.sound.gschema.xml +++ b/data/com.canonical.indicators.sound.gschema.xml @@ -25,5 +25,14 @@ On start up volume should not be muted. + + true + Initial setting for showing notify-osd notification on scroll volume-change + + When using the mouse scroll-wheel over the indicator-sound icon, the volume changes. + Enabling this setting, every scroll volume-change a notify-osd bubble with the + updated volume value will be shown (if supported by your notification daemon). + + diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 29a9f91..9867e04 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -49,6 +49,7 @@ struct _IndicatorSoundPrivate GList* transport_widgets_list; GDBusProxy *dbus_proxy; SoundStateManager* state_manager; + GSettings *settings_manager; NotifyNotification* notification; }; @@ -140,6 +141,7 @@ indicator_sound_init (IndicatorSound *self) priv->state_manager = g_object_new (SOUND_TYPE_STATE_MANAGER, NULL); priv->notification = NULL; + priv->settings_manager = g_settings_new("com.canonical.indicators.sound"); indicator_sound_notification_init (self); g_signal_connect ( G_OBJECT(self->service), @@ -651,5 +653,6 @@ indicator_sound_scroll (IndicatorObject *io, gint delta, //g_debug("indicator-sound-scroll - update slider with value %f", value); volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value); - indicator_sound_notification_show(INDICATOR_SOUND (io), current_state, value); + if (g_settings_get_boolean(priv->settings_manager, "show-notify-osd-on-scroll")) + indicator_sound_notification_show(INDICATOR_SOUND (io), current_state, value); } -- cgit v1.2.3 From 439e6943aa4b50684ea7ebafc663d1ed21947961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 27 Jan 2011 18:33:30 +0100 Subject: Unref the GSettings object... --- src/indicator-sound.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 9867e04..88ef27d 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -162,6 +162,8 @@ indicator_sound_dispose (GObject *object) g_list_free ( priv->transport_widgets_list ); + g_object_unref(priv->settings_manager); + if (priv->notification) { notify_uninit(); } -- cgit v1.2.3 From cf9b03167ed12086acbd74b97404b082f8e018a8 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 31 Jan 2011 13:14:47 -0600 Subject: players in menu now dynamically controllable from new dbus api --- src/mpris2-watcher.vala | 2 +- src/music-player-bridge.vala | 11 ++++++ src/player-controller.vala | 10 +++--- src/sound-service-dbus.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ src/sound-service.c | 4 +-- src/sound-service.xml | 5 +-- 6 files changed, 107 insertions(+), 10 deletions(-) diff --git a/src/mpris2-watcher.vala b/src/mpris2-watcher.vala index c20b04b..0b37506 100644 --- a/src/mpris2-watcher.vala +++ b/src/mpris2-watcher.vala @@ -50,7 +50,7 @@ public class Mpris2Watcher : GLib.Object // At startup check to see if there are clients up that we are interested in // More relevant for development and daemon's like mpd. - private async void check_for_active_clients() + public async void check_for_active_clients() { string[] interfaces; try{ diff --git a/src/music-player-bridge.vala b/src/music-player-bridge.vala index c167e08..c6c9913 100644 --- a/src/music-player-bridge.vala +++ b/src/music-player-bridge.vala @@ -41,6 +41,17 @@ public class MusicPlayerBridge : GLib.Object private void on_blacklist_update ( string[] blacklist ) { debug("some blacklist update"); + + foreach(var s in blacklist){ + string key = this.determine_key (s); + if (this.registered_clients.has_key (key)){ + debug ("Apparently %s is now blacklisted - remove thy self", key); + this.registered_clients[key].remove_from_menu(); + this.registered_clients.unset (key); + } + } + // double check present players to ensure dynamic removal/addition + this.watcher.check_for_active_clients.begin(); } private void try_to_add_inactive_familiar_clients() diff --git a/src/player-controller.vala b/src/player-controller.vala index 024b88b..d24eaa0 100644 --- a/src/player-controller.vala +++ b/src/player-controller.vala @@ -119,10 +119,10 @@ public class PlayerController : GLib.Object this.determine_state(); } - public void vanish() + public void remove_from_menu() { - foreach(Dbusmenu.Menuitem item in this.custom_items){ - root_menu.child_delete(item); + foreach(PlayerItem item in this.custom_items){ + this.root_menu.child_delete(item); } } @@ -180,7 +180,7 @@ public class PlayerController : GLib.Object foreach(PlayerItem item in this.custom_items){ if (this.custom_items.index_of(item) != 4) { - root_menu.child_add_position(item, this.menu_offset + this.custom_items.index_of(item)); + root_menu.child_add_position(item, this.menu_offset + this.custom_items.index_of(item)); } else{ PlaylistsMenuitem playlists_menuitem = item as PlaylistsMenuitem; @@ -188,7 +188,7 @@ public class PlayerController : GLib.Object } } } - + private void determine_state() { if(this.mpris_bridge.connected() == true){ diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index a532c0e..0fc2f50 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -85,6 +85,10 @@ static void sound_service_dbus_determine_state (SoundServiceDbus* self, gboolean availability, gboolean mute, gdouble volume); +static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, + gchar* player_name, + gboolean blacklist); + G_DEFINE_TYPE (SoundServiceDbus, sound_service_dbus, G_TYPE_OBJECT); @@ -400,12 +404,93 @@ bus_method_call (GDBusConnection * connection, g_debug("Get state - %i", priv->current_sound_state ); retval = g_variant_new ( "(i)", priv->current_sound_state); } + else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { + gboolean blacklist; + gchar* player_name; + g_variant_get (params, "(sb)", &player_name, &blacklist); + + g_debug ("BlacklistMediaPlayer - bool %i", blacklist); + g_debug ("BlacklistMediaPlayer - name %s", player_name); + gboolean result = sound_service_dbus_blacklist_player (service, + player_name, + blacklist); + retval = g_variant_new ("(b)", result); + } else { g_warning("Calling method '%s' on the sound service but it's unknown", method); } g_dbus_method_invocation_return_value (invocation, retval); } +static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, + gchar* player_name, + gboolean blacklist) +{ + gboolean result = FALSE; + GSettings* our_settings = g_settings_new ("com.canonical.indicators.sound"); + GVariant* the_black_list = g_settings_get_value (our_settings, + "blacklisted-media-players"); + + GVariantIter *iter; + gchar *str; + // Firstly prep new array which will be set on the key. + GVariantBuilder *builder; + g_variant_get (the_black_list, "as", &iter); + builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + + while (g_variant_iter_loop (iter, "s", &str)){ + g_variant_builder_add (builder, "s", str); + } + + g_variant_get (the_black_list, "as", &iter); + + if (blacklist == TRUE){ + while (g_variant_iter_loop (iter, "s", &str)){ + g_print ("first pass to check if %s is present\n", str); + if (g_strcmp0 (player_name, str) == 0){ + // Return if its already there + g_debug ("we have this already blacklisted"); + return result; + } + } + // Otherwise blacklist it ! + g_debug ("about to blacklist %s", player_name); + g_variant_builder_add (builder, "s", player_name); + } + else{ + //g_variant_builder_clear (builder); + gboolean present = FALSE; + g_variant_get (the_black_list, "as", &iter); + + while (g_variant_iter_loop (iter, "s", &str)){ + if (g_strcmp0 (player_name, str) == 0){ + present = TRUE; + } + } + // It was not there anyway, return false + if (present == FALSE) + return result; + + // Otherwise free the builder and reconstruct ensuring no duplicates. + g_variant_builder_unref (builder); + builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + + g_variant_get (the_black_list, "as", &iter); + while (g_variant_iter_loop (iter, "s", &str)){ + if (g_strcmp0 (player_name, str) != 0){ + g_variant_builder_add (builder, "s", str); + } + } + } + GVariant* value = g_variant_new ("as", builder); + g_variant_builder_unref (builder); + g_variant_iter_free (iter); + result = g_settings_set_value (our_settings, + "blacklisted-media-players", + value); + g_variant_unref (value); + return result; +} diff --git a/src/sound-service.c b/src/sound-service.c index 2cb33d3..c1bb9b4 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - close_pulse_activites(); - g_main_loop_quit(mainloop); + //close_pulse_activites(); + //g_main_loop_quit(mainloop); } return; } diff --git a/src/sound-service.xml b/src/sound-service.xml index 18e47fc..81ebc2d 100644 --- a/src/sound-service.xml +++ b/src/sound-service.xml @@ -2,12 +2,13 @@ - + + - + -- cgit v1.2.3 From 6da3712d5eda504073689da98eccba020d57a5cd Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 31 Jan 2011 15:26:06 -0600 Subject: blacklist / interested players work done --- src/settings-manager.vala | 24 ++++++++++++++++++++++-- src/sound-service-dbus.c | 1 - src/sound-service.c | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/settings-manager.vala b/src/settings-manager.vala index 380e442..b5322c0 100644 --- a/src/settings-manager.vala +++ b/src/settings-manager.vala @@ -28,6 +28,7 @@ public class SettingsManager : GLib.Object construct{ this.settings = new Settings ("com.canonical.indicators.sound"); this.settings.changed["blacklisted-media-players"].connect (on_blacklist_event); + //this.reveal_contents(); } public string[] fetch_blacklist() @@ -52,7 +53,7 @@ public class SettingsManager : GLib.Object this.settings.reset("interested-media-players"); } - public void add_interested(string app_desktop_name) + public void add_interested (string app_desktop_name) { var already_interested = this.settings.get_strv ("interested-media-players"); foreach (var s in already_interested){ @@ -67,5 +68,24 @@ public class SettingsManager : GLib.Object private void on_blacklist_event() { this.blacklist_updates(this.settings.get_strv ("blacklisted-media-players")); - } + } + + // Convenient debug method inorder to provide visability over + // the contents of both interested and blacklisted containers in its gsettings + private void reveal_contents() + { + var already_interested = this.settings.get_strv ("interested-media-players"); + foreach (var s in already_interested) + { + debug ("client %s is in interested array", s); + } + var blacklisted = this.settings.get_strv ("blacklisted-media-players"); + foreach (var s in blacklisted) + { + debug ("client %s is in blacklisted array", s); + } + + debug ("interested array size = %i", already_interested.length); + debug ("blacklisted array size = %i", blacklisted.length); + } } diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 0fc2f50..f29fab4 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -458,7 +458,6 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, g_variant_builder_add (builder, "s", player_name); } else{ - //g_variant_builder_clear (builder); gboolean present = FALSE; g_variant_get (the_black_list, "as", &iter); diff --git a/src/sound-service.c b/src/sound-service.c index c1bb9b4..2cb33d3 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - //close_pulse_activites(); - //g_main_loop_quit(mainloop); + close_pulse_activites(); + g_main_loop_quit(mainloop); } return; } -- cgit v1.2.3 From 43b7e22a13692edbba02c987975747a069881814 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 31 Jan 2011 19:33:46 -0600 Subject: moved builder and iter to the stack in blacklist method --- src/player-controller.vala | 4 +++ src/playlists-menu-item.vala | 2 +- src/settings-manager.vala | 1 - src/sound-service-dbus.c | 61 +++++++++++++++++++++++++------------------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/player-controller.vala b/src/player-controller.vala index d24eaa0..3ce121e 100644 --- a/src/player-controller.vala +++ b/src/player-controller.vala @@ -124,6 +124,10 @@ public class PlayerController : GLib.Object foreach(PlayerItem item in this.custom_items){ this.root_menu.child_delete(item); } + if (this.use_playlists == true){ + PlaylistsMenuitem playlists_menuitem = this.custom_items[widget_order.PLAYLISTS] as PlaylistsMenuitem; + this.root_menu.child_delete (playlists_menuitem.root_item); + } } public void hibernate() diff --git a/src/playlists-menu-item.vala b/src/playlists-menu-item.vala index 024839c..b8c6e7d 100644 --- a/src/playlists-menu-item.vala +++ b/src/playlists-menu-item.vala @@ -50,7 +50,7 @@ public class PlaylistsMenuitem : PlayerItem this.root_item.child_append( menuitem ); } } - + private bool already_observed (PlaylistDetails new_detail) { foreach ( PlaylistDetails detail in this.current_playlists.values ){ diff --git a/src/settings-manager.vala b/src/settings-manager.vala index b5322c0..057a47b 100644 --- a/src/settings-manager.vala +++ b/src/settings-manager.vala @@ -28,7 +28,6 @@ public class SettingsManager : GLib.Object construct{ this.settings = new Settings ("com.canonical.indicators.sound"); this.settings.changed["blacklisted-media-players"].connect (on_blacklist_event); - //this.reveal_contents(); } public string[] fetch_blacklist() diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index f29fab4..9ae0fd7 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -427,68 +427,77 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, gboolean blacklist) { gboolean result = FALSE; - GSettings* our_settings = g_settings_new ("com.canonical.indicators.sound"); + GSettings* our_settings = NULL; + our_settings = g_settings_new ("com.canonical.indicators.sound"); GVariant* the_black_list = g_settings_get_value (our_settings, "blacklisted-media-players"); - - GVariantIter *iter; + GVariantIter iter; gchar *str; // Firstly prep new array which will be set on the key. - GVariantBuilder *builder; - g_variant_get (the_black_list, "as", &iter); - builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + GVariantBuilder builder; + + g_variant_iter_init (&iter, the_black_list); + g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); - while (g_variant_iter_loop (iter, "s", &str)){ - g_variant_builder_add (builder, "s", str); + while (g_variant_iter_loop (&iter, "s", &str)){ + g_variant_builder_add (&builder, "s", str); } - - g_variant_get (the_black_list, "as", &iter); + g_variant_iter_init (&iter, the_black_list); if (blacklist == TRUE){ - while (g_variant_iter_loop (iter, "s", &str)){ + while (g_variant_iter_loop (&iter, "s", &str)){ g_print ("first pass to check if %s is present\n", str); if (g_strcmp0 (player_name, str) == 0){ // Return if its already there - g_debug ("we have this already blacklisted"); + g_debug ("we have this already blacklisted, no need to do anything"); + g_variant_builder_end (&builder); + g_object_unref (our_settings); return result; } } // Otherwise blacklist it ! g_debug ("about to blacklist %s", player_name); - g_variant_builder_add (builder, "s", player_name); + g_variant_builder_add (&builder, "s", player_name); } else{ gboolean present = FALSE; - g_variant_get (the_black_list, "as", &iter); - - while (g_variant_iter_loop (iter, "s", &str)){ + g_variant_iter_init (&iter, the_black_list); + g_debug ("attempting to UN-blacklist %s", player_name); + + while (g_variant_iter_loop (&iter, "s", &str)){ if (g_strcmp0 (player_name, str) == 0){ present = TRUE; } } // It was not there anyway, return false - if (present == FALSE) + if (present == FALSE){ + g_debug ("it was not blacklisted ?, no need to do anything"); + g_variant_builder_end (&builder); + g_object_unref (our_settings); return result; - + } + // Otherwise free the builder and reconstruct ensuring no duplicates. - g_variant_builder_unref (builder); - builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + g_variant_builder_end (&builder); + g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); - g_variant_get (the_black_list, "as", &iter); + g_variant_iter_init (&iter, the_black_list); - while (g_variant_iter_loop (iter, "s", &str)){ + while (g_variant_iter_loop (&iter, "s", &str)){ if (g_strcmp0 (player_name, str) != 0){ - g_variant_builder_add (builder, "s", str); + g_variant_builder_add (&builder, "s", str); } } } - GVariant* value = g_variant_new ("as", builder); - g_variant_builder_unref (builder); - g_variant_iter_free (iter); + GVariant* value = g_variant_builder_end (&builder); + g_variant_ref (value); result = g_settings_set_value (our_settings, "blacklisted-media-players", value); + g_variant_unref (value); + g_object_unref (our_settings); + return result; } -- cgit v1.2.3 From 2ea739c1cc14bbfdafbebec79aeae78cbf440145 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 1 Feb 2011 09:50:29 -0600 Subject: fixes applied --- src/sound-service-dbus.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 9ae0fd7..7f5afdc 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -450,8 +450,9 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, if (g_strcmp0 (player_name, str) == 0){ // Return if its already there g_debug ("we have this already blacklisted, no need to do anything"); - g_variant_builder_end (&builder); + g_variant_builder_clear (&builder); g_object_unref (our_settings); + g_object_unref (the_black_list); return result; } } @@ -472,17 +473,18 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, // It was not there anyway, return false if (present == FALSE){ g_debug ("it was not blacklisted ?, no need to do anything"); - g_variant_builder_end (&builder); + g_variant_builder_clear (&builder); g_object_unref (our_settings); + g_object_unref (the_black_list); return result; } // Otherwise free the builder and reconstruct ensuring no duplicates. - g_variant_builder_end (&builder); + g_variant_builder_clear (&builder); g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); g_variant_iter_init (&iter, the_black_list); - + while (g_variant_iter_loop (&iter, "s", &str)){ if (g_strcmp0 (player_name, str) != 0){ g_variant_builder_add (&builder, "s", str); @@ -490,13 +492,12 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, } } GVariant* value = g_variant_builder_end (&builder); - g_variant_ref (value); result = g_settings_set_value (our_settings, "blacklisted-media-players", value); - g_variant_unref (value); g_object_unref (our_settings); + g_object_unref (the_black_list); return result; } -- cgit v1.2.3 From 8507423eb5b7acaf1089fdaa4fc57cdca554abeb Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 1 Feb 2011 12:24:38 -0600 Subject: the title on the player menu item can now be dynamically changed using the Identity prop on the root MPRIS interface --- src/mpris2-controller.vala | 20 +++++++++++++++----- src/title-menu-item.vala | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index 03571e6..b9e7551 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -103,6 +103,11 @@ public class Mpris2Controller : GLib.Object this.fetch_playlists.begin(); this.fetch_active_playlist(); } + Variant? identity_v = changed_properties.lookup("Identity"); + if (identity_v != null){ + TitleMenuitem title = this.owner.custom_items[PlayerController.widget_order.TITLE] as TitleMenuitem; + title.alter_label (identity_v.get_string()); + } } private bool ensure_correct_playback_status(){ @@ -144,15 +149,20 @@ public class Mpris2Controller : GLib.Object public void initial_update() { TransportMenuitem.state update; + if(this.player.PlaybackStatus == null){ update = TransportMenuitem.state.PAUSED; } - - update = determine_play_state(null); - - (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state(TransportMenuitem.state.PAUSED); + else{ + update = determine_play_state (this.player.PlaybackStatus); + } + if (this.mpris2_root.Identity != null){ + TitleMenuitem title = this.owner.custom_items[PlayerController.widget_order.TITLE] as TitleMenuitem; + title.alter_label (this.mpris2_root.Identity); + } + (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state (update); GLib.HashTable? cleaned_metadata = this.clean_metadata(); - this.owner.custom_items[PlayerController.widget_order.METADATA].update(cleaned_metadata, + this.owner.custom_items[PlayerController.widget_order.METADATA].update (cleaned_metadata, MetadataMenuitem.attributes_format()); if ( this.owner.use_playlists == true ){ diff --git a/src/title-menu-item.vala b/src/title-menu-item.vala index 6ed24d8..fd81f65 100644 --- a/src/title-menu-item.vala +++ b/src/title-menu-item.vala @@ -26,8 +26,12 @@ public class TitleMenuitem : PlayerItem public TitleMenuitem(PlayerController parent) { Object(item_type: MENUITEM_TYPE, owner: parent); - this.property_set(MENUITEM_NAME, parent.app_info.get_name()); - this.property_set(MENUITEM_ICON, parent.icon_name); + } + + construct + { + this.property_set(MENUITEM_NAME, this.owner.app_info.get_name()); + this.property_set(MENUITEM_ICON, this.owner.icon_name); this.property_set_bool(MENUITEM_RUNNING, false); } @@ -42,6 +46,12 @@ public class TitleMenuitem : PlayerItem } } + public void alter_label (string new_title) + { + if (new_title != null) return; + this.property_set(MENUITEM_NAME, new_title); + } + public void toggle_active_triangle(bool update) { this.property_set_bool(MENUITEM_RUNNING, update); -- cgit v1.2.3 From ebf8fb61bea8de7d6d2df81015b538638207f2cf Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 1 Feb 2011 13:31:32 -0600 Subject: make sure it updates its own title --- src/mpris2-controller.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index b9e7551..d4cdc0c 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -106,7 +106,7 @@ public class Mpris2Controller : GLib.Object Variant? identity_v = changed_properties.lookup("Identity"); if (identity_v != null){ TitleMenuitem title = this.owner.custom_items[PlayerController.widget_order.TITLE] as TitleMenuitem; - title.alter_label (identity_v.get_string()); + title.alter_label (this.mpris2_root.Identity); } } -- cgit v1.2.3 From 2b6453d1a988eb4a82df18401b3ba9b3867a2f40 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 1 Feb 2011 14:40:51 -0600 Subject: fixes for the last two merge requests --- src/sound-service-dbus.c | 6 +++--- src/title-menu-item.vala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 7f5afdc..637bee4 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -452,7 +452,7 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, g_debug ("we have this already blacklisted, no need to do anything"); g_variant_builder_clear (&builder); g_object_unref (our_settings); - g_object_unref (the_black_list); + g_variant_unref (the_black_list); return result; } } @@ -475,7 +475,7 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, g_debug ("it was not blacklisted ?, no need to do anything"); g_variant_builder_clear (&builder); g_object_unref (our_settings); - g_object_unref (the_black_list); + g_variant_unref (the_black_list); return result; } @@ -497,7 +497,7 @@ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, value); g_object_unref (our_settings); - g_object_unref (the_black_list); + g_variant_unref (the_black_list); return result; } diff --git a/src/title-menu-item.vala b/src/title-menu-item.vala index fd81f65..ac93b89 100644 --- a/src/title-menu-item.vala +++ b/src/title-menu-item.vala @@ -48,7 +48,7 @@ public class TitleMenuitem : PlayerItem public void alter_label (string new_title) { - if (new_title != null) return; + if (new_title == null) return; this.property_set(MENUITEM_NAME, new_title); } -- cgit v1.2.3 From 73003df26f377fc226f2fba51c579da44132fdbb Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 1 Feb 2011 18:07:58 -0600 Subject: tidy up --- src/sound-service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound-service.c b/src/sound-service.c index c1bb9b4..2cb33d3 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - //close_pulse_activites(); - //g_main_loop_quit(mainloop); + close_pulse_activites(); + g_main_loop_quit(mainloop); } return; } -- cgit v1.2.3 From 9992cab449e6dbf1d87046fede2ec35bfab51cd6 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Wed, 2 Feb 2011 13:05:50 -0600 Subject: refactored notify patch --- src/indicator-sound.c | 85 ++----------------------------------- src/indicator-sound.h | 7 --- src/sound-state-manager.c | 106 +++++++++++++++++++++++++++++++++++++++++++--- src/sound-state-manager.h | 5 ++- 4 files changed, 107 insertions(+), 96 deletions(-) diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 6678750..7e5ebc7 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -27,8 +27,6 @@ with this program. If not, see . #include -#include - #include "indicator-sound.h" #include "transport-widget.h" #include "metadata-widget.h" @@ -49,8 +47,6 @@ struct _IndicatorSoundPrivate GList* transport_widgets_list; GDBusProxy *dbus_proxy; SoundStateManager* state_manager; - GSettings *settings_manager; - NotifyNotification* notification; }; #define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate)) @@ -74,11 +70,6 @@ static void indicator_sound_scroll (IndicatorObject* io, gint delta, IndicatorScrollDirection direction); -//Notification -static void indicator_sound_notification_init (IndicatorSound *self); -static void indicator_sound_notification_show (IndicatorSound *self, - SoundState state, double value); - //key/moust event handlers static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); static gboolean key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); @@ -142,10 +133,6 @@ indicator_sound_init (IndicatorSound *self) GList* t_list = NULL; priv->transport_widgets_list = t_list; priv->state_manager = g_object_new (SOUND_TYPE_STATE_MANAGER, NULL); - priv->notification = NULL; - - priv->settings_manager = g_settings_new("com.canonical.indicators.sound"); - indicator_sound_notification_init (self); g_signal_connect ( G_OBJECT(self->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, @@ -162,15 +149,8 @@ indicator_sound_dispose (GObject *object) g_object_unref(G_OBJECT(self->service)); self->service = NULL; } - g_list_free ( priv->transport_widgets_list ); - g_object_unref(priv->settings_manager); - - if (priv->notification) { - notify_uninit(); - } - G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object); return; } @@ -227,33 +207,6 @@ get_menu (IndicatorObject * io) return GTK_MENU(menu); } -static void -indicator_sound_notification_init (IndicatorSound *self) -{ - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - - if (!notify_init(PACKAGE_NAME)) - return; - - GList* caps = notify_get_server_caps(); - gboolean has_notify_osd = FALSE; - - if (caps) { - if (g_list_find_custom(caps, "x-canonical-private-synchronous", - (GCompareFunc) g_strcmp0)) { - has_notify_osd = TRUE; - } - g_list_foreach(caps, (GFunc) g_free, NULL); - g_list_free(caps); - } - - if (has_notify_osd) { - priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL, NULL); - notify_notification_set_hint_string(priv->notification, - "x-canonical-private-synchronous", ""); - } -} - static void connection_changed (IndicatorServiceManager * sm, gboolean connected, @@ -448,10 +401,8 @@ new_volume_slider_widget(DbusmenuMenuitem * newitem, newitem, menu_volume_item, parent); - - if (priv->notification) - notify_notification_attach_to_widget(priv->notification, volume_widget); - + sound_state_manager_attach_notification_to_volume_widget (priv->state_manager, + volume_widget); return TRUE; } @@ -613,35 +564,6 @@ key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) return digested; } -static void -indicator_sound_notification_show(IndicatorSound *self, SoundState state, double value) -{ - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - - if (priv->notification == NULL) - return; - - char *icon; - const int notify_value = CLAMP((int)value, -1, 101); - - if (state == ZERO_LEVEL) { - // Not available for all the themes - icon = "audio-volume-off"; - } else if (state == LOW_LEVEL) { - icon = "audio-volume-low"; - } else if (state == MEDIUM_LEVEL) { - icon = "audio-volume-medium"; - } else if (state == HIGH_LEVEL) { - icon = "audio-volume-high"; - } else { - icon = "audio-volume-muted"; - } - - notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); - notify_notification_set_hint_int32(priv->notification, "value", notify_value); - notify_notification_show(priv->notification, NULL); -} - static void indicator_sound_scroll (IndicatorObject *io, gint delta, IndicatorScrollDirection direction) @@ -669,6 +591,5 @@ indicator_sound_scroll (IndicatorObject *io, gint delta, //g_debug("indicator-sound-scroll - update slider with value %f", value); volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value); - if (g_settings_get_boolean(priv->settings_manager, "show-notify-osd-on-scroll")) - indicator_sound_notification_show(INDICATOR_SOUND (io), current_state, value); + sound_state_manager_show_notification (priv->state_manager, value); } diff --git a/src/indicator-sound.h b/src/indicator-sound.h index c52a62a..40a3e6f 100644 --- a/src/indicator-sound.h +++ b/src/indicator-sound.h @@ -53,11 +53,4 @@ struct _IndicatorSound { // GObject Boiler plate GType indicator_sound_get_type (void); -void prepare_state_machine(); -extern void determine_state_from_volume(gdouble volume_percent); -gint get_state(); -gchar* get_state_image_name(gint state); -void prepare_for_tests(IndicatorObject * io); -void tidy_up_hash(); - #endif diff --git a/src/sound-state-manager.c b/src/sound-state-manager.c index e8865d8..a592711 100644 --- a/src/sound-state-manager.c +++ b/src/sound-state-manager.c @@ -18,6 +18,10 @@ with this program. If not, see . */ #include +#include + +#include "config.h" + #include "sound-state-manager.h" #include "dbus-shared-names.h" @@ -30,6 +34,8 @@ struct _SoundStateManagerPrivate GList* blocked_animation_list; SoundState current_state; GtkImage* speaker_image; + NotifyNotification* notification; + GSettings *settings_manager; }; #define SOUND_STATE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_TYPE_STATE_MANAGER, SoundStateManagerPrivate)) @@ -41,7 +47,11 @@ static gint animation_id; static GList* blocked_iter = NULL; static gboolean can_animate = FALSE; -static void sound_state_manager_prepare_blocked_animation(SoundStateManager* self); +//Notifications +static void sound_state_manager_notification_init (SoundStateManager* self); + +//Animation/State related +static void sound_state_manager_prepare_blocked_animation (SoundStateManager* self); static gboolean sound_state_manager_start_animation (gpointer user_data); static gboolean sound_state_manager_fade_back_to_mute_image (gpointer user_data); static void sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self); @@ -54,6 +64,7 @@ static void sound_state_signal_cb ( GDBusProxy* proxy, gpointer user_data ); static gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self); + static void sound_state_manager_init (SoundStateManager* self) { @@ -63,6 +74,12 @@ sound_state_manager_init (SoundStateManager* self) priv->volume_states = NULL; priv->speaker_image = NULL; priv->blocked_animation_list = NULL; + priv->notification = NULL; + priv->settings_manager = NULL; + + priv->settings_manager = g_settings_new("com.canonical.indicators.sound"); + + sound_state_manager_notification_init (self); sound_state_manager_prepare_state_image_names (self); sound_state_manager_prepare_blocked_animation (self); @@ -89,9 +106,16 @@ sound_state_manager_dispose (GObject *object) g_hash_table_destroy (priv->volume_states); sound_state_manager_free_the_animation_list (self); + + if (priv->notification) { + notify_uninit(); + } + + g_object_unref(priv->settings_manager); + G_OBJECT_CLASS (sound_state_manager_parent_class)->dispose (object); } - + static void sound_state_manager_class_init (SoundStateManagerClass *klass) @@ -106,6 +130,77 @@ sound_state_manager_class_init (SoundStateManagerClass *klass) design_team_size = gtk_icon_size_register("design-team-size", 22, 22); } +static void +sound_state_manager_notification_init (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + if (!notify_init(PACKAGE_NAME)) + return; + + GList* caps = notify_get_server_caps(); + gboolean has_notify_osd = FALSE; + + if (caps) { + if (g_list_find_custom(caps, "x-canonical-private-synchronous", + (GCompareFunc) g_strcmp0)) { + has_notify_osd = TRUE; + } + g_list_foreach(caps, (GFunc) g_free, NULL); + g_list_free(caps); + } + + if (has_notify_osd) { + priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL, NULL); + notify_notification_set_hint_string(priv->notification, + "x-canonical-private-synchronous", ""); + } +} + +void +sound_state_manager_attach_notification_to_volume_widget (SoundStateManager *self, + GtkWidget* volume_widget) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + if (priv->notification) + notify_notification_attach_to_widget(priv->notification, volume_widget); +} + + +void +sound_state_manager_show_notification (SoundStateManager *self, + double value) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + if (priv->notification == NULL || + g_settings_get_boolean (priv->settings_manager, "show-notify-osd-on-scroll") == FALSE){ + return; + } + + char *icon; + const int notify_value = CLAMP((int)value, -1, 101); + SoundState state = sound_state_manager_get_current_state (self); + + if (state == ZERO_LEVEL) { + // Not available for all the themes + icon = "audio-volume-off"; + } else if (state == LOW_LEVEL) { + icon = "audio-volume-low"; + } else if (state == MEDIUM_LEVEL) { + icon = "audio-volume-medium"; + } else if (state == HIGH_LEVEL) { + icon = "audio-volume-high"; + } else { + icon = "audio-volume-muted"; + } + + notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); + notify_notification_set_hint_int32(priv->notification, "value", notify_value); + notify_notification_show(priv->notification, NULL); +} + + /* Prepare states versus images names hash. */ @@ -113,7 +208,8 @@ static void sound_state_manager_prepare_state_image_names (SoundStateManager* self) { SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - priv->volume_states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + priv->volume_states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MUTED), g_strdup("audio-volume-muted-panel")); g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(ZERO_LEVEL), g_strdup("audio-volume-low-zero-panel")); g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(LOW_LEVEL), g_strdup("audio-volume-low-panel")); @@ -281,8 +377,7 @@ sound_state_signal_cb ( GDBusProxy* proxy, blocked_id = g_timeout_add_seconds (4, sound_state_manager_start_animation, self); - indicator_image_helper_update (priv->speaker_image, image_name); - + indicator_image_helper_update (priv->speaker_image, image_name); } else{ indicator_image_helper_update (priv->speaker_image, image_name); @@ -291,7 +386,6 @@ sound_state_signal_cb ( GDBusProxy* proxy, else { g_warning ("sorry don't know what signal this is - %s", signal_name); } - } void diff --git a/src/sound-state-manager.h b/src/sound-state-manager.h index d73d5d9..0b919cb 100644 --- a/src/sound-state-manager.h +++ b/src/sound-state-manager.h @@ -58,8 +58,11 @@ void sound_state_manager_deal_with_disconnect (SoundStateManager* self); void sound_state_manager_get_state_cb (GObject *object, GAsyncResult *res, gpointer user_data); +void sound_state_manager_show_notification (SoundStateManager *self, + double value); - +void sound_state_manager_attach_notification_to_volume_widget (SoundStateManager *self, + GtkWidget* volume_widget); G_END_DECLS -- cgit v1.2.3 From 04a43bec0a144a9c7ed682471c438c499df41d1b Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 3 Feb 2011 11:56:22 +0000 Subject: beginnings of new pulsemgr --- src/pulseaudio-mgr.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/pulseaudio-mgr.h | 0 2 files changed, 197 insertions(+) create mode 100644 src/pulseaudio-mgr.c create mode 100644 src/pulseaudio-mgr.h diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c new file mode 100644 index 0000000..60b1b1a --- /dev/null +++ b/src/pulseaudio-mgr.c @@ -0,0 +1,197 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +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 + +#include "pulse-manager.h" + +#define RECONNECT_DELAY 5 + +static void context_state_callback(pa_context *c, void *userdata); + +static gint reconnect_idle_id = 0; +static pa_context *pulse_context = NULL; +static pa_glib_mainloop *pa_main_loop = NULL; + +// Entry Point +void establish_pulse_activities() +{ + 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), + "com.canonical.indicators.sound"); + g_assert(pulse_context); + + pa_context_set_state_callback (pulse_context, context_state_callback, /*active sink obj*/NULL); + sound_service_dbus_update_pa_state (dbus_service, FALSE, FALSE, 0); + pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, /*active sink obj*/NULL); +} + +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; + } + + pulse_context = pa_context_new( pa_glib_mainloop_get_api( pa_main_loop ), + "com.canonical.indicators.sound" ); + g_assert(pulse_context); + 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; +} + + +static void pulse_server_info_callback(pa_context *c, + const pa_server_info *info, + void *userdata) +{ + pa_operation *operation; + if (info == NULL) { + g_warning("No server - get the hell out of here"); + //sound_service_dbus_update_pa_state(dbus_service, FALSE, TRUE, 0); + return; + } + 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))) { + } 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); +} + + +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_sound_state(dbus_service, UNAVAILABLE); + + /* 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("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); + /*sound_service_dbus_update_pa_state( dbus_service, + 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_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) + (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; + } +} diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 513679bbf8169e69a6d78aa924c4f5b034c818b2 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 3 Feb 2011 16:09:16 +0000 Subject: starting to make sense --- src/active-sink.c | 0 src/active-sink.h | 54 ++++++++++++++++ src/pulseaudio-mgr.c | 177 ++++++++++++++++++++++++++++----------------------- 3 files changed, 152 insertions(+), 79 deletions(-) create mode 100644 src/active-sink.c create mode 100644 src/active-sink.h diff --git a/src/active-sink.c b/src/active-sink.c new file mode 100644 index 0000000..e69de29 diff --git a/src/active-sink.h b/src/active-sink.h new file mode 100644 index 0000000..240f43e --- /dev/null +++ b/src/active-sink.h @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Canonical Ltd. + * + * Authors: + * Conor Curran + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * 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 . + */ + +#ifndef __ACTIVE_SINK_H__ +#define __ACTIVE_SINK_H__ + +#include +#include +#include +#include "common-defs.h" + + +G_BEGIN_DECLS + +#define ACTIVE_SINK_TYPE (active_sink_get_type ()) +#define ACTIVE_SINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), ACTIVE_SINK_TYPE, ActiveSink)) +#define ACTIVE_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), ACTIVE_SINK_TYPE, ActiveSinkClass)) +#define IS_ACTIVE_SINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), ACTIVE_SINK_TYPE)) +#define IS_ACTIVE_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), ACTIVE_SINK_TYPE)) +#define ACTIVE_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ACTIVE_SINK_TYPE, ActiveSinkClass)) + +typedef struct _ActiveSink ActiveSink; +typedef struct _ActiveSinkClass ActiveSinkClass; + + +struct _ActiveSink { + GObject parent; +}; + +struct _ActiveSinkClass { + GObjectClass parent_class; +}; + +GType active_sink_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 60b1b1a..7b8c06a 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -21,34 +21,51 @@ with this program. If not, see . #include #include "pulse-manager.h" +#include "active-sink.h" #define RECONNECT_DELAY 5 -static void context_state_callback(pa_context *c, void *userdata); +static void pm_context_state_callback(pa_context *c, void *userdata); +static void pm_subscribed_events_callback (pa_context *c, + enum pa_subscription_event_type t, + uint32_t index, + void* userdata); +static void pm_server_info_callback (pa_context *c, + const pa_server_info *info, + void *userdata); + + +static gint connection_attempts = 0; static gint reconnect_idle_id = 0; static pa_context *pulse_context = NULL; static pa_glib_mainloop *pa_main_loop = NULL; // Entry Point -void establish_pulse_activities() +void +establish_pulse_activities (ActiveSink* active_sink) { - 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), + 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), "com.canonical.indicators.sound"); - g_assert(pulse_context); - - pa_context_set_state_callback (pulse_context, context_state_callback, /*active sink obj*/NULL); - sound_service_dbus_update_pa_state (dbus_service, FALSE, FALSE, 0); - pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, /*active sink obj*/NULL); + g_assert (pulse_context); + + pa_context_set_state_callback (pulse_context, + pm_context_state_callback, + (gpointer)active_sink); + + //TODO update active sink before init with state at unavailable + + pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, (gpointer)active_sink); } static gboolean -reconnect_to_pulse() +reconnect_to_pulse (gpointer user_data) { g_debug("Attempt to reconnect to pulse"); // reset + connection_attempts += 1; if (pulse_context != NULL) { pa_context_unref(pulse_context); pulse_context = NULL; @@ -57,83 +74,56 @@ reconnect_to_pulse() pulse_context = pa_context_new( pa_glib_mainloop_get_api( pa_main_loop ), "com.canonical.indicators.sound" ); g_assert(pulse_context); - pa_context_set_state_callback (pulse_context, context_state_callback, NULL); - int result = pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); + pa_context_set_state_callback (pulse_context, + pm_context_state_callback, + user_data); + int result = pa_context_connect (pulse_context, + NULL, + PA_CONTEXT_NOFAIL, + user_data); 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; -} - - -static void pulse_server_info_callback(pa_context *c, - const pa_server_info *info, - void *userdata) -{ - pa_operation *operation; - if (info == NULL) { - g_warning("No server - get the hell out of here"); - //sound_service_dbus_update_pa_state(dbus_service, FALSE, TRUE, 0); - return; - } - 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))) { - } else { - pa_operation_unref(operation); - return; - } + if (connection_attempts > 5){ + return FALSE; } - if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) { - g_warning("pa_context_get_sink_info_list() failed"); - return; + else{ + return TRUE; } - pa_operation_unref(operation); } - -static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) +static void +pm_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_sound_state(dbus_service, UNAVAILABLE); - - /* 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)); + // TODO check the sink index is not your active index and react appropriately } 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)); + } + else { + // query the info of the sink input to see if we have a blocking moment + // TODO investigate what the id is here. + 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 ???"); + g_debug("PA_SUBSCRIPTION_EVENT_SERVER event triggered."); pa_operation *o; - if (!(o = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) { + 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; } @@ -144,44 +134,39 @@ static void subscribed_events_callback(pa_context *c, enum pa_subscription_event static void -context_state_callback (pa_context *c, void *userdata) +pm_context_state_callback (pa_context *c, void *userdata) { switch (pa_context_get_state(c)) { case PA_CONTEXT_UNCONNECTED: - g_debug("unconnected"); + g_debug("unconnected"); break; case PA_CONTEXT_CONNECTING: - g_debug("connecting - waiting for the server to become available"); + 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("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); - /*sound_service_dbus_update_pa_state( dbus_service, - pa_server_available, - default_sink_is_muted(), - get_default_sink_volume() ); - */ + // TODO: update state to unvailable on active sink if (reconnect_idle_id == 0){ reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY, reconnect_to_pulse, - NULL); + userdata); } break; case PA_CONTEXT_TERMINATED: - /* g_debug("context terminated");*/ break; case PA_CONTEXT_READY: + + connection_attempts = 0; g_debug("PA_CONTEXT_READY"); pa_operation *o; - pa_context_set_subscribe_callback(c, subscribed_events_callback, userdata); + pa_context_set_subscribe_callback(c, pm_subscribed_events_callback, userdata); - if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) + 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))) { @@ -195,3 +180,37 @@ context_state_callback (pa_context *c, void *userdata) break; } } + +/** + After startup we go straight for the server info to see if it has details of + the default sink. If so it makes things much easier. + **/ +static void +pm_server_info_callback (pa_context *c, + const pa_server_info *info, + void *userdata) +{ + pa_operation *operation; + if (info == NULL) { + g_warning("No server - get the hell out of here"); + //TODO update active sink with state info + return; + } + if (info->default_sink_name != NULL) { + if (!(operation = pa_context_get_sink_info_by_name (c, + info->default_sink_name, + pm_default_sink_info_callback, + userdata) )) { + } + else{ + pa_operation_unref(operation); + return; + } + } + else 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); +} + -- cgit v1.2.3 From 7070e44eced4d173c0e175948b3da4ca9f9497b9 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 3 Feb 2011 17:00:30 +0000 Subject: starting to make sense --- src/active-sink.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/active-sink.h | 13 ++++++++-- src/pulseaudio-mgr.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++- src/pulseaudio-mgr.h | 6 +++++ 4 files changed, 146 insertions(+), 3 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index e69de29..ee211ef 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -0,0 +1,67 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +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 +#include +#include "active-sink.h" + +typedef struct _ActiveSinkPrivate ActiveSinkPrivate; + +struct _ActiveSinkPrivate +{ +}; + +#define ACTIVE_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACTIVE_SINK_TYPE, ActiveSinkPrivate)) + +/* Prototypes */ +static void active_sink_class_init (ActiveSinkClass *klass); +static void active_sink_init (ActiveSink *self); +static void active_sink_dispose (GObject *object); +static void active_sink_finalize (GObject *object); + +G_DEFINE_TYPE (ActiveSink, active_sink, G_TYPE_OBJECT); + +static void +active_sink_class_init (ActiveSinkClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + g_type_class_add_private (klass, sizeof (ActiveSinkPrivate)); + + gobject_class->dispose = active_sink_dispose; + gobject_class->finalize = active_sink_finalize; +} + +static void +active_sink_init(ActiveSink *self) +{ +} + +static void +active_sink_dispose (GObject *object) +{ + G_OBJECT_CLASS (active_sink_parent_class)->dispose (object); +} + +static void +active_sink_finalize (GObject *object) +{ + G_OBJECT_CLASS (active_sink_parent_class)->finalize (object); +} diff --git a/src/active-sink.h b/src/active-sink.h index 240f43e..12083b8 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -24,7 +24,7 @@ #include #include #include "common-defs.h" - +#include G_BEGIN_DECLS @@ -38,7 +38,6 @@ G_BEGIN_DECLS typedef struct _ActiveSink ActiveSink; typedef struct _ActiveSinkClass ActiveSinkClass; - struct _ActiveSink { GObject parent; }; @@ -47,6 +46,16 @@ struct _ActiveSinkClass { GObjectClass parent_class; }; +typedef struct { + gchar* name; + gint index; + pa_cvolume volume; + pa_channel_map channel_map; + gboolean mute; + pa_volume_t base_volume; +} sink_details; + + GType active_sink_get_type (void) G_GNUC_CONST; G_END_DECLS diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 7b8c06a..216c025 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -96,6 +96,17 @@ reconnect_to_pulse (gpointer user_data) } } +static void +populate_active_sink (const pa_sink_info *info, ActiveSink* sink) +{ + +} + +/**********************************************************************************************************************/ +// Pulse-Audio asychronous call-backs +/**********************************************************************************************************************/ + + static void pm_subscribed_events_callback (pa_context *c, enum pa_subscription_event_type t, @@ -192,7 +203,7 @@ pm_server_info_callback (pa_context *c, { pa_operation *operation; if (info == NULL) { - g_warning("No server - get the hell out of here"); + g_warning("No PA server - get the hell out of here"); //TODO update active sink with state info return; } @@ -214,3 +225,53 @@ pm_server_info_callback (pa_context *c, pa_operation_unref(operation); } +static void +pm_sink_info_callback (pa_context *c, + const pa_sink_info *sink, + int eol, + void *userdata) +{ + if (eol > 0) { + return; + } + 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 +pm_default_sink_info_callback (pa_context *c, + const pa_sink_info *info, + int eol, + void *userdata) +{ + if (eol > 0) { + 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 { + sound_service_dbus_update_pa_state(dbus_service, + determine_sink_availability(), + default_sink_is_muted(), + get_default_sink_volume()); + } + } +} + + diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index e69de29..6fb66a5 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -0,0 +1,6 @@ + + + + + + -- cgit v1.2.3 From ff857b05deb7f7385c9d4d8d43be19fca225c6ca Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 3 Feb 2011 18:36:34 +0000 Subject: basics established --- src/active-sink.c | 27 +++++++++++++++++++++++++++ src/active-sink.h | 4 +++- src/pulseaudio-mgr.c | 47 +++++++++++++++++++++-------------------------- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index ee211ef..8ba88d8 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -25,6 +25,7 @@ typedef struct _ActiveSinkPrivate ActiveSinkPrivate; struct _ActiveSinkPrivate { + sink_details* details; }; #define ACTIVE_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACTIVE_SINK_TYPE, ActiveSinkPrivate)) @@ -52,11 +53,21 @@ active_sink_class_init (ActiveSinkClass *klass) static void active_sink_init(ActiveSink *self) { + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + priv->details = NULL; } static void active_sink_dispose (GObject *object) { + ActiveSink * self = ACTIVE_SINK(object); + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + + if (priv->details != NULL) { + g_free (priv->details->name); + g_free (priv->details); + } + G_OBJECT_CLASS (active_sink_parent_class)->dispose (object); } @@ -65,3 +76,19 @@ active_sink_finalize (GObject *object) { G_OBJECT_CLASS (active_sink_parent_class)->finalize (object); } + +void +active_sink_update_details (ActiveSink* sink, sink_details* details) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + priv->details = details; +} + +void gboolean +active_sink_is_populated (ActiveSink* sink) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + return (priv->details != NULL) +} + + \ No newline at end of file diff --git a/src/active-sink.h b/src/active-sink.h index 12083b8..6aed0b6 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -55,9 +55,11 @@ typedef struct { pa_volume_t base_volume; } sink_details; - GType active_sink_get_type (void) G_GNUC_CONST; +void active_sink_update_details (ActiveSink* sink, sink_details* details); +void gboolean active_sink_is_populated (ActiveSink* sink) + G_END_DECLS #endif diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 216c025..59faaf0 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -99,7 +99,15 @@ reconnect_to_pulse (gpointer user_data) static void populate_active_sink (const pa_sink_info *info, ActiveSink* sink) { - + sink_details *details; + details = g_new0 (sink_details, 1); + details->index = info->index; + details->name = g_strdup (info->name); + details->mute = !!info->mute; + details->volume = construct_mono_volume (&info->volume); + details->base_volume = info->base_volume; + details->channel_map = info->channel_map; + active_sink_update_details (sink, details); } /**********************************************************************************************************************/ @@ -225,6 +233,9 @@ pm_server_info_callback (pa_context *c, pa_operation_unref(operation); } +// If the server doesn't have a default sink to give us +// we should attempt to pick up the first of the list of sinks which doesn't have +// the name 'auto_null' static void pm_sink_info_callback (pa_context *c, const pa_sink_info *sink, @@ -235,17 +246,11 @@ pm_sink_info_callback (pa_context *c, return; } 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");*/ + ActiveSink* a_sink = ACTIVESINK (userdata); + if (active_sink_is_populated (a_sink) && + g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ + populate_active_sink (info, ACTIVESINK (userdata)); + } } } @@ -256,21 +261,11 @@ pm_default_sink_info_callback (pa_context *c, void *userdata) { if (eol > 0) { + // TODO what happens here - high and dry! 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 { - sound_service_dbus_update_pa_state(dbus_service, - determine_sink_availability(), - default_sink_is_muted(), - get_default_sink_volume()); - } + } + else { + populate_active_sink (info, ACTIVESINK (userdata)); } } -- cgit v1.2.3 From 81c80e6e823127337573b3c522f78820e7635911 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 3 Feb 2011 20:16:00 +0000 Subject: we have a replacement pulse manager in the baking - working very nicely indeed --- src/active-sink.c | 11 +++---- src/active-sink.h | 2 +- src/pulseaudio-mgr.c | 93 +++++++++++++++++++++++++++++++++++++++++++--------- src/pulseaudio-mgr.h | 4 +++ 4 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 8ba88d8..c140fac 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -42,7 +42,6 @@ static void active_sink_class_init (ActiveSinkClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); g_type_class_add_private (klass, sizeof (ActiveSinkPrivate)); @@ -53,7 +52,7 @@ active_sink_class_init (ActiveSinkClass *klass) static void active_sink_init(ActiveSink *self) { - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); priv->details = NULL; } @@ -61,7 +60,7 @@ static void active_sink_dispose (GObject *object) { ActiveSink * self = ACTIVE_SINK(object); - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); if (priv->details != NULL) { g_free (priv->details->name); @@ -84,11 +83,11 @@ active_sink_update_details (ActiveSink* sink, sink_details* details) priv->details = details; } -void gboolean +gboolean active_sink_is_populated (ActiveSink* sink) { - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); - return (priv->details != NULL) + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); + return (priv->details != NULL); } \ No newline at end of file diff --git a/src/active-sink.h b/src/active-sink.h index 6aed0b6..e6970bf 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -58,7 +58,7 @@ typedef struct { GType active_sink_get_type (void) G_GNUC_CONST; void active_sink_update_details (ActiveSink* sink, sink_details* details); -void gboolean active_sink_is_populated (ActiveSink* sink) +gboolean active_sink_is_populated (ActiveSink* sink); G_END_DECLS diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 59faaf0..ee14b6e 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -17,11 +17,20 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - +/**Notes + * + * Approach now is to set up the communication channels then query the server + * fetch its default sink. If this fails then fetch the list of sinks and take + * the first one which is not the auto-null sink. + * TODO: need to handle the situation where one chink in this linear chain breaks + * i.e. start off the process again and count the attempts (note different to + reconnect attempts) + */ #include +#include +#include #include "pulse-manager.h" -#include "active-sink.h" #define RECONNECT_DELAY 5 @@ -34,6 +43,19 @@ static void pm_subscribed_events_callback (pa_context *c, static void pm_server_info_callback (pa_context *c, const pa_server_info *info, void *userdata); +static void pm_default_sink_info_callback (pa_context *c, + const pa_sink_info *info, + int eol, + void *userdata); +static void pm_sink_info_callback (pa_context *c, + const pa_sink_info *sink, + int eol, + void *userdata); + + +static void populate_active_sink (const pa_sink_info *info, ActiveSink* sink); +static gboolean reconnect_to_pulse (gpointer user_data); +static pa_cvolume construct_mono_volume(const pa_cvolume* vol); static gint connection_attempts = 0; @@ -60,6 +82,21 @@ establish_pulse_activities (ActiveSink* active_sink) pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, (gpointer)active_sink); } +/** +close_pulse_activites() +Gracefully close our connection with the Pulse async library. +**/ +void close_pulse_activites() +{ + if (pulse_context != NULL) { + pa_context_unref(pulse_context); + pulse_context = NULL; + } + pa_glib_mainloop_free(pa_main_loop); + pa_main_loop = NULL; +} + + static gboolean reconnect_to_pulse (gpointer user_data) { @@ -107,7 +144,19 @@ populate_active_sink (const pa_sink_info *info, ActiveSink* sink) details->volume = construct_mono_volume (&info->volume); details->base_volume = info->base_volume; details->channel_map = info->channel_map; - active_sink_update_details (sink, details); + active_sink_update_details (sink, details); + g_debug ("active sink populated with sink %s", details->name); +} + +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; } /**********************************************************************************************************************/ @@ -134,15 +183,15 @@ pm_subscribed_events_callback (pa_context *c, else { // query the info of the sink input to see if we have a blocking moment // TODO investigate what the id is here. - pa_operation_unref (pa_context_get_sink_input_info (c, - index, - pulse_sink_input_info_callback, userdata)); + //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("PA_SUBSCRIPTION_EVENT_SERVER event triggered."); pa_operation *o; - if (!(o = pa_context_get_server_info (c, pulse_server_info_callback, userdata))) { + if (!(o = pa_context_get_server_info (c, pm_server_info_callback, userdata))) { g_warning("subscribed_events_callback - pa_context_get_server_info() failed"); return; } @@ -190,11 +239,15 @@ pm_context_state_callback (pa_context *c, void *userdata) PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL))) { g_warning("pa_context_subscribe() failed"); - return; + + } + + if (!(o = pa_context_get_server_info (c, pm_server_info_callback, userdata))) { + g_warning("Initial - pa_context_get_server_info() failed"); } pa_operation_unref(o); - //gather_pulse_information(c, userdata); + break; } @@ -210,12 +263,15 @@ pm_server_info_callback (pa_context *c, void *userdata) { pa_operation *operation; + g_debug ("server info callback"); + if (info == NULL) { g_warning("No PA server - get the hell out of here"); //TODO update active sink with state info return; } if (info->default_sink_name != NULL) { + g_debug ("default sink name from the server ain't null'"); if (!(operation = pa_context_get_sink_info_by_name (c, info->default_sink_name, pm_default_sink_info_callback, @@ -226,7 +282,9 @@ pm_server_info_callback (pa_context *c, return; } } - else if (!(operation = pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL))) { + else if (!(operation = pa_context_get_sink_info_list(c, + pm_sink_info_callback, + NULL))) { g_warning("pa_context_get_sink_info_list() failed"); return; } @@ -235,21 +293,25 @@ pm_server_info_callback (pa_context *c, // If the server doesn't have a default sink to give us // we should attempt to pick up the first of the list of sinks which doesn't have -// the name 'auto_null' +// the name 'auto_null' (that was all really I was doing before) static void pm_sink_info_callback (pa_context *c, const pa_sink_info *sink, int eol, - void *userdata) + void* userdata) { if (eol > 0) { return; } else { - ActiveSink* a_sink = ACTIVESINK (userdata); + if (IS_ACTIVE_SINK (userdata) == FALSE){ + g_warning ("sink info callback - our user data is not what we think it should be"); + return; + } + ActiveSink* a_sink = ACTIVE_SINK (userdata); if (active_sink_is_populated (a_sink) && g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ - populate_active_sink (info, ACTIVESINK (userdata)); + populate_active_sink (sink, a_sink); } } } @@ -265,7 +327,8 @@ pm_default_sink_info_callback (pa_context *c, return; } else { - populate_active_sink (info, ACTIVESINK (userdata)); + g_debug ("server has handed us a default sink"); + populate_active_sink (info, ACTIVE_SINK (userdata)); } } diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index 6fb66a5..692a55a 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -1,3 +1,7 @@ +#include "active-sink.h" + +void establish_pulse_activities (ActiveSink* active_sink); +void close_pulse_activites(); -- cgit v1.2.3 From 33689fcba482b5c0d16fa318836457bcb4ae83bd Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 11:49:25 +0000 Subject: blocking handled --- src/active-sink.c | 11 +++++++ src/active-sink.h | 3 +- src/pulseaudio-mgr.c | 91 ++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 14 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index c140fac..7e84b58 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -90,4 +90,15 @@ active_sink_is_populated (ActiveSink* sink) return (priv->details != NULL); } +gboolean +active_sink_is_muted (ActiveSink* self) +{ + return FALSE; +} + +gint +active_sink_get_index (ActiveSink* self) +{ + return 0; +} \ No newline at end of file diff --git a/src/active-sink.h b/src/active-sink.h index e6970bf..051da85 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -59,7 +59,8 @@ GType active_sink_get_type (void) G_GNUC_CONST; void active_sink_update_details (ActiveSink* sink, sink_details* details); gboolean active_sink_is_populated (ActiveSink* sink); - +gboolean active_sink_is_muted (ActiveSink* self); +gint active_sink_get_index (ActiveSink* self); G_END_DECLS #endif diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index ee14b6e..5f128eb 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -51,6 +51,15 @@ static void pm_sink_info_callback (pa_context *c, const pa_sink_info *sink, int eol, void *userdata); +static void pm_sink_input_info_callback (pa_context *c, + const pa_sink_input_info *info, + int eol, + void *userdata); + +static void pm_update_active_sink (pa_context *c, + const pa_sink_info *info, + int eol, + void *userdata); static void populate_active_sink (const pa_sink_info *info, ActiveSink* sink); @@ -172,20 +181,31 @@ pm_subscribed_events_callback (pa_context *c, { switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: + if (IS_ACTIVE_SINK (userdata) == FALSE){ + g_warning ("subscribed events callback - our userdata is not what we think it should be"); + return; + } + ActiveSink* sink = ACTIVE_SINK (userdata); + // We don't care about any other sink other than the active one. + if (index != active_sink_get_index (sink)) + return; + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - // TODO check the sink index is not your active index and react appropriately + // TODO: Fire of an unavailable state signal and try to find another sink + } + else{ + pa_operation_unref (pa_context_get_sink_info_by_index (c, + index, + pm_update_active_sink, + userdata) ); } break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - //handle the sink input remove event - not relevant for current design - } - else { - // query the info of the sink input to see if we have a blocking moment - // TODO investigate what the id is here. - //pa_operation_unref (pa_context_get_sink_input_info (c, - // index, - // pulse_sink_input_info_callback, userdata)); + // We don't care about sink input removals. + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_REMOVE) { + pa_operation_unref (pa_context_get_sink_input_info (c, + index, + pm_sink_input_info_callback, userdata)); } break; case PA_SUBSCRIPTION_EVENT_SERVER: @@ -246,9 +266,7 @@ pm_context_state_callback (pa_context *c, void *userdata) g_warning("Initial - pa_context_get_server_info() failed"); } pa_operation_unref(o); - - - + break; } } @@ -327,9 +345,56 @@ pm_default_sink_info_callback (pa_context *c, return; } else { + if (IS_ACTIVE_SINK (userdata) == FALSE){ + g_warning ("Default sink info callback - our user data is not what we think it should be"); + return; + } + g_debug ("server has handed us a default sink"); populate_active_sink (info, ACTIVE_SINK (userdata)); } } +static void +pm_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_warning("\n Sink input info callback : SINK INPUT INFO IS NULL BUT EOL was not POSITIVE!!!"); + return; + } + if (IS_ACTIVE_SINK (userdata) == FALSE){ + g_warning ("sink input info callback - our user data is not what we think it should be"); + return; + } + + ActiveSink* a_sink = ACTIVE_SINK (userdata); + if (active_sink_get_index (a_sink) == info->sink->index && + active_sink_is_muted () == TRUE) { + // TODO fire off blocking signal + } + } +} + +static void +pm_update_active_sink (pa_context *c, + const pa_sink_info *info, + int eol, + void *userdata) +{ + if (eol > 0) { + return; + } + else{ + + } +} + -- cgit v1.2.3 From ad214980e84c32ac93b43301f54406c6952c0819 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 12:17:06 +0000 Subject: active-sink api beginning to emerge --- src/active-sink.c | 11 ++++++++++- src/active-sink.h | 4 ++++ src/pulseaudio-mgr.c | 14 ++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 7e84b58..e85aab8 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -101,4 +101,13 @@ active_sink_get_index (ActiveSink* self) { return 0; } - \ No newline at end of file + +void +active_sink_update_volume (ActiveSink* self, gdouble percent) +{ +} + +void +active_sink_update_mute (ActiveSink* self, gboolean muted) +{ +} diff --git a/src/active-sink.h b/src/active-sink.h index 051da85..251d0a7 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -61,6 +61,10 @@ void active_sink_update_details (ActiveSink* sink, sink_details* details); gboolean active_sink_is_populated (ActiveSink* sink); gboolean active_sink_is_muted (ActiveSink* self); gint active_sink_get_index (ActiveSink* self); +void active_sink_update_volume (ActiveSink* self, gdouble vol_percent); +void active_sink_update_mute (ActiveSink* self, gboolean muted); + + G_END_DECLS #endif diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 5f128eb..5089e23 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -30,7 +30,7 @@ with this program. If not, see . #include #include -#include "pulse-manager.h" +#include "pulseaudio-mgr.h" #define RECONNECT_DELAY 5 @@ -376,8 +376,8 @@ pm_sink_input_info_callback (pa_context *c, } ActiveSink* a_sink = ACTIVE_SINK (userdata); - if (active_sink_get_index (a_sink) == info->sink->index && - active_sink_is_muted () == TRUE) { + if (active_sink_get_index (a_sink) == info->sink && + active_sink_is_muted (a_sink) == TRUE) { // TODO fire off blocking signal } } @@ -393,7 +393,13 @@ pm_update_active_sink (pa_context *c, return; } else{ - + if (IS_ACTIVE_SINK (userdata) == FALSE){ + g_warning ("update_active_sink - our user data is not what we think it should be"); + return; + } + pa_volume_t vol = pa_cvolume_max (&info->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + active_sink_update_volume (ACTIVE_SINK(userdata), volume_percent); } } -- cgit v1.2.3 From 7ba3797b9006f0a7e048787ee6de91fd05e60d2b Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 14:08:09 +0000 Subject: on the last hurdle --- src/active-sink.c | 101 ++++++++++++++++++++++++++++--- src/active-sink.h | 1 + src/pulseaudio-mgr.c | 8 +-- src/sound-service-dbus.c | 150 ++++++----------------------------------------- 4 files changed, 116 insertions(+), 144 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index e85aab8..b41d6d3 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -17,15 +17,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include -#include +#include + #include "active-sink.h" +#include "slider-menu-item.h" +#include "mute-menu-item.h" + + typedef struct _ActiveSinkPrivate ActiveSinkPrivate; struct _ActiveSinkPrivate { - sink_details* details; + gboolean is_active; + SliderMenuItem* volume_slider_menuitem; + MuteMenuItem* mute_menuitem; + SoundState current_sound_state; + gint index; + SoundServiceDbus* service; }; #define ACTIVE_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACTIVE_SINK_TYPE, ActiveSinkPrivate)) @@ -36,6 +45,8 @@ static void active_sink_init (ActiveSink *self); static void active_sink_dispose (GObject *object); static void active_sink_finalize (GObject *object); +static SoundState active_sink_get_state_from_volume (ActiveSink* self); + G_DEFINE_TYPE (ActiveSink, active_sink, G_TYPE_OBJECT); static void @@ -54,6 +65,15 @@ active_sink_init(ActiveSink *self) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); priv->details = NULL; + priv->mute_menuitem = NULL; + priv->volume_slider_menuitem = NULL; + priv->current_sound_state = UNAVAILABLE; + priv->is_active = TRUE; + priv->index = -1; + + // Init our menu items. + priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); + priv->volume_slider_menuitem = g_object_new (SLIDER_MENU_ITEM_TYPE, NULL); } static void @@ -76,38 +96,103 @@ active_sink_finalize (GObject *object) G_OBJECT_CLASS (active_sink_parent_class)->finalize (object); } +// This needs to populate the appropriate values on the menu items void -active_sink_update_details (ActiveSink* sink, sink_details* details) +active_sink_populate (ActiveSink* sink, + gdouble volume, + gboolean mute, + gint device_index) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); - priv->details = details; + active_sink_update_volume (sink, volume); + active_sink_update_mute (sink, mute); + priv->index = device_index; + priv->is_active = TRUE; } gboolean active_sink_is_populated (ActiveSink* sink) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); - return (priv->details != NULL); + return priv->is_active; } gboolean active_sink_is_muted (ActiveSink* self) { - return FALSE; + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return mute_menu_item_is_muted (priv->mute_menuitem); } gint active_sink_get_index (ActiveSink* self) { - return 0; + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return priv->index; } void active_sink_update_volume (ActiveSink* self, gdouble percent) { + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + slider_menu_item_update (priv->volume_slider_menuitem, percent); + sound_service_dbus_update_sound_state (priv->service, + active_sink_get_state_from_volume (self)); } void active_sink_update_mute (ActiveSink* self, gboolean muted) { + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + mute_menu_item_update (priv->mute_menuitem, muted); + SoundState state = active_sink_get_state_from_volume (self); + + if (muted == TRUE){ + state = MUTED; + } + sound_service_dbus_update_sound_state (priv->service, state); +} + +SoundState +active_sink_get_state (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return priv->current_sound_state; +} + + +static SoundState +active_sink_get_state_from_volume (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + GVariant* v = dbusmenu_menuitem_property_get_variant (DBUSMENU_MENUITEM(priv->volume_slider_menuitem), + DBUSMENU_VOLUME_MENUITEM_LEVEL); + gdouble volume_percent = g_variant_get_double (v); + + SoundState state = LOW_LEVEL; + + if (volume_percent < 30.0 && volume_percent > 0) { + state = LOW_LEVEL; + } + else if (volume_percent < 70.0 && volume_percent >= 30.0) { + state = MEDIUM_LEVEL; + } + else if (volume_percent >= 70.0) { + state = HIGH_LEVEL; + } + else if (volume_percent == 0.0) { + state = ZERO_LEVEL; + } + return state; +} + +ActiveSink* active_sink_new (SoundServiceDbus* service) +{ + ActiveSink* sink = g_object_new (ACTIVE_SINK_TYPE, NULL); + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); + priv->service = service; + sound_service_dbus_build_sound_menu (service, + priv->mute_menuitem, + priv->voluem_slider_menuitem); + return sink; } diff --git a/src/active-sink.h b/src/active-sink.h index 251d0a7..827b8a7 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -61,6 +61,7 @@ void active_sink_update_details (ActiveSink* sink, sink_details* details); gboolean active_sink_is_populated (ActiveSink* sink); gboolean active_sink_is_muted (ActiveSink* self); gint active_sink_get_index (ActiveSink* self); +SoundState active_sink_get_state (ActiveSink* self); void active_sink_update_volume (ActiveSink* self, gdouble vol_percent); void active_sink_update_mute (ActiveSink* self, gboolean muted); diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 5089e23..28340b7 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -62,7 +62,7 @@ static void pm_update_active_sink (pa_context *c, void *userdata); -static void populate_active_sink (const pa_sink_info *info, ActiveSink* sink); +static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink); static gboolean reconnect_to_pulse (gpointer user_data); static pa_cvolume construct_mono_volume(const pa_cvolume* vol); @@ -143,10 +143,8 @@ reconnect_to_pulse (gpointer user_data) } static void -populate_active_sink (const pa_sink_info *info, ActiveSink* sink) +pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink) { - sink_details *details; - details = g_new0 (sink_details, 1); details->index = info->index; details->name = g_strdup (info->name); details->mute = !!info->mute; @@ -351,7 +349,7 @@ pm_default_sink_info_callback (pa_context *c, } g_debug ("server has handed us a default sink"); - populate_active_sink (info, ACTIVE_SINK (userdata)); + pm_populate_active_sink (info, ACTIVE_SINK (userdata)); } } diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 637bee4..9009869 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -32,10 +32,6 @@ #include "gen-sound-service.xml.h" #include "dbus-shared-names.h" -#include "pulse-manager.h" -#include "slider-menu-item.h" -#include "mute-menu-item.h" -#include "pulse-manager.h" // DBUS methods static void bus_method_call (GDBusConnection * connection, @@ -57,16 +53,15 @@ static GDBusInterfaceVTable interface_table = { typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; struct _SoundServiceDbusPrivate { - GDBusConnection* connection; - DbusmenuMenuitem* root_menuitem; - SliderMenuItem* volume_slider_menuitem; - MuteMenuItem* mute_menuitem; - SoundState current_sound_state; + GDBusConnection* connection; + DbusmenuMenuitem* root_menuitem; + ActiveSink* active_sink; }; static GDBusNodeInfo * node_info = NULL; static GDBusInterfaceInfo * interface_info = NULL; static gboolean b_startup = TRUE; + #define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate)) static void sound_service_dbus_class_init (SoundServiceDbusClass *klass); @@ -133,8 +128,6 @@ sound_service_dbus_init (SoundServiceDbus *self) priv->connection = NULL; - priv->current_sound_state = UNAVAILABLE; - /* Fetch the session bus */ priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); @@ -167,32 +160,26 @@ sound_service_dbus_create_root_item (SoundServiceDbus* self) DbusmenuServer *server = dbusmenu_server_new(INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); dbusmenu_server_set_root (server, priv->root_menuitem); g_object_unref (priv->root_menuitem); - establish_pulse_activities (self); + priv->active_sink = active_sink_new (self); + //establish_pulse_activities (self); return priv->root_menuitem; } -static void +void sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, - gboolean mute_update, - gboolean availability, - gdouble volume ) + DbusmenuMenuitem* mute_item, + DbusmenuMenuitem* slider_item) { SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); // Mute button - priv->mute_menuitem = mute_menu_item_new ( mute_update, availability); - dbusmenu_menuitem_child_append (priv->root_menuitem, - mute_menu_item_get_button (priv->mute_menuitem)); - - // Slider - priv->volume_slider_menuitem = slider_menu_item_new ( availability, volume ); - dbusmenu_menuitem_child_append (priv->root_menuitem, DBUSMENU_MENUITEM ( priv->volume_slider_menuitem )); + dbusmenu_menuitem_child_append (priv->root_menuitem, mute_item)); + dbusmenu_menuitem_child_append (priv->root_menuitem, slider_item )); // Separator - DbusmenuMenuitem* separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set( separator, + dbusmenu_menuitem_property_set (separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); dbusmenu_menuitem_child_append(priv->root_menuitem, separator); @@ -207,9 +194,7 @@ sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, dbusmenu_menuitem_child_append(priv->root_menuitem, settings_mi); g_object_unref (settings_mi); g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(show_sound_settings_dialog), NULL); - - sound_service_dbus_determine_state (self, availability, mute_update, volume); + G_CALLBACK(show_sound_settings_dialog), NULL); } /** @@ -229,41 +214,11 @@ show_sound_settings_dialog (DbusmenuMenuitem *mi, } } -void -sound_service_dbus_update_pa_state ( SoundServiceDbus* self, - gboolean availability, - gboolean mute_update, - gdouble volume ) -{ - g_debug("update pa state with availability of %i, mute value of %i and a volume percent is %f", availability, mute_update, volume); - SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); - - if (b_startup == TRUE) { - sound_service_dbus_build_sound_menu ( self, - mute_update, - availability, - volume ); - b_startup = FALSE; - return; - } - - mute_menu_item_update ( priv->mute_menuitem, - mute_update ); - slider_menu_item_update ( priv->volume_slider_menuitem, - volume ); - - mute_menu_item_enable ( priv->mute_menuitem, availability); - slider_menu_item_enable ( priv->volume_slider_menuitem, - availability ); - sound_service_dbus_determine_state (self, availability, mute_update, volume); - -} - - static void sound_service_dbus_dispose (GObject *object) { G_OBJECT_CLASS (sound_service_dbus_parent_class)->dispose (object); + //TODO dispose of the active sink instance ! return; } @@ -274,76 +229,6 @@ sound_service_dbus_finalize (GObject *object) return; } -// UNTIL PA-MANAGER IS REFACTORED AND THE ACTIVESINK CLASS IS CREATED LEAVE -// THE UI ELEMENTS SEPARATELY HANDLED LIKE THIS. -void -sound_service_dbus_update_volume (SoundServiceDbus* self, - gdouble volume) -{ - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); - slider_menu_item_update (priv->volume_slider_menuitem, volume); - sound_service_dbus_update_sound_state (self, - sound_service_dbus_get_state_from_volume (self)); -} - -void -sound_service_dbus_update_sink_mute (SoundServiceDbus* self, - gboolean mute_update) -{ - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); - mute_menu_item_update (priv->mute_menuitem, mute_update); - SoundState state = sound_service_dbus_get_state_from_volume (self); - if (mute_update == TRUE){ - state = MUTED; - } - sound_service_dbus_update_sound_state (self, state); -} - -/*------- State calculators ------------------*/ -static SoundState -sound_service_dbus_get_state_from_volume (SoundServiceDbus* self) -{ - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); - GVariant* v = dbusmenu_menuitem_property_get_variant (DBUSMENU_MENUITEM(priv->volume_slider_menuitem), - DBUSMENU_VOLUME_MENUITEM_LEVEL); - gdouble volume_percent = g_variant_get_double (v); - - SoundState state = LOW_LEVEL; - - if (volume_percent < 30.0 && volume_percent > 0) { - state = LOW_LEVEL; - } - else if (volume_percent < 70.0 && volume_percent >= 30.0) { - state = MEDIUM_LEVEL; - } - else if (volume_percent >= 70.0) { - state = HIGH_LEVEL; - } - else if (volume_percent == 0.0) { - state = ZERO_LEVEL; - } - return state; -} - -static void -sound_service_dbus_determine_state (SoundServiceDbus* self, - gboolean availability, - gboolean mute, - gdouble volume) -{ - SoundState update; - if (availability == FALSE) { - update = UNAVAILABLE; - } - else if (mute == TRUE) { - update = MUTED; - } - else{ - update = sound_service_dbus_get_state_from_volume (self); - } - sound_service_dbus_update_sound_state (self, update); -} - // EMIT STATE SIGNAL @@ -401,8 +286,8 @@ bus_method_call (GDBusConnection * connection, SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); if (g_strcmp0(method, "GetSoundState") == 0) { - g_debug("Get state - %i", priv->current_sound_state ); - retval = g_variant_new ( "(i)", priv->current_sound_state); + g_debug("Get state - %i", active_sink_get_state (priv->active_sink); + retval = g_variant_new ( "(i)", active_sink_get_state (priv->active_sink)); } else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { gboolean blacklist; @@ -422,6 +307,9 @@ bus_method_call (GDBusConnection * connection, g_dbus_method_invocation_return_value (invocation, retval); } +/** + TODO - Works nicely but refactor into at least two different methods +**/ static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, gchar* player_name, gboolean blacklist) -- cgit v1.2.3 From 025fb0a3df226ab127ee435c341882addfafcbba Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 16:17:31 +0000 Subject: almost in place --- src/Makefile.am | 9 ++++---- src/active-sink.c | 60 +++++++++++++++++++++++++++++++++--------------- src/active-sink.h | 11 ++++++--- src/pulseaudio-mgr.c | 27 ++++++++-------------- src/pulseaudio-mgr.h | 21 ++++++++++++++++- src/sound-service-dbus.c | 31 +++++-------------------- src/sound-service-dbus.h | 10 ++++---- 7 files changed, 94 insertions(+), 75 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ed64aeb..63d6d5a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,7 +72,6 @@ music_bridge_VALAFLAGS = \ --pkg gdk-pixbuf-2.0 \ --pkg libxml-2.0 - $(MAINTAINER_VALAFLAGS) music_bridge_APIFILES = \ @@ -89,8 +88,10 @@ indicator_sound_service_SOURCES = \ common-defs.h \ sound-service.h \ sound-service.c \ - pulse-manager.h \ - pulse-manager.c \ + pulseaudio-mgr.h \ + pulseaudio-mgr.c \ + active-sink.c \ + active-sink.h \ sound-service-dbus.h \ sound-service-dbus.c \ slider-menu-item.h \ @@ -108,7 +109,7 @@ indicator_sound_service_LDADD = $(PULSEAUDIO_LIBS) $(SOUNDSERVICE_LIBS) $(GCONF_ # Service xml compilation ######################### DBUS_SPECS = \ - sound-service.xml + sound-service.xml gen-%.xml.h: %.xml @echo "Building $@ from $<" diff --git a/src/active-sink.c b/src/active-sink.c index b41d6d3..b84e03f 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -16,25 +16,27 @@ 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 #include "active-sink.h" #include "slider-menu-item.h" #include "mute-menu-item.h" - +#include "pulseaudio-mgr.h" typedef struct _ActiveSinkPrivate ActiveSinkPrivate; struct _ActiveSinkPrivate { - gboolean is_active; SliderMenuItem* volume_slider_menuitem; MuteMenuItem* mute_menuitem; SoundState current_sound_state; - gint index; SoundServiceDbus* service; + gint index; + gchar* name; + pa_cvolume volume; + pa_channel_map channel_map; + pa_volume_t base_volume; }; #define ACTIVE_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACTIVE_SINK_TYPE, ActiveSinkPrivate)) @@ -46,6 +48,8 @@ static void active_sink_dispose (GObject *object); static void active_sink_finalize (GObject *object); static SoundState active_sink_get_state_from_volume (ActiveSink* self); +static pa_cvolume active_sink_construct_mono_volume (const pa_cvolume* vol); + G_DEFINE_TYPE (ActiveSink, active_sink, G_TYPE_OBJECT); @@ -64,12 +68,12 @@ static void active_sink_init(ActiveSink *self) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - priv->details = NULL; priv->mute_menuitem = NULL; priv->volume_slider_menuitem = NULL; priv->current_sound_state = UNAVAILABLE; - priv->is_active = TRUE; priv->index = -1; + priv->name = NULL; + priv->service = NULL; // Init our menu items. priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); @@ -82,10 +86,10 @@ active_sink_dispose (GObject *object) ActiveSink * self = ACTIVE_SINK(object); ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - if (priv->details != NULL) { + /*if (priv->details != NULL) { g_free (priv->details->name); g_free (priv->details); - } + }*/ G_OBJECT_CLASS (active_sink_parent_class)->dispose (object); } @@ -96,25 +100,30 @@ active_sink_finalize (GObject *object) G_OBJECT_CLASS (active_sink_parent_class)->finalize (object); } -// This needs to populate the appropriate values on the menu items void active_sink_populate (ActiveSink* sink, - gdouble volume, - gboolean mute, - gint device_index) + const pa_sink_info* update) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); - active_sink_update_volume (sink, volume); - active_sink_update_mute (sink, mute); - priv->index = device_index; - priv->is_active = TRUE; + + priv->name = g_strdup (update->name); + priv->index = update->index; + // Why the double negative !? + active_sink_update_mute (sink, !!update->mute); + priv->volume = active_sink_construct_mono_volume (&update->volume); + priv->base_volume = update->base_volume; + priv->channel_map = update->channel_map; + + pa_volume_t vol = pa_cvolume_max (&update->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + active_sink_update_volume (sink, volume_percent); } gboolean active_sink_is_populated (ActiveSink* sink) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); - return priv->is_active; + return (priv->index != -1); } gboolean @@ -186,13 +195,26 @@ active_sink_get_state_from_volume (ActiveSink* self) return state; } +static pa_cvolume +active_sink_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; +} + + ActiveSink* active_sink_new (SoundServiceDbus* service) { ActiveSink* sink = g_object_new (ACTIVE_SINK_TYPE, NULL); ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); priv->service = service; sound_service_dbus_build_sound_menu (service, - priv->mute_menuitem, - priv->voluem_slider_menuitem); + mute_menu_item_get_button (priv->mute_menuitem), + DBUSMENU_MENUITEM (priv->volume_slider_menuitem)); + pm_establish_pulse_connection (sink); return sink; } diff --git a/src/active-sink.h b/src/active-sink.h index 827b8a7..3b21d94 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -22,8 +22,10 @@ #include #include -#include + #include "common-defs.h" +#include "sound-service-dbus.h" + #include G_BEGIN_DECLS @@ -46,7 +48,7 @@ struct _ActiveSinkClass { GObjectClass parent_class; }; -typedef struct { +/*typedef struct { gchar* name; gint index; pa_cvolume volume; @@ -54,17 +56,20 @@ typedef struct { gboolean mute; pa_volume_t base_volume; } sink_details; +*/ GType active_sink_get_type (void) G_GNUC_CONST; -void active_sink_update_details (ActiveSink* sink, sink_details* details); +void active_sink_populate (ActiveSink* sink, const pa_sink_info* update); gboolean active_sink_is_populated (ActiveSink* sink); gboolean active_sink_is_muted (ActiveSink* self); gint active_sink_get_index (ActiveSink* self); SoundState active_sink_get_state (ActiveSink* self); + void active_sink_update_volume (ActiveSink* self, gdouble vol_percent); void active_sink_update_mute (ActiveSink* self, gboolean muted); +ActiveSink* active_sink_new (SoundServiceDbus* service); G_END_DECLS diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 28340b7..9fd449d 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -62,7 +62,7 @@ static void pm_update_active_sink (pa_context *c, void *userdata); -static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink); +//static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink); static gboolean reconnect_to_pulse (gpointer user_data); static pa_cvolume construct_mono_volume(const pa_cvolume* vol); @@ -74,7 +74,7 @@ static pa_glib_mainloop *pa_main_loop = NULL; // Entry Point void -establish_pulse_activities (ActiveSink* active_sink) +pm_establish_pulse_connection (ActiveSink* active_sink) { pa_main_loop = pa_glib_mainloop_new (g_main_context_default ()); g_assert (pa_main_loop); @@ -142,7 +142,7 @@ reconnect_to_pulse (gpointer user_data) } } -static void +/*static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink) { details->index = info->index; @@ -153,18 +153,9 @@ pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink) details->channel_map = info->channel_map; active_sink_update_details (sink, details); g_debug ("active sink populated with sink %s", details->name); -} + +}*/ -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; -} /**********************************************************************************************************************/ // Pulse-Audio asychronous call-backs @@ -325,9 +316,10 @@ pm_sink_info_callback (pa_context *c, return; } ActiveSink* a_sink = ACTIVE_SINK (userdata); - if (active_sink_is_populated (a_sink) && + if (active_sink_is_populated (a_sink) == FALSE && g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ - populate_active_sink (sink, a_sink); + active_sink_populate (a_sink, sink); + //populate_active_sink (sink, a_sink); } } } @@ -349,7 +341,8 @@ pm_default_sink_info_callback (pa_context *c, } g_debug ("server has handed us a default sink"); - pm_populate_active_sink (info, ACTIVE_SINK (userdata)); + active_sink_populate (ACTIVE_SINK (userdata), info); + //pm_populate_active_sink (info, ACTIVE_SINK (userdata)); } } diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index 692a55a..af4f29c 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -1,6 +1,25 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +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 "active-sink.h" -void establish_pulse_activities (ActiveSink* active_sink); +void pm_establish_pulse_connection (ActiveSink* active_sink); void close_pulse_activites(); diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 9009869..1617a47 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -29,7 +29,7 @@ #include #include "sound-service-dbus.h" - +#include "active-sink.h" #include "gen-sound-service.xml.h" #include "dbus-shared-names.h" @@ -60,7 +60,6 @@ struct _SoundServiceDbusPrivate { static GDBusNodeInfo * node_info = NULL; static GDBusInterfaceInfo * interface_info = NULL; -static gboolean b_startup = TRUE; #define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate)) @@ -69,17 +68,8 @@ static void sound_service_dbus_init (SoundServiceDbus *self); static void sound_service_dbus_dispose (GObject *object); static void sound_service_dbus_finalize (GObject *object); -static void sound_service_dbus_build_sound_menu ( SoundServiceDbus* root, - gboolean mute_update, - gboolean availability, - gdouble volume ); static void show_sound_settings_dialog (DbusmenuMenuitem *mi, gpointer user_data); -static SoundState sound_service_dbus_get_state_from_volume (SoundServiceDbus* self); -static void sound_service_dbus_determine_state (SoundServiceDbus* self, - gboolean availability, - gboolean mute, - gdouble volume); static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, gchar* player_name, gboolean blacklist); @@ -173,8 +163,8 @@ sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); // Mute button - dbusmenu_menuitem_child_append (priv->root_menuitem, mute_item)); - dbusmenu_menuitem_child_append (priv->root_menuitem, slider_item )); + dbusmenu_menuitem_child_append (priv->root_menuitem, mute_item); + dbusmenu_menuitem_child_append (priv->root_menuitem, slider_item); // Separator DbusmenuMenuitem* separator = dbusmenu_menuitem_new(); @@ -239,21 +229,12 @@ sound_service_dbus_update_sound_state (SoundServiceDbus* self, SoundState new_state) { SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); - SoundState update = new_state; - // Ensure that after it has become available update the state with the current volume level - if (new_state == AVAILABLE && - mute_menu_item_is_muted (priv->mute_menuitem) == FALSE){ - update = sound_service_dbus_get_state_from_volume (self); - } - if (update != BLOCKED){ - priv->current_sound_state = update; - } - GVariant* v_output = g_variant_new("(i)", (int)update); + GVariant* v_output = g_variant_new("(i)", (int)new_state); GError * error = NULL; - g_debug ("emitting signal with value %i", (int)update); + g_debug ("emitting state signal with value %i", (int)new_state); g_dbus_connection_emit_signal( priv->connection, NULL, INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, @@ -286,7 +267,7 @@ bus_method_call (GDBusConnection * connection, SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); if (g_strcmp0(method, "GetSoundState") == 0) { - g_debug("Get state - %i", active_sink_get_state (priv->active_sink); + g_debug("Get state - %i", active_sink_get_state (priv->active_sink)); retval = g_variant_new ( "(i)", active_sink_get_state (priv->active_sink)); } else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h index fab3549..cdc4608 100644 --- a/src/sound-service-dbus.h +++ b/src/sound-service-dbus.h @@ -55,12 +55,10 @@ GType sound_service_dbus_get_type (void) G_GNUC_CONST; DbusmenuMenuitem* sound_service_dbus_create_root_item (SoundServiceDbus* self); void sound_service_dbus_update_sound_state (SoundServiceDbus* self, SoundState new_state); -void sound_service_dbus_update_sink_mute(SoundServiceDbus* self, gboolean sink_mute); -void sound_service_dbus_update_volume(SoundServiceDbus* self, gdouble volume); -void sound_service_dbus_update_pa_state ( SoundServiceDbus* root, - gboolean availability, - gboolean mute_update, - gdouble volume ); +void sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, + DbusmenuMenuitem* mute_item, + DbusmenuMenuitem* slider_item); + G_END_DECLS -- cgit v1.2.3 From 39430b4d1797d16b2152fddb864a38c26f8fb97f Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 17:31:16 +0000 Subject: putting in back together --- src/active-sink.c | 7 ++++++- src/mute-menu-item.c | 2 +- src/pulseaudio-mgr.c | 6 ++++-- src/slider-menu-item.c | 20 +++++++++++++------- src/sound-service-dbus.c | 1 + src/sound-service.c | 8 ++++---- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index b84e03f..1aa6c67 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -117,6 +117,7 @@ active_sink_populate (ActiveSink* sink, pa_volume_t vol = pa_cvolume_max (&update->volume); gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; active_sink_update_volume (sink, volume_percent); + g_debug ("Active sink has been populated - volume %f", volume_percent); } gboolean @@ -145,8 +146,11 @@ active_sink_update_volume (ActiveSink* self, gdouble percent) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); slider_menu_item_update (priv->volume_slider_menuitem, percent); + + priv->current_sound_state = active_sink_get_state_from_volume (self); + sound_service_dbus_update_sound_state (priv->service, - active_sink_get_state_from_volume (self)); + priv->current_sound_state); } void @@ -159,6 +163,7 @@ active_sink_update_mute (ActiveSink* self, gboolean muted) if (muted == TRUE){ state = MUTED; } + priv->current_sound_state = state; sound_service_dbus_update_sound_state (priv->service, state); } diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c index f7f3824..fdd4391 100644 --- a/src/mute-menu-item.c +++ b/src/mute-menu-item.c @@ -93,7 +93,7 @@ mute_menu_item_set_global_mute_from_ui (gpointer user_data) gboolean new_value = !current_value; // pa manager api - to be refactored - toggle_global_mute (new_value); + //toggle_global_mute (new_value); } void diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 9fd449d..eaff2b7 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -64,7 +64,7 @@ static void pm_update_active_sink (pa_context *c, //static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink); static gboolean reconnect_to_pulse (gpointer user_data); -static pa_cvolume construct_mono_volume(const pa_cvolume* vol); +//static pa_cvolume construct_mono_volume(const pa_cvolume* vol); static gint connection_attempts = 0; @@ -72,7 +72,9 @@ static gint reconnect_idle_id = 0; static pa_context *pulse_context = NULL; static pa_glib_mainloop *pa_main_loop = NULL; -// Entry Point +/** + Entry Point + **/ void pm_establish_pulse_connection (ActiveSink* active_sink) { diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index a20bb00..3554b0d 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -60,6 +60,14 @@ static void slider_menu_item_class_init (SliderMenuItemClass *klass) static void slider_menu_item_init (SliderMenuItem *self) { g_debug("Building new Slider Menu Item"); + dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_VOLUME_MENUITEM_TYPE ); + + /*dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(self), + DBUSMENU_MENUITEM_PROP_VISIBLE, + TRUE);*/ + return; } @@ -89,12 +97,13 @@ handle_event (DbusmenuMenuitem * mi, gboolean volume_input = g_variant_get_double(input); if (value != NULL){ - set_sink_volume(volume_input); - // TODO -when the ACTIVESINK instance exists this will be handled nicely + // TODO - when the ACTIVESINK instance exists this will be handled nicely // PA MANAGER will be refactored first. - if (default_sink_is_muted () == TRUE){ + + //set_sink_volume(volume_input); + /*if (default_sink_is_muted () == TRUE){ toggle_global_mute (FALSE); - } + }*/ } } @@ -121,9 +130,6 @@ SliderMenuItem* slider_menu_item_new (gboolean sinks_available, gdouble start_volume) { SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL); - dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_VOLUME_MENUITEM_TYPE ); slider_menu_item_update (self, start_volume); slider_menu_item_enable (self, sinks_available); diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 1617a47..f9428cc 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -164,6 +164,7 @@ sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, // Mute button dbusmenu_menuitem_child_append (priv->root_menuitem, mute_item); + g_debug ("just about to add the slider %i", DBUSMENU_IS_MENUITEM(slider_item)); dbusmenu_menuitem_child_append (priv->root_menuitem, slider_item); // Separator diff --git a/src/sound-service.c b/src/sound-service.c index 2cb33d3..d80127e 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - close_pulse_activites(); - g_main_loop_quit(mainloop); + //close_pulse_activites(); + //g_main_loop_quit(mainloop); } return; } @@ -67,8 +67,8 @@ main (int argc, char ** argv) SoundServiceDbus* sound_service = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL); DbusmenuMenuitem* root_menuitem = sound_service_dbus_create_root_item(sound_service); - MusicPlayerBridge* server = music_player_bridge_new(); - music_player_bridge_set_root_menu_item(server, root_menuitem); + //MusicPlayerBridge* server = music_player_bridge_new(); + //music_player_bridge_set_root_menu_item(server, root_menuitem); // Run the loop mainloop = g_main_loop_new(NULL, FALSE); -- cgit v1.2.3 From 6bfc46de9234f0ef39d90b934fb406eebec4c59c Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 18:25:54 +0000 Subject: tidy ups --- src/active-sink.c | 43 +++++++++++++++++++++++++++---------------- src/active-sink.h | 16 +++++----------- src/pulseaudio-mgr.c | 37 ++++++++----------------------------- src/slider-menu-item.c | 9 +-------- src/sound-service-dbus.c | 5 ----- 5 files changed, 41 insertions(+), 69 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 1aa6c67..37cdf51 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -35,8 +35,8 @@ struct _ActiveSinkPrivate gint index; gchar* name; pa_cvolume volume; - pa_channel_map channel_map; - pa_volume_t base_volume; + pa_channel_map channel_map; + pa_volume_t base_volume; }; #define ACTIVE_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACTIVE_SINK_TYPE, ActiveSinkPrivate)) @@ -82,15 +82,7 @@ active_sink_init(ActiveSink *self) static void active_sink_dispose (GObject *object) -{ - ActiveSink * self = ACTIVE_SINK(object); - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - - /*if (priv->details != NULL) { - g_free (priv->details->name); - g_free (priv->details); - }*/ - +{ G_OBJECT_CLASS (active_sink_parent_class)->dispose (object); } @@ -127,11 +119,18 @@ active_sink_is_populated (ActiveSink* sink) return (priv->index != -1); } -gboolean -active_sink_is_muted (ActiveSink* self) +void +active_sink_determine_blocking_state (ActiveSink* self) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return mute_menu_item_is_muted (priv->mute_menuitem); + if (mute_menu_item_is_muted (priv->mute_menuitem)){ + /** + We don't want to set the current state to blocking + as this is a fire and forget event. + */ + sound_service_dbus_update_sound_state (priv->service, + BLOCKED); + } } gint @@ -153,6 +152,18 @@ active_sink_update_volume (ActiveSink* self, gdouble percent) priv->current_sound_state); } +void +active_sink_deactivate (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + priv->current_sound_state = UNAVAILABLE; + sound_service_dbus_update_sound_state (priv->service, + priv->current_sound_state); + priv->index = -1; + g_free(priv->name); + priv->name = NULL; +} + void active_sink_update_mute (ActiveSink* self, gboolean muted) { @@ -211,8 +222,8 @@ active_sink_construct_mono_volume (const pa_cvolume* vol) return new_volume; } - -ActiveSink* active_sink_new (SoundServiceDbus* service) +ActiveSink* +active_sink_new (SoundServiceDbus* service) { ActiveSink* sink = g_object_new (ACTIVE_SINK_TYPE, NULL); ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); diff --git a/src/active-sink.h b/src/active-sink.h index 3b21d94..5fdcba9 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -48,24 +48,18 @@ struct _ActiveSinkClass { GObjectClass parent_class; }; -/*typedef struct { - gchar* name; - gint index; - pa_cvolume volume; - pa_channel_map channel_map; - gboolean mute; - pa_volume_t base_volume; -} sink_details; -*/ - GType active_sink_get_type (void) G_GNUC_CONST; void active_sink_populate (ActiveSink* sink, const pa_sink_info* update); + gboolean active_sink_is_populated (ActiveSink* sink); -gboolean active_sink_is_muted (ActiveSink* self); +void active_sink_determine_blocking_state (ActiveSink* self); + gint active_sink_get_index (ActiveSink* self); SoundState active_sink_get_state (ActiveSink* self); +void active_sink_deactivate (ActiveSink* self); + void active_sink_update_volume (ActiveSink* self, gdouble vol_percent); void active_sink_update_mute (ActiveSink* self, gboolean muted); diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index eaff2b7..cb786de 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -62,10 +62,7 @@ static void pm_update_active_sink (pa_context *c, void *userdata); -//static void pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink); static gboolean reconnect_to_pulse (gpointer user_data); -//static pa_cvolume construct_mono_volume(const pa_cvolume* vol); - static gint connection_attempts = 0; static gint reconnect_idle_id = 0; @@ -87,9 +84,7 @@ pm_establish_pulse_connection (ActiveSink* active_sink) pa_context_set_state_callback (pulse_context, pm_context_state_callback, (gpointer)active_sink); - - //TODO update active sink before init with state at unavailable - + pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, (gpointer)active_sink); } @@ -144,20 +139,6 @@ reconnect_to_pulse (gpointer user_data) } } -/*static void -pm_populate_active_sink (const pa_sink_info *info, ActiveSink* sink) -{ - details->index = info->index; - details->name = g_strdup (info->name); - details->mute = !!info->mute; - details->volume = construct_mono_volume (&info->volume); - details->base_volume = info->base_volume; - details->channel_map = info->channel_map; - active_sink_update_details (sink, details); - g_debug ("active sink populated with sink %s", details->name); - -}*/ - /**********************************************************************************************************************/ // Pulse-Audio asychronous call-backs @@ -182,7 +163,8 @@ pm_subscribed_events_callback (pa_context *c, return; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - // TODO: Fire of an unavailable state signal and try to find another sink + active_sink_deactivate (ACTIVE_SINK (userdata)); + } else{ pa_operation_unref (pa_context_get_sink_info_by_index (c, @@ -228,7 +210,7 @@ pm_context_state_callback (pa_context *c, void *userdata) break; case PA_CONTEXT_FAILED: g_warning("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); - // TODO: update state to unvailable on active sink + active_sink_deactivate (ACTIVE_SINK (userdata)); if (reconnect_idle_id == 0){ reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY, reconnect_to_pulse, @@ -276,7 +258,7 @@ pm_server_info_callback (pa_context *c, if (info == NULL) { g_warning("No PA server - get the hell out of here"); - //TODO update active sink with state info + active_sink_deactivate (ACTIVE_SINK (userdata)); return; } if (info->default_sink_name != NULL) { @@ -321,7 +303,6 @@ pm_sink_info_callback (pa_context *c, if (active_sink_is_populated (a_sink) == FALSE && g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ active_sink_populate (a_sink, sink); - //populate_active_sink (sink, a_sink); } } } @@ -333,7 +314,6 @@ pm_default_sink_info_callback (pa_context *c, void *userdata) { if (eol > 0) { - // TODO what happens here - high and dry! return; } else { @@ -344,7 +324,6 @@ pm_default_sink_info_callback (pa_context *c, g_debug ("server has handed us a default sink"); active_sink_populate (ACTIVE_SINK (userdata), info); - //pm_populate_active_sink (info, ACTIVE_SINK (userdata)); } } @@ -369,9 +348,8 @@ pm_sink_input_info_callback (pa_context *c, } ActiveSink* a_sink = ACTIVE_SINK (userdata); - if (active_sink_get_index (a_sink) == info->sink && - active_sink_is_muted (a_sink) == TRUE) { - // TODO fire off blocking signal + if (active_sink_get_index (a_sink) == info->sink){ + active_sink_determine_blocking_state (a_sink); } } } @@ -393,6 +371,7 @@ pm_update_active_sink (pa_context *c, pa_volume_t vol = pa_cvolume_max (&info->volume); gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; active_sink_update_volume (ACTIVE_SINK(userdata), volume_percent); + active_sink_update_mute (ACTIVE_SINK(userdata), info->mute); } } diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index 3554b0d..6fd4dbc 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -62,12 +62,7 @@ static void slider_menu_item_init (SliderMenuItem *self) g_debug("Building new Slider Menu Item"); dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_VOLUME_MENUITEM_TYPE ); - - /*dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_VISIBLE, - TRUE);*/ - + DBUSMENU_VOLUME_MENUITEM_TYPE ); return; } @@ -110,8 +105,6 @@ handle_event (DbusmenuMenuitem * mi, void slider_menu_item_update (SliderMenuItem* item, gdouble update) { - // TODO - // Check if that variant below will leak !!! GVariant* new_volume = g_variant_new_double(update); dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(item), DBUSMENU_VOLUME_MENUITEM_LEVEL, diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index f9428cc..58367f4 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -151,7 +151,6 @@ sound_service_dbus_create_root_item (SoundServiceDbus* self) dbusmenu_server_set_root (server, priv->root_menuitem); g_object_unref (priv->root_menuitem); priv->active_sink = active_sink_new (self); - //establish_pulse_activities (self); return priv->root_menuitem; } @@ -222,9 +221,6 @@ sound_service_dbus_finalize (GObject *object) // EMIT STATE SIGNAL - -// TODO: this will be a bit messy until the pa_manager is sorted. -// And we figure out all of the edge cases. void sound_service_dbus_update_sound_state (SoundServiceDbus* self, SoundState new_state) @@ -251,7 +247,6 @@ sound_service_dbus_update_sound_state (SoundServiceDbus* self, } //HANDLE DBUS METHOD CALLS -// TODO we will need to implement the black_list method. static void bus_method_call (GDBusConnection * connection, const gchar * sender, -- cgit v1.2.3 From 381d827c0da72499f6092c7bb8cb6238ba0d2746 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Fri, 4 Feb 2011 19:55:20 +0000 Subject: hook back volume and mute setting and test --- src/active-sink.c | 56 +++++++++++++++++++++++++++++++++----------------- src/active-sink.h | 6 ++++-- src/pulseaudio-mgr.c | 6 ++---- src/pulseaudio-mgr.h | 1 + src/slider-menu-item.c | 32 +++++++++++++++++++---------- src/slider-menu-item.h | 4 ++-- 6 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 37cdf51..16ab784 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -77,7 +77,7 @@ active_sink_init(ActiveSink *self) // Init our menu items. priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); - priv->volume_slider_menuitem = g_object_new (SLIDER_MENU_ITEM_TYPE, NULL); + priv->volume_slider_menuitem = slider_menu_item_new (self); } static void @@ -101,14 +101,14 @@ active_sink_populate (ActiveSink* sink, priv->name = g_strdup (update->name); priv->index = update->index; // Why the double negative !? - active_sink_update_mute (sink, !!update->mute); + active_sink_mute_update (sink, !!update->mute); priv->volume = active_sink_construct_mono_volume (&update->volume); priv->base_volume = update->base_volume; priv->channel_map = update->channel_map; pa_volume_t vol = pa_cvolume_max (&update->volume); gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; - active_sink_update_volume (sink, volume_percent); + active_sink_volume_update (sink, volume_percent); g_debug ("Active sink has been populated - volume %f", volume_percent); } @@ -141,7 +141,27 @@ active_sink_get_index (ActiveSink* self) } void -active_sink_update_volume (ActiveSink* self, gdouble percent) +active_sink_deactivate (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + priv->current_sound_state = UNAVAILABLE; + sound_service_dbus_update_sound_state (priv->service, + priv->current_sound_state); + priv->index = -1; + g_free(priv->name); + priv->name = NULL; +} + +SoundState +active_sink_get_state (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return priv->current_sound_state; +} + +// To the UI +void +active_sink_volume_update (ActiveSink* self, gdouble percent) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); slider_menu_item_update (priv->volume_slider_menuitem, percent); @@ -152,20 +172,25 @@ active_sink_update_volume (ActiveSink* self, gdouble percent) priv->current_sound_state); } +// From the UI void -active_sink_deactivate (ActiveSink* self) +active_sink_update_volume (ActiveSink* self, gdouble percent) { + 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); + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - priv->current_sound_state = UNAVAILABLE; - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); - priv->index = -1; - g_free(priv->name); - priv->name = NULL; + + pa_cvolume_set(&priv->volume, priv->channel_map.channels, new_volume_value); + } + void -active_sink_update_mute (ActiveSink* self, gboolean muted) +active_sink_mute_update (ActiveSink* self, gboolean muted) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); mute_menu_item_update (priv->mute_menuitem, muted); @@ -178,13 +203,6 @@ active_sink_update_mute (ActiveSink* self, gboolean muted) sound_service_dbus_update_sound_state (priv->service, state); } -SoundState -active_sink_get_state (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return priv->current_sound_state; -} - static SoundState active_sink_get_state_from_volume (ActiveSink* self) diff --git a/src/active-sink.h b/src/active-sink.h index 5fdcba9..40dd84e 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -60,8 +60,10 @@ SoundState active_sink_get_state (ActiveSink* self); void active_sink_deactivate (ActiveSink* self); -void active_sink_update_volume (ActiveSink* self, gdouble vol_percent); -void active_sink_update_mute (ActiveSink* self, gboolean muted); +void active_sink_volume_update (ActiveSink* self, gdouble vol_percent); +void active_sink_update_volume (ActiveSink* self, gdouble percent); + +void active_sink_mute_update (ActiveSink* self, gboolean muted); ActiveSink* active_sink_new (SoundServiceDbus* service); diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index cb786de..c8439e8 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -55,13 +55,11 @@ static void pm_sink_input_info_callback (pa_context *c, const pa_sink_input_info *info, int eol, void *userdata); - static void pm_update_active_sink (pa_context *c, const pa_sink_info *info, int eol, void *userdata); - static gboolean reconnect_to_pulse (gpointer user_data); static gint connection_attempts = 0; @@ -370,8 +368,8 @@ pm_update_active_sink (pa_context *c, } pa_volume_t vol = pa_cvolume_max (&info->volume); gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; - active_sink_update_volume (ACTIVE_SINK(userdata), volume_percent); - active_sink_update_mute (ACTIVE_SINK(userdata), info->mute); + active_sink_volume_update (ACTIVE_SINK(userdata), volume_percent); + active_sink_mute_update (ACTIVE_SINK(userdata), info->mute); } } diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index af4f29c..524b323 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -21,6 +21,7 @@ with this program. If not, see . void pm_establish_pulse_connection (ActiveSink* active_sink); void close_pulse_activites(); +//void pm_update_volume (gint sink_index); diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index 6fd4dbc..31d4774 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -25,10 +25,10 @@ with this program. If not, see . #include "pulse-manager.h" #include "common-defs.h" - typedef struct _SliderMenuItemPrivate SliderMenuItemPrivate; struct _SliderMenuItemPrivate { + ActiveSink* a_sink; }; #define SLIDER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SLIDER_MENU_ITEM_TYPE, SliderMenuItemPrivate)) @@ -43,7 +43,8 @@ static void handle_event (DbusmenuMenuitem * mi, const gchar * name, G_DEFINE_TYPE (SliderMenuItem, slider_menu_item, DBUSMENU_TYPE_MENUITEM); -static void slider_menu_item_class_init (SliderMenuItemClass *klass) +static void +slider_menu_item_class_init (SliderMenuItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -57,7 +58,8 @@ static void slider_menu_item_class_init (SliderMenuItemClass *klass) return; } -static void slider_menu_item_init (SliderMenuItem *self) +static void +slider_menu_item_init (SliderMenuItem *self) { g_debug("Building new Slider Menu Item"); dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), @@ -66,7 +68,8 @@ static void slider_menu_item_init (SliderMenuItem *self) return; } -static void slider_menu_item_dispose (GObject *object) +static void +slider_menu_item_dispose (GObject *object) { G_OBJECT_CLASS (slider_menu_item_parent_class)->dispose (object); return; @@ -92,6 +95,12 @@ handle_event (DbusmenuMenuitem * mi, gboolean volume_input = g_variant_get_double(input); if (value != NULL){ + if (IS_SLIDER_MENU_ITEM (mi)) { + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (SLIDER_MENU_ITEM (mi)); + active_sink_update_volume (priv->a_sink, volume_input); + } + + //active_sink_update_volume ( // TODO - when the ACTIVESINK instance exists this will be handled nicely // PA MANAGER will be refactored first. @@ -102,7 +111,8 @@ handle_event (DbusmenuMenuitem * mi, } } -void slider_menu_item_update (SliderMenuItem* item, +void +slider_menu_item_update (SliderMenuItem* item, gdouble update) { GVariant* new_volume = g_variant_new_double(update); @@ -111,7 +121,8 @@ void slider_menu_item_update (SliderMenuItem* item, new_volume); } -void slider_menu_item_enable (SliderMenuItem* item, +void +slider_menu_item_enable (SliderMenuItem* item, gboolean active) { dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(item), @@ -119,12 +130,11 @@ void slider_menu_item_enable (SliderMenuItem* item, active ); } -SliderMenuItem* slider_menu_item_new (gboolean sinks_available, - gdouble start_volume) +SliderMenuItem* +slider_menu_item_new (ActiveSink* sink) { SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL); - slider_menu_item_update (self, start_volume); - slider_menu_item_enable (self, sinks_available); - + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + priv->a_sink = sink; return self; } \ No newline at end of file diff --git a/src/slider-menu-item.h b/src/slider-menu-item.h index 51336ae..f094c71 100644 --- a/src/slider-menu-item.h +++ b/src/slider-menu-item.h @@ -23,6 +23,7 @@ with this program. If not, see . #include #include +#include "active-sink.h" G_BEGIN_DECLS @@ -49,8 +50,7 @@ GType slider_menu_item_get_type (void); void slider_menu_item_update(SliderMenuItem* item, gdouble update); void slider_menu_item_enable(SliderMenuItem* item, gboolean active); -SliderMenuItem* slider_menu_item_new (gboolean sinks_available, - gdouble current_vol); +SliderMenuItem* slider_menu_item_new (ActiveSink* sink); G_END_DECLS -- cgit v1.2.3 From df4cae2aab47e33f20528b9d35a3c942c4a97eac Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 11:19:17 +0000 Subject: fully functional once again --- src/active-sink.c | 118 +++++++++++++++++++++++++++++-------------------- src/active-sink.h | 6 +-- src/mute-menu-item.c | 8 ++-- src/pulseaudio-mgr.c | 53 +++++++++++++++++----- src/pulseaudio-mgr.h | 3 +- src/slider-menu-item.c | 8 +--- 6 files changed, 121 insertions(+), 75 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 16ab784..78eb79f 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -49,6 +49,8 @@ static void active_sink_finalize (GObject *object); static SoundState active_sink_get_state_from_volume (ActiveSink* self); static pa_cvolume active_sink_construct_mono_volume (const pa_cvolume* vol); +static void active_sink_volume_update (ActiveSink* self, gdouble percent); +static void active_sink_mute_update (ActiveSink* self, gboolean muted); G_DEFINE_TYPE (ActiveSink, active_sink, G_TYPE_OBJECT); @@ -65,7 +67,7 @@ active_sink_class_init (ActiveSinkClass *klass) } static void -active_sink_init(ActiveSink *self) +active_sink_init (ActiveSink *self) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); priv->mute_menuitem = NULL; @@ -108,66 +110,37 @@ active_sink_populate (ActiveSink* sink, pa_volume_t vol = pa_cvolume_max (&update->volume); gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + active_sink_volume_update (sink, volume_percent); - g_debug ("Active sink has been populated - volume %f", volume_percent); -} + active_sink_mute_update (sink, !!update->mute); -gboolean -active_sink_is_populated (ActiveSink* sink) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); - return (priv->index != -1); + g_debug ("Active sink has been populated - volume %f", volume_percent); } void -active_sink_determine_blocking_state (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - if (mute_menu_item_is_muted (priv->mute_menuitem)){ - /** - We don't want to set the current state to blocking - as this is a fire and forget event. - */ - sound_service_dbus_update_sound_state (priv->service, - BLOCKED); - } -} - -gint -active_sink_get_index (ActiveSink* self) +active_sink_update (ActiveSink* sink, + const pa_sink_info* update) { - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return priv->index; -} + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); + active_sink_mute_update (sink, update->mute); + priv->volume = active_sink_construct_mono_volume (&update->volume); + priv->base_volume = update->base_volume; + priv->channel_map = update->channel_map; -void -active_sink_deactivate (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - priv->current_sound_state = UNAVAILABLE; - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); - priv->index = -1; - g_free(priv->name); - priv->name = NULL; -} + pa_volume_t vol = pa_cvolume_max (&update->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; -SoundState -active_sink_get_state (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return priv->current_sound_state; + active_sink_volume_update (sink, volume_percent); + active_sink_mute_update (sink, update->mute); } // To the UI -void +static void active_sink_volume_update (ActiveSink* self, gdouble percent) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); slider_menu_item_update (priv->volume_slider_menuitem, percent); - priv->current_sound_state = active_sink_get_state_from_volume (self); - sound_service_dbus_update_sound_state (priv->service, priv->current_sound_state); } @@ -185,11 +158,11 @@ active_sink_update_volume (ActiveSink* self, gdouble percent) ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); pa_cvolume_set(&priv->volume, priv->channel_map.channels, new_volume_value); - + pm_update_volume (priv->index, new_volume); } -void +static void active_sink_mute_update (ActiveSink* self, gboolean muted) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); @@ -240,7 +213,54 @@ active_sink_construct_mono_volume (const pa_cvolume* vol) return new_volume; } -ActiveSink* +void +active_sink_determine_blocking_state (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + if (mute_menu_item_is_muted (priv->mute_menuitem)){ + /** + We don't want to set the current state to blocking + as this is a fire and forget event. + */ + sound_service_dbus_update_sound_state (priv->service, + BLOCKED); + } +} + +gint +active_sink_get_index (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return priv->index; +} + +gboolean +active_sink_is_populated (ActiveSink* sink) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); + return (priv->index != -1); +} + +void +active_sink_deactivate (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + priv->current_sound_state = UNAVAILABLE; + sound_service_dbus_update_sound_state (priv->service, + priv->current_sound_state); + priv->index = -1; + g_free(priv->name); + priv->name = NULL; +} + +SoundState +active_sink_get_state (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + return priv->current_sound_state; +} + +ActiveSink* active_sink_new (SoundServiceDbus* service) { ActiveSink* sink = g_object_new (ACTIVE_SINK_TYPE, NULL); @@ -250,5 +270,5 @@ active_sink_new (SoundServiceDbus* service) mute_menu_item_get_button (priv->mute_menuitem), DBUSMENU_MENUITEM (priv->volume_slider_menuitem)); pm_establish_pulse_connection (sink); - return sink; + return sink; } diff --git a/src/active-sink.h b/src/active-sink.h index 40dd84e..3d57829 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -51,6 +51,7 @@ struct _ActiveSinkClass { GType active_sink_get_type (void) G_GNUC_CONST; void active_sink_populate (ActiveSink* sink, const pa_sink_info* update); +void active_sink_update (ActiveSink* sink, const pa_sink_info* update); gboolean active_sink_is_populated (ActiveSink* sink); void active_sink_determine_blocking_state (ActiveSink* self); @@ -60,10 +61,9 @@ SoundState active_sink_get_state (ActiveSink* self); void active_sink_deactivate (ActiveSink* self); -void active_sink_volume_update (ActiveSink* self, gdouble vol_percent); -void active_sink_update_volume (ActiveSink* self, gdouble percent); +//void active_sink_volume_update (ActiveSink* self, gdouble vol_percent); -void active_sink_mute_update (ActiveSink* self, gboolean muted); +void active_sink_update_volume (ActiveSink* self, gdouble percent); ActiveSink* active_sink_new (SoundServiceDbus* service); diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c index fdd4391..df98d5d 100644 --- a/src/mute-menu-item.c +++ b/src/mute-menu-item.c @@ -1,4 +1,4 @@ -/* +#/* Copyright 2011 Canonical Ltd. Authors: @@ -24,7 +24,7 @@ with this program. If not, see . #include "common-defs.h" #include "mute-menu-item.h" -#include "pulse-manager.h" +#include "pulseaudio-mgr.h" typedef struct _MuteMenuItemPrivate MuteMenuItemPrivate; @@ -90,10 +90,8 @@ mute_menu_item_set_global_mute_from_ui (gpointer user_data) DbusmenuMenuitem* button = DBUSMENU_MENUITEM (user_data); gboolean current_value = dbusmenu_menuitem_property_get_bool (button, DBUSMENU_MUTE_MENUITEM_VALUE); - gboolean new_value = !current_value; - // pa manager api - to be refactored - //toggle_global_mute (new_value); + pm_update_mute (new_value); } void diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index c8439e8..736b26d 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -59,6 +59,10 @@ static void pm_update_active_sink (pa_context *c, const pa_sink_info *info, int eol, void *userdata); +static void pm_toggle_mute_for_every_sink_callback (pa_context *c, + const pa_sink_info *sink, + int eol, + void* userdata); static gboolean reconnect_to_pulse (gpointer user_data); @@ -137,6 +141,23 @@ reconnect_to_pulse (gpointer user_data) } } +void +pm_update_volume (gint sink_index, pa_cvolume new_volume) +{ + pa_operation_unref (pa_context_set_sink_volume_by_index (pulse_context, + sink_index, + &new_volume, + NULL, + NULL) ); +} + +void +pm_update_mute (gboolean update) +{ + pa_operation_unref (pa_context_get_sink_info_list (pulse_context, + pm_toggle_mute_for_every_sink_callback, + GINT_TO_POINTER (update))); +} /**********************************************************************************************************************/ // Pulse-Audio asychronous call-backs @@ -212,17 +233,16 @@ pm_context_state_callback (pa_context *c, void *userdata) if (reconnect_idle_id == 0){ reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY, reconnect_to_pulse, - userdata); - } + userdata); + } break; case PA_CONTEXT_TERMINATED: break; case PA_CONTEXT_READY: - connection_attempts = 0; g_debug("PA_CONTEXT_READY"); pa_operation *o; - + pa_context_set_subscribe_callback(c, pm_subscribed_events_callback, userdata); if (!(o = pa_context_subscribe (c, (pa_subscription_mask_t) @@ -318,8 +338,7 @@ pm_default_sink_info_callback (pa_context *c, if (IS_ACTIVE_SINK (userdata) == FALSE){ g_warning ("Default sink info callback - our user data is not what we think it should be"); return; - } - + } g_debug ("server has handed us a default sink"); active_sink_populate (ACTIVE_SINK (userdata), info); } @@ -366,11 +385,25 @@ pm_update_active_sink (pa_context *c, g_warning ("update_active_sink - our user data is not what we think it should be"); return; } - pa_volume_t vol = pa_cvolume_max (&info->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; - active_sink_volume_update (ACTIVE_SINK(userdata), volume_percent); - active_sink_mute_update (ACTIVE_SINK(userdata), info->mute); + active_sink_update (ACTIVE_SINK(userdata), info); } } +static void +pm_toggle_mute_for_every_sink_callback (pa_context *c, + const pa_sink_info *sink, + int eol, + void* userdata) +{ + if (eol > 0) { + return; + } + else { + pa_operation_unref (pa_context_set_sink_mute_by_index (c, + sink->index, + GPOINTER_TO_INT(userdata), + NULL, + NULL)); + } +} diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index 524b323..c0ab9c0 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -21,7 +21,8 @@ with this program. If not, see . void pm_establish_pulse_connection (ActiveSink* active_sink); void close_pulse_activites(); -//void pm_update_volume (gint sink_index); +void pm_update_volume (gint sink_index, pa_cvolume new_volume); +void pm_update_mute (gboolean update); diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index 31d4774..aaa6787 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -98,13 +98,7 @@ handle_event (DbusmenuMenuitem * mi, if (IS_SLIDER_MENU_ITEM (mi)) { SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (SLIDER_MENU_ITEM (mi)); active_sink_update_volume (priv->a_sink, volume_input); - } - - //active_sink_update_volume ( - // TODO - when the ACTIVESINK instance exists this will be handled nicely - // PA MANAGER will be refactored first. - - //set_sink_volume(volume_input); + } /*if (default_sink_is_muted () == TRUE){ toggle_global_mute (FALSE); }*/ -- cgit v1.2.3 From 04aeb610a1b29aa3c3a43385434b011d93a1bf03 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 11:45:06 +0000 Subject: switch back on the music player section --- src/active-sink.c | 9 +++++++++ src/active-sink.h | 4 ++-- src/slider-menu-item.c | 4 +--- src/sound-service.c | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 78eb79f..62aa8d2 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -176,6 +176,15 @@ active_sink_mute_update (ActiveSink* self, gboolean muted) sound_service_dbus_update_sound_state (priv->service, state); } +void +active_sink_ensure_sink_is_unmuted (ActiveSink* self) +{ + ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); + if (mute_menu_item_is_muted (priv->mute_menuitem)){ + pm_update_mute (FALSE); + } +} + static SoundState active_sink_get_state_from_volume (ActiveSink* self) diff --git a/src/active-sink.h b/src/active-sink.h index 3d57829..ab05ebc 100644 --- a/src/active-sink.h +++ b/src/active-sink.h @@ -61,9 +61,9 @@ SoundState active_sink_get_state (ActiveSink* self); void active_sink_deactivate (ActiveSink* self); -//void active_sink_volume_update (ActiveSink* self, gdouble vol_percent); - +void active_sink_update_mute (ActiveSink* self, gboolean mute_update); void active_sink_update_volume (ActiveSink* self, gdouble percent); +void active_sink_ensure_sink_is_unmuted (ActiveSink* self); ActiveSink* active_sink_new (SoundServiceDbus* service); diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index aaa6787..687e43b 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -98,10 +98,8 @@ handle_event (DbusmenuMenuitem * mi, if (IS_SLIDER_MENU_ITEM (mi)) { SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (SLIDER_MENU_ITEM (mi)); active_sink_update_volume (priv->a_sink, volume_input); + active_sink_ensure_sink_is_unmuted (priv->a_sink); } - /*if (default_sink_is_muted () == TRUE){ - toggle_global_mute (FALSE); - }*/ } } diff --git a/src/sound-service.c b/src/sound-service.c index d80127e..c1bb9b4 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -67,8 +67,8 @@ main (int argc, char ** argv) SoundServiceDbus* sound_service = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL); DbusmenuMenuitem* root_menuitem = sound_service_dbus_create_root_item(sound_service); - //MusicPlayerBridge* server = music_player_bridge_new(); - //music_player_bridge_set_root_menu_item(server, root_menuitem); + MusicPlayerBridge* server = music_player_bridge_new(); + music_player_bridge_set_root_menu_item(server, root_menuitem); // Run the loop mainloop = g_main_loop_new(NULL, FALSE); -- cgit v1.2.3 From 373460533ffcd4217b96ed1e95672f7e73141824 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 12:00:50 +0000 Subject: filter the number of signals sent, only send a signal when the state changes --- src/active-sink.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 62aa8d2..762511d 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -140,9 +140,12 @@ active_sink_volume_update (ActiveSink* self, gdouble percent) { ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); slider_menu_item_update (priv->volume_slider_menuitem, percent); - priv->current_sound_state = active_sink_get_state_from_volume (self); - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); + SoundState state = active_sink_get_state_from_volume (self); + if (priv->current_sound_state != state){ + priv->current_sound_state = state; + sound_service_dbus_update_sound_state (priv->service, + priv->current_sound_state); + } } // From the UI @@ -172,8 +175,10 @@ active_sink_mute_update (ActiveSink* self, gboolean muted) if (muted == TRUE){ state = MUTED; } - priv->current_sound_state = state; - sound_service_dbus_update_sound_state (priv->service, state); + if (priv->current_sound_state != state){ + priv->current_sound_state = state; + sound_service_dbus_update_sound_state (priv->service, state); + } } void -- cgit v1.2.3 From 89ea8fc69cd0b3253d6b5f4ba2d205b41e431a5d Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 12:53:45 +0000 Subject: tidy up --- src/active-sink.c | 11 ++++++++--- src/mute-menu-item.c | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/active-sink.c b/src/active-sink.c index 762511d..b7954be 100644 --- a/src/active-sink.c +++ b/src/active-sink.c @@ -80,6 +80,8 @@ active_sink_init (ActiveSink *self) // Init our menu items. priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); priv->volume_slider_menuitem = slider_menu_item_new (self); + mute_menu_item_enable (priv->mute_menuitem, FALSE); + slider_menu_item_enable (priv->volume_slider_menuitem, FALSE); } static void @@ -102,8 +104,7 @@ active_sink_populate (ActiveSink* sink, priv->name = g_strdup (update->name); priv->index = update->index; - // Why the double negative !? - active_sink_mute_update (sink, !!update->mute); + active_sink_mute_update (sink, update->mute); priv->volume = active_sink_construct_mono_volume (&update->volume); priv->base_volume = update->base_volume; priv->channel_map = update->channel_map; @@ -112,7 +113,9 @@ active_sink_populate (ActiveSink* sink, gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; active_sink_volume_update (sink, volume_percent); - active_sink_mute_update (sink, !!update->mute); + active_sink_mute_update (sink, update->mute); + mute_menu_item_enable (priv->mute_menuitem, TRUE); + slider_menu_item_enable (priv->volume_slider_menuitem, TRUE); g_debug ("Active sink has been populated - volume %f", volume_percent); } @@ -262,6 +265,8 @@ active_sink_deactivate (ActiveSink* self) priv->current_sound_state = UNAVAILABLE; sound_service_dbus_update_sound_state (priv->service, priv->current_sound_state); + mute_menu_item_enable (priv->mute_menuitem, FALSE); + slider_menu_item_enable (priv->volume_slider_menuitem, FALSE); priv->index = -1; g_free(priv->name); priv->name = NULL; diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c index df98d5d..4740ecf 100644 --- a/src/mute-menu-item.c +++ b/src/mute-menu-item.c @@ -62,6 +62,9 @@ mute_menu_item_init (MuteMenuItem *self) g_debug("Building new Mute Menu Item"); MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE(self); priv->button = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set_bool (priv->button, + DBUSMENU_MENUITEM_PROP_VISIBLE, + TRUE); g_signal_connect (G_OBJECT (priv->button), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, @@ -111,6 +114,9 @@ void mute_menu_item_enable (MuteMenuItem* item, gboolean active) { MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item); + dbusmenu_menuitem_property_set_bool (priv->button, + DBUSMENU_MENUITEM_PROP_VISIBLE, + TRUE); dbusmenu_menuitem_property_set_bool (priv->button, DBUSMENU_MENUITEM_PROP_ENABLED, -- cgit v1.2.3 From d5e7257a721e0bac80e8cdb392429896ab2aa79b Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 12:56:30 +0000 Subject: tidy up --- src/sound-service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound-service.c b/src/sound-service.c index c1bb9b4..2cb33d3 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - //close_pulse_activites(); - //g_main_loop_quit(mainloop); + close_pulse_activites(); + g_main_loop_quit(mainloop); } return; } -- cgit v1.2.3 From a87a201a7873fa28c08bdee08d710efd7a2ae731 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 13:03:24 +0000 Subject: removed the old pulsemanager --- src/pulse-manager.c | 589 ------------------------------------------------- src/pulse-manager.h | 45 ---- src/slider-menu-item.c | 1 - src/sound-service.c | 3 +- 4 files changed, 1 insertion(+), 637 deletions(-) delete mode 100644 src/pulse-manager.c delete mode 100644 src/pulse-manager.h diff --git a/src/pulse-manager.c b/src/pulse-manager.c deleted file mode 100644 index 457992b..0000000 --- a/src/pulse-manager.c +++ /dev/null @@ -1,589 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -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 -#include -#include - -#include "pulse-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; -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); -static void pulse_server_info_callback(pa_context *c, const pa_server_info *info, void *userdata); -static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, void *userdata); -static void destroy_sink_info(void *value); -static gboolean determine_sink_availability(); - -static gboolean has_volume_changed(const pa_sink_info* new_sink, sink_info* cached_sink); -static pa_cvolume construct_mono_volume(const pa_cvolume* vol); - -/** -Future Refactoring notes - - rewrite in vala. - - make sure all state is kept in the service for volume icon switching. -**/ - -/** -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), - "com.canonical.indicators.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); - sound_service_dbus_update_pa_state (dbus_service, FALSE, FALSE, 0); - pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL); -} - -/** -get_context() -Needed for testing - bah! -**/ -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 ), - "com.canonical.indicators.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. -**/ -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");*/ -} - -/** -destroy_sink_info() -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); -} - -/* -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 robust 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; -} - -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; -} - -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");*/ - - if (default_sink_is_muted(sink_index) == TRUE) { - sound_service_dbus_update_sound_state(dbus_service, BLOCKED); - } -// Why do you need to send a false for a blocked event, it times out after 5 secs anyway -//} 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; -} - -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_volume(dbus_service, get_default_sink_volume()); - } -} - -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);*/ -} - - -/* -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; - } - - 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)); -} - - -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; -} - -/**********************************************************************************************************************/ -// Pulse-Audio asychronous call-backs -/**********************************************************************************************************************/ - -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_unref(operation); - return; -} - - -static void context_success_callback(pa_context *c, int success, void *userdata) -{ - /* g_debug("Context Success Callback - result = %i", success);*/ -} - -/** -On Service startup this callback will be called multiple times resulting our sinks_hash container to be filled with the -available sinks. -For now this callback assumes it only used at startup. It may be necessary to use if sinks become available after startup. -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) { - sound_service_dbus_update_pa_state( dbus_service, - 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 ..."); - sound_service_dbus_update_pa_state( dbus_service, - 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) { - 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 { - sound_service_dbus_update_pa_state(dbus_service, - 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; - } 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); - } -} - -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 (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_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); - 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_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_sound_state(dbus_service, AVAILABLE); - } -} - - -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; - - 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; -} - - -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"); - sound_service_dbus_update_pa_state(dbus_service, 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); -} - - -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_sound_state(dbus_service, UNAVAILABLE); - - /* 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("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); - pa_server_available = FALSE; - sound_service_dbus_update_pa_state( dbus_service, - 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_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) - (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; - } -} - diff --git a/src/pulse-manager.h b/src/pulse-manager.h deleted file mode 100644 index 5895aeb..0000000 --- a/src/pulse-manager.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __INCLUDE_PULSE_MANAGER_H__ -#define __INCLUDE_PULSE_MANAGER_H__ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -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 -#include -#include "sound-service-dbus.h" - - -typedef struct { - gchar* name; - gint index; - pa_cvolume volume; - pa_channel_map channel_map; - gboolean mute; - pa_volume_t base_volume; -} sink_info; - - -pa_context* get_context(void); -void establish_pulse_activities(SoundServiceDbus *service); -void set_sink_volume(gdouble percent); -void toggle_global_mute(gboolean mute_value); -void close_pulse_activites(); -gboolean default_sink_is_muted(); -#endif - diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index 687e43b..b89f5ca 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -22,7 +22,6 @@ with this program. If not, see . #include #include "slider-menu-item.h" -#include "pulse-manager.h" #include "common-defs.h" typedef struct _SliderMenuItemPrivate SliderMenuItemPrivate; diff --git a/src/sound-service.c b/src/sound-service.c index 2cb33d3..cfc0b7e 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -18,8 +18,7 @@ with this program. If not, see . */ #include "sound-service.h" - -#include "pulse-manager.h" +#include "pulseaudio-mgr.h" #include "sound-service-dbus.h" #include "music-player-bridge.h" -- cgit v1.2.3 From fba8f5aa4d7619b6e796ebb7cd4c96d30f5fd0ff Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Mon, 7 Feb 2011 18:08:19 +0000 Subject: tidy ups and comments --- src/mute-menu-item.c | 2 +- src/pulseaudio-mgr.c | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c index 4740ecf..8409b9f 100644 --- a/src/mute-menu-item.c +++ b/src/mute-menu-item.c @@ -1,4 +1,4 @@ -#/* +/* Copyright 2011 Canonical Ltd. Authors: diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 736b26d..1a2b3e0 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -79,15 +79,7 @@ pm_establish_pulse_connection (ActiveSink* active_sink) { 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), - "com.canonical.indicators.sound"); - g_assert (pulse_context); - - pa_context_set_state_callback (pulse_context, - pm_context_state_callback, - (gpointer)active_sink); - - pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, (gpointer)active_sink); + reconnect_to_pulse ((gpointer)active_sink); } /** @@ -104,7 +96,10 @@ void close_pulse_activites() pa_main_loop = NULL; } - +/** +reconnect_to_pulse (gpointer user_data) +Method which connects to the pulse server and is used to track reconnects. + */ static gboolean reconnect_to_pulse (gpointer user_data) { -- cgit v1.2.3 From 800023f7ab5854c19bdaf426ba86d24feea014ec Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Tue, 8 Feb 2011 18:58:10 +0000 Subject: work done around playlist changed --- src/common-defs.h | 2 ++ src/mpris2-controller.vala | 9 +++++++-- src/mpris2-interfaces.vala | 3 +++ src/playlists-menu-item.vala | 35 ++++++++++++++++++++++++++--------- src/sound-service.c | 4 ++-- vapi/common-defs.vapi | 4 ++++ 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/common-defs.h b/src/common-defs.h index 5458dc5..63d9d40 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -64,4 +64,6 @@ typedef enum { #define DBUSMENU_PLAYLISTS_MENUITEM_TITLE "x-canonical-sound-menu-player-playlists-title" #define DBUSMENU_PLAYLISTS_MENUITEM_PLAYLISTS "x-canonical-sound-menu-player-playlists-playlists" +#define DBUSMENU_PLAYLIST_MENUITEM_PATH "x-canonical-sound-menu-player-playlist-path" + #endif diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index d4cdc0c..444bdf6 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -48,6 +48,7 @@ public class Mpris2Controller : GLib.Object this.playlists = Bus.get_proxy_sync ( BusType.SESSION, this.owner.dbus_name, "/org/mpris/MediaPlayer2" ); + this.playlists.PlaylistChanged.connect (on_playlistdetails_changed); } this.properties_interface = Bus.get_proxy_sync ( BusType.SESSION, "org.freedesktop.Properties.PropertiesChanged", @@ -109,7 +110,7 @@ public class Mpris2Controller : GLib.Object title.alter_label (this.mpris2_root.Identity); } } - + private bool ensure_correct_playback_status(){ debug("TEST playback status = %s", this.player.PlaybackStatus); TransportMenuitem.state p = (TransportMenuitem.state)this.determine_play_state(this.player.PlaybackStatus); @@ -185,7 +186,6 @@ public class Mpris2Controller : GLib.Object } } - public bool connected() { return (this.player != null && this.mpris2_root != null); @@ -198,6 +198,11 @@ public class Mpris2Controller : GLib.Object } } + private void on_playlistdetails_changed (PlaylistDetails details) + { + + } + public async void fetch_playlists() { PlaylistDetails[] current_playlists = null; diff --git a/src/mpris2-interfaces.vala b/src/mpris2-interfaces.vala index 0a0909f..5506a47 100644 --- a/src/mpris2-interfaces.vala +++ b/src/mpris2-interfaces.vala @@ -72,4 +72,7 @@ public interface MprisPlaylists : Object { uint32 max_count, string order, bool reverse_order ) throws IOError; + //signals + public signal void PlaylistChanged (PlaylistDetails details); + } \ No newline at end of file diff --git a/src/playlists-menu-item.vala b/src/playlists-menu-item.vala index b8c6e7d..8a2ccac 100644 --- a/src/playlists-menu-item.vala +++ b/src/playlists-menu-item.vala @@ -19,18 +19,20 @@ with this program. If not, see . using Dbusmenu; using DbusmenuPlaylists; +using DbusmenuPlaylist; using Gee; public class PlaylistsMenuitem : PlayerItem { - private HashMap current_playlists; + private HashMap current_playlists; public Menuitem root_item; + public PlaylistsMenuitem ( PlayerController parent ) { Object ( item_type: MENUITEM_TYPE, owner: parent ); } construct{ - this.current_playlists = new HashMap(); + this.current_playlists = new HashMap(); this.root_item = new Menuitem(); this.root_item.property_set ( MENUITEM_PROP_LABEL, "Choose Playlist" ); } @@ -38,23 +40,38 @@ public class PlaylistsMenuitem : PlayerItem public new void update (PlaylistDetails[] playlists) { foreach ( PlaylistDetails detail in playlists ){ + if (this.already_observed(detail)) continue; + Dbusmenu.Menuitem menuitem = new Menuitem(); menuitem.property_set (MENUITEM_PROP_LABEL, detail.name); - menuitem.property_set (MENUITEM_PROP_ICON_NAME, "source-smart-playlist"); + menuitem.property_set (MENUITEM_PROP_ICON_NAME, detail.icon_path); + menuitem.property_set (MENUITEM_PATH, (string)detail.path); menuitem.property_set_bool (MENUITEM_PROP_VISIBLE, true); menuitem.property_set_bool (MENUITEM_PROP_ENABLED, true); - this.current_playlists.set( menuitem.id, detail ); + menuitem.item_activated.connect(() => { submenu_item_activated (menuitem.id );}); + this.current_playlists.set( menuitem.id, menuitem ); this.root_item.child_append( menuitem ); } } - + + public void update_individual_playlist (PlaylistDetails new_detail) + { + foreach ( Dbusmenu.Menuitem item in this.current_playlists.values ){ + if (new_detail.path == item.property_get (MENUITEM_PATH)){ + item.property_set (MENUITEM_PROP_LABEL, new_detail.name); + item.property_set (MENUITEM_PROP_ICON_NAME, new_detail.icon_path); + } + } + } + private bool already_observed (PlaylistDetails new_detail) { - foreach ( PlaylistDetails detail in this.current_playlists.values ){ - if (new_detail.path == detail.path) return true; + foreach ( Dbusmenu.Menuitem item in this.current_playlists.values ){ + var path = item.property_get (MENUITEM_PATH); + if (new_detail.path == path) return true; } return false; } @@ -68,12 +85,12 @@ public class PlaylistsMenuitem : PlayerItem private void submenu_item_activated (int menu_item_id) { - if(!this.current_playlists.has_key(menu_item_id)){ + if (!this.current_playlists.has_key(menu_item_id)) { warning( "item %i was activated but we don't have a corresponding playlist", menu_item_id ); return; } - this.owner.mpris_bridge.activate_playlist ( this.current_playlists[menu_item_id].path ); + this.owner.mpris_bridge.activate_playlist ( (GLib.ObjectPath)this.current_playlists[menu_item_id].property_get (MENUITEM_PATH) ); } public static HashSet attributes_format() diff --git a/src/sound-service.c b/src/sound-service.c index cfc0b7e..b5e6224 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -39,8 +39,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - close_pulse_activites(); - g_main_loop_quit(mainloop); + //close_pulse_activites(); + //g_main_loop_quit(mainloop); } return; } diff --git a/vapi/common-defs.vapi b/vapi/common-defs.vapi index 2946d25..7b38e9c 100644 --- a/vapi/common-defs.vapi +++ b/vapi/common-defs.vapi @@ -53,4 +53,8 @@ namespace DbusmenuPlaylists{ public const string MENUITEM_TYPE; public const string MENUITEM_TITLE; public const string MENUITEM_PLAYLISTS; +} +[CCode (cheader_filename = "common-defs.h")] +namespace DbusmenuPlaylist{ + public const string MENUITEM_PATH; } \ No newline at end of file -- cgit v1.2.3 From 17f01f35c7b474f4286dd55b129fcf72075760dc Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Wed, 9 Feb 2011 10:56:49 +0000 Subject: fixed racey active playlist property and commented some debugs --- src/mpris2-controller.vala | 19 +++++++++++-------- src/player-item.vala | 16 ++++++++-------- src/transport-menu-item.vala | 6 +++--- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index 444bdf6..3e06487 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -64,7 +64,7 @@ public class Mpris2Controller : GLib.Object HashTable changed_properties, string[] invalid ) { - debug("properties-changed for interface %s and owner %s", interface_source, this.owner.dbus_name); + //debug("properties-changed for interface %s and owner %s", interface_source, this.owner.dbus_name); if ( changed_properties == null || interface_source.has_prefix ( MPRIS_PREFIX ) == false ){ warning("Property-changed hash is null or this is an interface that doesn't concerns us"); @@ -92,7 +92,9 @@ public class Mpris2Controller : GLib.Object } Variant? playlist_v = changed_properties.lookup("ActivePlaylist"); if ( playlist_v != null && this.owner.use_playlists == true ){ - this.fetch_active_playlist(); + // Once again GDBus race condition, the property_changed signal is sent + // before the value is set on the respective property. + Timeout.add (300, this.fetch_active_playlist); } Variant? playlist_count_v = changed_properties.lookup("PlaylistCount"); if ( playlist_count_v != null && this.owner.use_playlists == true ){ @@ -112,7 +114,7 @@ public class Mpris2Controller : GLib.Object } private bool ensure_correct_playback_status(){ - debug("TEST playback status = %s", this.player.PlaybackStatus); + //debug("TEST playback status = %s", this.player.PlaybackStatus); TransportMenuitem.state p = (TransportMenuitem.state)this.determine_play_state(this.player.PlaybackStatus); (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state(p); return false; @@ -174,7 +176,7 @@ public class Mpris2Controller : GLib.Object public void transport_update(TransportMenuitem.action command) { - debug("transport_event input = %i", (int)command); + //debug("transport_event input = %i", (int)command); if(command == TransportMenuitem.action.PLAY_PAUSE){ this.player.PlayPause.begin(); } @@ -219,7 +221,7 @@ public class Mpris2Controller : GLib.Object } if( current_playlists != null ){ - debug( "Size of the playlist array = %i", current_playlists.length ); + //debug( "Size of the playlist array = %i", current_playlists.length ); PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; playlists_item.update(current_playlists); } @@ -229,13 +231,14 @@ public class Mpris2Controller : GLib.Object } } - private void fetch_active_playlist() + private bool fetch_active_playlist() { if (this.playlists.ActivePlaylist.valid == false){ - debug("We don't have an active playlist"); - } + debug(" We don't have an active playlist"); + } PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; playlists_item.update_active_playlist ( this.playlists.ActivePlaylist.details ); + return false; } public void activate_playlist (ObjectPath path) diff --git a/src/player-item.vala b/src/player-item.vala index f883a1e..e146d4a 100644 --- a/src/player-item.vala +++ b/src/player-item.vala @@ -52,19 +52,19 @@ public class PlayerItem : Dbusmenu.Menuitem { debug("PlayerItem::update()"); if(data == null){ - debug("PlayerItem::Update -> The hashtable was null - just leave it!"); + warning("PlayerItem::Update -> The hashtable was null - just leave it!"); return; } foreach(string property in attributes){ string[] input_keys = property.split("-"); string search_key = input_keys[input_keys.length-1 : input_keys.length][0]; - debug("search key = %s", search_key); + //debug("search key = %s", search_key); Variant? v = data.lookup(search_key); if (v.is_of_type ( VariantType.STRING )){ string update = v.get_string().strip(); - debug("with value : %s", update); + //debug("with value : %s", update); if(property.contains("mpris:artUrl")){ // We know its a metadata instance because thats the only // object with the arturl prop @@ -75,15 +75,15 @@ public class PlayerItem : Dbusmenu.Menuitem this.property_set(property, update); } else if (v.is_of_type (VariantType.INT32 )){ - debug("with value : %i", v.get_int32()); + //debug("with value : %i", v.get_int32()); this.property_set_int(property, v.get_int32()); } else if (v.is_of_type (VariantType.INT64 )){ - debug("with value : %i", (int)v.get_int64()); + //debug("with value : %i", (int)v.get_int64()); this.property_set_int(property, (int)v.get_int64()); } else if(v.is_of_type ( VariantType.BOOLEAN )){ - debug("with value : %s", v.get_boolean().to_string()); + //debug("with value : %s", v.get_boolean().to_string()); this.property_set_bool(property, v.get_boolean()); } } @@ -93,10 +93,10 @@ public class PlayerItem : Dbusmenu.Menuitem public bool populated(HashSet attrs) { foreach(string prop in attrs){ - debug("populated ? - prop: %s", prop); + //debug("populated ? - prop: %s", prop); int value_int = property_get_int(prop); if(property_get_int(prop) != EMPTY){ - debug("populated - prop %s and value %i", prop, value_int); + //debug("populated - prop %s and value %i", prop, value_int); return true; } } diff --git a/src/transport-menu-item.vala b/src/transport-menu-item.vala index b8f55b5..b0009d9 100644 --- a/src/transport-menu-item.vala +++ b/src/transport-menu-item.vala @@ -42,8 +42,8 @@ public class TransportMenuitem : PlayerItem public void change_play_state(state update) { - debug("UPDATING THE TRANSPORT DBUSMENUITEM PLAY STATE WITH VALUE %i", - (int)update); + //debug("UPDATING THE TRANSPORT DBUSMENUITEM PLAY STATE WITH VALUE %i", + // (int)update); int temp = (int)update; this.property_set_int(MENUITEM_PLAY_STATE, temp); } @@ -60,7 +60,7 @@ public class TransportMenuitem : PlayerItem } int32 input = v.get_int32(); - debug("transport menu item -> handle_event with value %s", input.to_string()); + //debug("transport menu item -> handle_event with value %s", input.to_string()); //debug("transport owner name = %s", this.owner.app_info.get_name()); this.owner.mpris_bridge.transport_update((action)input); } -- cgit v1.2.3 From 8c00af69e0064e624c9aa3f93fd5ebb5ae10fab5 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Wed, 9 Feb 2011 10:57:13 +0000 Subject: tidy up --- src/sound-service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound-service.c b/src/sound-service.c index b5e6224..cfc0b7e 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -39,8 +39,8 @@ service_shutdown (IndicatorService *service, gpointer user_data) { if (mainloop != NULL) { g_debug("Service shutdown !"); - //close_pulse_activites(); - //g_main_loop_quit(mainloop); + close_pulse_activites(); + g_main_loop_quit(mainloop); } return; } -- cgit v1.2.3 From f184a09b5f7691c350684e03461a9ab658686f2e Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Wed, 9 Feb 2011 11:02:31 +0000 Subject: tidy up --- src/mpris2-controller.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index 3e06487..b4d0fc4 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -92,7 +92,7 @@ public class Mpris2Controller : GLib.Object } Variant? playlist_v = changed_properties.lookup("ActivePlaylist"); if ( playlist_v != null && this.owner.use_playlists == true ){ - // Once again GDBus race condition, the property_changed signal is sent + // Once again A GDBus race condition, the property_changed signal is sent // before the value is set on the respective property. Timeout.add (300, this.fetch_active_playlist); } -- cgit v1.2.3 From 5347a41ef9a04cc52c4f25bddfac9cb8660348a4 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Wed, 9 Feb 2011 11:16:03 +0000 Subject: and plug it together --- src/mpris2-controller.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index b4d0fc4..bf930fc 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -202,7 +202,8 @@ public class Mpris2Controller : GLib.Object private void on_playlistdetails_changed (PlaylistDetails details) { - + PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; + playlists_item.update_individual_playlist (details); } public async void fetch_playlists() -- cgit v1.2.3 From c8dc3a51330c1d70eb896f3686e1794028a4e5f7 Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 10 Feb 2011 14:34:51 +0000 Subject: remember to cancel the reconnect timeout loop once a connection has been established --- src/pulseaudio-mgr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 1a2b3e0..3aed1f1 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -126,8 +126,6 @@ reconnect_to_pulse (gpointer user_data) g_warning ("Failed to connect context: %s", pa_strerror (pa_context_errno (pulse_context))); } - - reconnect_idle_id = 0; if (connection_attempts > 5){ return FALSE; } @@ -236,6 +234,10 @@ pm_context_state_callback (pa_context *c, void *userdata) case PA_CONTEXT_READY: connection_attempts = 0; g_debug("PA_CONTEXT_READY"); + if (reconnect_idle_id != 0){ + g_source_remove (reconnect_idle_id); + reconnect_idle_id = 0; + } pa_operation *o; pa_context_set_subscribe_callback(c, pm_subscribed_events_callback, userdata); -- cgit v1.2.3 From c963e37be35b53d6f9da68a92b2bb9f1d42a788d Mon Sep 17 00:00:00 2001 From: Conor Curran Date: Thu, 10 Feb 2011 14:35:59 +0000 Subject: prep for 059 release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d677e7c..d42f574 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ -AC_INIT(indicator-sound, 0.5.8, conor.curran@canonical.com) +AC_INIT(indicator-sound, 0.5.9, conor.curran@canonical.com) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-sound, 0.5.8) +AM_INIT_AUTOMAKE(indicator-sound, 0.5.9) AM_MAINTAINER_MODE -- cgit v1.2.3