summaryrefslogtreecommitdiff
path: root/backends/pulse
diff options
context:
space:
mode:
authorStefano Karapetsas <[email protected]>2014-10-09 15:59:09 +0200
committerStefano Karapetsas <[email protected]>2014-10-09 15:59:09 +0200
commit526fdf477edc40452c18b51e13cbdffaa69de52b (patch)
treedd73763b097fca2a86288bcb55881a96f3e5faaf /backends/pulse
parentb4695e82ae0cc3183e9d3be4fca191394292609f (diff)
parent0ab66491e3847f6de92fc5358e9687c6d2f458ce (diff)
downloadlibmatemixer-526fdf477edc40452c18b51e13cbdffaa69de52b.tar.bz2
libmatemixer-526fdf477edc40452c18b51e13cbdffaa69de52b.tar.xz
Merge branch 'after-gsoc'
Diffstat (limited to 'backends/pulse')
-rw-r--r--backends/pulse/pulse-backend.c31
-rw-r--r--backends/pulse/pulse-device.c9
-rw-r--r--backends/pulse/pulse-ext-stream.c520
-rw-r--r--backends/pulse/pulse-ext-stream.h4
-rw-r--r--backends/pulse/pulse-port-switch.c20
-rw-r--r--backends/pulse/pulse-sink.c2
-rw-r--r--backends/pulse/pulse-source.c2
-rw-r--r--backends/pulse/pulse-stream-control.c2
-rw-r--r--backends/pulse/pulse-stream.c5
9 files changed, 455 insertions, 140 deletions
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index e1b7ed5..4c0697a 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -38,6 +38,10 @@
#define BACKEND_NAME "PulseAudio"
#define BACKEND_PRIORITY 100
+#define BACKEND_FLAGS (MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS | \
+ MATE_MIXER_BACKEND_HAS_STORED_CONTROLS | \
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM | \
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM)
struct _PulseBackendPrivate
{
@@ -99,8 +103,7 @@ struct _PulseBackendPrivate
NULL))
#define PULSE_GET_HANGING(o) \
- ((gboolean) g_object_get_data (G_OBJECT (o), \
- "__matemixer_pulse_hanging"))
+ ((gboolean) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (o), "__matemixer_pulse_hanging")))
#define PULSE_SET_HANGING(o) \
(g_object_set_data (G_OBJECT (o), \
@@ -210,10 +213,11 @@ backend_module_init (GTypeModule *module)
{
pulse_backend_register_type (module);
- info.name = BACKEND_NAME;
- info.priority = BACKEND_PRIORITY;
- info.g_type = PULSE_TYPE_BACKEND;
- info.backend_type = MATE_MIXER_BACKEND_PULSEAUDIO;
+ info.name = BACKEND_NAME;
+ info.priority = BACKEND_PRIORITY;
+ info.g_type = PULSE_TYPE_BACKEND;
+ info.backend_flags = BACKEND_FLAGS;
+ info.backend_type = MATE_MIXER_BACKEND_PULSEAUDIO;
}
const MateMixerBackendInfo *backend_module_get_info (void)
@@ -433,11 +437,6 @@ pulse_backend_open (MateMixerBackend *backend)
return FALSE;
}
- _mate_mixer_backend_set_flags (backend,
- MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS |
- MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM |
- MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM);
-
pulse->priv->connection = connection;
return TRUE;
}
@@ -762,7 +761,7 @@ on_connection_card_info (PulseConnection *connection,
g_hash_table_insert (pulse->priv->devices,
GUINT_TO_POINTER (info->index),
- device);
+ g_object_ref (device));
free_list_devices (pulse);
g_signal_emit_by_name (G_OBJECT (pulse),
@@ -814,7 +813,7 @@ on_connection_sink_info (PulseConnection *connection,
free_list_streams (pulse);
g_hash_table_insert (pulse->priv->sinks,
GUINT_TO_POINTER (info->index),
- stream);
+ g_object_ref (stream));
if (device != NULL) {
pulse_device_add_stream (device, stream);
@@ -932,7 +931,7 @@ on_connection_source_info (PulseConnection *connection,
free_list_streams (pulse);
g_hash_table_insert (pulse->priv->sources,
GUINT_TO_POINTER (info->index),
- stream);
+ g_object_ref (stream));
if (device != NULL) {
pulse_device_add_stream (device, stream);
@@ -1051,7 +1050,7 @@ on_connection_ext_stream_info (PulseConnection *connection,
free_list_ext_streams (pulse);
g_hash_table_insert (pulse->priv->ext_streams,
g_strdup (info->name),
- ext);
+ g_object_ref (ext));
g_signal_emit_by_name (G_OBJECT (pulse),
"stored-control-added",
@@ -1091,7 +1090,7 @@ on_connection_ext_stream_loaded (PulseConnection *connection, PulseBackend *puls
continue;
free_list_ext_streams (pulse);
- g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
+ g_hash_table_iter_remove (&iter);
g_signal_emit_by_name (G_OBJECT (pulse),
"stored-control-removed",
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index 5403712..9f33132 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -281,7 +281,10 @@ pulse_device_add_stream (PulseDevice *device, PulseStream *stream)
free_list_streams (device);
- g_hash_table_insert (device->priv->streams, g_strdup (name), stream);
+ g_hash_table_insert (device->priv->streams,
+ g_strdup (name),
+ g_object_ref (stream));
+
g_signal_emit_by_name (G_OBJECT (device),
"stream-added",
name);
@@ -382,7 +385,9 @@ pulse_device_load (PulseDevice *device, const pa_card_info *info)
icon,
info->ports[i]->priority);
- g_hash_table_insert (device->priv->ports, g_strdup (name), port);
+ g_hash_table_insert (device->priv->ports,
+ g_strdup (name),
+ g_object_ref (port));
}
#endif
diff --git a/backends/pulse/pulse-ext-stream.c b/backends/pulse/pulse-ext-stream.c
index 3e7490a..48b11d1 100644
--- a/backends/pulse/pulse-ext-stream.c
+++ b/backends/pulse/pulse-ext-stream.c
@@ -33,16 +33,20 @@
struct _PulseExtStreamPrivate
{
- MateMixerAppInfo *app_info;
- MateMixerDirection direction;
+ guint volume;
+ pa_cvolume cvolume;
+ pa_channel_map channel_map;
+ MateMixerAppInfo *app_info;
+ PulseConnection *connection;
};
enum {
PROP_0,
- PROP_DIRECTION
+ PROP_CONNECTION,
+ N_PROPERTIES
};
-static void mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void pulse_ext_stream_class_init (PulseExtStreamClass *klass);
@@ -56,52 +60,95 @@ static void pulse_ext_stream_set_property (GObject *object,
GParamSpec *pspec);
static void pulse_ext_stream_init (PulseExtStream *ext);
+static void pulse_ext_stream_dispose (GObject *object);
+static void pulse_ext_stream_finalize (GObject *object);
-G_DEFINE_TYPE_WITH_CODE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_STREAM_CONTROL,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STORED_CONTROL,
- mate_mixer_stored_control_interface_init))
+G_DEFINE_TYPE (PulseExtStream, pulse_ext_stream, MATE_MIXER_TYPE_STORED_CONTROL)
-static MateMixerDirection pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc);
+static MateMixerAppInfo * pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc);
-static MateMixerAppInfo * pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc);
+static gboolean pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc,
+ MateMixerStream *mms);
-static gboolean pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc,
- MateMixerStream *mms);
+static gboolean pulse_ext_stream_set_mute (MateMixerStreamControl *mmsc,
+ gboolean mute);
-static gboolean pulse_ext_stream_set_mute (PulseStreamControl *control,
- gboolean mute);
-static gboolean pulse_ext_stream_set_volume (PulseStreamControl *control,
- pa_cvolume *cvolume);
+static guint pulse_ext_stream_get_num_channels (MateMixerStreamControl *mmsc);
-static void fill_ext_stream_restore_info (PulseStreamControl *control,
- pa_ext_stream_restore_info *info);
+static guint pulse_ext_stream_get_volume (MateMixerStreamControl *mmsc);
+static gboolean pulse_ext_stream_set_volume (MateMixerStreamControl *mmsc,
+ guint volume);
-static void
-mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface)
-{
- iface->get_direction = pulse_ext_stream_get_direction;
-}
+static guint pulse_ext_stream_get_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_ext_stream_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume);
+
+static MateMixerChannelPosition pulse_ext_stream_get_channel_position (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_ext_stream_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position);
+
+static gboolean pulse_ext_stream_set_balance (MateMixerStreamControl *mmsc,
+ gfloat balance);
+
+static gboolean pulse_ext_stream_set_fade (MateMixerStreamControl *mmsc,
+ gfloat fade);
+
+static guint pulse_ext_stream_get_min_volume (MateMixerStreamControl *mmsc);
+static guint pulse_ext_stream_get_max_volume (MateMixerStreamControl *mmsc);
+static guint pulse_ext_stream_get_normal_volume (MateMixerStreamControl *mmsc);
+static guint pulse_ext_stream_get_base_volume (MateMixerStreamControl *mmsc);
+
+static void fill_ext_stream_restore_info (PulseExtStream *ext,
+ pa_ext_stream_restore_info *info);
+
+static gboolean write_cvolume (PulseExtStream *ext,
+ const pa_cvolume *cvolume);
+static void store_cvolume (PulseExtStream *ext,
+ const pa_cvolume *cvolume);
static void
pulse_ext_stream_class_init (PulseExtStreamClass *klass)
{
GObjectClass *object_class;
MateMixerStreamControlClass *control_class;
- PulseStreamControlClass *pulse_class;
object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_ext_stream_dispose;
+ object_class->finalize = pulse_ext_stream_finalize;
object_class->get_property = pulse_ext_stream_get_property;
object_class->set_property = pulse_ext_stream_set_property;
control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
- control_class->get_app_info = pulse_ext_stream_get_app_info;
- control_class->set_stream = pulse_ext_stream_set_stream;
-
- pulse_class = PULSE_STREAM_CONTROL_CLASS (klass);
- pulse_class->set_mute = pulse_ext_stream_set_mute;
- pulse_class->set_volume = pulse_ext_stream_set_volume;
-
- g_object_class_override_property (object_class, PROP_DIRECTION, "direction");
+ control_class->get_app_info = pulse_ext_stream_get_app_info;
+ control_class->set_stream = pulse_ext_stream_set_stream;
+ control_class->set_mute = pulse_ext_stream_set_mute;
+ control_class->get_num_channels = pulse_ext_stream_get_num_channels;
+ control_class->get_volume = pulse_ext_stream_get_volume;
+ control_class->set_volume = pulse_ext_stream_set_volume;
+ control_class->get_channel_volume = pulse_ext_stream_get_channel_volume;
+ control_class->set_channel_volume = pulse_ext_stream_set_channel_volume;
+ control_class->get_channel_position = pulse_ext_stream_get_channel_position;
+ control_class->has_channel_position = pulse_ext_stream_has_channel_position;
+ control_class->set_balance = pulse_ext_stream_set_balance;
+ control_class->set_fade = pulse_ext_stream_set_fade;
+ control_class->get_min_volume = pulse_ext_stream_get_min_volume;
+ control_class->get_max_volume = pulse_ext_stream_get_max_volume;
+ control_class->get_normal_volume = pulse_ext_stream_get_normal_volume;
+ control_class->get_base_volume = pulse_ext_stream_get_base_volume;
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (PulseExtStreamPrivate));
}
@@ -117,8 +164,8 @@ pulse_ext_stream_get_property (GObject *object,
ext = PULSE_EXT_STREAM (object);
switch (param_id) {
- case PROP_DIRECTION:
- g_value_set_enum (value, ext->priv->direction);
+ case PROP_CONNECTION:
+ g_value_set_object (value, ext->priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -137,8 +184,9 @@ pulse_ext_stream_set_property (GObject *object,
ext = PULSE_EXT_STREAM (object);
switch (param_id) {
- case PROP_DIRECTION:
- ext->priv->direction = g_value_get_enum (value);
+ case PROP_CONNECTION:
+ /* Construct-only object */
+ ext->priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -154,26 +202,61 @@ pulse_ext_stream_init (PulseExtStream *ext)
PulseExtStreamPrivate);
}
+static void
+pulse_ext_stream_dispose (GObject *object)
+{
+ PulseExtStream *ext;
+
+ ext = PULSE_EXT_STREAM (object);
+
+ g_clear_object (&ext->priv->connection);
+
+ G_OBJECT_CLASS (pulse_ext_stream_parent_class)->dispose (object);
+}
+
+static void
+pulse_ext_stream_finalize (GObject *object)
+{
+ PulseExtStream *ext;
+
+ ext = PULSE_EXT_STREAM (object);
+
+ if (ext->priv->app_info != NULL)
+ _mate_mixer_app_info_free (ext->priv->app_info);
+
+ G_OBJECT_CLASS (pulse_ext_stream_parent_class)->finalize (object);
+}
+
PulseExtStream *
pulse_ext_stream_new (PulseConnection *connection,
const pa_ext_stream_restore_info *info,
PulseStream *parent)
{
- PulseExtStream *ext;
- gchar *suffix;
- MateMixerDirection direction;
- MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
- MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
- MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
- MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE;
- MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- MateMixerAppInfo *app_info;
-
- MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
+ PulseExtStream *ext;
+ gchar *suffix;
+ MateMixerAppInfo *app_info = NULL;
+ MateMixerDirection direction;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_MOVABLE |
+ MATE_MIXER_STREAM_CONTROL_STORED;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
+ MateMixerStreamControlMediaRole media_role =
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
+ /* The name of an ext-stream is in one of the following formats:
+ * sink-input-by-media-role: ...
+ * sink-input-by-application-name: ...
+ * sink-input-by-application-id: ...
+ * sink-input-by-media-name: ...
+ * source-output-by-media-role: ...
+ * source-output-by-application-name: ...
+ * source-output-by-application-id: ...
+ * source-output-by-media-name: ...
+ */
if (g_str_has_prefix (info->name, "sink-input"))
direction = MATE_MIXER_DIRECTION_OUTPUT;
else if (g_str_has_prefix (info->name, "source-output"))
@@ -181,26 +264,36 @@ pulse_ext_stream_new (PulseConnection *connection,
else
direction = MATE_MIXER_DIRECTION_UNKNOWN;
- app_info = _mate_mixer_app_info_new ();
-
suffix = strchr (info->name, ':');
if (suffix != NULL)
suffix++;
if (strstr (info->name, "-by-media-role:")) {
- if (G_LIKELY (suffix != NULL))
+ if G_LIKELY (suffix != NULL)
media_role = pulse_convert_media_role_name (suffix);
}
else if (strstr (info->name, "-by-application-name:")) {
role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- if (G_LIKELY (suffix != NULL))
+ /* Make sure an application ext-stream always has a MateMixerAppInfo
+ * structure available, even in the case no application info is
+ * available */
+ if (app_info == NULL)
+ app_info = _mate_mixer_app_info_new ();
+
+ if G_LIKELY (suffix != NULL)
_mate_mixer_app_info_set_name (app_info, suffix);
}
else if (strstr (info->name, "-by-application-id:")) {
role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- if (G_LIKELY (suffix != NULL))
+ /* Make sure an application ext-stream always has a MateMixerAppInfo
+ * structure available, even in the case no application info is
+ * available */
+ if (app_info == NULL)
+ app_info = _mate_mixer_app_info_new ();
+
+ if G_LIKELY (suffix != NULL)
_mate_mixer_app_info_set_id (app_info, suffix);
}
@@ -214,12 +307,12 @@ pulse_ext_stream_new (PulseConnection *connection,
"stream", parent,
NULL);
- if (role == MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION)
- ext->priv->app_info = app_info;
- else
- _mate_mixer_app_info_free (app_info);
+ // XXX property?
+ ext->priv->app_info = app_info;
+ /* Store values which are expected to be changed */
pulse_ext_stream_update (ext, info, parent);
+
return ext;
}
@@ -228,6 +321,9 @@ pulse_ext_stream_update (PulseExtStream *ext,
const pa_ext_stream_restore_info *info,
PulseStream *parent)
{
+ MateMixerStreamControlFlags flags;
+ gboolean volume_changed = FALSE;
+
g_return_if_fail (PULSE_IS_EXT_STREAM (ext));
g_return_if_fail (info != NULL);
@@ -237,27 +333,54 @@ pulse_ext_stream_update (PulseExtStream *ext,
_mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (ext),
info->mute ? TRUE : FALSE);
- pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (ext),
- &info->channel_map);
+ flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (ext));
+
+ if (pa_channel_map_valid (&info->channel_map) != 0) {
+ if (pa_channel_map_can_balance (&info->channel_map) != 0)
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ if (pa_channel_map_can_fade (&info->channel_map) != 0)
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+
+ ext->priv->channel_map = info->channel_map;
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_CAN_BALANCE | MATE_MIXER_STREAM_CONTROL_CAN_FADE);
+
+ /* If the channel map is not valid, create an empty channel map, which
+ * also won't validate, but at least we know what it is */
+ pa_channel_map_init (&ext->priv->channel_map);
+ }
- pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (ext),
- &info->volume,
- 0);
+ if (pa_cvolume_valid (&info->volume) != 0) {
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
+ if (pa_cvolume_equal (&ext->priv->cvolume, &info->volume) == 0)
+ volume_changed = TRUE;
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE);
+
+ if (ext->priv->volume != (guint) PA_VOLUME_MUTED)
+ volume_changed = TRUE;
+ }
+
+ if (volume_changed == TRUE)
+ store_cvolume (ext, &info->volume);
+
+ _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (ext), flags);
+
+ /* Also set initially, but may change at any time */
_mate_mixer_stream_control_set_stream (MATE_MIXER_STREAM_CONTROL (ext),
MATE_MIXER_STREAM (parent));
g_object_thaw_notify (G_OBJECT (ext));
}
-static MateMixerDirection
-pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc)
-{
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), MATE_MIXER_DIRECTION_UNKNOWN);
-
- return PULSE_EXT_STREAM (mmsc)->priv->direction;
-}
-
static MateMixerAppInfo *
pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc)
{
@@ -269,76 +392,277 @@ pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc)
static gboolean
pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc, MateMixerStream *mms)
{
+ PulseExtStream *ext;
pa_ext_stream_restore_info info;
g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
g_return_val_if_fail (mms == NULL || PULSE_IS_STREAM (mms), FALSE);
- fill_ext_stream_restore_info (PULSE_STREAM_CONTROL (mms), &info);
+ ext = PULSE_EXT_STREAM (mmsc);
+ fill_ext_stream_restore_info (ext, &info);
if (mms != NULL)
info.device = mate_mixer_stream_get_name (mms);
else
info.device = NULL;
- return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (PULSE_STREAM_CONTROL (mmsc)),
- &info);
+ return pulse_connection_write_ext_stream (ext->priv->connection, &info);
}
static gboolean
-pulse_ext_stream_set_mute (PulseStreamControl *control, gboolean mute)
+pulse_ext_stream_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
{
+ PulseExtStream *ext;
pa_ext_stream_restore_info info;
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
- fill_ext_stream_restore_info (control, &info);
+ ext = PULSE_EXT_STREAM (mmsc);
+ fill_ext_stream_restore_info (ext, &info);
info.mute = mute;
- return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
- &info);
+ return pulse_connection_write_ext_stream (ext->priv->connection, &info);
+}
+
+static guint
+pulse_ext_stream_get_num_channels (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), 0);
+
+ return PULSE_EXT_STREAM (mmsc)->priv->channel_map.channels;
+}
+
+static guint
+pulse_ext_stream_get_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return PULSE_EXT_STREAM (mmsc)->priv->volume;
}
static gboolean
-pulse_ext_stream_set_volume (PulseStreamControl *control, pa_cvolume *cvolume)
+pulse_ext_stream_set_volume (MateMixerStreamControl *mmsc, guint volume)
{
- pa_ext_stream_restore_info info;
+ PulseExtStream *ext;
+ pa_cvolume cvolume;
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
- fill_ext_stream_restore_info (control, &info);
+ ext = PULSE_EXT_STREAM (mmsc);
+ cvolume = ext->priv->cvolume;
- info.volume = *cvolume;
+ /* Modify a temporary cvolume structure as the change may be irreversible */
+ if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
+ return FALSE;
+
+ return write_cvolume (ext, &cvolume);
+}
+
+static guint
+pulse_ext_stream_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseExtStream *ext;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), (guint) PA_VOLUME_MUTED);
+
+ ext = PULSE_EXT_STREAM (mmsc);
+
+ if (channel >= ext->priv->cvolume.channels)
+ return (guint) PA_VOLUME_MUTED;
+
+ return (guint) ext->priv->cvolume.values[channel];
+}
+
+static gboolean
+pulse_ext_stream_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume)
+{
+ PulseExtStream *ext;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+
+ ext = PULSE_EXT_STREAM (mmsc);
- return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
- &info);
+ if (channel >= ext->priv->cvolume.channels)
+ return FALSE;
+
+ /* Modify a temporary cvolume structure as the change may be irreversible */
+ cvolume = ext->priv->cvolume;
+ cvolume.values[channel] = (pa_volume_t) volume;
+
+ return write_cvolume (ext, &cvolume);
+}
+
+static MateMixerChannelPosition
+pulse_ext_stream_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseExtStream *ext;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ ext = PULSE_EXT_STREAM (mmsc);
+
+ if (channel >= ext->priv->channel_map.channels)
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+
+ return pulse_convert_position_from_pulse (ext->priv->channel_map.map[channel]);
+}
+
+static gboolean
+pulse_ext_stream_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position)
+{
+ PulseExtStream *ext;
+ pa_channel_position_t p;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+
+ ext = PULSE_EXT_STREAM (mmsc);
+
+ /* Handle invalid position as a special case, otherwise this function would
+ * return TRUE for e.g. unknown index in a default channel map */
+ p = pulse_convert_position_to_pulse (position);
+
+ if (p == PA_CHANNEL_POSITION_INVALID)
+ return FALSE;
+
+ if (pa_channel_map_has_position (&ext->priv->channel_map, p) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+pulse_ext_stream_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
+{
+ PulseExtStream *ext;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+
+ ext = PULSE_EXT_STREAM (mmsc);
+ cvolume = ext->priv->cvolume;
+
+ /* Modify a temporary cvolume structure as the change may be irreversible */
+ if (pa_cvolume_set_balance (&cvolume, &ext->priv->channel_map, balance) == NULL)
+ return FALSE;
+
+ return write_cvolume (ext, &cvolume);
+}
+
+static gboolean
+pulse_ext_stream_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
+{
+ PulseExtStream *ext;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+
+ ext = PULSE_EXT_STREAM (mmsc);
+ cvolume = ext->priv->cvolume;
+
+ /* Modify a temporary cvolume structure as the change may be irreversible */
+ if (pa_cvolume_set_fade (&cvolume, &ext->priv->channel_map, fade) == NULL)
+ return FALSE;
+
+ return write_cvolume (ext, &cvolume);
+}
+
+static guint
+pulse_ext_stream_get_min_volume (MateMixerStreamControl *mmsc)
+{
+ return (guint) PA_VOLUME_MUTED;
+}
+
+static guint
+pulse_ext_stream_get_max_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_UI_MAX;
+}
+
+static guint
+pulse_ext_stream_get_normal_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_NORM;
+}
+
+static guint
+pulse_ext_stream_get_base_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), (guint) PA_VOLUME_MUTED);
+
+ /* Base volume is not supported/used in ext-streams */
+ return (guint) PA_VOLUME_NORM;
}
static void
-fill_ext_stream_restore_info (PulseStreamControl *control,
+fill_ext_stream_restore_info (PulseExtStream *ext,
pa_ext_stream_restore_info *info)
{
- MateMixerStream *stream;
+ MateMixerStream *mms;
MateMixerStreamControl *mmsc;
- const pa_channel_map *map;
- const pa_cvolume *cvolume;
- mmsc = MATE_MIXER_STREAM_CONTROL (control);
+ mmsc = MATE_MIXER_STREAM_CONTROL (ext);
info->name = mate_mixer_stream_control_get_name (mmsc);
info->mute = mate_mixer_stream_control_get_mute (mmsc);
+ info->volume = ext->priv->cvolume;
+ info->channel_map = ext->priv->channel_map;
- map = pulse_stream_control_get_channel_map (control);
- info->channel_map = *map;
-
- cvolume = pulse_stream_control_get_cvolume (control);
- info->volume = *cvolume;
-
- stream = mate_mixer_stream_control_get_stream (mmsc);
- if (stream != NULL)
- info->device = mate_mixer_stream_get_name (stream);
+ mms = mate_mixer_stream_control_get_stream (mmsc);
+ if (mms != NULL)
+ info->device = mate_mixer_stream_get_name (mms);
else
info->device = NULL;
}
+
+static gboolean
+write_cvolume (PulseExtStream *ext, const pa_cvolume *cvolume)
+{
+ pa_ext_stream_restore_info info;
+
+ /* Make sure to only store a valid and modified volume */
+ if (pa_cvolume_valid (cvolume) == 0)
+ return FALSE;
+ if (pa_cvolume_equal (cvolume, &ext->priv->cvolume) != 0)
+ return TRUE;
+
+ fill_ext_stream_restore_info (ext, &info);
+ info.volume = *cvolume;
+
+ if (pulse_connection_write_ext_stream (ext->priv->connection, &info) == FALSE)
+ return FALSE;
+
+ store_cvolume (ext, cvolume);
+ return TRUE;
+}
+
+static void
+store_cvolume (PulseExtStream *ext, const pa_cvolume *cvolume)
+{
+ gfloat value;
+
+ /* Avoid validating whether the volume has changed, it should be done by
+ * the caller */
+ ext->priv->cvolume = *cvolume;
+ ext->priv->volume = (guint) pa_cvolume_max (cvolume);
+
+ g_object_notify (G_OBJECT (ext), "volume");
+
+ /* PulseAudio returns the default 0.0f value on error, so skip checking validity
+ * of the channel map and cvolume */
+ value = pa_cvolume_get_balance (&ext->priv->cvolume,
+ &ext->priv->channel_map);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (ext), value);
+
+ value = pa_cvolume_get_fade (&ext->priv->cvolume,
+ &ext->priv->channel_map);
+
+ _mate_mixer_stream_control_set_fade (MATE_MIXER_STREAM_CONTROL (ext), value);
+}
diff --git a/backends/pulse/pulse-ext-stream.h b/backends/pulse/pulse-ext-stream.h
index b667dc7..af3d75f 100644
--- a/backends/pulse/pulse-ext-stream.h
+++ b/backends/pulse/pulse-ext-stream.h
@@ -47,7 +47,7 @@ typedef struct _PulseExtStreamPrivate PulseExtStreamPrivate;
struct _PulseExtStream
{
- PulseStreamControl parent;
+ MateMixerStoredControl parent;
/*< private >*/
PulseExtStreamPrivate *priv;
@@ -55,7 +55,7 @@ struct _PulseExtStream
struct _PulseExtStreamClass
{
- PulseStreamControlClass parent_class;
+ MateMixerStoredControlClass parent_class;
};
GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/pulse-port-switch.c b/backends/pulse/pulse-port-switch.c
index 08f1543..db06a7c 100644
--- a/backends/pulse/pulse-port-switch.c
+++ b/backends/pulse/pulse-port-switch.c
@@ -53,7 +53,6 @@ static void pulse_port_switch_set_property (GObject *object,
GParamSpec *pspec);
static void pulse_port_switch_init (PulsePortSwitch *swtch);
-static void pulse_port_switch_dispose (GObject *object);
G_DEFINE_ABSTRACT_TYPE (PulsePortSwitch, pulse_port_switch, MATE_MIXER_TYPE_SWITCH)
@@ -74,7 +73,6 @@ pulse_port_switch_class_init (PulsePortSwitchClass *klass)
MateMixerSwitchClass *switch_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_port_switch_dispose;
object_class->get_property = pulse_port_switch_get_property;
object_class->set_property = pulse_port_switch_set_property;
@@ -129,7 +127,11 @@ pulse_port_switch_set_property (GObject *object,
switch (param_id) {
case PROP_STREAM:
/* Construct-only object */
- swtch->priv->stream = g_value_dup_object (value);
+ swtch->priv->stream = g_value_get_object (value);
+
+ if (swtch->priv->stream != NULL)
+ g_object_add_weak_pointer (G_OBJECT (swtch->priv->stream),
+ (gpointer *) &swtch->priv->stream);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -145,18 +147,6 @@ pulse_port_switch_init (PulsePortSwitch *swtch)
PulsePortSwitchPrivate);
}
-static void
-pulse_port_switch_dispose (GObject *object)
-{
- PulsePortSwitch *swtch;
-
- swtch = PULSE_PORT_SWITCH (object);
-
- g_clear_object (&swtch->priv->stream);
-
- G_OBJECT_CLASS (pulse_port_switch_parent_class)->dispose (object);
-}
-
PulseStream *
pulse_port_switch_get_stream (PulsePortSwitch *swtch)
{
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index d2f0280..aedd5c8 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -188,7 +188,7 @@ pulse_sink_add_input (PulseSink *sink, const pa_sink_input_info *info)
input = pulse_sink_input_new (sink, info);
g_hash_table_insert (sink->priv->inputs,
GINT_TO_POINTER (info->index),
- input);
+ g_object_ref (input));
name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (input));
g_signal_emit_by_name (G_OBJECT (sink),
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index 0d095a7..99c7432 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -183,7 +183,7 @@ pulse_source_add_output (PulseSource *source, const pa_source_output_info *info)
output = pulse_source_output_new (source, info);
g_hash_table_insert (source->priv->outputs,
GINT_TO_POINTER (info->index),
- output);
+ g_object_ref (output));
name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
g_signal_emit_by_name (G_OBJECT (source),
diff --git a/backends/pulse/pulse-stream-control.c b/backends/pulse/pulse-stream-control.c
index fa17e6b..f61a616 100644
--- a/backends/pulse/pulse-stream-control.c
+++ b/backends/pulse/pulse-stream-control.c
@@ -550,7 +550,7 @@ pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint c
if (channel >= control->priv->channel_map.channels)
return MATE_MIXER_CHANNEL_UNKNOWN;
- return pulse_convert_position_to_pulse (control->priv->channel_map.map[channel]);
+ return pulse_convert_position_from_pulse (control->priv->channel_map.map[channel]);
}
static gboolean
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index 752c3e6..9856c98 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -63,16 +63,13 @@ G_DEFINE_ABSTRACT_TYPE (PulseStream, pulse_stream, MATE_MIXER_TYPE_STREAM)
static void
pulse_stream_class_init (PulseStreamClass *klass)
{
- GObjectClass *object_class;
- MateMixerStreamClass *stream_class;
+ GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pulse_stream_dispose;
object_class->get_property = pulse_stream_get_property;
object_class->set_property = pulse_stream_set_property;
- stream_class = MATE_MIXER_STREAM_CLASS (klass);
-
properties[PROP_INDEX] =
g_param_spec_uint ("index",
"Index",