diff options
Diffstat (limited to 'backends/pulse/pulse-device.c')
-rw-r--r-- | backends/pulse/pulse-device.c | 376 |
1 files changed, 243 insertions, 133 deletions
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c index 368d85b..96e06c8 100644 --- a/backends/pulse/pulse-device.c +++ b/backends/pulse/pulse-device.c @@ -15,14 +15,16 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include <string.h> #include <glib.h> #include <glib-object.h> -#include <string.h> #include <libmatemixer/matemixer-device.h> #include <libmatemixer/matemixer-device-profile.h> +#include <libmatemixer/matemixer-device-profile-private.h> #include <libmatemixer/matemixer-enums.h> #include <libmatemixer/matemixer-port.h> +#include <libmatemixer/matemixer-port-private.h> #include <pulse/pulseaudio.h> @@ -34,27 +36,23 @@ struct _PulseDevicePrivate guint32 index; gchar *name; gchar *description; - GList *profiles; - GList *ports; - GList *streams; - gboolean streams_sorted; gchar *icon; + GHashTable *ports; + GList *ports_list; + GHashTable *profiles; + GList *profiles_list; PulseConnection *connection; MateMixerDeviceProfile *profile; }; -enum -{ +enum { PROP_0, PROP_NAME, PROP_DESCRIPTION, PROP_ICON, - PROP_PORTS, - PROP_PROFILES, PROP_ACTIVE_PROFILE, PROP_INDEX, - PROP_CONNECTION, - N_PROPERTIES + PROP_CONNECTION }; static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface); @@ -78,35 +76,50 @@ G_DEFINE_TYPE_WITH_CODE (PulseDevice, pulse_device, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE, mate_mixer_device_interface_init)) -static const gchar * device_get_name (MateMixerDevice *device); -static const gchar * device_get_description (MateMixerDevice *device); -static const gchar * device_get_icon (MateMixerDevice *device); +#if PA_CHECK_VERSION (5, 0, 0) +typedef pa_card_profile_info2 _pa_card_profile_info; +#else +typedef pa_card_profile_info _pa_card_profile_info; +#endif + +static const gchar * pulse_device_get_name (MateMixerDevice *device); +static const gchar * pulse_device_get_description (MateMixerDevice *device); +static const gchar * pulse_device_get_icon (MateMixerDevice *device); -static const GList * device_list_ports (MateMixerDevice *device); -static const GList * device_list_profiles (MateMixerDevice *device); +static MateMixerPort * pulse_device_get_port (MateMixerDevice *device, + const gchar *name); +static MateMixerDeviceProfile *pulse_device_get_profile (MateMixerDevice *device, + const gchar *name); -static MateMixerDeviceProfile *device_get_active_profile (MateMixerDevice *device); -static gboolean device_set_active_profile (MateMixerDevice *device, - const gchar *profile); +static const GList * pulse_device_list_ports (MateMixerDevice *device); +static const GList * pulse_device_list_profiles (MateMixerDevice *device); -static gint device_compare_ports (gconstpointer a, - gconstpointer b); -static gint device_compare_profiles (gconstpointer a, - gconstpointer b); +static MateMixerDeviceProfile *pulse_device_get_active_profile (MateMixerDevice *device); +static gboolean pulse_device_set_active_profile (MateMixerDevice *device, + MateMixerDeviceProfile *profile); -static void device_free_ports (PulseDevice *device); -static void device_free_profiles (PulseDevice *device); +static void update_port (PulseDevice *device, + pa_card_port_info *p_info); +static void update_profile (PulseDevice *device, + _pa_card_profile_info *p_info); + +static gint compare_ports (gconstpointer a, + gconstpointer b); +static gint compare_profiles (gconstpointer a, + gconstpointer b); static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface) { - iface->get_name = device_get_name; - iface->get_description = device_get_description; - iface->get_icon = device_get_icon; - iface->list_ports = device_list_ports; - iface->list_profiles = device_list_profiles; - iface->get_active_profile = device_get_active_profile; - iface->set_active_profile = device_set_active_profile; + iface->get_name = pulse_device_get_name; + iface->get_description = pulse_device_get_description; + iface->get_icon = pulse_device_get_icon; + iface->get_port = pulse_device_get_port; + iface->get_profile = pulse_device_get_profile; + iface->list_ports = pulse_device_list_ports; + iface->list_profiles = pulse_device_list_profiles; + iface->get_active_profile = pulse_device_get_active_profile; + iface->set_active_profile = pulse_device_set_active_profile; } static void @@ -144,8 +157,6 @@ pulse_device_class_init (PulseDeviceClass *klass) g_object_class_override_property (object_class, PROP_NAME, "name"); g_object_class_override_property (object_class, PROP_DESCRIPTION, "description"); g_object_class_override_property (object_class, PROP_ICON, "icon"); - g_object_class_override_property (object_class, PROP_PORTS, "ports"); - g_object_class_override_property (object_class, PROP_PROFILES, "profiles"); g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile"); g_type_class_add_private (object_class, sizeof (PulseDevicePrivate)); @@ -171,12 +182,6 @@ pulse_device_get_property (GObject *object, case PROP_ICON: g_value_set_string (value, device->priv->icon); break; - case PROP_PORTS: - g_value_set_pointer (value, device->priv->ports); - break; - case PROP_PROFILES: - g_value_set_pointer (value, device->priv->profiles); - break; case PROP_ACTIVE_PROFILE: g_value_set_object (value, device->priv->profile); break; @@ -222,6 +227,16 @@ pulse_device_init (PulseDevice *device) device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, PULSE_TYPE_DEVICE, PulseDevicePrivate); + + device->priv->ports = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + + device->priv->profiles = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); } static void @@ -231,9 +246,19 @@ pulse_device_dispose (GObject *object) device = PULSE_DEVICE (object); - device_free_ports (device); - device_free_profiles (device); + if (device->priv->ports_list != NULL) { + g_list_free_full (device->priv->ports_list, g_object_unref); + device->priv->ports_list = NULL; + } + g_hash_table_remove_all (device->priv->ports); + if (device->priv->profiles_list != NULL) { + g_list_free_full (device->priv->profiles_list, g_object_unref); + device->priv->profiles_list = NULL; + } + g_hash_table_remove_all (device->priv->profiles); + + g_clear_object (&device->priv->profile); g_clear_object (&device->priv->connection); G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object); @@ -250,6 +275,9 @@ pulse_device_finalize (GObject *object) g_free (device->priv->description); g_free (device->priv->icon); + g_hash_table_destroy (device->priv->ports); + g_hash_table_destroy (device->priv->profiles); + G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object); } @@ -276,6 +304,7 @@ pulse_device_new (PulseConnection *connection, const pa_card_info *info) gboolean pulse_device_update (PulseDevice *device, const pa_card_info *info) { + MateMixerDeviceProfile *profile = NULL; const gchar *prop; guint32 i; @@ -286,7 +315,7 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info) g_object_freeze_notify (G_OBJECT (device)); /* Name */ - if (g_strcmp0 (device->priv->name, info->name)) { + if (g_strcmp0 (device->priv->name, info->name) != 0) { g_free (device->priv->name); device->priv->name = g_strdup (info->name); @@ -299,7 +328,7 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info) if (G_UNLIKELY (prop == NULL)) prop = info->name; - if (g_strcmp0 (device->priv->description, prop)) { + if (g_strcmp0 (device->priv->description, prop) != 0) { g_free (device->priv->description); device->priv->description = g_strdup (prop); @@ -312,49 +341,23 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info) if (G_UNLIKELY (prop == NULL)) prop = "audio-card"; - if (g_strcmp0 (device->priv->icon, prop)) { + if (g_strcmp0 (device->priv->icon, prop) != 0) { g_free (device->priv->icon); device->priv->icon = g_strdup (prop); g_object_notify (G_OBJECT (device), "icon"); } +#if PA_CHECK_VERSION (2, 0, 0) /* List of ports */ - device_free_ports (device); - for (i = 0; i < info->n_ports; i++) { - MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS; - - prop = pa_proplist_gets (info->ports[i]->proplist, "device.icon_name"); - -#if PA_CHECK_VERSION(2, 0, 0) - if (info->ports[i]->available == PA_PORT_AVAILABLE_YES) - flags |= MATE_MIXER_PORT_AVAILABLE; - - if (info->ports[i]->direction & PA_DIRECTION_INPUT) - flags |= MATE_MIXER_PORT_INPUT; - if (info->ports[i]->direction & PA_DIRECTION_OUTPUT) - flags |= MATE_MIXER_PORT_OUTPUT; -#endif - device->priv->ports = - g_list_prepend (device->priv->ports, - mate_mixer_port_new (info->ports[i]->name, - info->ports[i]->description, - prop, - info->ports[i]->priority, - flags)); + update_port (device, info->ports[i]); } - device->priv->ports = g_list_sort (device->priv->ports, device_compare_ports); - - g_object_notify (G_OBJECT (device), "ports"); +#endif /* List of profiles */ - device_free_profiles (device); - for (i = 0; i < info->n_profiles; i++) { - MateMixerDeviceProfile *profile; - -#if PA_CHECK_VERSION(5, 0, 0) +#if PA_CHECK_VERSION (5, 0, 0) pa_card_profile_info2 *p_info = info->profiles2[i]; /* PulseAudio 5.0 includes a new pa_card_profile_info2 which only @@ -366,28 +369,28 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info) /* The old profile list is an array of structs, not pointers */ pa_card_profile_info *p_info = &info->profiles[i]; #endif - profile = mate_mixer_device_profile_new ( - p_info->name, - p_info->description, - p_info->priority, - p_info->n_sources, - p_info->n_sinks); - - if (device->priv->profile == NULL) { -#if PA_CHECK_VERSION(5, 0, 0) - if (!g_strcmp0 (p_info->name, info->active_profile2->name)) - device->priv->profile = g_object_ref (profile); + update_profile (device, p_info); + } + + /* Figure out whether the currently active profile has changed */ + profile = NULL; + +#if PA_CHECK_VERSION (5, 0, 0) + if (G_LIKELY (info->active_profile2 != NULL)) + profile = g_hash_table_lookup (device->priv->profiles, info->active_profile2->name); #else - if (!g_strcmp0 (p_info->name, info->active_profile->name)) - device->priv->profile = g_object_ref (profile); + if (G_LIKELY (info->active_profile != NULL)) + profile = g_hash_table_lookup (device->priv->profiles, info->active_profile->name); #endif - } - device->priv->profiles = g_list_prepend (device->priv->profiles, profile); - } - device->priv->profiles = g_list_sort (device->priv->profiles, - device_compare_profiles); - g_object_notify (G_OBJECT (device), "profiles"); + if (profile != device->priv->profile) { + g_clear_object (&device->priv->profile); + + if (G_LIKELY (profile != NULL)) + device->priv->profile = g_object_ref (profile); + + g_object_notify (G_OBJECT (device), "active-profile"); + } g_object_thaw_notify (G_OBJECT (device)); return TRUE; @@ -410,7 +413,7 @@ pulse_device_get_index (PulseDevice *device) } static const gchar * -device_get_name (MateMixerDevice *device) +pulse_device_get_name (MateMixerDevice *device) { g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); @@ -418,7 +421,7 @@ device_get_name (MateMixerDevice *device) } static const gchar * -device_get_description (MateMixerDevice *device) +pulse_device_get_description (MateMixerDevice *device) { g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); @@ -426,31 +429,77 @@ device_get_description (MateMixerDevice *device) } static const gchar * -device_get_icon (MateMixerDevice *device) +pulse_device_get_icon (MateMixerDevice *device) { g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); return PULSE_DEVICE (device)->priv->icon; } +static MateMixerPort * +pulse_device_get_port (MateMixerDevice *device, const gchar *name) +{ + g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); + g_return_val_if_fail (name != NULL, NULL); + + return g_hash_table_lookup (PULSE_DEVICE (device)->priv->ports, name); +} + +static MateMixerDeviceProfile * +pulse_device_get_profile (MateMixerDevice *device, const gchar *name) +{ + g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); + g_return_val_if_fail (name != NULL, NULL); + + return g_hash_table_lookup (PULSE_DEVICE (device)->priv->profiles, name); +} + static const GList * -device_list_ports (MateMixerDevice *device) +pulse_device_list_ports (MateMixerDevice *device) { + PulseDevice *pulse; + g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); - return (const GList *) PULSE_DEVICE (device)->priv->ports; + pulse = PULSE_DEVICE (device); + + if (pulse->priv->ports_list == NULL) { + GList *list = g_hash_table_get_values (pulse->priv->ports); + + if (list != NULL) { + g_list_foreach (list, (GFunc) g_object_ref, NULL); + + pulse->priv->ports_list = g_list_sort (list, compare_ports); + } + } + + return (const GList *) pulse->priv->ports_list; } static const GList * -device_list_profiles (MateMixerDevice *device) +pulse_device_list_profiles (MateMixerDevice *device) { + PulseDevice *pulse; + g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); - return (const GList *) PULSE_DEVICE (device)->priv->profiles; + pulse = PULSE_DEVICE (device); + + if (pulse->priv->profiles_list == NULL) { + GList *list = g_hash_table_get_values (pulse->priv->profiles); + + if (list != NULL) { + g_list_foreach (list, (GFunc) g_object_ref, NULL); + + pulse->priv->profiles_list = g_list_sort (list, compare_profiles); + } + } + + return (const GList *) pulse->priv->profiles_list; } static MateMixerDeviceProfile * -device_get_active_profile (MateMixerDevice *device) +pulse_device_get_active_profile (MateMixerDevice *device) { g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL); @@ -458,18 +507,103 @@ device_get_active_profile (MateMixerDevice *device) } static gboolean -device_set_active_profile (MateMixerDevice *device, const gchar *profile) +pulse_device_set_active_profile (MateMixerDevice *device, MateMixerDeviceProfile *profile) { + PulseDevice *pulse; + const gchar *name; + gboolean ret; + g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE); - g_return_val_if_fail (profile != NULL, FALSE); + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); + + pulse = PULSE_DEVICE (device); + + name = mate_mixer_device_profile_get_name (profile); + + /* Make sure the profile belongs to the device */ + if (g_hash_table_lookup (pulse->priv->profiles, name) == NULL) { + g_warning ("Profile %s does not belong to device %s", name, pulse->priv->name); + return FALSE; + } + + ret = pulse_connection_set_card_profile (pulse->priv->connection, + pulse->priv->name, + name); + if (ret == TRUE) { + if (pulse->priv->profile != NULL) + g_object_unref (pulse->priv->profile); + + pulse->priv->profile = g_object_ref (profile); + + g_object_notify (G_OBJECT (device), "active-profile"); + } + return ret; +} + +static void +update_port (PulseDevice *device, pa_card_port_info *p_info) +{ + MateMixerPort *port; + MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS; + const gchar *icon; + + icon = pa_proplist_gets (p_info->proplist, "device.icon_name"); + + if (p_info->available == PA_PORT_AVAILABLE_YES) + flags |= MATE_MIXER_PORT_AVAILABLE; + + if (p_info->direction & PA_DIRECTION_INPUT) + flags |= MATE_MIXER_PORT_INPUT; + if (p_info->direction & PA_DIRECTION_OUTPUT) + flags |= MATE_MIXER_PORT_OUTPUT; + + port = g_hash_table_lookup (device->priv->ports, p_info->name); + + if (port != NULL) { + /* Update existing port */ + _mate_mixer_port_update_description (port, p_info->description); + _mate_mixer_port_update_icon (port, icon); + _mate_mixer_port_update_priority (port, p_info->priority); + _mate_mixer_port_update_flags (port, flags); + } else { + /* Add previously unknown port to the hash table */ + port = _mate_mixer_port_new (p_info->name, + p_info->description, + icon, + p_info->priority, + flags); + + g_hash_table_insert (device->priv->ports, g_strdup (p_info->name), port); + } +} + +static void +update_profile (PulseDevice *device, _pa_card_profile_info *p_info) +{ + MateMixerDeviceProfile *profile; - return pulse_connection_set_card_profile (PULSE_DEVICE (device)->priv->connection, - PULSE_DEVICE (device)->priv->name, - profile); + profile = g_hash_table_lookup (device->priv->profiles, p_info->name); + + if (profile != NULL) { + /* Update existing profile */ + _mate_mixer_device_profile_update_description (profile, p_info->description); + _mate_mixer_device_profile_update_priority (profile, p_info->priority); + _mate_mixer_device_profile_update_num_input_streams (profile, p_info->n_sources); + _mate_mixer_device_profile_update_num_output_streams (profile, p_info->n_sinks); + } else { + /* Add previously unknown profile to the hash table */ + profile = _mate_mixer_device_profile_new (p_info->name, + p_info->description, + p_info->priority, + p_info->n_sources, + p_info->n_sinks); + + g_hash_table_insert (device->priv->profiles, g_strdup (p_info->name), profile); + } } static gint -device_compare_ports (gconstpointer a, gconstpointer b) +compare_ports (gconstpointer a, gconstpointer b) { MateMixerPort *p1 = MATE_MIXER_PORT (a); MateMixerPort *p2 = MATE_MIXER_PORT (b); @@ -484,7 +618,7 @@ device_compare_ports (gconstpointer a, gconstpointer b) } static gint -device_compare_profiles (gconstpointer a, gconstpointer b) +compare_profiles (gconstpointer a, gconstpointer b) { MateMixerDeviceProfile *p1 = MATE_MIXER_DEVICE_PROFILE (a); MateMixerDeviceProfile *p2 = MATE_MIXER_DEVICE_PROFILE (b); @@ -497,27 +631,3 @@ device_compare_profiles (gconstpointer a, gconstpointer b) return strcmp (mate_mixer_device_profile_get_name (p1), mate_mixer_device_profile_get_name (p2)); } - -static void -device_free_ports (PulseDevice *device) -{ - if (device->priv->ports == NULL) - return; - - g_list_free_full (device->priv->ports, g_object_unref); - - device->priv->ports = NULL; -} - -static void -device_free_profiles (PulseDevice *device) -{ - if (device->priv->profiles == NULL) - return; - - g_list_free_full (device->priv->profiles, g_object_unref); - - g_clear_object (&device->priv->profile); - - device->priv->profiles = NULL; -} |