gnome-settings-daemon/0001-Update-gnome-volume-control-code-from-master.patch

1770 lines
71 KiB
Diff

From dffcd6f60cb6984b28d673d013b436de4ee54f4e Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 22 Jun 2009 15:40:19 +0100
Subject: [PATCH 1/4] Update gnome-volume-control code from master
And make slight changes to gsd-media-keys-manager.c to match
the new API.
---
plugins/media-keys/cut-n-paste/gvc-channel-map.c | 175 +++++++++++--
plugins/media-keys/cut-n-paste/gvc-channel-map.h | 24 ++-
plugins/media-keys/cut-n-paste/gvc-mixer-control.c | 276 ++++++++++++++++----
plugins/media-keys/cut-n-paste/gvc-mixer-control.h | 1 +
.../media-keys/cut-n-paste/gvc-mixer-event-role.c | 29 +-
.../media-keys/cut-n-paste/gvc-mixer-event-role.h | 5 +-
.../media-keys/cut-n-paste/gvc-mixer-sink-input.c | 40 ++--
plugins/media-keys/cut-n-paste/gvc-mixer-sink.c | 53 ++--
.../cut-n-paste/gvc-mixer-source-output.c | 6 +-
plugins/media-keys/cut-n-paste/gvc-mixer-source.c | 48 ++--
plugins/media-keys/cut-n-paste/gvc-mixer-stream.c | 225 ++++++++++++++---
plugins/media-keys/cut-n-paste/gvc-mixer-stream.h | 23 ++-
plugins/media-keys/gsd-media-keys-manager.c | 10 +-
13 files changed, 708 insertions(+), 207 deletions(-)
diff --git a/plugins/media-keys/cut-n-paste/gvc-channel-map.c b/plugins/media-keys/cut-n-paste/gvc-channel-map.c
index e7c9b22..32750ef 100644
--- a/plugins/media-keys/cut-n-paste/gvc-channel-map.c
+++ b/plugins/media-keys/cut-n-paste/gvc-channel-map.c
@@ -33,15 +33,26 @@
#define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate))
+#ifndef PA_CHECK_VERSION
+#define PA_CHECK_VERSION(major,minor,micro) \
+ ((PA_MAJOR > (major)) || \
+ (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
+ (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
+#endif
+
+
struct GvcChannelMapPrivate
{
- guint num_channels;
- pa_channel_position_t positions[PA_CHANNELS_MAX];
- gdouble gains[PA_CHANNELS_MAX];
+ pa_channel_map pa_map;
+ pa_cvolume pa_volume;
+ gdouble extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */
+ gboolean can_balance;
+ gboolean can_fade;
+ gboolean has_lfe;
};
enum {
- GAINS_CHANGED,
+ VOLUME_CHANGED,
LAST_SIGNAL
};
@@ -53,25 +64,135 @@ static void gvc_channel_map_finalize (GObject *object);
G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
+/* FIXME remove when we depend on a newer PA */
+static int
+gvc_pa_channel_map_has_position (const pa_channel_map *map, pa_channel_position_t p) {
+ unsigned c;
+
+ g_return_val_if_fail(pa_channel_map_valid(map), 0);
+ g_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
+
+ for (c = 0; c < map->channels; c++)
+ if (map->map[c] == p)
+ return 1;
+
+ return 0;
+}
+
+#if !PA_CHECK_VERSION(0,9,16)
+/* The PulseAudio master increase version only when tagged, so let's avoid clashing with pa_ namespace */
+#define pa_cvolume_get_position gvc_cvolume_get_position
+static pa_volume_t
+gvc_cvolume_get_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) {
+ unsigned c;
+ pa_volume_t v = PA_VOLUME_MUTED;
+
+ g_assert(cv);
+ g_assert(map);
+
+ g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
+ g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
+
+ for (c = 0; c < map->channels; c++)
+ if (map->map[c] == t)
+ if (cv->values[c] > v)
+ v = cv->values[c];
+
+ return v;
+}
+#endif
+
guint
gvc_channel_map_get_num_channels (GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0);
- return map->priv->num_channels;
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return 0;
+
+ return map->priv->pa_map.channels;
+}
+
+const gdouble *
+gvc_channel_map_get_volume (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume);
+ if (gvc_channel_map_can_balance (map))
+ map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
+ else
+ map->priv->extern_volume[BALANCE] = 0;
+ if (gvc_channel_map_can_fade (map))
+ map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
+ else
+ map->priv->extern_volume[FADE] = 0;
+ if (gvc_channel_map_has_lfe (map))
+ map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE);
+ else
+ map->priv->extern_volume[LFE] = 0;
+
+ return map->priv->extern_volume;
+}
+
+gboolean
+gvc_channel_map_can_balance (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->can_balance;
+}
+
+gboolean
+gvc_channel_map_can_fade (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->can_fade;
+}
+
+const char *
+gvc_channel_map_get_mapping (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return pa_channel_map_to_pretty_name (&map->priv->pa_map);
}
-gdouble *
-gvc_channel_map_get_gains (GvcChannelMap *map)
+gboolean
+gvc_channel_map_has_lfe (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->has_lfe;
+}
+
+const pa_channel_map *
+gvc_channel_map_get_pa_channel_map (GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
- return map->priv->gains;
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return &map->priv->pa_map;
}
-pa_channel_position_t *
-gvc_channel_map_get_positions (GvcChannelMap *map)
+const pa_cvolume *
+gvc_channel_map_get_cvolume (GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
- return map->priv->positions;
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return &map->priv->pa_volume;
}
static void
@@ -81,11 +202,11 @@ gvc_channel_map_class_init (GvcChannelMapClass *klass)
gobject_class->finalize = gvc_channel_map_finalize;
- signals [GAINS_CHANGED] =
- g_signal_new ("gains-changed",
+ signals [VOLUME_CHANGED] =
+ g_signal_new ("volume-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GvcChannelMapClass, gains_changed),
+ G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -94,10 +215,19 @@ gvc_channel_map_class_init (GvcChannelMapClass *klass)
}
void
-gvc_channel_map_gains_changed (GvcChannelMap *map)
+gvc_channel_map_volume_changed (GvcChannelMap *map,
+ const pa_cvolume *cv)
{
g_return_if_fail (GVC_IS_CHANNEL_MAP (map));
- g_signal_emit (map, signals[GAINS_CHANGED], 0);
+ g_return_if_fail (cv != NULL);
+ g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map));
+
+ if (pa_cvolume_equal(cv, &map->priv->pa_volume))
+ return;
+
+ map->priv->pa_volume = *cv;
+
+ g_signal_emit (map, signals[VOLUME_CHANGED], 0);
}
static void
@@ -133,13 +263,14 @@ static void
set_from_pa_map (GvcChannelMap *map,
const pa_channel_map *pa_map)
{
- guint i;
+ g_assert (pa_channel_map_valid(pa_map));
+
+ map->priv->can_balance = pa_channel_map_can_balance (pa_map);
+ map->priv->can_fade = pa_channel_map_can_fade (pa_map);
+ map->priv->has_lfe = gvc_pa_channel_map_has_position (pa_map, PA_CHANNEL_POSITION_LFE);
- map->priv->num_channels = pa_map->channels;
- for (i = 0; i < pa_map->channels; i++) {
- map->priv->positions[i] = pa_map->map[i];
- map->priv->gains[i] = 1.0;
- }
+ map->priv->pa_map = *pa_map;
+ pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM);
}
GvcChannelMap *
diff --git a/plugins/media-keys/cut-n-paste/gvc-channel-map.h b/plugins/media-keys/cut-n-paste/gvc-channel-map.h
index 963904f..b35c9cb 100644
--- a/plugins/media-keys/cut-n-paste/gvc-channel-map.h
+++ b/plugins/media-keys/cut-n-paste/gvc-channel-map.h
@@ -44,19 +44,35 @@ typedef struct
typedef struct
{
GObjectClass parent_class;
- void (*gains_changed) (GvcChannelMap *channel_map);
+ void (*volume_changed) (GvcChannelMap *channel_map);
} GvcChannelMapClass;
+enum {
+ VOLUME,
+ BALANCE,
+ FADE,
+ LFE,
+};
+
+#define NUM_TYPES LFE + 1
+
GType gvc_channel_map_get_type (void);
GvcChannelMap * gvc_channel_map_new (void);
GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map);
guint gvc_channel_map_get_num_channels (GvcChannelMap *map);
-pa_channel_position_t * gvc_channel_map_get_positions (GvcChannelMap *map);
-gdouble * gvc_channel_map_get_gains (GvcChannelMap *map);
+const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map);
+gboolean gvc_channel_map_can_balance (GvcChannelMap *map);
+gboolean gvc_channel_map_can_fade (GvcChannelMap *map);
+gboolean gvc_channel_map_has_lfe (GvcChannelMap *map);
-void gvc_channel_map_gains_changed (GvcChannelMap *map);
+void gvc_channel_map_volume_changed (GvcChannelMap *map,
+ const pa_cvolume *cv);
+const char * gvc_channel_map_get_mapping (GvcChannelMap *map);
+/* private */
+const pa_cvolume * gvc_channel_map_get_cvolume (GvcChannelMap *map);
+const pa_channel_map * gvc_channel_map_get_pa_channel_map (GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_CHANNEL_MAP_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-control.c b/plugins/media-keys/cut-n-paste/gvc-mixer-control.c
index e7dd18b..92b0286 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-control.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-control.c
@@ -48,6 +48,7 @@ struct GvcMixerControlPrivate
pa_mainloop_api *pa_api;
pa_context *pa_context;
int n_outstanding;
+ guint reconnect_id;
gboolean default_sink_is_set;
guint default_sink_id;
@@ -65,9 +66,12 @@ struct GvcMixerControlPrivate
GHashTable *sink_inputs; /* routable output streams */
GHashTable *source_outputs; /* routable input streams */
GHashTable *clients;
+
+ GvcMixerStream *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink () */
};
enum {
+ CONNECTING,
READY,
STREAM_ADDED,
STREAM_REMOVED,
@@ -104,6 +108,42 @@ gvc_mixer_control_get_event_sink_input (GvcMixerControl *control)
return stream;
}
+static void
+gvc_mixer_control_stream_restore_cb (pa_context *c,
+ const pa_ext_stream_restore_info *info,
+ int eol,
+ void *userdata)
+{
+ pa_operation *o;
+ GvcMixerControl *control = (GvcMixerControl *) userdata;
+ pa_ext_stream_restore_info new_info;
+
+ if (eol || control->priv->new_default_stream == NULL)
+ return;
+
+ new_info.name = info->name;
+ new_info.channel_map = info->channel_map;
+ new_info.volume = info->volume;
+ new_info.mute = info->mute;
+
+ new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream);
+
+ o = pa_ext_stream_restore_write (control->priv->pa_context,
+ PA_UPDATE_REPLACE,
+ &new_info, 1,
+ TRUE, NULL, NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_write() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ return;
+ }
+
+ g_debug ("Changed default device for %s to %s", info->name, info->device);
+
+ pa_operation_unref (o);
+}
+
gboolean
gvc_mixer_control_set_default_sink (GvcMixerControl *control,
GvcMixerStream *stream)
@@ -118,7 +158,23 @@ gvc_mixer_control_set_default_sink (GvcMixerControl *control,
NULL,
NULL);
if (o == NULL) {
- g_warning ("pa_context_set_default_sink() failed");
+ g_warning ("pa_context_set_default_sink() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ return FALSE;
+ }
+
+ pa_operation_unref (o);
+
+ control->priv->new_default_stream = stream;
+ g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream);
+
+ o = pa_ext_stream_restore_read (control->priv->pa_context,
+ gvc_mixer_control_stream_restore_cb,
+ control);
+
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_read() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
return FALSE;
}
@@ -220,6 +276,13 @@ gvc_stream_collate (GvcMixerStream *a,
namea = gvc_mixer_stream_get_name (a);
nameb = gvc_mixer_stream_get_name (b);
+ if (nameb == NULL && namea == NULL)
+ return 0;
+ if (nameb == NULL)
+ return 1;
+ if (namea == NULL)
+ return -1;
+
return g_utf8_collate (namea, nameb);
}
@@ -320,12 +383,14 @@ _set_default_source (GvcMixerControl *control,
{
guint new_id;
- new_id = 0;
-
- if (stream != NULL) {
- new_id = gvc_mixer_stream_get_id (stream);
+ if (stream == NULL) {
+ control->priv->default_source_id = 0;
+ control->priv->default_source_is_set = FALSE;
+ return;
}
+ new_id = gvc_mixer_stream_get_id (stream);
+
if (control->priv->default_source_id != new_id) {
control->priv->default_source_id = new_id;
control->priv->default_source_is_set = TRUE;
@@ -342,12 +407,14 @@ _set_default_sink (GvcMixerControl *control,
{
guint new_id;
- new_id = 0;
-
- if (stream != NULL) {
- new_id = gvc_mixer_stream_get_id (stream);
+ if (stream == NULL) {
+ control->priv->default_sink_id = 0;
+ control->priv->default_sink_is_set = FALSE;
+ return;
}
+ new_id = gvc_mixer_stream_get_id (stream);
+
if (control->priv->default_sink_id != new_id) {
control->priv->default_sink_id = new_id;
control->priv->default_sink_is_set = TRUE;
@@ -495,6 +562,7 @@ update_sink (GvcMixerControl *control,
GvcMixerStream *stream;
gboolean is_new;
pa_volume_t max_volume;
+ GvcChannelMap *map;
char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX];
pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map);
@@ -506,22 +574,21 @@ update_sink (GvcMixerControl *control,
map_buff);
#endif
- /* for now completely ignore virtual streams */
- if (!(info->flags & PA_SINK_HARDWARE)) {
- return;
- }
-
+ map = NULL;
is_new = FALSE;
stream = g_hash_table_lookup (control->priv->sinks,
GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- GvcChannelMap *map;
map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
stream = gvc_mixer_sink_new (control->priv->pa_context,
info->index,
map);
g_object_unref (map);
is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
}
max_volume = pa_cvolume_max (&info->volume);
@@ -531,11 +598,6 @@ update_sink (GvcMixerControl *control,
gvc_mixer_stream_set_volume (stream, (guint)max_volume);
gvc_mixer_stream_set_is_muted (stream, info->mute);
gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME));
- if (!!(info->flags & PA_SINK_DECIBEL_VOLUME)) {
- gdouble db;
- db = pa_sw_volume_to_dB (max_volume);
- gvc_mixer_stream_set_decibel (stream, db);
- }
if (is_new) {
g_hash_table_insert (control->priv->sinks,
@@ -549,6 +611,10 @@ update_sink (GvcMixerControl *control,
&& strcmp (control->priv->default_sink_name, info->name) == 0) {
_set_default_sink (control, stream);
}
+
+ if (map == NULL)
+ map = gvc_mixer_stream_get_channel_map (stream);
+ gvc_channel_map_volume_changed (map, &info->volume);
}
static void
@@ -566,8 +632,8 @@ update_source (GvcMixerControl *control,
info->description);
#endif
- /* for now completely ignore virtual streams */
- if (!(info->flags & PA_SOURCE_HARDWARE)) {
+ /* completely ignore monitors, they're not real sources */
+ if (info->monitor_of_sink != PA_INVALID_INDEX) {
return;
}
@@ -583,6 +649,10 @@ update_source (GvcMixerControl *control,
map);
g_object_unref (map);
is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
}
max_volume = pa_cvolume_max (&info->volume);
@@ -593,11 +663,7 @@ update_source (GvcMixerControl *control,
gvc_mixer_stream_set_volume (stream, (guint)max_volume);
gvc_mixer_stream_set_is_muted (stream, info->mute);
gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME));
- if (!!(info->flags & PA_SINK_DECIBEL_VOLUME)) {
- gdouble db;
- db = pa_sw_volume_to_dB (max_volume);
- gvc_mixer_stream_set_decibel (stream, db);
- }
+ gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
if (is_new) {
g_hash_table_insert (control->priv->sources,
@@ -662,6 +728,34 @@ set_icon_name_from_proplist (GvcMixerStream *stream,
}
static void
+set_is_event_stream_from_proplist (GvcMixerStream *stream,
+ pa_proplist *l)
+{
+ const char *t;
+ gboolean is_event_stream;
+
+ is_event_stream = FALSE;
+
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
+ if (g_str_equal (t, "event"))
+ is_event_stream = TRUE;
+ }
+
+ gvc_mixer_stream_set_is_event_stream (stream, is_event_stream);
+}
+
+static void
+set_application_id_from_proplist (GvcMixerStream *stream,
+ pa_proplist *l)
+{
+ const char *t;
+
+ if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) {
+ gvc_mixer_stream_set_application_id (stream, t);
+ }
+}
+
+static void
update_sink_input (GvcMixerControl *control,
const pa_sink_input_info *info)
{
@@ -690,6 +784,10 @@ update_sink_input (GvcMixerControl *control,
map);
g_object_unref (map);
is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
}
max_volume = pa_cvolume_max (&info->volume);
@@ -699,9 +797,12 @@ update_sink_input (GvcMixerControl *control,
gvc_mixer_stream_set_name (stream, name);
gvc_mixer_stream_set_description (stream, info->name);
+ set_application_id_from_proplist (stream, info->proplist);
+ set_is_event_stream_from_proplist (stream, info->proplist);
set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia");
gvc_mixer_stream_set_volume (stream, (guint)max_volume);
gvc_mixer_stream_set_is_muted (stream, info->mute);
+ gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX);
if (is_new) {
g_hash_table_insert (control->priv->sink_inputs,
@@ -745,7 +846,9 @@ update_source_output (GvcMixerControl *control,
gvc_mixer_stream_set_name (stream, name);
gvc_mixer_stream_set_description (stream, info->name);
- set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia");
+ set_application_id_from_proplist (stream, info->proplist);
+ set_is_event_stream_from_proplist (stream, info->proplist);
+ set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone");
if (is_new) {
g_hash_table_insert (control->priv->source_outputs,
@@ -938,8 +1041,16 @@ update_event_role_stream (GvcMixerControl *control,
is_new = FALSE;
if (!control->priv->event_sink_input_is_set) {
+ pa_channel_map pa_map;
+ GvcChannelMap *map;
+
+ pa_map.channels = 1;
+ pa_map.map[0] = PA_CHANNEL_POSITION_MONO;
+ map = gvc_channel_map_new_from_pa_channel_map (&pa_map);
+
stream = gvc_mixer_event_role_new (control->priv->pa_context,
- info->device);
+ info->device,
+ map);
control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream);
control->priv->event_sink_input_is_set = TRUE;
@@ -1346,6 +1457,78 @@ gvc_mixer_control_ready (GvcMixerControl *control)
}
static void
+gvc_mixer_new_pa_context (GvcMixerControl *self)
+{
+ pa_proplist *proplist;
+
+ g_return_if_fail (self);
+ g_return_if_fail (!self->priv->pa_context);
+
+ /* FIXME: read these from an object property */
+ proplist = pa_proplist_new ();
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_NAME,
+ _("GNOME Volume Control"));
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_ID,
+ "org.gnome.VolumeControl");
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_ICON_NAME,
+ "multimedia-volume-control");
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_VERSION,
+ PACKAGE_VERSION);
+
+ self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist);
+
+ pa_proplist_free (proplist);
+ g_assert (self->priv->pa_context);
+}
+
+static void
+remove_all_streams (GvcMixerControl *control, GHashTable *hash_table)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, hash_table);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ remove_stream (control, value);
+ g_hash_table_iter_remove (&iter);
+ }
+}
+
+static gboolean
+idle_reconnect (gpointer data)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (data);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail (control, FALSE);
+
+ if (control->priv->pa_context) {
+ pa_context_unref (control->priv->pa_context);
+ control->priv->pa_context = NULL;
+ gvc_mixer_new_pa_context (control);
+ }
+
+ remove_all_streams (control, control->priv->sinks);
+ remove_all_streams (control, control->priv->sources);
+ remove_all_streams (control, control->priv->sink_inputs);
+ remove_all_streams (control, control->priv->source_outputs);
+
+ g_hash_table_iter_init (&iter, control->priv->clients);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ g_hash_table_iter_remove (&iter);
+
+ gvc_mixer_control_open (control); /* cannot fail */
+
+ control->priv->reconnect_id = 0;
+ return FALSE;
+}
+
+static void
_pa_context_state_cb (pa_context *context,
void *userdata)
{
@@ -1363,7 +1546,9 @@ _pa_context_state_cb (pa_context *context,
break;
case PA_CONTEXT_FAILED:
- g_warning ("Connection failed");
+ g_warning ("Connection failed, reconnecting...");
+ if (control->priv->reconnect_id == 0)
+ control->priv->reconnect_id = g_timeout_add_seconds (5, idle_reconnect, control);
break;
case PA_CONTEXT_TERMINATED:
@@ -1386,7 +1571,8 @@ gvc_mixer_control_open (GvcMixerControl *control)
_pa_context_state_cb,
control);
- res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) 0, NULL);
+ g_signal_emit (G_OBJECT (control), signals[CONNECTING], 0);
+ res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL);
if (res < 0) {
g_warning ("Failed to connect context: %s",
pa_strerror (pa_context_errno (control->priv->pa_context)));
@@ -1465,30 +1651,12 @@ gvc_mixer_control_constructor (GType type,
{
GObject *object;
GvcMixerControl *self;
- pa_proplist *proplist;
object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params);
self = GVC_MIXER_CONTROL (object);
- /* FIXME: read these from an object property */
- proplist = pa_proplist_new ();
- pa_proplist_sets (proplist,
- PA_PROP_APPLICATION_NAME,
- _("GNOME Volume Control"));
- pa_proplist_sets (proplist,
- PA_PROP_APPLICATION_ID,
- "org.gnome.VolumeControl");
- pa_proplist_sets (proplist,
- PA_PROP_APPLICATION_ICON_NAME,
- "multimedia-volume-control");
- pa_proplist_sets (proplist,
- PA_PROP_APPLICATION_VERSION,
- PACKAGE_VERSION);
-
- self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist);
- g_assert (self->priv->pa_context);
- pa_proplist_free (proplist);
+ gvc_mixer_new_pa_context (self);
return object;
}
@@ -1502,6 +1670,14 @@ gvc_mixer_control_class_init (GvcMixerControlClass *klass)
object_class->dispose = gvc_mixer_control_dispose;
object_class->finalize = gvc_mixer_control_finalize;
+ signals [CONNECTING] =
+ g_signal_new ("connecting",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, connecting),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals [READY] =
g_signal_new ("ready",
G_TYPE_FROM_CLASS (klass),
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-control.h b/plugins/media-keys/cut-n-paste/gvc-mixer-control.h
index 33e745a..3de9e62 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-control.h
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-control.h
@@ -46,6 +46,7 @@ typedef struct
{
GObjectClass parent_class;
+ void (*connecting) (GvcMixerControl *control);
void (*ready) (GvcMixerControl *control);
void (*stream_added) (GvcMixerControl *control,
guint id);
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c
index b5469ca..69e38ce 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c
@@ -53,21 +53,22 @@ G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
static gboolean
update_settings (GvcMixerEventRole *role,
- guint volume,
- gboolean is_muted)
+ gboolean is_muted,
+ gpointer *op)
{
pa_operation *o;
guint index;
+ GvcChannelMap *map;
pa_context *context;
pa_ext_stream_restore_info info;
index = gvc_mixer_stream_get_index (GVC_MIXER_STREAM (role));
- pa_cvolume_set (&info.volume, 1, (pa_volume_t)volume);
+ map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
+ info.volume = *gvc_channel_map_get_cvolume(map);
info.name = "sink-input-by-media-role:event";
- info.channel_map.channels = 1;
- info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
+ info.channel_map = *gvc_channel_map_get_pa_channel_map(map);
info.device = role->priv->device;
info.mute = is_muted;
@@ -86,18 +87,17 @@ update_settings (GvcMixerEventRole *role,
return FALSE;
}
- pa_operation_unref(o);
+ if (op != NULL)
+ *op = o;
return TRUE;
}
static gboolean
-gvc_mixer_event_role_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op)
{
return update_settings (GVC_MIXER_EVENT_ROLE (stream),
- volume,
- gvc_mixer_stream_get_is_muted (stream));
+ gvc_mixer_stream_get_is_muted (stream), op);
}
static gboolean
@@ -105,8 +105,7 @@ gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
return update_settings (GVC_MIXER_EVENT_ROLE (stream),
- gvc_mixer_stream_get_volume (stream),
- is_muted);
+ is_muted, NULL);
}
static gboolean
@@ -184,7 +183,7 @@ gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
object_class->set_property = gvc_mixer_event_role_set_property;
object_class->get_property = gvc_mixer_event_role_get_property;
- stream_class->change_volume = gvc_mixer_event_role_change_volume;
+ stream_class->push_volume = gvc_mixer_event_role_push_volume;
stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
g_object_class_install_property (object_class,
@@ -224,7 +223,8 @@ gvc_mixer_event_role_finalize (GObject *object)
GvcMixerStream *
gvc_mixer_event_role_new (pa_context *context,
- const char *device)
+ const char *device,
+ GvcChannelMap *channel_map)
{
GObject *object;
@@ -232,6 +232,7 @@ gvc_mixer_event_role_new (pa_context *context,
"pa-context", context,
"index", 0,
"device", device,
+ "channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h
index 280c597..ab4c509 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h
@@ -48,8 +48,9 @@ typedef struct
GType gvc_mixer_event_role_get_type (void);
-GvcMixerStream * gvc_mixer_event_role_new (pa_context *context,
- const char *device);
+GvcMixerStream * gvc_mixer_event_role_new (pa_context *context,
+ const char *device,
+ GvcChannelMap *channel_map);
G_END_DECLS
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c
index b2c7172..35551bb 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c
@@ -40,44 +40,33 @@ struct GvcMixerSinkInputPrivate
static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass);
static void gvc_mixer_sink_input_init (GvcMixerSinkInput *mixer_sink_input);
-static void gvc_mixer_sink_input_finalize (GObject *object);
+static void gvc_mixer_sink_input_finalize (GObject *object);
+static void gvc_mixer_sink_input_dispose (GObject *object);
G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
static gboolean
-gvc_mixer_sink_input_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
GvcChannelMap *map;
pa_context *context;
- pa_cvolume cv;
- guint i;
+ const pa_cvolume *cv;
guint num_channels;
- gdouble *gains;
index = gvc_mixer_stream_get_index (stream);
map = gvc_mixer_stream_get_channel_map (stream);
num_channels = gvc_channel_map_get_num_channels (map);
- gains = gvc_channel_map_get_gains (map);
- /* set all values to nominal level */
- pa_cvolume_set (&cv, num_channels, (pa_volume_t)volume);
-
- /* apply channel gain mapping */
- for (i = 0; i < num_channels; i++) {
- pa_volume_t v;
- v = (double) volume * gains[i];
- cv.values[i] = v;
- }
+ cv = gvc_channel_map_get_cvolume(map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_input_volume (context,
index,
- &cv,
+ cv,
NULL,
NULL);
@@ -86,7 +75,7 @@ gvc_mixer_sink_input_change_volume (GvcMixerStream *stream,
return FALSE;
}
- pa_operation_unref(o);
+ *op = o;
return TRUE;
}
@@ -140,9 +129,10 @@ gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->constructor = gvc_mixer_sink_input_constructor;
+ object_class->dispose = gvc_mixer_sink_input_dispose;
object_class->finalize = gvc_mixer_sink_input_finalize;
- stream_class->change_volume = gvc_mixer_sink_input_change_volume;
+ stream_class->push_volume = gvc_mixer_sink_input_push_volume;
stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
@@ -152,7 +142,19 @@ static void
gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
{
sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input);
+}
+
+static void
+gvc_mixer_sink_input_dispose (GObject *object)
+{
+ GvcMixerSinkInput *mixer_sink_input;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
+
+ mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
+ G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->dispose (object);
}
static void
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c
index 76eb3d7..06e5af6 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c
@@ -40,57 +40,41 @@ struct GvcMixerSinkPrivate
static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass);
static void gvc_mixer_sink_init (GvcMixerSink *mixer_sink);
-static void gvc_mixer_sink_finalize (GObject *object);
+static void gvc_mixer_sink_finalize (GObject *object);
+static void gvc_mixer_sink_dispose (GObject *object);
G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
static gboolean
-gvc_mixer_sink_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
GvcChannelMap *map;
pa_context *context;
- pa_cvolume cv;
- guint i;
- guint num_channels;
- gdouble *gains;
+ const pa_cvolume *cv;
index = gvc_mixer_stream_get_index (stream);
-
map = gvc_mixer_stream_get_channel_map (stream);
- num_channels = gvc_channel_map_get_num_channels (map);
- gains = gvc_channel_map_get_gains (map);
-
- g_debug ("Changing volume for sink: n=%d vol=%u", num_channels, (guint)volume);
- /* set all values to nominal level */
- pa_cvolume_set (&cv, num_channels, (pa_volume_t)volume);
-
- /* apply channel gain mapping */
- for (i = 0; i < num_channels; i++) {
- pa_volume_t v;
- v = (double) volume * gains[i];
- g_debug ("Channel %d v=%u", i, v);
- cv.values[i] = v;
- }
+ /* set the volume */
+ cv = gvc_channel_map_get_cvolume(map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_volume_by_index (context,
index,
- &cv,
+ cv,
NULL,
NULL);
if (o == NULL) {
- g_warning ("pa_context_set_sink_volume_by_index() failed");
+ g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
- pa_operation_unref(o);
+ *op = o;
return TRUE;
}
@@ -113,7 +97,7 @@ gvc_mixer_sink_change_is_muted (GvcMixerStream *stream,
NULL);
if (o == NULL) {
- g_warning ("pa_context_set_sink_mute_by_index() failed");
+ g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
@@ -127,7 +111,7 @@ gvc_mixer_sink_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
- GObject *object;
+ GObject *object;
GvcMixerSink *self;
object = G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->constructor (type, n_construct_properties, construct_params);
@@ -144,9 +128,10 @@ gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->constructor = gvc_mixer_sink_constructor;
+ object_class->dispose = gvc_mixer_sink_dispose;
object_class->finalize = gvc_mixer_sink_finalize;
- stream_class->change_volume = gvc_mixer_sink_change_volume;
+ stream_class->push_volume = gvc_mixer_sink_push_volume;
stream_class->change_is_muted = gvc_mixer_sink_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate));
@@ -156,7 +141,19 @@ static void
gvc_mixer_sink_init (GvcMixerSink *sink)
{
sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
+}
+
+static void
+gvc_mixer_sink_dispose (GObject *object)
+{
+ GvcMixerSink *mixer_sink;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK (object));
+
+ mixer_sink = GVC_MIXER_SINK (object);
+ G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->dispose (object);
}
static void
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c
index b71ad23..b4cc34d 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c
@@ -45,10 +45,10 @@ static void gvc_mixer_source_output_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
static gboolean
-gvc_mixer_source_output_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op)
{
/* FIXME: */
+ *op = NULL;
return TRUE;
}
@@ -84,7 +84,7 @@ gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
object_class->constructor = gvc_mixer_source_output_constructor;
object_class->finalize = gvc_mixer_source_output_finalize;
- stream_class->change_volume = gvc_mixer_source_output_change_volume;
+ stream_class->push_volume = gvc_mixer_source_output_push_volume;
stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source.c b/plugins/media-keys/cut-n-paste/gvc-mixer-source.c
index de1b09e..ae02d85 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-source.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source.c
@@ -41,53 +41,40 @@ struct GvcMixerSourcePrivate
static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass);
static void gvc_mixer_source_init (GvcMixerSource *mixer_source);
static void gvc_mixer_source_finalize (GObject *object);
+static void gvc_mixer_source_dispose (GObject *object);
G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
static gboolean
-gvc_mixer_source_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
GvcChannelMap *map;
pa_context *context;
- pa_cvolume cv;
- guint num_channels;
- guint i;
- gdouble *gains;
+ const pa_cvolume *cv;
index = gvc_mixer_stream_get_index (stream);
map = gvc_mixer_stream_get_channel_map (stream);
- num_channels = gvc_channel_map_get_num_channels (map);
- gains = gvc_channel_map_get_gains (map);
- /* set all values to nominal level */
- pa_cvolume_set (&cv, num_channels, (pa_volume_t)volume);
-
-
- /* apply channel gain mapping */
- for (i = 0; i < num_channels; i++) {
- pa_volume_t v;
- v = (double) volume * gains[i];
- cv.values[i] = v;
- }
+ /* set the volume */
+ cv = gvc_channel_map_get_cvolume (map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_source_volume_by_index (context,
index,
- &cv,
+ cv,
NULL,
NULL);
if (o == NULL) {
- g_warning ("pa_context_set_source_volume_by_index() failed");
+ g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
- pa_operation_unref(o);
+ *op = o;
return TRUE;
}
@@ -110,7 +97,7 @@ gvc_mixer_source_change_is_muted (GvcMixerStream *stream,
NULL);
if (o == NULL) {
- g_warning ("pa_context_set_source_mute_by_index() failed");
+ g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
@@ -124,7 +111,7 @@ gvc_mixer_source_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
- GObject *object;
+ GObject *object;
GvcMixerSource *self;
object = G_OBJECT_CLASS (gvc_mixer_source_parent_class)->constructor (type, n_construct_properties, construct_params);
@@ -141,9 +128,10 @@ gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->constructor = gvc_mixer_source_constructor;
+ object_class->dispose = gvc_mixer_source_dispose;
object_class->finalize = gvc_mixer_source_finalize;
- stream_class->change_volume = gvc_mixer_source_change_volume;
+ stream_class->push_volume = gvc_mixer_source_push_volume;
stream_class->change_is_muted = gvc_mixer_source_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
@@ -153,7 +141,19 @@ static void
gvc_mixer_source_init (GvcMixerSource *source)
{
source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source);
+}
+
+static void
+gvc_mixer_source_dispose (GObject *object)
+{
+ GvcMixerSource *mixer_source;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
+
+ mixer_source = GVC_MIXER_SOURCE (object);
+ G_OBJECT_CLASS (gvc_mixer_source_parent_class)->dispose (object);
}
static void
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c
index 69d8598..e5cfb19 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c
@@ -41,13 +41,16 @@ struct GvcMixerStreamPrivate
guint id;
guint index;
GvcChannelMap *channel_map;
- guint volume;
- gdouble decibel;
char *name;
char *description;
+ char *application_id;
char *icon_name;
gboolean is_muted;
gboolean can_decibel;
+ gboolean is_event_stream;
+ gboolean is_virtual;
+ pa_volume_t base_volume;
+ pa_operation *change_volume_op;
};
enum
@@ -59,11 +62,14 @@ enum
PROP_INDEX,
PROP_NAME,
PROP_DESCRIPTION,
+ PROP_APPLICATION_ID,
PROP_ICON_NAME,
PROP_VOLUME,
PROP_DECIBEL,
PROP_IS_MUTED,
- PROP_CAN_DECIBEL
+ PROP_CAN_DECIBEL,
+ PROP_IS_EVENT_STREAM,
+ PROP_IS_VIRTUAL,
};
static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass);
@@ -114,28 +120,36 @@ gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
return stream->priv->channel_map;
}
-guint
+pa_volume_t
gvc_mixer_stream_get_volume (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
- return stream->priv->volume;
+
+ return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
}
gdouble
gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
- return stream->priv->decibel;
+
+ return pa_sw_volume_to_dB(
+ (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
}
gboolean
gvc_mixer_stream_set_volume (GvcMixerStream *stream,
- pa_volume_t volume)
+ pa_volume_t volume)
{
+ pa_cvolume cv;
+
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
- if (volume != stream->priv->volume) {
- stream->priv->volume = volume;
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+ pa_cvolume_scale(&cv, volume);
+
+ if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+ gvc_channel_map_volume_changed(stream->priv->channel_map, &cv);
g_object_notify (G_OBJECT (stream), "volume");
}
@@ -146,11 +160,16 @@ gboolean
gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
gdouble db)
{
+ pa_cvolume cv;
+
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
- if (db != stream->priv->decibel) {
- stream->priv->decibel = db;
- g_object_notify (G_OBJECT (stream), "decibel");
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+ pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
+
+ if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+ gvc_channel_map_volume_changed(stream->priv->channel_map, &cv);
+ g_object_notify (G_OBJECT (stream), "volume");
}
return TRUE;
@@ -238,12 +257,73 @@ gvc_mixer_stream_set_description (GvcMixerStream *stream,
return TRUE;
}
+gboolean
+gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ return stream->priv->is_event_stream;
+}
+
+gboolean
+gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
+ gboolean is_event_stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->is_event_stream = is_event_stream;
+ g_object_notify (G_OBJECT (stream), "is-event-stream");
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ return stream->priv->is_virtual;
+}
+
+gboolean
+gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
+ gboolean is_virtual)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->is_virtual = is_virtual;
+ g_object_notify (G_OBJECT (stream), "is-virtual");
+
+ return TRUE;
+}
+
+const char *
+gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->application_id;
+}
+
+gboolean
+gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
+ const char *application_id)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ g_free (stream->priv->application_id);
+ stream->priv->application_id = g_strdup (application_id);
+ g_object_notify (G_OBJECT (stream), "application-id");
+
+ return TRUE;
+}
+
static void
-on_channel_map_gains_changed (GvcChannelMap *channel_map,
- GvcMixerStream *stream)
+on_channel_map_volume_changed (GvcChannelMap *channel_map,
+ GvcMixerStream *stream)
{
- g_debug ("Gains changed");
- gvc_mixer_stream_change_volume (stream, stream->priv->volume);
+ gvc_mixer_stream_push_volume (stream);
+
+ g_object_notify (G_OBJECT (stream), "volume");
}
static gboolean
@@ -258,7 +338,7 @@ gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
if (stream->priv->channel_map != NULL) {
g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
- on_channel_map_gains_changed,
+ on_channel_map_volume_changed,
stream);
g_object_unref (stream->priv->channel_map);
}
@@ -267,8 +347,8 @@ gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
if (stream->priv->channel_map != NULL) {
g_signal_connect (stream->priv->channel_map,
- "gains-changed",
- G_CALLBACK (on_channel_map_gains_changed),
+ "volume-changed",
+ G_CALLBACK (on_channel_map_volume_changed),
stream);
g_object_notify (G_OBJECT (stream), "channel-map");
@@ -297,6 +377,25 @@ gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
return TRUE;
}
+pa_volume_t
+gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+
+ return stream->priv->base_volume;
+}
+
+gboolean
+gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
+ pa_volume_t base_volume)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->base_volume = base_volume;
+
+ return TRUE;
+}
+
static void
gvc_mixer_stream_set_property (GObject *object,
guint prop_id,
@@ -324,6 +423,9 @@ gvc_mixer_stream_set_property (GObject *object,
case PROP_DESCRIPTION:
gvc_mixer_stream_set_description (self, g_value_get_string (value));
break;
+ case PROP_APPLICATION_ID:
+ gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
+ break;
case PROP_ICON_NAME:
gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
break;
@@ -336,6 +438,12 @@ gvc_mixer_stream_set_property (GObject *object,
case PROP_IS_MUTED:
gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
break;
+ case PROP_IS_EVENT_STREAM:
+ gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
+ break;
+ case PROP_IS_VIRTUAL:
+ gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
+ break;
case PROP_CAN_DECIBEL:
gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
break;
@@ -372,18 +480,29 @@ gvc_mixer_stream_get_property (GObject *object,
case PROP_DESCRIPTION:
g_value_set_string (value, self->priv->description);
break;
+ case PROP_APPLICATION_ID:
+ g_value_set_string (value, self->priv->application_id);
+ break;
case PROP_ICON_NAME:
g_value_set_string (value, self->priv->icon_name);
break;
case PROP_VOLUME:
- g_value_set_ulong (value, self->priv->volume);
+ g_value_set_ulong (value,
+ pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
break;
case PROP_DECIBEL:
- g_value_set_double (value, self->priv->decibel);
+ g_value_set_double (value,
+ pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
break;
case PROP_IS_MUTED:
g_value_set_boolean (value, self->priv->is_muted);
break;
+ case PROP_IS_EVENT_STREAM:
+ g_value_set_boolean (value, self->priv->is_event_stream);
+ break;
+ case PROP_IS_VIRTUAL:
+ g_value_set_boolean (value, self->priv->is_virtual);
+ break;
case PROP_CAN_DECIBEL:
g_value_set_boolean (value, self->priv->can_decibel);
break;
@@ -411,8 +530,7 @@ gvc_mixer_stream_constructor (GType type,
}
static gboolean
-gvc_mixer_stream_real_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
{
return FALSE;
}
@@ -425,12 +543,17 @@ gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
}
gboolean
-gvc_mixer_stream_change_volume (GvcMixerStream *stream,
- guint volume)
+gvc_mixer_stream_push_volume (GvcMixerStream *stream)
{
+ pa_operation *op;
gboolean ret;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
- ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_volume (stream, volume);
+ ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
+ if (ret) {
+ if (stream->priv->change_volume_op != NULL)
+ pa_operation_unref (stream->priv->change_volume_op);
+ stream->priv->change_volume_op = op;
+ }
return ret;
}
@@ -444,6 +567,21 @@ gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
return ret;
}
+gboolean
+gvc_mixer_stream_is_running (GvcMixerStream *stream)
+{
+ if (stream->priv->change_volume_op == NULL)
+ return FALSE;
+
+ if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
+ return TRUE;
+
+ pa_operation_unref(stream->priv->change_volume_op);
+ stream->priv->change_volume_op = NULL;
+
+ return FALSE;
+}
+
static void
gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
{
@@ -454,7 +592,7 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
gobject_class->set_property = gvc_mixer_stream_set_property;
gobject_class->get_property = gvc_mixer_stream_get_property;
- klass->change_volume = gvc_mixer_stream_real_change_volume;
+ klass->push_volume = gvc_mixer_stream_real_push_volume;
klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
g_object_class_install_property (gobject_class,
@@ -490,7 +628,7 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
"Volume",
"The volume for this stream",
0, G_MAXULONG, 0,
- G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DECIBEL,
g_param_spec_double ("decibel",
@@ -514,6 +652,13 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
+ PROP_APPLICATION_ID,
+ g_param_spec_string ("application-id",
+ "Application identifier",
+ "Application identifier for this stream",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
PROP_ICON_NAME,
g_param_spec_string ("icon-name",
"Icon Name",
@@ -534,7 +679,20 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
"Whether stream volume can be converted to decibel units",
FALSE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
-
+ g_object_class_install_property (gobject_class,
+ PROP_IS_EVENT_STREAM,
+ g_param_spec_boolean ("is-event-stream",
+ "is event stream",
+ "Whether stream's role is to play an event",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_IS_VIRTUAL,
+ g_param_spec_boolean ("is-virtual",
+ "is virtual stream",
+ "Whether the stream is virtual",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate));
}
@@ -542,7 +700,6 @@ static void
gvc_mixer_stream_init (GvcMixerStream *stream)
{
stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
-
}
static void
@@ -563,8 +720,16 @@ gvc_mixer_stream_finalize (GObject *object)
g_free (mixer_stream->priv->description);
mixer_stream->priv->description = NULL;
+ g_free (mixer_stream->priv->application_id);
+ mixer_stream->priv->application_id = NULL;
+
g_free (mixer_stream->priv->icon_name);
mixer_stream->priv->icon_name = NULL;
+ if (mixer_stream->priv->change_volume_op) {
+ pa_operation_unref(mixer_stream->priv->change_volume_op);
+ mixer_stream->priv->change_volume_op = NULL;
+ }
+
G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h
index 3dee03b..4171ca3 100644
--- a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h
@@ -48,8 +48,7 @@ typedef struct
GObjectClass parent_class;
/* vtable */
- gboolean (*change_volume) (GvcMixerStream *stream,
- guint volume);
+ gboolean (*push_volume) (GvcMixerStream *stream, gpointer *operation);
gboolean (*change_is_muted) (GvcMixerStream *stream,
gboolean is_muted);
} GvcMixerStreamClass;
@@ -61,22 +60,26 @@ guint gvc_mixer_stream_get_index (GvcMixerStream *stream);
guint gvc_mixer_stream_get_id (GvcMixerStream *stream);
GvcChannelMap * gvc_mixer_stream_get_channel_map (GvcMixerStream *stream);
-guint gvc_mixer_stream_get_volume (GvcMixerStream *stream);
+pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream);
gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream);
-gboolean gvc_mixer_stream_change_volume (GvcMixerStream *stream,
- guint volume);
+gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream);
+pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream);
gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream);
gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
gboolean is_muted);
+gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_name (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_description (GvcMixerStream *stream);
+const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream);
/* private */
gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream,
- guint volume);
+ pa_volume_t volume);
gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
gdouble db);
gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
@@ -89,6 +92,14 @@ gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream,
const char *description);
gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
const char *name);
+gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
+ gboolean is_event_stream);
+gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
+ gboolean is_event_stream);
+gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
+ const char *application_id);
+gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
+ pa_volume_t base_volume);
G_END_DECLS
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index d35048c..3eeea71 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -687,17 +687,17 @@ do_sound_action (GsdMediaKeysManager *manager,
if (!muted && (vol <= norm_vol_step)) {
manager->priv->num_expected_update_signals = 2;
gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
- gvc_mixer_stream_change_volume (manager->priv->stream, 0);
+ gvc_mixer_stream_set_volume (manager->priv->stream, 0);
} else if (!muted) {
manager->priv->num_expected_update_signals = 1;
- gvc_mixer_stream_change_volume (manager->priv->stream, vol - norm_vol_step);
+ gvc_mixer_stream_set_volume (manager->priv->stream, vol - norm_vol_step);
}
break;
case VOLUME_UP_KEY:
if (muted) {
if (vol == 0) {
manager->priv->num_expected_update_signals = 2;
- gvc_mixer_stream_change_volume (manager->priv->stream, vol + norm_vol_step);
+ gvc_mixer_stream_set_volume (manager->priv->stream, vol + norm_vol_step);
gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
} else {
manager->priv->num_expected_update_signals = 1;
@@ -707,9 +707,9 @@ do_sound_action (GsdMediaKeysManager *manager,
if (vol < MAX_VOLUME) {
manager->priv->num_expected_update_signals = 1;
if (vol + norm_vol_step >= MAX_VOLUME) {
- gvc_mixer_stream_change_volume (manager->priv->stream, MAX_VOLUME);
+ gvc_mixer_stream_set_volume (manager->priv->stream, MAX_VOLUME);
} else {
- gvc_mixer_stream_change_volume (manager->priv->stream, vol + norm_vol_step);
+ gvc_mixer_stream_set_volume (manager->priv->stream, vol + norm_vol_step);
}
}
}
--
1.6.2.5