summaryrefslogtreecommitdiff
path: root/backends/pulse/pulse-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'backends/pulse/pulse-device.c')
-rw-r--r--backends/pulse/pulse-device.c376
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;
-}