diff options
author | Michal Ratajsky <[email protected]> | 2014-07-05 15:19:53 +0200 |
---|---|---|
committer | infirit <[email protected]> | 2014-10-09 16:53:00 +0200 |
commit | 25445eb4cb2d7b49bc435113056587f83b742104 (patch) | |
tree | 08e4af546649fe70416a2b57c45cc8b0451ebdb4 /mate-volume-control/src/gvc-mixer-control.c | |
parent | 1d5fb97b21f2fe6d2ed5cf912989929ba58d1afd (diff) | |
download | mate-media-25445eb4cb2d7b49bc435113056587f83b742104.tar.bz2 mate-media-25445eb4cb2d7b49bc435113056587f83b742104.tar.xz |
Remove the rest of obsolete PulseAudio code
Diffstat (limited to 'mate-volume-control/src/gvc-mixer-control.c')
-rw-r--r-- | mate-volume-control/src/gvc-mixer-control.c | 2150 |
1 files changed, 0 insertions, 2150 deletions
diff --git a/mate-volume-control/src/gvc-mixer-control.c b/mate-volume-control/src/gvc-mixer-control.c deleted file mode 100644 index 4d69e27..0000000 --- a/mate-volume-control/src/gvc-mixer-control.c +++ /dev/null @@ -1,2150 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2006-2008 Lennart Poettering - * Copyright (C) 2008 Sjoerd Simons <[email protected]> - * Copyright (C) 2008 William Jon McCann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include <glib.h> -#include <glib/gi18n.h> - -#include <pulse/pulseaudio.h> -#include <pulse/glib-mainloop.h> -#include <pulse/ext-stream-restore.h> - -#include "gvc-mixer-control.h" -#include "gvc-mixer-sink.h" -#include "gvc-mixer-source.h" -#include "gvc-mixer-sink-input.h" -#include "gvc-mixer-source-output.h" -#include "gvc-mixer-event-role.h" -#include "gvc-mixer-card.h" - -#define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate)) - -#define RECONNECT_DELAY 5 - -enum { - PROP_0, - PROP_NAME -}; - -struct GvcMixerControlPrivate -{ - pa_glib_mainloop *pa_mainloop; - pa_mainloop_api *pa_api; - pa_context *pa_context; - int n_outstanding; - guint reconnect_id; - char *name; - - gboolean default_sink_is_set; - guint default_sink_id; - char *default_sink_name; - gboolean default_source_is_set; - guint default_source_id; - char *default_source_name; - - gboolean event_sink_input_is_set; - guint event_sink_input_id; - - GHashTable *all_streams; - GHashTable *sinks; /* fixed outputs */ - GHashTable *sources; /* fixed inputs */ - GHashTable *sink_inputs; /* routable output streams */ - GHashTable *source_outputs; /* routable input streams */ - GHashTable *clients; - GHashTable *cards; - - GvcMixerStream *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink () */ -}; - -enum { - CONNECTING, - READY, - STREAM_ADDED, - STREAM_REMOVED, - CARD_ADDED, - CARD_REMOVED, - DEFAULT_SINK_CHANGED, - DEFAULT_SOURCE_CHANGED, - LAST_SIGNAL -}; - -static guint signals [LAST_SIGNAL] = { 0, }; - -static void gvc_mixer_control_class_init (GvcMixerControlClass *klass); -static void gvc_mixer_control_init (GvcMixerControl *mixer_control); -static void gvc_mixer_control_finalize (GObject *object); - -G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT) - -pa_context * -gvc_mixer_control_get_pa_context (GvcMixerControl *control) -{ - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - return control->priv->pa_context; -} - -GvcMixerStream * -gvc_mixer_control_get_event_sink_input (GvcMixerControl *control) -{ - GvcMixerStream *stream; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - stream = g_hash_table_lookup (control->priv->all_streams, - GUINT_TO_POINTER (control->priv->event_sink_input_id)); - - return stream; -} - -static void -gvc_mixer_control_stream_restore_cb (pa_context *c, - const pa_ext_stream_restore_info *info, - int eol, - void *userdata) -{ - pa_operation *o; - GvcMixerControl *control = (GvcMixerControl *) userdata; - pa_ext_stream_restore_info new_info; - - if (eol || control->priv->new_default_stream == NULL) - return; - - new_info.name = info->name; - new_info.channel_map = info->channel_map; - new_info.volume = info->volume; - new_info.mute = info->mute; - - new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream); - - o = pa_ext_stream_restore_write (control->priv->pa_context, - PA_UPDATE_REPLACE, - &new_info, 1, - TRUE, NULL, NULL); - - if (o == NULL) { - g_warning ("pa_ext_stream_restore_write() failed: %s", - pa_strerror (pa_context_errno (control->priv->pa_context))); - return; - } - - g_debug ("Changed default device for %s to %s", info->name, info->device); - - pa_operation_unref (o); -} - -gboolean -gvc_mixer_control_set_default_sink (GvcMixerControl *control, - GvcMixerStream *stream) -{ - pa_operation *o; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); - g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); - - o = pa_context_set_default_sink (control->priv->pa_context, - gvc_mixer_stream_get_name (stream), - NULL, - NULL); - if (o == NULL) { - g_warning ("pa_context_set_default_sink() failed: %s", - pa_strerror (pa_context_errno (control->priv->pa_context))); - return FALSE; - } - - pa_operation_unref (o); - - control->priv->new_default_stream = stream; - g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream); - - o = pa_ext_stream_restore_read (control->priv->pa_context, - gvc_mixer_control_stream_restore_cb, - control); - - if (o == NULL) { - g_warning ("pa_ext_stream_restore_read() failed: %s", - pa_strerror (pa_context_errno (control->priv->pa_context))); - return FALSE; - } - - pa_operation_unref (o); - - return TRUE; -} - -gboolean -gvc_mixer_control_set_default_source (GvcMixerControl *control, - GvcMixerStream *stream) -{ - pa_operation *o; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); - g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); - - o = pa_context_set_default_source (control->priv->pa_context, - gvc_mixer_stream_get_name (stream), - NULL, - NULL); - if (o == NULL) { - g_warning ("pa_context_set_default_source() failed"); - return FALSE; - } - - pa_operation_unref (o); - - return TRUE; -} - -GvcMixerStream * -gvc_mixer_control_get_default_sink (GvcMixerControl *control) -{ - GvcMixerStream *stream; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - if (control->priv->default_sink_is_set) { - stream = g_hash_table_lookup (control->priv->all_streams, - GUINT_TO_POINTER (control->priv->default_sink_id)); - } else { - stream = NULL; - } - - return stream; -} - -GvcMixerStream * -gvc_mixer_control_get_default_source (GvcMixerControl *control) -{ - GvcMixerStream *stream; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - if (control->priv->default_source_is_set) { - stream = g_hash_table_lookup (control->priv->all_streams, - GUINT_TO_POINTER (control->priv->default_source_id)); - } else { - stream = NULL; - } - - return stream; -} - -static gpointer -gvc_mixer_control_lookup_id (GHashTable *hash_table, - guint id) -{ - return g_hash_table_lookup (hash_table, - GUINT_TO_POINTER (id)); -} - -GvcMixerStream * -gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, - guint id) -{ - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - return gvc_mixer_control_lookup_id (control->priv->all_streams, id); -} - -GvcMixerCard * -gvc_mixer_control_lookup_card_id (GvcMixerControl *control, - guint id) -{ - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - return gvc_mixer_control_lookup_id (control->priv->cards, id); -} - -static void -listify_hash_values_hfunc (gpointer key, - gpointer value, - gpointer user_data) -{ - GSList **list = user_data; - - *list = g_slist_prepend (*list, value); -} - -static int -gvc_name_collate (const char *namea, - const char *nameb) -{ - if (nameb == NULL && namea == NULL) - return 0; - if (nameb == NULL) - return 1; - if (namea == NULL) - return -1; - - return g_utf8_collate (namea, nameb); -} - -static int -gvc_card_collate (GvcMixerCard *a, - GvcMixerCard *b) -{ - const char *namea; - const char *nameb; - - g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0); - g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0); - - namea = gvc_mixer_card_get_name (a); - nameb = gvc_mixer_card_get_name (b); - - return gvc_name_collate (namea, nameb); -} - -GSList * -gvc_mixer_control_get_cards (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->cards, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_card_collate); -} - -static int -gvc_stream_collate (GvcMixerStream *a, - GvcMixerStream *b) -{ - const char *namea; - const char *nameb; - - g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0); - g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0); - - namea = gvc_mixer_stream_get_name (a); - nameb = gvc_mixer_stream_get_name (b); - - return gvc_name_collate (namea, nameb); -} - -GSList * -gvc_mixer_control_get_streams (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->all_streams, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); -} - -GSList * -gvc_mixer_control_get_sinks (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->sinks, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); -} - -GSList * -gvc_mixer_control_get_sources (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->sources, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); -} - -GSList * -gvc_mixer_control_get_sink_inputs (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->sink_inputs, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); -} - -GSList * -gvc_mixer_control_get_source_outputs (GvcMixerControl *control) -{ - GSList *retval; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); - - retval = NULL; - g_hash_table_foreach (control->priv->source_outputs, - listify_hash_values_hfunc, - &retval); - return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); -} - -static void -dec_outstanding (GvcMixerControl *control) -{ - if (control->priv->n_outstanding <= 0) { - return; - } - - if (--control->priv->n_outstanding <= 0) { - g_signal_emit (G_OBJECT (control), signals[READY], 0); - } -} - -gboolean -gvc_mixer_control_is_ready (GvcMixerControl *control) -{ - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); - - return (control->priv->n_outstanding == 0); -} - - -static void -_set_default_source (GvcMixerControl *control, - GvcMixerStream *stream) -{ - guint new_id; - - if (stream == NULL) { - control->priv->default_source_id = 0; - control->priv->default_source_is_set = FALSE; - g_signal_emit (control, - signals[DEFAULT_SOURCE_CHANGED], - 0, - PA_INVALID_INDEX); - return; - } - - new_id = gvc_mixer_stream_get_id (stream); - - if (control->priv->default_source_id != new_id) { - control->priv->default_source_id = new_id; - control->priv->default_source_is_set = TRUE; - g_signal_emit (control, - signals[DEFAULT_SOURCE_CHANGED], - 0, - new_id); - } -} - -static void -_set_default_sink (GvcMixerControl *control, - GvcMixerStream *stream) -{ - guint new_id; - - if (stream == NULL) { - /* Don't tell front-ends about an unset default - * sink if it's already unset */ - if (control->priv->default_sink_is_set == FALSE) - return; - control->priv->default_sink_id = 0; - control->priv->default_sink_is_set = FALSE; - g_signal_emit (control, - signals[DEFAULT_SINK_CHANGED], - 0, - PA_INVALID_INDEX); - return; - } - - new_id = gvc_mixer_stream_get_id (stream); - - if (control->priv->default_sink_id != new_id) { - control->priv->default_sink_id = new_id; - control->priv->default_sink_is_set = TRUE; - g_signal_emit (control, - signals[DEFAULT_SINK_CHANGED], - 0, - new_id); - } -} - -static gboolean -_stream_has_name (gpointer key, - GvcMixerStream *stream, - const char *name) -{ - const char *t_name; - - t_name = gvc_mixer_stream_get_name (stream); - - if (t_name != NULL - && name != NULL - && strcmp (t_name, name) == 0) { - return TRUE; - } - - return FALSE; -} - -static GvcMixerStream * -find_stream_for_name (GvcMixerControl *control, - const char *name) -{ - GvcMixerStream *stream; - - stream = g_hash_table_find (control->priv->all_streams, - (GHRFunc)_stream_has_name, - (char *)name); - return stream; -} - -static void -update_default_source_from_name (GvcMixerControl *control, - const char *name) -{ - gboolean changed; - - if ((control->priv->default_source_name == NULL - && name != NULL) - || (control->priv->default_source_name != NULL - && name == NULL) - || strcmp (control->priv->default_source_name, name) != 0) { - changed = TRUE; - } - - if (changed) { - GvcMixerStream *stream; - - g_free (control->priv->default_source_name); - control->priv->default_source_name = g_strdup (name); - - stream = find_stream_for_name (control, name); - _set_default_source (control, stream); - } -} - -static void -update_default_sink_from_name (GvcMixerControl *control, - const char *name) -{ - gboolean changed; - - if ((control->priv->default_sink_name == NULL - && name != NULL) - || (control->priv->default_sink_name != NULL - && name == NULL) - || strcmp (control->priv->default_sink_name, name) != 0) { - changed = TRUE; - } - - if (changed) { - GvcMixerStream *stream; - g_free (control->priv->default_sink_name); - control->priv->default_sink_name = g_strdup (name); - - stream = find_stream_for_name (control, name); - _set_default_sink (control, stream); - } -} - -static void -update_server (GvcMixerControl *control, - const pa_server_info *info) -{ - if (info->default_source_name != NULL) { - update_default_source_from_name (control, info->default_source_name); - } - if (info->default_sink_name != NULL) { - update_default_sink_from_name (control, info->default_sink_name); - } -} - -static void -remove_stream (GvcMixerControl *control, - GvcMixerStream *stream) -{ - guint id; - - g_object_ref (stream); - - id = gvc_mixer_stream_get_id (stream); - - if (id == control->priv->default_sink_id) { - _set_default_sink (control, NULL); - } else if (id == control->priv->default_source_id) { - _set_default_source (control, NULL); - } - - g_hash_table_remove (control->priv->all_streams, - GUINT_TO_POINTER (id)); - g_signal_emit (G_OBJECT (control), - signals[STREAM_REMOVED], - 0, - gvc_mixer_stream_get_id (stream)); - g_object_unref (stream); -} - -static void -add_stream (GvcMixerControl *control, - GvcMixerStream *stream) -{ - g_hash_table_insert (control->priv->all_streams, - GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)), - stream); - g_signal_emit (G_OBJECT (control), - signals[STREAM_ADDED], - 0, - gvc_mixer_stream_get_id (stream)); -} - -static void -update_sink (GvcMixerControl *control, - const pa_sink_info *info) -{ - GvcMixerStream *stream; - gboolean is_new; - pa_volume_t max_volume; - GvcChannelMap *map; - char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX]; - - pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map); -#if 1 - g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'", - info->index, - info->name, - info->description, - map_buff); -#endif - - map = NULL; - is_new = FALSE; - stream = g_hash_table_lookup (control->priv->sinks, - GUINT_TO_POINTER (info->index)); - if (stream == NULL) { -#if PA_MICRO > 15 - GList *list = NULL; - guint i; -#endif /* PA_MICRO > 15 */ - - map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); - stream = gvc_mixer_sink_new (control->priv->pa_context, - info->index, - map); -#if PA_MICRO > 15 - for (i = 0; i < info->n_ports; i++) { - GvcMixerStreamPort *port; - - port = g_new0 (GvcMixerStreamPort, 1); - port->port = g_strdup (info->ports[i]->name); - port->human_port = g_strdup (info->ports[i]->description); - port->priority = info->ports[i]->priority; - list = g_list_prepend (list, port); - } - gvc_mixer_stream_set_ports (stream, list); -#endif /* PA_MICRO > 15 */ - g_object_unref (map); - is_new = TRUE; - } else if (gvc_mixer_stream_is_running (stream)) { - /* Ignore events if volume changes are outstanding */ - g_debug ("Ignoring event, volume changes are outstanding"); - return; - } - - max_volume = pa_cvolume_max (&info->volume); - gvc_mixer_stream_set_name (stream, info->name); - gvc_mixer_stream_set_card_index (stream, info->card); - gvc_mixer_stream_set_description (stream, info->description); - gvc_mixer_stream_set_icon_name (stream, "audio-card"); - gvc_mixer_stream_set_volume (stream, (guint)max_volume); - gvc_mixer_stream_set_is_muted (stream, info->mute); - gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME)); - gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); -#if PA_MICRO > 15 - if (info->active_port != NULL) - gvc_mixer_stream_set_port (stream, info->active_port->name); -#endif /* PA_MICRO > 15 */ - - if (is_new) { - g_hash_table_insert (control->priv->sinks, - GUINT_TO_POINTER (info->index), - g_object_ref (stream)); - add_stream (control, stream); - } - - if (control->priv->default_sink_name != NULL - && info->name != NULL - && strcmp (control->priv->default_sink_name, info->name) == 0) { - _set_default_sink (control, stream); - } - - if (map == NULL) - map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream); - gvc_channel_map_volume_changed (map, &info->volume, FALSE); -} - -static void -update_source (GvcMixerControl *control, - const pa_source_info *info) -{ - GvcMixerStream *stream; - gboolean is_new; - pa_volume_t max_volume; - -#if 1 - g_debug ("Updating source: index=%u name='%s' description='%s'", - info->index, - info->name, - info->description); -#endif - - /* completely ignore monitors, they're not real sources */ - if (info->monitor_of_sink != PA_INVALID_INDEX) { - return; - } - - is_new = FALSE; - - stream = g_hash_table_lookup (control->priv->sources, - GUINT_TO_POINTER (info->index)); - if (stream == NULL) { -#if PA_MICRO > 15 - GList *list = NULL; - guint i; -#endif /* PA_MICRO > 15 */ - GvcChannelMap *map; - - map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); - stream = gvc_mixer_source_new (control->priv->pa_context, - info->index, - map); -#if PA_MICRO > 15 - for (i = 0; i < info->n_ports; i++) { - GvcMixerStreamPort *port; - - port = g_new0 (GvcMixerStreamPort, 1); - port->port = g_strdup (info->ports[i]->name); - port->human_port = g_strdup (info->ports[i]->description); - port->priority = info->ports[i]->priority; - list = g_list_prepend (list, port); - } - gvc_mixer_stream_set_ports (stream, list); -#endif /* PA_MICRO > 15 */ - - g_object_unref (map); - is_new = TRUE; - } else if (gvc_mixer_stream_is_running (stream)) { - /* Ignore events if volume changes are outstanding */ - g_debug ("Ignoring event, volume changes are outstanding"); - return; - } - - max_volume = pa_cvolume_max (&info->volume); - - gvc_mixer_stream_set_name (stream, info->name); - gvc_mixer_stream_set_card_index (stream, info->card); - gvc_mixer_stream_set_description (stream, info->description); - gvc_mixer_stream_set_icon_name (stream, "audio-input-microphone"); - gvc_mixer_stream_set_volume (stream, (guint)max_volume); - gvc_mixer_stream_set_is_muted (stream, info->mute); - gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME)); - gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); -#if PA_MICRO > 15 - if (info->active_port != NULL) - gvc_mixer_stream_set_port (stream, info->active_port->name); -#endif /* PA_MICRO > 15 */ - - if (is_new) { - g_hash_table_insert (control->priv->sources, - GUINT_TO_POINTER (info->index), - g_object_ref (stream)); - add_stream (control, stream); - } - - if (control->priv->default_source_name != NULL - && info->name != NULL - && strcmp (control->priv->default_source_name, info->name) == 0) { - _set_default_source (control, stream); - } -} - -static void -set_icon_name_from_proplist (GvcMixerStream *stream, - pa_proplist *l, - const char *default_icon_name) -{ - const char *t; - - if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) { - goto finish; - } - - if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) { - goto finish; - } - - if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) { - goto finish; - } - - if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { - - if (strcmp (t, "video") == 0 || - strcmp (t, "phone") == 0) { - goto finish; - } - - if (strcmp (t, "music") == 0) { - t = "audio"; - goto finish; - } - - if (strcmp (t, "game") == 0) { - t = "applications-games"; - goto finish; - } - - if (strcmp (t, "event") == 0) { - t = "dialog-information"; - goto finish; - } - } - - t = default_icon_name; - - finish: - gvc_mixer_stream_set_icon_name (stream, t); -} - -static void -set_is_event_stream_from_proplist (GvcMixerStream *stream, - pa_proplist *l) -{ - const char *t; - gboolean is_event_stream; - - is_event_stream = FALSE; - - if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { - if (g_str_equal (t, "event")) - is_event_stream = TRUE; - } - - gvc_mixer_stream_set_is_event_stream (stream, is_event_stream); -} - -static void -set_application_id_from_proplist (GvcMixerStream *stream, - pa_proplist *l) -{ - const char *t; - - if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) { - gvc_mixer_stream_set_application_id (stream, t); - } -} - -static void -update_sink_input (GvcMixerControl *control, - const pa_sink_input_info *info) -{ - GvcMixerStream *stream; - gboolean is_new; - pa_volume_t max_volume; - const char *name; - -#if 0 - g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u", - info->index, - info->name, - info->client, - info->sink); -#endif - - is_new = FALSE; - - stream = g_hash_table_lookup (control->priv->sink_inputs, - GUINT_TO_POINTER (info->index)); - if (stream == NULL) { - GvcChannelMap *map; - map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); - stream = gvc_mixer_sink_input_new (control->priv->pa_context, - info->index, - map); - g_object_unref (map); - is_new = TRUE; - } else if (gvc_mixer_stream_is_running (stream)) { - /* Ignore events if volume changes are outstanding */ - g_debug ("Ignoring event, volume changes are outstanding"); - return; - } - - max_volume = pa_cvolume_max (&info->volume); - - name = (const char *)g_hash_table_lookup (control->priv->clients, - GUINT_TO_POINTER (info->client)); - gvc_mixer_stream_set_name (stream, name); - gvc_mixer_stream_set_description (stream, info->name); - - set_application_id_from_proplist (stream, info->proplist); - set_is_event_stream_from_proplist (stream, info->proplist); - set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia"); - gvc_mixer_stream_set_volume (stream, (guint)max_volume); - gvc_mixer_stream_set_is_muted (stream, info->mute); - gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX); - - if (is_new) { - g_hash_table_insert (control->priv->sink_inputs, - GUINT_TO_POINTER (info->index), - g_object_ref (stream)); - add_stream (control, stream); - } -} - -static void -update_source_output (GvcMixerControl *control, - const pa_source_output_info *info) -{ - GvcMixerStream *stream; - gboolean is_new; - const char *name; - -#if 1 - g_debug ("Updating source output: index=%u name='%s' client=%u source=%u", - info->index, - info->name, - info->client, - info->source); -#endif - - is_new = FALSE; - stream = g_hash_table_lookup (control->priv->source_outputs, - GUINT_TO_POINTER (info->index)); - if (stream == NULL) { - GvcChannelMap *map; - map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); - stream = gvc_mixer_source_output_new (control->priv->pa_context, - info->index, - map); - g_object_unref (map); - is_new = TRUE; - } - - name = (const char *)g_hash_table_lookup (control->priv->clients, - GUINT_TO_POINTER (info->client)); - - gvc_mixer_stream_set_name (stream, name); - gvc_mixer_stream_set_description (stream, info->name); - set_application_id_from_proplist (stream, info->proplist); - set_is_event_stream_from_proplist (stream, info->proplist); - set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); - - if (is_new) { - g_hash_table_insert (control->priv->source_outputs, - GUINT_TO_POINTER (info->index), - g_object_ref (stream)); - add_stream (control, stream); - } -} - -static void -update_client (GvcMixerControl *control, - const pa_client_info *info) -{ -#if 1 - g_debug ("Updating client: index=%u name='%s'", - info->index, - info->name); -#endif - g_hash_table_insert (control->priv->clients, - GUINT_TO_POINTER (info->index), - g_strdup (info->name)); -} - -static char * -card_num_streams_to_status (guint sinks, - guint sources) -{ - char *sinks_str; - char *sources_str; - char *ret; - - if (sinks == 0 && sources == 0) { - /* translators: - * The device has been disabled */ - return g_strdup (_("Disabled")); - } - if (sinks == 0) { - sinks_str = NULL; - } else { - /* translators: - * The number of sound outputs on a particular device */ - sinks_str = g_strdup_printf (ngettext ("%u Output", - "%u Outputs", - sinks), - sinks); - } - if (sources == 0) { - sources_str = NULL; - } else { - /* translators: - * The number of sound inputs on a particular device */ - sources_str = g_strdup_printf (ngettext ("%u Input", - "%u Inputs", - sources), - sources); - } - if (sources_str == NULL) - return sinks_str; - if (sinks_str == NULL) - return sources_str; - ret = g_strdup_printf ("%s / %s", sinks_str, sources_str); - g_free (sinks_str); - g_free (sources_str); - return ret; -} - -static void -update_card (GvcMixerControl *control, - const pa_card_info *info) -{ - GvcMixerCard *card; - gboolean is_new; -#if 1 - guint i; - const char *key; - void *state; - - g_debug ("Udpating card %s (index: %u driver: %s):", - info->name, info->index, info->driver); - - for (i = 0; i < info->n_profiles; i++) { - struct pa_card_profile_info pi = info->profiles[i]; - gboolean is_default; - - is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0); - g_debug ("\tProfile '%s': %d sources %d sinks%s", - pi.name, pi.n_sources, pi.n_sinks, - is_default ? " (Current)" : ""); - } - state = NULL; - key = pa_proplist_iterate (info->proplist, &state); - while (key != NULL) { - g_debug ("\tProperty: '%s' = '%s'", - key, pa_proplist_gets (info->proplist, key)); - key = pa_proplist_iterate (info->proplist, &state); - } -#endif - card = g_hash_table_lookup (control->priv->cards, - GUINT_TO_POINTER (info->index)); - if (card == NULL) { - GList *list = NULL; - - for (i = 0; i < info->n_profiles; i++) { - struct pa_card_profile_info pi = info->profiles[i]; - GvcMixerCardProfile *profile; - - profile = g_new0 (GvcMixerCardProfile, 1); - profile->profile = g_strdup (pi.name); - profile->human_profile = g_strdup (pi.description); - profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources); - profile->n_sinks = pi.n_sinks; - profile->n_sources = pi.n_sources; - profile->priority = pi.priority; - list = g_list_prepend (list, profile); - } - card = gvc_mixer_card_new (control->priv->pa_context, - info->index); - gvc_mixer_card_set_profiles (card, list); - is_new = TRUE; - } - - gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description")); - gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name")); - gvc_mixer_card_set_profile (card, info->active_profile->name); - - if (is_new) { - g_hash_table_insert (control->priv->cards, - GUINT_TO_POINTER (info->index), - g_object_ref (card)); - } - g_signal_emit (G_OBJECT (control), - signals[CARD_ADDED], - 0, - info->index); -} - -static void -_pa_context_get_sink_info_cb (pa_context *context, - const pa_sink_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) { - return; - } - - g_warning ("Sink callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_sink (control, i); -} - -static void -_pa_context_get_source_info_cb (pa_context *context, - const pa_source_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) { - return; - } - - g_warning ("Source callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_source (control, i); -} - -static void -_pa_context_get_sink_input_info_cb (pa_context *context, - const pa_sink_input_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) { - return; - } - - g_warning ("Sink input callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_sink_input (control, i); -} - -static void -_pa_context_get_source_output_info_cb (pa_context *context, - const pa_source_output_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) { - return; - } - - g_warning ("Source output callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_source_output (control, i); -} - -static void -_pa_context_get_client_info_cb (pa_context *context, - const pa_client_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) { - return; - } - - g_warning ("Client callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_client (control, i); -} - -static void -_pa_context_get_card_info_by_index_cb (pa_context *context, - const pa_card_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - if (pa_context_errno (context) == PA_ERR_NOENTITY) - return; - - g_warning ("Card callback failure"); - return; - } - - if (eol > 0) { - dec_outstanding (control); - return; - } - - update_card (control, i); -} - -static void -_pa_context_get_server_info_cb (pa_context *context, - const pa_server_info *i, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (i == NULL) { - g_warning ("Server info callback failure"); - return; - } - - update_server (control, i); - dec_outstanding (control); -} - -static void -remove_event_role_stream (GvcMixerControl *control) -{ - g_debug ("Removing event role"); -} - -static void -update_event_role_stream (GvcMixerControl *control, - const pa_ext_stream_restore_info *info) -{ - GvcMixerStream *stream; - gboolean is_new; - pa_volume_t max_volume; - - if (strcmp (info->name, "sink-input-by-media-role:event") != 0) { - return; - } - -#if 0 - g_debug ("Updating event role: name='%s' device='%s'", - info->name, - info->device); -#endif - - is_new = FALSE; - - if (!control->priv->event_sink_input_is_set) { - pa_channel_map pa_map; - GvcChannelMap *map; - - pa_map.channels = 1; - pa_map.map[0] = PA_CHANNEL_POSITION_MONO; - map = gvc_channel_map_new_from_pa_channel_map (&pa_map); - - stream = gvc_mixer_event_role_new (control->priv->pa_context, - info->device, - map); - control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream); - control->priv->event_sink_input_is_set = TRUE; - - is_new = TRUE; - } else { - stream = g_hash_table_lookup (control->priv->all_streams, - GUINT_TO_POINTER (control->priv->event_sink_input_id)); - } - - max_volume = pa_cvolume_max (&info->volume); - - gvc_mixer_stream_set_name (stream, _("System Sounds")); - gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control"); - gvc_mixer_stream_set_volume (stream, (guint)max_volume); - gvc_mixer_stream_set_is_muted (stream, info->mute); - - if (is_new) { - add_stream (control, stream); - } -} - -static void -_pa_ext_stream_restore_read_cb (pa_context *context, - const pa_ext_stream_restore_info *i, - int eol, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - if (eol < 0) { - g_debug ("Failed to initialized stream_restore extension: %s", - pa_strerror (pa_context_errno (context))); - remove_event_role_stream (control); - return; - } - - if (eol > 0) { - dec_outstanding (control); - /* If we don't have an event stream to restore, then - * set one up with a default 100% volume */ - if (!control->priv->event_sink_input_is_set) { - pa_ext_stream_restore_info info; - - memset (&info, 0, sizeof(info)); - info.name = "sink-input-by-media-role:event"; - info.volume.channels = 1; - info.volume.values[0] = PA_VOLUME_NORM; - update_event_role_stream (control, &info); - } - return; - } - - update_event_role_stream (control, i); -} - -static void -_pa_ext_stream_restore_subscribe_cb (pa_context *context, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - pa_operation *o; - - o = pa_ext_stream_restore_read (context, - _pa_ext_stream_restore_read_cb, - control); - if (o == NULL) { - g_warning ("pa_ext_stream_restore_read() failed"); - return; - } - - pa_operation_unref (o); -} - -static void -req_update_server_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - o = pa_context_get_server_info (control->priv->pa_context, - _pa_context_get_server_info_cb, - control); - if (o == NULL) { - g_warning ("pa_context_get_server_info() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_client_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_client_info_list (control->priv->pa_context, - _pa_context_get_client_info_cb, - control); - } else { - o = pa_context_get_client_info (control->priv->pa_context, - index, - _pa_context_get_client_info_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_client_info_list() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_card (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_card_info_list (control->priv->pa_context, - _pa_context_get_card_info_by_index_cb, - control); - } else { - o = pa_context_get_card_info_by_index (control->priv->pa_context, - index, - _pa_context_get_card_info_by_index_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_get_card_info_by_index() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_sink_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_sink_info_list (control->priv->pa_context, - _pa_context_get_sink_info_cb, - control); - } else { - o = pa_context_get_sink_info_by_index (control->priv->pa_context, - index, - _pa_context_get_sink_info_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_get_sink_info_list() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_source_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_source_info_list (control->priv->pa_context, - _pa_context_get_source_info_cb, - control); - } else { - o = pa_context_get_source_info_by_index(control->priv->pa_context, - index, - _pa_context_get_source_info_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_get_source_info_list() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_sink_input_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_sink_input_info_list (control->priv->pa_context, - _pa_context_get_sink_input_info_cb, - control); - } else { - o = pa_context_get_sink_input_info (control->priv->pa_context, - index, - _pa_context_get_sink_input_info_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_get_sink_input_info_list() failed"); - return; - } - pa_operation_unref (o); -} - -static void -req_update_source_output_info (GvcMixerControl *control, - int index) -{ - pa_operation *o; - - if (index < 0) { - o = pa_context_get_source_output_info_list (control->priv->pa_context, - _pa_context_get_source_output_info_cb, - control); - } else { - o = pa_context_get_source_output_info (control->priv->pa_context, - index, - _pa_context_get_source_output_info_cb, - control); - } - - if (o == NULL) { - g_warning ("pa_context_get_source_output_info_list() failed"); - return; - } - pa_operation_unref (o); -} - -static void -remove_client (GvcMixerControl *control, - guint index) -{ - g_hash_table_remove (control->priv->clients, - GUINT_TO_POINTER (index)); -} - -static void -remove_card (GvcMixerControl *control, - guint index) -{ - g_hash_table_remove (control->priv->cards, - GUINT_TO_POINTER (index)); - - g_signal_emit (G_OBJECT (control), - signals[CARD_REMOVED], - 0, - index); -} - -static void -remove_sink (GvcMixerControl *control, - guint index) -{ - GvcMixerStream *stream; - -#if 0 - g_debug ("Removing sink: index=%u", index); -#endif - - stream = g_hash_table_lookup (control->priv->sinks, - GUINT_TO_POINTER (index)); - if (stream == NULL) { - return; - } - g_hash_table_remove (control->priv->sinks, - GUINT_TO_POINTER (index)); - - remove_stream (control, stream); -} - -static void -remove_source (GvcMixerControl *control, - guint index) -{ - GvcMixerStream *stream; - -#if 0 - g_debug ("Removing source: index=%u", index); -#endif - - stream = g_hash_table_lookup (control->priv->sources, - GUINT_TO_POINTER (index)); - if (stream == NULL) { - return; - } - g_hash_table_remove (control->priv->sources, - GUINT_TO_POINTER (index)); - - remove_stream (control, stream); -} - -static void -remove_sink_input (GvcMixerControl *control, - guint index) -{ - GvcMixerStream *stream; - -#if 0 - g_debug ("Removing sink input: index=%u", index); -#endif - stream = g_hash_table_lookup (control->priv->sink_inputs, - GUINT_TO_POINTER (index)); - if (stream == NULL) { - return; - } - g_hash_table_remove (control->priv->sink_inputs, - GUINT_TO_POINTER (index)); - - remove_stream (control, stream); -} - -static void -remove_source_output (GvcMixerControl *control, - guint index) -{ - GvcMixerStream *stream; - -#if 0 - g_debug ("Removing source output: index=%u", index); -#endif - - stream = g_hash_table_lookup (control->priv->source_outputs, - GUINT_TO_POINTER (index)); - if (stream == NULL) { - return; - } - g_hash_table_remove (control->priv->source_outputs, - GUINT_TO_POINTER (index)); - - remove_stream (control, stream); -} - -static void -_pa_context_subscribe_cb (pa_context *context, - pa_subscription_event_type_t t, - uint32_t index, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_sink (control, index); - } else { - req_update_sink_info (control, index); - } - break; - - case PA_SUBSCRIPTION_EVENT_SOURCE: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_source (control, index); - } else { - req_update_source_info (control, index); - } - break; - - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_sink_input (control, index); - } else { - req_update_sink_input_info (control, index); - } - break; - - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_source_output (control, index); - } else { - req_update_source_output_info (control, index); - } - break; - - case PA_SUBSCRIPTION_EVENT_CLIENT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_client (control, index); - } else { - req_update_client_info (control, index); - } - break; - - case PA_SUBSCRIPTION_EVENT_SERVER: - req_update_server_info (control, index); - break; - - case PA_SUBSCRIPTION_EVENT_CARD: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - remove_card (control, index); - } else { - req_update_card (control, index); - } - break; - } -} - -static void -gvc_mixer_control_ready (GvcMixerControl *control) -{ - pa_operation *o; - - pa_context_set_subscribe_callback (control->priv->pa_context, - _pa_context_subscribe_cb, - control); - o = pa_context_subscribe (control->priv->pa_context, - (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SOURCE| - PA_SUBSCRIPTION_MASK_SINK_INPUT| - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| - PA_SUBSCRIPTION_MASK_CLIENT| - PA_SUBSCRIPTION_MASK_SERVER| - PA_SUBSCRIPTION_MASK_CARD), - NULL, - NULL); - - if (o == NULL) { - g_warning ("pa_context_subscribe() failed"); - return; - } - pa_operation_unref (o); - - req_update_server_info (control, -1); - req_update_client_info (control, -1); - req_update_sink_info (control, -1); - req_update_source_info (control, -1); - req_update_sink_input_info (control, -1); - req_update_source_output_info (control, -1); - req_update_card (control, -1); - - control->priv->n_outstanding = 6; - - /* This call is not always supported */ - o = pa_ext_stream_restore_read (control->priv->pa_context, - _pa_ext_stream_restore_read_cb, - control); - if (o != NULL) { - pa_operation_unref (o); - control->priv->n_outstanding++; - - pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context, - _pa_ext_stream_restore_subscribe_cb, - control); - - o = pa_ext_stream_restore_subscribe (control->priv->pa_context, - 1, - NULL, - NULL); - if (o != NULL) { - pa_operation_unref (o); - } - - } else { - g_debug ("Failed to initialized stream_restore extension: %s", - pa_strerror (pa_context_errno (control->priv->pa_context))); - } -} - -static void -gvc_mixer_new_pa_context (GvcMixerControl *self) -{ - pa_proplist *proplist; - - g_return_if_fail (self); - g_return_if_fail (!self->priv->pa_context); - - proplist = pa_proplist_new (); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_NAME, - self->priv->name); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_ID, - "org.mate.VolumeControl"); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_ICON_NAME, - "multimedia-volume-control"); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_VERSION, - PACKAGE_VERSION); - - self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist); - - pa_proplist_free (proplist); - g_assert (self->priv->pa_context); -} - -static void -remove_all_streams (GvcMixerControl *control, GHashTable *hash_table) -{ - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, hash_table); - while (g_hash_table_iter_next (&iter, &key, &value)) { - remove_stream (control, value); - g_hash_table_iter_remove (&iter); - } -} - -static gboolean -idle_reconnect (gpointer data) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (data); - GHashTableIter iter; - gpointer key, value; - - g_return_val_if_fail (control, FALSE); - - if (control->priv->pa_context) { - pa_context_unref (control->priv->pa_context); - control->priv->pa_context = NULL; - gvc_mixer_new_pa_context (control); - } - - remove_all_streams (control, control->priv->sinks); - remove_all_streams (control, control->priv->sources); - remove_all_streams (control, control->priv->sink_inputs); - remove_all_streams (control, control->priv->source_outputs); - - g_hash_table_iter_init (&iter, control->priv->clients); - while (g_hash_table_iter_next (&iter, &key, &value)) - g_hash_table_iter_remove (&iter); - - gvc_mixer_control_open (control); /* cannot fail */ - - control->priv->reconnect_id = 0; - return FALSE; -} - -static void -_pa_context_state_cb (pa_context *context, - void *userdata) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); - - switch (pa_context_get_state (context)) { - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - - case PA_CONTEXT_READY: - gvc_mixer_control_ready (control); - break; - - case PA_CONTEXT_FAILED: - g_warning ("Connection failed, reconnecting..."); - if (control->priv->reconnect_id == 0) - control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control); - break; - - case PA_CONTEXT_TERMINATED: - default: - /* FIXME: */ - break; - } -} - -gboolean -gvc_mixer_control_open (GvcMixerControl *control) -{ - int res; - - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); - g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); - g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE); - - pa_context_set_state_callback (control->priv->pa_context, - _pa_context_state_cb, - control); - - g_signal_emit (G_OBJECT (control), signals[CONNECTING], 0); - res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL); - if (res < 0) { - g_warning ("Failed to connect context: %s", - pa_strerror (pa_context_errno (control->priv->pa_context))); - } - - return res; -} - -gboolean -gvc_mixer_control_close (GvcMixerControl *control) -{ - g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); - g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); - - pa_context_disconnect (control->priv->pa_context); - return TRUE; -} - -static void -gvc_mixer_control_dispose (GObject *object) -{ - GvcMixerControl *control = GVC_MIXER_CONTROL (object); - - if (control->priv->pa_context != NULL) { - pa_context_unref (control->priv->pa_context); - control->priv->pa_context = NULL; - } - - if (control->priv->default_source_name != NULL) { - g_free (control->priv->default_source_name); - control->priv->default_source_name = NULL; - } - if (control->priv->default_sink_name != NULL) { - g_free (control->priv->default_sink_name); - control->priv->default_sink_name = NULL; - } - - if (control->priv->pa_mainloop != NULL) { - pa_glib_mainloop_free (control->priv->pa_mainloop); - control->priv->pa_mainloop = NULL; - } - - if (control->priv->all_streams != NULL) { - g_hash_table_destroy (control->priv->all_streams); - control->priv->all_streams = NULL; - } - - if (control->priv->sinks != NULL) { - g_hash_table_destroy (control->priv->sinks); - control->priv->sinks = NULL; - } - if (control->priv->sources != NULL) { - g_hash_table_destroy (control->priv->sources); - control->priv->sources = NULL; - } - if (control->priv->sink_inputs != NULL) { - g_hash_table_destroy (control->priv->sink_inputs); - control->priv->sink_inputs = NULL; - } - if (control->priv->source_outputs != NULL) { - g_hash_table_destroy (control->priv->source_outputs); - control->priv->source_outputs = NULL; - } - if (control->priv->clients != NULL) { - g_hash_table_destroy (control->priv->clients); - control->priv->clients = NULL; - } - if (control->priv->cards != NULL) { - g_hash_table_destroy (control->priv->cards); - control->priv->cards = NULL; - } - - G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object); -} - -static void -gvc_mixer_control_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GvcMixerControl *self = GVC_MIXER_CONTROL (object); - - switch (prop_id) { - case PROP_NAME: - g_free (self->priv->name); - self->priv->name = g_value_dup_string (value); - g_object_notify (G_OBJECT (self), "name"); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gvc_mixer_control_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GvcMixerControl *self = GVC_MIXER_CONTROL (object); - - switch (prop_id) { - case PROP_NAME: - g_value_set_string (value, self->priv->name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static GObject * -gvc_mixer_control_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) -{ - GObject *object; - GvcMixerControl *self; - - object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params); - - self = GVC_MIXER_CONTROL (object); - - gvc_mixer_new_pa_context (self); - - return object; -} - -static void -gvc_mixer_control_class_init (GvcMixerControlClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructor = gvc_mixer_control_constructor; - object_class->dispose = gvc_mixer_control_dispose; - object_class->finalize = gvc_mixer_control_finalize; - object_class->set_property = gvc_mixer_control_set_property; - object_class->get_property = gvc_mixer_control_get_property; - - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "Name to display for this mixer control", - NULL, - G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); - - signals [CONNECTING] = - g_signal_new ("connecting", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, connecting), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals [READY] = - g_signal_new ("ready", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, ready), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals [STREAM_ADDED] = - g_signal_new ("stream-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, stream_added), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - signals [STREAM_REMOVED] = - g_signal_new ("stream-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - signals [CARD_ADDED] = - g_signal_new ("card-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, card_added), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - signals [CARD_REMOVED] = - g_signal_new ("card-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, card_removed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - signals [DEFAULT_SINK_CHANGED] = - g_signal_new ("default-sink-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - signals [DEFAULT_SOURCE_CHANGED] = - g_signal_new ("default-source-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate)); -} - -static void -gvc_mixer_control_init (GvcMixerControl *control) -{ - control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control); - - control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ()); - g_assert (control->priv->pa_mainloop); - - control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop); - g_assert (control->priv->pa_api); - - control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); - - control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free); -} - -static void -gvc_mixer_control_finalize (GObject *object) -{ - GvcMixerControl *mixer_control; - - g_return_if_fail (object != NULL); - g_return_if_fail (GVC_IS_MIXER_CONTROL (object)); - - mixer_control = GVC_MIXER_CONTROL (object); - g_free (mixer_control->priv->name); - mixer_control->priv->name = NULL; - - g_return_if_fail (mixer_control->priv != NULL); - G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object); -} - -GvcMixerControl * -gvc_mixer_control_new (const char *name) -{ - GObject *control; - control = g_object_new (GVC_TYPE_MIXER_CONTROL, - "name", name, - NULL); - return GVC_MIXER_CONTROL (control); -} |