diff options
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/active-sink.c | 349 | ||||
-rw-r--r-- | src/active-sink.h | 85 | ||||
-rw-r--r-- | src/common-defs.h | 3 | ||||
-rw-r--r-- | src/device.c | 289 | ||||
-rw-r--r-- | src/device.h | 84 | ||||
-rw-r--r-- | src/indicator-sound.c | 56 | ||||
-rw-r--r-- | src/pulseaudio-mgr.c | 88 | ||||
-rw-r--r-- | src/pulseaudio-mgr.h | 4 | ||||
-rw-r--r-- | src/slider-menu-item.c | 134 | ||||
-rw-r--r-- | src/slider-menu-item.h | 12 | ||||
-rw-r--r-- | src/sound-service-dbus.c | 10 | ||||
-rw-r--r-- | src/voip-input-menu-item.c | 6 | ||||
-rw-r--r-- | src/voip-input-menu-item.h | 4 | ||||
-rw-r--r-- | src/voip-input-widget.c | 4 | ||||
-rw-r--r-- | src/volume-widget.c | 39 |
16 files changed, 638 insertions, 533 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7525d71..f7dc2ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,8 +92,8 @@ indicator_sound_service_SOURCES = \ sound-service.c \ pulseaudio-mgr.h \ pulseaudio-mgr.c \ - active-sink.c \ - active-sink.h \ + device.c \ + device.h \ sound-service-dbus.h \ sound-service-dbus.c \ slider-menu-item.h \ diff --git a/src/active-sink.c b/src/active-sink.c deleted file mode 100644 index a78d33e..0000000 --- a/src/active-sink.c +++ /dev/null @@ -1,349 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -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 <http://www.gnu.org/licenses/>. -*/ -#include <libdbusmenu-glib/menuitem.h> - -#include "active-sink.h" -#include "slider-menu-item.h" -#include "mute-menu-item.h" -#include "voip-input-menu-item.h" -#include "pulseaudio-mgr.h" - -typedef struct _ActiveSinkPrivate ActiveSinkPrivate; - -struct _ActiveSinkPrivate -{ - SliderMenuItem* volume_slider_menuitem; - MuteMenuItem* mute_menuitem; - VoipInputMenuItem* voip_input_menu_item; - SoundState current_sound_state; - 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)) - -/* 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); - -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); - -static void -active_sink_class_init (ActiveSinkClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_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) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - priv->mute_menuitem = NULL; - priv->volume_slider_menuitem = NULL; - priv->voip_input_menu_item = NULL; - priv->current_sound_state = UNAVAILABLE; - priv->index = -1; - priv->name = NULL; - priv->service = NULL; - - // Init our menu items. - priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); - priv->voip_input_menu_item = g_object_new (VOIP_INPUT_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 -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); -} - -void -active_sink_populate (ActiveSink* sink, - const pa_sink_info* update) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE(sink); - - priv->name = g_strdup (update->name); - priv->index = update->index; - 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_volume_update (sink, volume_percent); - 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); -} - -void -active_sink_activate_voip_item (ActiveSink* self, gint sink_input_index, gint client_index) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - if (voip_input_menu_item_is_interested (priv->voip_input_menu_item, - sink_input_index, - client_index)){ - voip_input_menu_item_enable (priv->voip_input_menu_item, TRUE); - } -} - -void -active_sink_deactivate_voip_source (ActiveSink* self, gboolean visible) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - visible &= voip_input_menu_item_is_active (priv->voip_input_menu_item); - voip_input_menu_item_deactivate_source (priv->voip_input_menu_item, visible); -} - -void -active_sink_deactivate_voip_client (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - voip_input_menu_item_deactivate_voip_client (priv->voip_input_menu_item); -} - -void -active_sink_update (ActiveSink* sink, - const pa_sink_info* update) -{ - 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; - - 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); - active_sink_mute_update (sink, update->mute); -} - -// To the UI -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); - 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 -void -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); - - pa_cvolume_set(&priv->volume, priv->channel_map.channels, new_volume_value); - pm_update_volume (priv->index, new_volume); -} - - -gint -active_sink_get_current_sink_input_index (ActiveSink* sink) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (sink); - return voip_input_menu_item_get_sink_input_index (priv->voip_input_menu_item); -} - -static void -active_sink_mute_update (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; - } - if (priv->current_sound_state != state){ - priv->current_sound_state = state; - 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) -{ - 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; -} - -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; -} - -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); - 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; -} - -SoundState -active_sink_get_state (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return priv->current_sound_state; -} - -void -active_sink_update_voip_input_source (ActiveSink* self, const pa_source_info* update) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - voip_input_menu_item_update (priv->voip_input_menu_item, update); -} - -gboolean -active_sink_is_voip_source_populated (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return voip_input_menu_item_is_populated (priv->voip_input_menu_item); -} - -gint active_sink_get_source_index (ActiveSink* self) -{ - ActiveSinkPrivate* priv = ACTIVE_SINK_GET_PRIVATE (self); - return voip_input_menu_item_get_index (priv->voip_input_menu_item); -} - -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, - mute_menu_item_get_button (priv->mute_menuitem), - DBUSMENU_MENUITEM (priv->volume_slider_menuitem), - DBUSMENU_MENUITEM (priv->voip_input_menu_item)); - pm_establish_pulse_connection (sink); - return sink; -} diff --git a/src/active-sink.h b/src/active-sink.h deleted file mode 100644 index 57b3079..0000000 --- a/src/active-sink.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010 Canonical Ltd. - * - * Authors: - * Conor Curran <conor.curran@canonical.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#ifndef __ACTIVE_SINK_H__ -#define __ACTIVE_SINK_H__ - -#include <glib.h> -#include <glib-object.h> - -#include "common-defs.h" -#include "sound-service-dbus.h" - -#include <pulse/pulseaudio.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; - -/** - * TODO - * Refactor this to become a device manager obj basically acting as wrapper for - * the communication between pulseaudio-mgr and the individual items. - * First steps collapse slider/volume related stuff into slider-menu-item. - */ - -// Sink related -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); -gint active_sink_get_index (ActiveSink* self); -void active_sink_deactivate (ActiveSink* self); -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); - -// source and sinkinput/client related for VOIP functionality -void active_sink_update_voip_input_source (ActiveSink* sink, const pa_source_info* update); -void active_sink_activate_voip_item (ActiveSink* sink, gint sink_input_index, gint client_index); -gint active_sink_get_current_sink_input_index (ActiveSink* sink); -gboolean active_sink_is_voip_source_populated (ActiveSink* sink); -gint active_sink_get_source_index (ActiveSink* self); -void active_sink_determine_blocking_state (ActiveSink* self); -void active_sink_deactivate_voip_source (ActiveSink* self, gboolean visible); -void active_sink_deactivate_voip_client (ActiveSink* self); -SoundState active_sink_get_state (ActiveSink* self); - -ActiveSink* active_sink_new (SoundServiceDbus* service); - -G_END_DECLS - -#endif diff --git a/src/common-defs.h b/src/common-defs.h index da504de..21aab60 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -45,12 +45,13 @@ typedef enum { TRANSPORT_STATE_PAUSED }TransportState; -#define NOT_ACTIVE -1 +#define NOT_ACTIVE -1 #define DBUSMENU_PROPERTY_EMPTY -1 /* DBUS Custom Items */ #define DBUSMENU_VOLUME_MENUITEM_TYPE "x-canonical-ido-volume-type" #define DBUSMENU_VOLUME_MENUITEM_LEVEL "x-canonical-ido-volume-level" +#define DBUSMENU_VOLUME_MENUITEM_MUTE "x-canonical-ido-volume-mute" #define DBUSMENU_VOIP_INPUT_MENUITEM_TYPE "x-canonical-ido-voip-input-type" #define DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL "x-canonical-ido-voip-input-level" diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..79b7b50 --- /dev/null +++ b/src/device.c @@ -0,0 +1,289 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +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 <http://www.gnu.org/licenses/>. +*/ +#include <libdbusmenu-glib/menuitem.h> + +#include "device.h" +#include "slider-menu-item.h" +#include "mute-menu-item.h" +#include "voip-input-menu-item.h" +#include "pulseaudio-mgr.h" + +typedef struct _DevicePrivate DevicePrivate; + +struct _DevicePrivate +{ + SliderMenuItem* volume_slider_menuitem; + MuteMenuItem* mute_menuitem; + VoipInputMenuItem* voip_input_menu_item; + SoundState current_sound_state; + SoundServiceDbus* service; +}; + +#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVICE_TYPE, DevicePrivate)) + +/* Prototypes */ +static void device_class_init (DeviceClass *klass); +static void device_init (Device *self); +static void device_dispose (GObject *object); +static void device_finalize (GObject *object); + +static SoundState device_get_state_from_volume (Device* self); +static void device_mute_update (Device* self, gboolean muted); + +G_DEFINE_TYPE (Device, device, G_TYPE_OBJECT); + +static void +device_class_init (DeviceClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (DevicePrivate)); + + gobject_class->dispose = device_dispose; + gobject_class->finalize = device_finalize; +} + +static void +device_init (Device *self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + priv->mute_menuitem = NULL; + priv->volume_slider_menuitem = NULL; + priv->voip_input_menu_item = NULL; + priv->current_sound_state = UNAVAILABLE; + priv->service = NULL; + + // Init our menu items. + priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); + priv->voip_input_menu_item = g_object_new (VOIP_INPUT_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 +device_dispose (GObject *object) +{ + G_OBJECT_CLASS (device_parent_class)->dispose (object); +} + +static void +device_finalize (GObject *object) +{ + G_OBJECT_CLASS (device_parent_class)->finalize (object); +} + +void +device_sink_populate (Device* self, + const pa_sink_info* update) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE(self); + mute_menu_item_enable (priv->mute_menuitem, TRUE); + slider_menu_item_populate (priv->volume_slider_menuitem, update); + SoundState state = device_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); + } + device_mute_update (self, update->mute); +} + +void +device_sink_update (Device* self, + const pa_sink_info* update) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + slider_menu_item_update (priv->volume_slider_menuitem, update); + + SoundState state = device_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); + } + + device_mute_update (self, update->mute); +} + +gint +device_get_current_sink_input_index (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return voip_input_menu_item_get_sink_input_index (priv->voip_input_menu_item); +} + +static void +device_mute_update (Device* self, gboolean muted) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + mute_menu_item_update (priv->mute_menuitem, muted); + SoundState state = device_get_state_from_volume (self); + + if (muted == TRUE){ + state = MUTED; + } + // Only send signals if something has changed + if (priv->current_sound_state != state){ + priv->current_sound_state = state; + sound_service_dbus_update_sound_state (priv->service, state); + } +} + +void +device_ensure_sink_is_unmuted (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + if (mute_menu_item_is_muted (priv->mute_menuitem)){ + pm_update_mute (FALSE); + } +} + + +static SoundState +device_get_state_from_volume (Device* self) +{ + DevicePrivate* priv = DEVICE_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; +} + +void +device_determine_blocking_state (Device* self) +{ + DevicePrivate* priv = DEVICE_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 +device_get_sink_index (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return slider_menu_item_get_sink_index (priv->volume_slider_menuitem); +} + +gboolean +device_is_sink_populated (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM (priv->volume_slider_menuitem), + DBUSMENU_MENUITEM_PROP_ENABLED); +} + +void +device_activate_voip_item (Device* self, gint sink_input_index, gint client_index) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + if (voip_input_menu_item_is_interested (priv->voip_input_menu_item, + sink_input_index, + client_index)){ + voip_input_menu_item_enable (priv->voip_input_menu_item, TRUE); + } +} + +void +device_deactivate_voip_source (Device* self, gboolean visible) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + visible &= voip_input_menu_item_is_active (priv->voip_input_menu_item); + voip_input_menu_item_deactivate_source (priv->voip_input_menu_item, visible); +} + +void +device_deactivate_voip_client (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + voip_input_menu_item_deactivate_voip_client (priv->voip_input_menu_item); +} + +void +device_sink_deactivated (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (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); +} + +SoundState +device_get_state (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return priv->current_sound_state; +} + +void +device_update_voip_input_source (Device* self, const pa_source_info* update) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + voip_input_menu_item_update (priv->voip_input_menu_item, update); +} + +gboolean +device_is_voip_source_populated (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return voip_input_menu_item_is_populated (priv->voip_input_menu_item); +} + +gint device_get_source_index (Device* self) +{ + DevicePrivate* priv = DEVICE_GET_PRIVATE (self); + return voip_input_menu_item_get_index (priv->voip_input_menu_item); +} + +Device* +device_new (SoundServiceDbus* service) +{ + Device* sink = g_object_new (DEVICE_TYPE, NULL); + DevicePrivate* priv = DEVICE_GET_PRIVATE (sink); + priv->service = service; + sound_service_dbus_build_sound_menu (service, + mute_menu_item_get_button (priv->mute_menuitem), + DBUSMENU_MENUITEM (priv->volume_slider_menuitem), + DBUSMENU_MENUITEM (priv->voip_input_menu_item)); + pm_establish_pulse_connection (sink); + return sink; +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..9c74344 --- /dev/null +++ b/src/device.h @@ -0,0 +1,84 @@ +/* + * Copyright 2010 Canonical Ltd. + * + * Authors: + * Conor Curran <conor.curran@canonical.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#include <glib.h> +#include <glib-object.h> + +#include "common-defs.h" +#include "sound-service-dbus.h" + +#include <pulse/pulseaudio.h> + +G_BEGIN_DECLS + +#define DEVICE_TYPE (device_get_type ()) +#define DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVICE_TYPE, Device)) +#define DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DEVICE_TYPE, DeviceClass)) +#define IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVICE_TYPE)) +#define IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVICE_TYPE)) +#define DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVICE_TYPE, DeviceClass)) + +typedef struct _Device Device; +typedef struct _DeviceClass DeviceClass; + +struct _Device { + GObject parent; +}; + +struct _DeviceClass { + GObjectClass parent_class; +}; + +GType device_get_type (void) G_GNUC_CONST; + +/** + * TODO + * Refactor this to become a device manager obj basically acting as wrapper for + * the communication between pulseaudio-mgr and the individual items. + * First steps collapse slider/volume related stuff into slider-menu-item. + */ + +// Sink related +void device_sink_populate (Device* sink, const pa_sink_info* update); +void device_sink_update (Device* sink, const pa_sink_info* update); +gboolean device_is_sink_populated (Device* sink); +gint device_get_sink_index (Device* self); +void device_sink_deactivated (Device* self); +void device_update_mute (Device* self, gboolean mute_update); +void device_ensure_sink_is_unmuted (Device* self); + +// source and sinkinput/client related for VOIP functionality +void device_update_voip_input_source (Device* sink, const pa_source_info* update); +void device_activate_voip_item (Device* sink, gint sink_input_index, gint client_index); +gint device_get_current_sink_input_index (Device* sink); +gboolean device_is_voip_source_populated (Device* sink); +gint device_get_source_index (Device* self); +void device_determine_blocking_state (Device* self); +void device_deactivate_voip_source (Device* self, gboolean visible); +void device_deactivate_voip_client (Device* self); +SoundState device_get_state (Device* self); + +Device* device_new (SoundServiceDbus* service); + +G_END_DECLS + +#endif diff --git a/src/indicator-sound.c b/src/indicator-sound.c index a7d3808..7d74a42 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -45,6 +45,7 @@ typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate; struct _IndicatorSoundPrivate { GtkWidget* volume_widget; + GtkWidget* voip_widget; GList* transport_widgets_list; GDBusProxy *dbus_proxy; SoundStateManager* state_manager; @@ -443,11 +444,16 @@ new_voip_slider_widget (DbusmenuMenuitem * newitem, { g_debug("indicator-sound: new_voip_slider_widget"); GtkWidget* voip_widget = NULL; + IndicatorObject *io = NULL; g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + io = g_object_get_data (G_OBJECT (client), "indicator"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + voip_widget = voip_input_widget_new (newitem); + priv->voip_widget = voip_widget; GtkWidget* ido_slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(voip_widget)); @@ -478,21 +484,35 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) IndicatorSound *indicator = INDICATOR_SOUND (data); IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); - if(priv->volume_widget == NULL){ - return FALSE; - } - - GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); - GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); - GtkRange* range = (GtkRange*)slider; - g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); - gdouble current_value = gtk_range_get_value(range); - gdouble new_value = current_value; - const gdouble five_percent = 5; GtkWidget *menuitem; - menuitem = GTK_MENU_SHELL (widget)->active_menu_item; - if (IDO_IS_SCALE_MENU_ITEM(menuitem) == TRUE) { + + if (IDO_IS_SCALE_MENU_ITEM(menuitem) == TRUE){ + gdouble current_value = 0; + gdouble new_value = 0; + const gdouble five_percent = 5; + gboolean is_voip_slider = FALSE; + + if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOLUME") == 0) { + g_debug ("vOLUME SLIDER KEY PRESS"); + GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); + GtkRange* range = (GtkRange*)slider; + g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); + current_value = gtk_range_get_value(range); + new_value = current_value; + } + else if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOIP") == 0) { + g_debug ("VOIP SLIDER KEY PRESS"); + GtkWidget* slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(priv->voip_widget)); + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); + GtkRange* range = (GtkRange*)slider; + g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); + current_value = gtk_range_get_value(range); + new_value = current_value; + is_voip_slider = TRUE; + } + switch (event->keyval) { case GDK_Right: digested = TRUE; @@ -514,9 +534,13 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) break; } new_value = CLAMP(new_value, 0, 100); - if (new_value != current_value && sound_state_manager_get_current_state (priv->state_manager) != MUTED) { - //g_debug("Attempting to set the range from the key listener to %f", new_value); - volume_widget_update(VOLUME_WIDGET(priv->volume_widget), new_value); + if (new_value != current_value){ + if (is_voip_slider == TRUE){ + voip_input_widget_update (VOIP_INPUT_WIDGET(priv->voip_widget), new_value); + } + else{ + volume_widget_update (VOLUME_WIDGET(priv->volume_widget), new_value); + } } } else if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) { diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c index 6d11221..95f4c06 100644 --- a/src/pulseaudio-mgr.c +++ b/src/pulseaudio-mgr.c @@ -68,7 +68,7 @@ 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, +static void pm_update_device (pa_context *c, const pa_sink_info *info, int eol, void *userdata); @@ -89,11 +89,11 @@ static pa_glib_mainloop *pa_main_loop = NULL; Entry Point **/ void -pm_establish_pulse_connection (ActiveSink* active_sink) +pm_establish_pulse_connection (Device* device) { pa_main_loop = pa_glib_mainloop_new (g_main_context_default ()); g_assert (pa_main_loop); - reconnect_to_pulse ((gpointer)active_sink); + reconnect_to_pulse ((gpointer)device); } /** @@ -119,7 +119,7 @@ reconnect_to_pulse (gpointer user_data) { g_debug("Attempt a pulse connection"); // reset - g_return_val_if_fail (IS_ACTIVE_SINK (user_data), FALSE); + g_return_val_if_fail (IS_DEVICE (user_data), FALSE); connection_attempts += 1; if (pulse_context != NULL) { @@ -216,38 +216,38 @@ pm_subscribed_events_callback (pa_context *c, uint32_t index, void* userdata) { - if (IS_ACTIVE_SINK (userdata) == FALSE){ + if (IS_DEVICE (userdata) == FALSE){ g_critical ("subscribed events callback - our userdata is not what we think it should be"); return; } - ActiveSink* sink = ACTIVE_SINK (userdata); + Device* sink = DEVICE (userdata); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: // We don't care about any other sink other than the active one. - if (index != active_sink_get_index (sink)) + if (index != device_get_sink_index (sink)) return; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - active_sink_deactivate (sink); + device_sink_deactivated (sink); } else{ pa_operation_unref (pa_context_get_sink_info_by_index (c, index, - pm_update_active_sink, + pm_update_device, userdata) ); } break; case PA_SUBSCRIPTION_EVENT_SOURCE: g_debug ("Looks like source event of some description - index = %i", index); // We don't care about any other sink other than the active one. - if (index != active_sink_get_source_index (sink)) + if (index != device_get_source_index (sink)) return; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { g_debug ("Source removal event - index = %i", index); - active_sink_deactivate_voip_source (sink, FALSE); + device_deactivate_voip_source (sink, FALSE); } else{ pa_operation_unref (pa_context_get_source_info_by_index (c, @@ -260,12 +260,12 @@ pm_subscribed_events_callback (pa_context *c, // We don't care about sink input removals. g_debug ("sink input event"); if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - gint cached_index = active_sink_get_current_sink_input_index (sink); + gint cached_index = device_get_current_sink_input_index (sink); g_debug ("Just saw a sink input removal event - index = %i and cached index = %i", index, cached_index); if (index == cached_index){ - active_sink_deactivate_voip_client (sink); + device_deactivate_voip_client (sink); } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { @@ -308,7 +308,7 @@ pm_context_state_callback (pa_context *c, void *userdata) break; case PA_CONTEXT_FAILED: g_warning("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); - active_sink_deactivate (ACTIVE_SINK (userdata)); + device_sink_deactivated (DEVICE (userdata)); if (reconnect_idle_id == 0){ reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY, reconnect_to_pulse, @@ -362,7 +362,7 @@ pm_server_info_callback (pa_context *c, if (info == NULL) { g_warning("No PA server - get the hell out of here"); - active_sink_deactivate (ACTIVE_SINK (userdata)); + device_sink_deactivated (DEVICE (userdata)); return; } // Go for the default sink @@ -373,7 +373,7 @@ pm_server_info_callback (pa_context *c, pm_default_sink_info_callback, userdata) )) { g_warning("pa_context_get_sink_info_by_namet() failed"); - active_sink_deactivate (ACTIVE_SINK (userdata)); + device_sink_deactivated (DEVICE (userdata)); pa_operation_unref(operation); return; } @@ -382,7 +382,7 @@ pm_server_info_callback (pa_context *c, pm_sink_info_callback, userdata))) { g_warning("pa_context_get_sink_info_list() failed"); - active_sink_deactivate (ACTIVE_SINK (userdata)); + device_sink_deactivated (DEVICE (userdata)); pa_operation_unref(operation); return; } @@ -421,14 +421,14 @@ pm_sink_info_callback (pa_context *c, return; } else { - if (IS_ACTIVE_SINK (userdata) == FALSE || sink == NULL){ + if (IS_DEVICE (userdata) == FALSE || sink == NULL){ g_warning ("sink info callback - our user data is not what we think it should be or the sink parameter is null"); return; } - ActiveSink* a_sink = ACTIVE_SINK (userdata); - if (active_sink_is_populated (a_sink) == FALSE && + Device* a_sink = DEVICE (userdata); + if (device_is_sink_populated (a_sink) == FALSE && g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ - active_sink_populate (a_sink, sink); + device_sink_populate (a_sink, sink); } } } @@ -443,16 +443,16 @@ pm_default_sink_info_callback (pa_context *c, return; } else { - if (IS_ACTIVE_SINK (userdata) == FALSE || info == NULL){ + if (IS_DEVICE (userdata) == FALSE || info == NULL){ g_warning ("Default sink info callback - our user data is not what we think it should be or the info parameter is null"); return; } // Only repopulate if there is a change with regards the index - if (active_sink_get_index (ACTIVE_SINK (userdata)) == info->index) + if (device_get_sink_index (DEVICE (userdata)) == info->index) return; g_debug ("Pulse Server has handed us a new default sink"); - active_sink_populate (ACTIVE_SINK (userdata), info); + device_sink_populate (DEVICE (userdata), info); } } @@ -466,26 +466,26 @@ pm_sink_input_info_callback (pa_context *c, return; } else { - if (info == NULL || IS_ACTIVE_SINK (userdata) == FALSE) { + if (info == NULL || IS_DEVICE (userdata) == FALSE) { g_warning("Sink input info callback : SINK INPUT INFO IS NULL or our user_data is not what we think it should be"); return; } - if (IS_ACTIVE_SINK (userdata) == FALSE){ + if (IS_DEVICE (userdata) == FALSE){ g_warning ("sink input info callback - our user data is not what we think it should be"); return; } // Check if this is Voip sink input gint result = pa_proplist_contains (info->proplist, PA_PROP_MEDIA_ROLE); - ActiveSink* a_sink = ACTIVE_SINK (userdata); + Device* a_sink = DEVICE (userdata); if (result == 1){ g_debug ("Sink input info has media role property"); const char* value = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE); g_debug ("prop role = %s", value); - if (g_strcmp0 (value, "phone") == 0) { + if (g_strcmp0 (value, "phone") == 0 || g_strcmp0 (value, "production") == 0) { g_debug ("And yes its a VOIP app ... sink input index = %i", info->index); - active_sink_activate_voip_item (a_sink, (gint)info->index, (gint)info->client); + device_activate_voip_item (a_sink, (gint)info->index, (gint)info->client); // TODO to start with we will assume our source is the same as what this 'client' // is pointing at. This should probably be more intelligent : // query for the list of source output info's and going on the name of the client @@ -494,14 +494,14 @@ pm_sink_input_info_callback (pa_context *c, } // And finally check for the mute blocking state - if (active_sink_get_index (a_sink) == info->sink){ - active_sink_determine_blocking_state (a_sink); + if (device_get_sink_index (a_sink) == info->sink){ + device_determine_blocking_state (a_sink); } } } static void -pm_update_active_sink (pa_context *c, +pm_update_device (pa_context *c, const pa_sink_info *info, int eol, void *userdata) @@ -510,11 +510,11 @@ pm_update_active_sink (pa_context *c, return; } else{ - if (IS_ACTIVE_SINK (userdata) == FALSE || info == NULL){ - g_warning ("update_active_sink - our user data is not what we think it should be or the info parameter is null"); + if (IS_DEVICE (userdata) == FALSE || info == NULL){ + g_warning ("update_device - our user data is not what we think it should be or the info parameter is null"); return; } - active_sink_update (ACTIVE_SINK(userdata), info); + device_sink_update (DEVICE(userdata), info); } } @@ -551,16 +551,16 @@ pm_default_source_info_callback (pa_context *c, return; } else { - if (IS_ACTIVE_SINK (userdata) == FALSE || info == NULL){ + if (IS_DEVICE (userdata) == FALSE || info == NULL){ g_warning ("Default source info callback - our user data is not what we think it should be or the source info parameter is null"); return; } // If there is an index change we need to change our cached source - if (active_sink_get_source_index (ACTIVE_SINK (userdata)) == info->index) + if (device_get_source_index (DEVICE (userdata)) == info->index) return; g_debug ("Pulse Server has handed us a new default source"); - active_sink_deactivate_voip_source (ACTIVE_SINK (userdata), TRUE); - active_sink_update_voip_input_source (ACTIVE_SINK (userdata), info); + device_deactivate_voip_source (DEVICE (userdata), TRUE); + device_update_voip_input_source (DEVICE (userdata), info); } } @@ -574,13 +574,13 @@ pm_source_info_callback (pa_context *c, return; } else { - if (IS_ACTIVE_SINK (userdata) == FALSE || info == NULL){ + if (IS_DEVICE (userdata) == FALSE || info == NULL){ g_warning ("source info callback - our user data is not what we think it should be or the source info parameter is null"); return; } // For now we will take the first available - if (active_sink_is_voip_source_populated (ACTIVE_SINK (userdata)) == FALSE){ - active_sink_update_voip_input_source (ACTIVE_SINK (userdata), info); + if (device_is_voip_source_populated (DEVICE (userdata)) == FALSE){ + device_update_voip_input_source (DEVICE (userdata), info); } } } @@ -595,11 +595,11 @@ pm_update_source_info_callback (pa_context *c, return; } else { - if (IS_ACTIVE_SINK (userdata) == FALSE || info == NULL ){ + if (IS_DEVICE (userdata) == FALSE || info == NULL ){ g_warning ("source info update callback - our user data is not what we think it should be or the source info paramter is null"); return; } g_debug ("Got a source update for %s , index %i", info->name, info->index); - active_sink_update_voip_input_source (ACTIVE_SINK (userdata), info); + device_update_voip_input_source (DEVICE (userdata), info); } } diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h index d61117d..ace47f3 100644 --- a/src/pulseaudio-mgr.h +++ b/src/pulseaudio-mgr.h @@ -17,9 +17,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "active-sink.h" +#include "device.h" -void pm_establish_pulse_connection (ActiveSink* active_sink); +void pm_establish_pulse_connection (Device* device); void close_pulse_activites(); void pm_update_volume (gint sink_index, pa_cvolume new_volume); void pm_update_mic_gain (gint source_index, pa_cvolume new_gain); diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index 1c88f01..974749f 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -23,11 +23,18 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib/gi18n.h> #include "slider-menu-item.h" #include "common-defs.h" +#include "pulseaudio-mgr.h" typedef struct _SliderMenuItemPrivate SliderMenuItemPrivate; struct _SliderMenuItemPrivate { - ActiveSink* a_sink; + Device* a_sink; + gint index; + gchar* name; + gboolean mute; + pa_cvolume volume; + pa_channel_map channel_map; + pa_volume_t base_volume; }; #define SLIDER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SLIDER_MENU_ITEM_TYPE, SliderMenuItemPrivate)) @@ -39,6 +46,8 @@ static void slider_menu_item_dispose (GObject *object); static void slider_menu_item_finalize (GObject *object); static void handle_event (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp); +static pa_cvolume slider_menu_item_construct_mono_volume (const pa_cvolume* vol); +static void slider_menu_item_update_volume (SliderMenuItem* self, gdouble percent); G_DEFINE_TYPE (SliderMenuItem, slider_menu_item, DBUSMENU_TYPE_MENUITEM); @@ -63,7 +72,13 @@ 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_VOLUME_MENUITEM_TYPE ); + + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + + priv->index = NOT_ACTIVE; + priv->name = NULL; + return; } @@ -97,33 +112,122 @@ handle_event (DbusmenuMenuitem * mi, SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (SLIDER_MENU_ITEM (mi)); gdouble volume_input = g_variant_get_double(input); //g_debug ("slider menu item about to update volume %f", volume_input); - active_sink_update_volume (priv->a_sink, volume_input); - active_sink_ensure_sink_is_unmuted (priv->a_sink); + slider_menu_item_update_volume (SLIDER_MENU_ITEM (mi), volume_input); + device_ensure_sink_is_unmuted (priv->a_sink); } } } + void -slider_menu_item_update (SliderMenuItem* item, - gdouble update) +slider_menu_item_populate (SliderMenuItem* self, const pa_sink_info* update) +{ + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + priv->name = g_strdup (update->name); + priv->index = update->index; + priv->volume = slider_menu_item_construct_mono_volume (&update->volume); + priv->base_volume = update->base_volume; + priv->channel_map = update->channel_map; + priv->mute = update->mute; + + pa_volume_t vol = pa_cvolume_max (&update->volume); + gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; + GVariant* new_volume = g_variant_new_double (volume_percent); + dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), + DBUSMENU_VOLUME_MENUITEM_LEVEL, + new_volume); + GVariant* new_mute_update = g_variant_new_int32 (update->mute); + dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), + DBUSMENU_VOLUME_MENUITEM_MUTE, + new_mute_update); + + slider_menu_item_enable (self, TRUE); +} + +// From the UI +static void +slider_menu_item_update_volume (SliderMenuItem* self, gdouble percent) { - GVariant* new_volume = g_variant_new_double(update); - dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(item), - DBUSMENU_VOLUME_MENUITEM_LEVEL, - new_volume); + 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); + + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + + pa_cvolume_set(&priv->volume, priv->channel_map.channels, new_volume_value); + pm_update_volume (priv->index, new_volume); } +// To the UI void -slider_menu_item_enable (SliderMenuItem* item, - gboolean active) +slider_menu_item_update (SliderMenuItem* self, const pa_sink_info* update) { - dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(item), + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + + priv->volume = slider_menu_item_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; + + GVariant* new_volume = g_variant_new_double (volume_percent); + dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), + DBUSMENU_VOLUME_MENUITEM_LEVEL, + new_volume); + if (priv->mute != update->mute){ + priv->mute = update->mute; + g_debug ("volume menu item - update - mute = %i", update->mute); + GVariant* new_mute_update = g_variant_new_int32 (update->mute); + dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), + DBUSMENU_VOLUME_MENUITEM_MUTE, + new_mute_update); + } +} + +/* + * Enable/Disabled can be considered the equivalent of whether we have an active + * sink or not, let the widget have inherent state. + */ +void +slider_menu_item_enable (SliderMenuItem* self, gboolean active) +{ + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + + dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ENABLED, - active ); + active); + if(active == FALSE){ + priv->index = NOT_ACTIVE; + if(priv->name != NULL){ + g_free(priv->name); + priv->name = NULL; + } + } +} + +gint +slider_menu_item_get_sink_index (SliderMenuItem* self) +{ + SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); + return priv->index; +} + +static pa_cvolume +slider_menu_item_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; } SliderMenuItem* -slider_menu_item_new (ActiveSink* sink) +slider_menu_item_new (Device* sink) { SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL); SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); diff --git a/src/slider-menu-item.h b/src/slider-menu-item.h index f094c71..4375971 100644 --- a/src/slider-menu-item.h +++ b/src/slider-menu-item.h @@ -23,7 +23,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib-object.h> #include <libdbusmenu-glib/menuitem.h> -#include "active-sink.h" +#include "device.h" G_BEGIN_DECLS @@ -47,10 +47,16 @@ struct _SliderMenuItem { GType slider_menu_item_get_type (void); -void slider_menu_item_update(SliderMenuItem* item, gdouble update); +void slider_menu_item_update(SliderMenuItem* item, const pa_sink_info* update); void slider_menu_item_enable(SliderMenuItem* item, gboolean active); +void slider_menu_item_populate (SliderMenuItem* self, const pa_sink_info* update); +//void +//active_sink_update (ActiveSink* sink, +// const pa_sink_info* update) -SliderMenuItem* slider_menu_item_new (ActiveSink* sink); +gint slider_menu_item_get_sink_index (SliderMenuItem* self); + +SliderMenuItem* slider_menu_item_new (Device* sink); G_END_DECLS diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 8d0cc0b..7c817af 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -29,7 +29,7 @@ #include <libdbusmenu-glib/client.h> #include "sound-service-dbus.h" -#include "active-sink.h" +#include "device.h" #include "gen-sound-service.xml.h" #include "dbus-shared-names.h" @@ -55,7 +55,7 @@ typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; struct _SoundServiceDbusPrivate { GDBusConnection* connection; DbusmenuMenuitem* root_menuitem; - ActiveSink* active_sink; + Device* device; }; static GDBusNodeInfo * node_info = NULL; @@ -155,7 +155,7 @@ sound_service_dbus_create_root_item (SoundServiceDbus* self) paths); dbusmenu_server_set_root (server, priv->root_menuitem); g_object_unref (priv->root_menuitem); - priv->active_sink = active_sink_new (self); + priv->device = device_new (self); return priv->root_menuitem; } @@ -272,8 +272,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", active_sink_get_state (priv->active_sink)); - retval = g_variant_new ( "(i)", active_sink_get_state (priv->active_sink)); + g_debug("Get state - %i", device_get_state (priv->device)); + retval = g_variant_new ( "(i)", device_get_state (priv->device)); } else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { gboolean blacklist; diff --git a/src/voip-input-menu-item.c b/src/voip-input-menu-item.c index a742654..a92f91c 100644 --- a/src/voip-input-menu-item.c +++ b/src/voip-input-menu-item.c @@ -28,7 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. typedef struct _VoipInputMenuItemPrivate VoipInputMenuItemPrivate; struct _VoipInputMenuItemPrivate { - ActiveSink* a_sink; + Device* a_sink; pa_cvolume volume; gint mute; guint32 volume_steps; @@ -129,8 +129,6 @@ handle_event (DbusmenuMenuitem * mi, if (priv->mute == 1) { pm_update_mic_mute (priv->source_index, 0); } - //active_sink_update_volume (priv->a_sink, volume_input); - //active_sink_ensure_sink_is_unmuted (priv->a_sink); } } } @@ -268,7 +266,7 @@ voip_input_menu_item_enable (VoipInputMenuItem* item, } VoipInputMenuItem* -voip_input_menu_item_new (ActiveSink* sink) +voip_input_menu_item_new (Device* sink) { VoipInputMenuItem *self = g_object_new(VOIP_INPUT_MENU_ITEM_TYPE, NULL); VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (self); diff --git a/src/voip-input-menu-item.h b/src/voip-input-menu-item.h index 6f4ed85..30ada5a 100644 --- a/src/voip-input-menu-item.h +++ b/src/voip-input-menu-item.h @@ -22,7 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <pulse/pulseaudio.h> #include <libdbusmenu-glib/menuitem.h> -#include "active-sink.h" +#include "device.h" G_BEGIN_DECLS @@ -62,7 +62,7 @@ gint voip_input_menu_item_get_sink_input_index (VoipInputMenuItem* item); void voip_input_menu_item_deactivate_source (VoipInputMenuItem* item, gboolean visible); void voip_input_menu_item_deactivate_voip_client (VoipInputMenuItem* item); -VoipInputMenuItem* voip_input_menu_item_new (ActiveSink* sink); +VoipInputMenuItem* voip_input_menu_item_new (Device* sink); G_END_DECLS diff --git a/src/voip-input-widget.c b/src/voip-input-widget.c index fc295ce..6878361 100644 --- a/src/voip-input-widget.c +++ b/src/voip-input-widget.c @@ -80,6 +80,8 @@ voip_input_widget_init (VoipInputWidget *self) priv->ido_voip_input_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1); g_object_ref (priv->ido_voip_input_slider); + ido_scale_menu_item_set_primary_label (IDO_SCALE_MENU_ITEM(priv->ido_voip_input_slider), "VOIP"); + ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_voip_input_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); g_object_set(priv->ido_voip_input_slider, "reverse-scroll-events", TRUE, NULL); @@ -95,7 +97,7 @@ voip_input_widget_init (VoipInputWidget *self) g_signal_connect(priv->ido_voip_input_slider, "slider-released", G_CALLBACK(voip_input_widget_slider_released), self); GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-none-panel"); + GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-zero-panel"); gtk_image_set_from_gicon(GTK_IMAGE(primary_image), primary_gicon, GTK_ICON_SIZE_MENU); g_object_unref(primary_gicon); diff --git a/src/volume-widget.c b/src/volume-widget.c index 5c842dc..f638bd4 100644 --- a/src/volume-widget.c +++ b/src/volume-widget.c @@ -83,7 +83,8 @@ volume_widget_init (VolumeWidget *self) priv->ido_volume_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1); g_object_ref (priv->ido_volume_slider); - ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_volume_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); + ido_scale_menu_item_set_primary_label (IDO_SCALE_MENU_ITEM(priv->ido_volume_slider), "VOLUME"); + ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_volume_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); g_object_set(priv->ido_volume_slider, "reverse-scroll-events", TRUE, NULL); g_signal_connect (priv->ido_volume_slider, @@ -128,11 +129,11 @@ volume_widget_property_update( DbusmenuMenuitem* item, gchar* property, GVariant* value, gpointer userdata) { g_return_if_fail (IS_VOLUME_WIDGET (userdata)); - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE) ); VolumeWidget* mitem = VOLUME_WIDGET(userdata); VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - //g_debug("scrub-widget::property_update for prop %s", property); + if(g_ascii_strcasecmp(DBUSMENU_VOLUME_MENUITEM_LEVEL, property) == 0){ + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE) ); if(priv->grabbed == FALSE){ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); GtkRange *range = (GtkRange*)slider; @@ -141,6 +142,27 @@ volume_widget_property_update( DbusmenuMenuitem* item, gchar* property, update_accessible_desc(priv->indicator); } } + if(g_ascii_strcasecmp(DBUSMENU_VOLUME_MENUITEM_MUTE, property) == 0){ + g_debug ("volume widget - mute update "); + if(priv->grabbed == FALSE){ + GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); + GtkRange *range = (GtkRange*)slider; + gint update = g_variant_get_int32 (value); + gdouble level; + + g_debug ("volume widget - mute update %i", update); + + if (update == 1){ + level = 0; + } + else{ + level = g_variant_get_double (dbusmenu_menuitem_property_get_variant (priv->twin_item, + DBUSMENU_VOLUME_MENUITEM_LEVEL)); + } + gtk_range_set_value(range, level); + g_debug ("volume-widget - update mute with value %i", update); + } + } } static void @@ -154,9 +176,15 @@ volume_widget_set_twin_item(VolumeWidget* self, G_CALLBACK(volume_widget_property_update), self); gdouble initial_level = g_variant_get_double (dbusmenu_menuitem_property_get_variant(twin_item, DBUSMENU_VOLUME_MENUITEM_LEVEL)); + gint initial_mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant(twin_item, + DBUSMENU_VOLUME_MENUITEM_MUTE)); + //g_debug("volume_widget_set_twin_item initial level = %f", initial_level); GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); GtkRange *range = (GtkRange*)slider; + if(initial_mute == 1){ + initial_level = 0; + } gtk_range_set_value(range, initial_level); update_accessible_desc(priv->indicator); } @@ -188,7 +216,10 @@ volume_widget_value_changed_cb (GtkRange *range, gpointer user_data) GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(slider)), 0, 100); //g_debug ("value changed %f", gtk_range_get_value(GTK_RANGE(slider))); - if(current_value == 0 || current_value == 100){ + gint mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant (priv->twin_item, + DBUSMENU_VOLUME_MENUITEM_MUTE)); + + if((current_value == 0 && mute != 1) || current_value == 100){ volume_widget_update(mitem, current_value); } |