diff options
Diffstat (limited to 'backends/pulse')
-rw-r--r-- | backends/pulse/pulse-backend.c | 31 | ||||
-rw-r--r-- | backends/pulse/pulse-device.c | 9 | ||||
-rw-r--r-- | backends/pulse/pulse-ext-stream.c | 520 | ||||
-rw-r--r-- | backends/pulse/pulse-ext-stream.h | 4 | ||||
-rw-r--r-- | backends/pulse/pulse-port-switch.c | 20 | ||||
-rw-r--r-- | backends/pulse/pulse-sink.c | 2 | ||||
-rw-r--r-- | backends/pulse/pulse-source.c | 2 | ||||
-rw-r--r-- | backends/pulse/pulse-stream-control.c | 2 | ||||
-rw-r--r-- | backends/pulse/pulse-stream.c | 5 |
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", |