summaryrefslogtreecommitdiff
path: root/backends/pulse/pulse-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'backends/pulse/pulse-backend.c')
-rw-r--r--backends/pulse/pulse-backend.c1078
1 files changed, 469 insertions, 609 deletions
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index 0494545..e1b7ed5 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -19,9 +19,8 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-backend.h>
-#include <libmatemixer/matemixer-backend-module.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
@@ -38,72 +37,110 @@
#include "pulse-source-output.h"
#define BACKEND_NAME "PulseAudio"
-#define BACKEND_PRIORITY 10
+#define BACKEND_PRIORITY 100
struct _PulseBackendPrivate
{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- gchar *server_address;
- gboolean connected_once;
- GSource *connect_source;
- MateMixerStream *default_sink;
- MateMixerStream *default_source;
- GHashTable *devices;
- GHashTable *streams;
- GHashTable *ext_streams;
- MateMixerState state;
- PulseConnection *connection;
-};
-
-enum {
- PROP_0,
- PROP_STATE,
- PROP_DEFAULT_INPUT,
- PROP_DEFAULT_OUTPUT,
- N_PROPERTIES
+ guint connect_tag;
+ gboolean connected_once;
+ GHashTable *devices;
+ GHashTable *sinks;
+ GHashTable *sources;
+ GHashTable *sink_inputs;
+ GHashTable *source_outputs;
+ GHashTable *ext_streams;
+ GList *devices_list;
+ GList *streams_list;
+ GList *ext_streams_list;
+ MateMixerAppInfo *app_info;
+ gchar *server_address;
+ PulseConnection *connection;
};
-static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+#define PULSE_CHANGE_STATE(p, s) \
+ (_mate_mixer_backend_set_state (MATE_MIXER_BACKEND (p), (s)))
+#define PULSE_GET_DEFAULT_SINK(p) \
+ (mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_GET_DEFAULT_SOURCE(p) \
+ (mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_SET_DEFAULT_SINK(p, s) \
+ (_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+#define PULSE_SET_DEFAULT_SOURCE(p, s) \
+ (_mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+
+#define PULSE_GET_PENDING_SINK(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink")) \
+
+#define PULSE_SET_PENDING_SINK(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SINK_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ NULL))
+
+#define PULSE_GET_PENDING_SOURCE(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source")) \
+
+#define PULSE_SET_PENDING_SOURCE(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SOURCE_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ NULL))
+
+#define PULSE_GET_HANGING(o) \
+ ((gboolean) g_object_get_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
+
+#define PULSE_SET_HANGING(o) \
+ (g_object_set_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging", \
+ GUINT_TO_POINTER (1)))
+
+#define PULSE_UNSET_HANGING(o) \
+ (g_object_steal_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
static void pulse_backend_class_init (PulseBackendClass *klass);
static void pulse_backend_class_finalize (PulseBackendClass *klass);
-static void pulse_backend_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-
static void pulse_backend_init (PulseBackend *pulse);
static void pulse_backend_dispose (GObject *object);
static void pulse_backend_finalize (GObject *object);
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (PulseBackend, pulse_backend,
- G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
- mate_mixer_backend_interface_init))
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+G_DEFINE_DYNAMIC_TYPE (PulseBackend, pulse_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
-static gboolean pulse_backend_open (MateMixerBackend *backend);
-static void pulse_backend_close (MateMixerBackend *backend);
+static gboolean pulse_backend_open (MateMixerBackend *backend);
+static void pulse_backend_close (MateMixerBackend *backend);
-static MateMixerState pulse_backend_get_state (MateMixerBackend *backend);
+static void pulse_backend_set_app_info (MateMixerBackend *backend,
+ MateMixerAppInfo *info);
-static void pulse_backend_set_data (MateMixerBackend *backend,
- const MateMixerBackendData *data);
+static void pulse_backend_set_server_address (MateMixerBackend *backend,
+ const gchar *address);
-static GList * pulse_backend_list_devices (MateMixerBackend *backend);
-static GList * pulse_backend_list_streams (MateMixerBackend *backend);
-static GList * pulse_backend_list_cached_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_devices (MateMixerBackend *backend);
+static const GList * pulse_backend_list_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_stored_controls (MateMixerBackend *backend);
-static MateMixerStream *pulse_backend_get_default_input_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-static MateMixerStream *pulse_backend_get_default_output_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
static void on_connection_state_notify (PulseConnection *connection,
GParamSpec *pspec,
@@ -152,32 +189,16 @@ static void on_connection_ext_stream_info (PulseConnection
PulseBackend *pulse);
static gboolean connect_source_reconnect (PulseBackend *pulse);
-static void connect_source_remove (PulseBackend *pulse);
static void check_pending_sink (PulseBackend *pulse,
PulseStream *stream);
static void check_pending_source (PulseBackend *pulse,
PulseStream *stream);
-static void mark_hanging (PulseBackend *pulse);
-static void mark_hanging_hash (GHashTable *hash);
-
-static void unmark_hanging (PulseBackend *pulse,
- GObject *object);
-
-static void remove_hanging (PulseBackend *pulse);
-static void remove_device (PulseBackend *pulse,
- PulseDevice *device);
-static void remove_stream (PulseBackend *pulse,
- PulseStream *stream);
-
-static void change_state (PulseBackend *backend,
- MateMixerState state);
+static void free_list_devices (PulseBackend *pulse);
+static void free_list_streams (PulseBackend *pulse);
+static void free_list_ext_streams (PulseBackend *pulse);
-static gint compare_devices (gconstpointer a,
- gconstpointer b);
-static gint compare_streams (gconstpointer a,
- gconstpointer b);
static gboolean compare_stream_names (gpointer key,
gpointer value,
gpointer user_data);
@@ -195,78 +216,42 @@ backend_module_init (GTypeModule *module)
info.backend_type = MATE_MIXER_BACKEND_PULSEAUDIO;
}
-const MateMixerBackendInfo *
-backend_module_get_info (void)
+const MateMixerBackendInfo *backend_module_get_info (void)
{
return &info;
}
static void
-mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
-{
- iface->open = pulse_backend_open;
- iface->close = pulse_backend_close;
- iface->get_state = pulse_backend_get_state;
- iface->set_data = pulse_backend_set_data;
- iface->list_devices = pulse_backend_list_devices;
- iface->list_streams = pulse_backend_list_streams;
- iface->list_cached_streams = pulse_backend_list_cached_streams;
- iface->get_default_input_stream = pulse_backend_get_default_input_stream;
- iface->set_default_input_stream = pulse_backend_set_default_input_stream;
- iface->get_default_output_stream = pulse_backend_get_default_output_stream;
- iface->set_default_output_stream = pulse_backend_set_default_output_stream;
-}
-
-static void
pulse_backend_class_init (PulseBackendClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerBackendClass *backend_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_backend_dispose;
- object_class->finalize = pulse_backend_finalize;
- object_class->get_property = pulse_backend_get_property;
-
- g_object_class_override_property (object_class, PROP_STATE, "state");
- g_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input");
- g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output");
+ object_class->dispose = pulse_backend_dispose;
+ object_class->finalize = pulse_backend_finalize;
+
+ backend_class = MATE_MIXER_BACKEND_CLASS (klass);
+ backend_class->set_app_info = pulse_backend_set_app_info;
+ backend_class->set_server_address = pulse_backend_set_server_address;
+ backend_class->open = pulse_backend_open;
+ backend_class->close = pulse_backend_close;
+ backend_class->list_devices = pulse_backend_list_devices;
+ backend_class->list_streams = pulse_backend_list_streams;
+ backend_class->list_stored_controls = pulse_backend_list_stored_controls;
+ backend_class->set_default_input_stream = pulse_backend_set_default_input_stream;
+ backend_class->set_default_output_stream = pulse_backend_set_default_output_stream;
g_type_class_add_private (object_class, sizeof (PulseBackendPrivate));
}
-/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */
static void
pulse_backend_class_finalize (PulseBackendClass *klass)
{
}
static void
-pulse_backend_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PulseBackend *pulse;
-
- pulse = PULSE_BACKEND (object);
-
- switch (param_id) {
- case PROP_STATE:
- g_value_set_enum (value, pulse->priv->state);
- break;
- case PROP_DEFAULT_INPUT:
- g_value_set_object (value, pulse->priv->default_source);
- break;
- case PROP_DEFAULT_OUTPUT:
- g_value_set_object (value, pulse->priv->default_sink);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
pulse_backend_init (PulseBackend *pulse)
{
pulse->priv = G_TYPE_INSTANCE_GET_PRIVATE (pulse,
@@ -279,22 +264,46 @@ pulse_backend_init (PulseBackend *pulse)
g_direct_equal,
NULL,
g_object_unref);
- pulse->priv->streams =
- g_hash_table_new_full (g_int64_hash,
- g_int64_equal,
- g_free,
+ pulse->priv->sinks =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
g_object_unref);
+ pulse->priv->sources =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
pulse->priv->ext_streams =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
+
+ pulse->priv->sink_inputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->source_outputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
}
static void
pulse_backend_dispose (GObject *object)
{
- pulse_backend_close (MATE_MIXER_BACKEND (object));
+ MateMixerBackend *backend;
+ MateMixerState state;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ state = mate_mixer_backend_get_state (backend);
+ if (state != MATE_MIXER_STATE_IDLE)
+ pulse_backend_close (backend);
G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
}
@@ -306,19 +315,24 @@ pulse_backend_finalize (GObject *object)
pulse = PULSE_BACKEND (object);
- g_free (pulse->priv->app_name);
- g_free (pulse->priv->app_id);
- g_free (pulse->priv->app_version);
- g_free (pulse->priv->app_icon);
- g_free (pulse->priv->server_address);
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
- g_hash_table_destroy (pulse->priv->devices);
- g_hash_table_destroy (pulse->priv->streams);
- g_hash_table_destroy (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->devices);
+ g_hash_table_unref (pulse->priv->sinks);
+ g_hash_table_unref (pulse->priv->sources);
+ g_hash_table_unref (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->sink_inputs);
+ g_hash_table_unref (pulse->priv->source_outputs);
G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
}
+#define PULSE_APP_NAME(p) (mate_mixer_app_info_get_name (p->priv->app_info))
+#define PULSE_APP_ID(p) (mate_mixer_app_info_get_id (p->priv->app_info))
+#define PULSE_APP_VERSION(p) (mate_mixer_app_info_get_version (p->priv->app_info))
+#define PULSE_APP_ICON(p) (mate_mixer_app_info_get_icon (p->priv->app_info))
+
static gboolean
pulse_backend_open (MateMixerBackend *backend)
{
@@ -329,22 +343,22 @@ pulse_backend_open (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- if (G_UNLIKELY (pulse->priv->connection != NULL)) {
+ if G_UNLIKELY (pulse->priv->connection != NULL) {
g_warn_if_reached ();
return TRUE;
}
- connection = pulse_connection_new (pulse->priv->app_name,
- pulse->priv->app_id,
- pulse->priv->app_version,
- pulse->priv->app_icon,
+ connection = pulse_connection_new (PULSE_APP_NAME (pulse),
+ PULSE_APP_ID (pulse),
+ PULSE_APP_VERSION (pulse),
+ PULSE_APP_ICON (pulse),
pulse->priv->server_address);
/* No connection attempt is made during the construction of the connection,
* but it sets up the PulseAudio structures, which might fail in an
* unlikely case */
- if (G_UNLIKELY (connection == NULL)) {
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ if G_UNLIKELY (connection == NULL) {
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -409,16 +423,21 @@ pulse_backend_open (MateMixerBackend *backend)
G_CALLBACK (on_connection_ext_stream_info),
pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (backend, MATE_MIXER_STATE_CONNECTING);
/* Connect to the PulseAudio server, this might fail either instantly or
* asynchronously, for example when remote connection timeouts */
if (pulse_connection_connect (connection, FALSE) == FALSE) {
g_object_unref (connection);
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
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;
}
@@ -432,7 +451,10 @@ pulse_backend_close (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- connect_source_remove (pulse);
+ if (pulse->priv->connect_tag != 0) {
+ g_source_remove (pulse->priv->connect_tag);
+ pulse->priv->connect_tag = 0;
+ }
if (pulse->priv->connection != NULL) {
g_signal_handlers_disconnect_by_data (G_OBJECT (pulse->priv->connection),
@@ -441,109 +463,100 @@ pulse_backend_close (MateMixerBackend *backend)
g_clear_object (&pulse->priv->connection);
}
- g_clear_object (&pulse->priv->default_sink);
- g_clear_object (&pulse->priv->default_source);
-
g_hash_table_remove_all (pulse->priv->devices);
- g_hash_table_remove_all (pulse->priv->streams);
+ g_hash_table_remove_all (pulse->priv->sinks);
+ g_hash_table_remove_all (pulse->priv->sources);
g_hash_table_remove_all (pulse->priv->ext_streams);
pulse->priv->connected_once = FALSE;
- change_state (pulse, MATE_MIXER_STATE_IDLE);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_IDLE);
}
-static MateMixerState
-pulse_backend_get_state (MateMixerBackend *backend)
+static void
+pulse_backend_set_app_info (MateMixerBackend *backend, MateMixerAppInfo *info)
{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+ PulseBackend *pulse;
+
+ g_return_if_fail (PULSE_IS_BACKEND (backend));
+ g_return_if_fail (info != NULL);
+
+ pulse = PULSE_BACKEND (backend);
- return PULSE_BACKEND (backend)->priv->state;
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
+
+ pulse->priv->app_info = _mate_mixer_app_info_copy (info);
}
static void
-pulse_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+pulse_backend_set_server_address (MateMixerBackend *backend, const gchar *address)
{
- PulseBackend *pulse;
-
g_return_if_fail (PULSE_IS_BACKEND (backend));
- g_return_if_fail (data != NULL);
- pulse = PULSE_BACKEND (backend);
+ g_free (PULSE_BACKEND (backend)->priv->server_address);
- g_free (pulse->priv->app_name);
- g_free (pulse->priv->app_id);
- g_free (pulse->priv->app_version);
- g_free (pulse->priv->app_icon);
- g_free (pulse->priv->server_address);
-
- pulse->priv->app_name = g_strdup (data->app_name);
- pulse->priv->app_id = g_strdup (data->app_id);
- pulse->priv->app_version = g_strdup (data->app_version);
- pulse->priv->app_icon = g_strdup (data->app_icon);
- pulse->priv->server_address = g_strdup (data->server_address);
+ PULSE_BACKEND (backend)->priv->server_address = g_strdup (address);
}
-static GList *
+static const GList *
pulse_backend_list_devices (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ pulse = PULSE_BACKEND (backend);
- return g_list_sort (list, compare_devices);
+ if (pulse->priv->devices_list == NULL) {
+ pulse->priv->devices_list = g_hash_table_get_values (pulse->priv->devices);
+ if (pulse->priv->devices_list != NULL)
+ g_list_foreach (pulse->priv->devices_list, (GFunc) g_object_ref, NULL);
}
- return NULL;
+ return pulse->priv->devices_list;
}
-static GList *
+static const GList *
pulse_backend_list_streams (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return g_list_sort (list, compare_streams);
- }
- return NULL;
-}
+ pulse = PULSE_BACKEND (backend);
-static GList *
-pulse_backend_list_cached_streams (MateMixerBackend *backend)
-{
- GList *list;
+ if (pulse->priv->streams_list == NULL) {
+ GList *sinks;
+ GList *sources;
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ sinks = g_hash_table_get_values (pulse->priv->sinks);
+ if (sinks != NULL)
+ g_list_foreach (sinks, (GFunc) g_object_ref, NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->ext_streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ sources = g_hash_table_get_values (pulse->priv->sources);
+ if (sources != NULL)
+ g_list_foreach (sources, (GFunc) g_object_ref, NULL);
- return g_list_sort (list, compare_streams);
+ pulse->priv->streams_list = g_list_concat (sinks, sources);
}
- return NULL;
+ return pulse->priv->streams_list;
}
-static MateMixerStream *
-pulse_backend_get_default_input_stream (MateMixerBackend *backend)
+static const GList *
+pulse_backend_list_stored_controls (MateMixerBackend *backend)
{
+ PulseBackend *pulse;
+
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- return PULSE_BACKEND (backend)->priv->default_source;
+ pulse = PULSE_BACKEND (backend);
+
+ if (pulse->priv->ext_streams_list == NULL) {
+ pulse->priv->ext_streams_list = g_hash_table_get_values (pulse->priv->ext_streams);
+ if (pulse->priv->ext_streams_list != NULL)
+ g_list_foreach (pulse->priv->ext_streams_list, (GFunc) g_object_ref, NULL);
+ }
+ return pulse->priv->ext_streams_list;
}
static gboolean
@@ -562,29 +575,13 @@ pulse_backend_set_default_input_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_source (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_source != NULL)
- g_object_unref (pulse->priv->default_source);
-
- pulse->priv->default_source = g_object_ref (stream);
-
/* We might be in the process of setting a default source for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
return TRUE;
}
-static MateMixerStream *
-pulse_backend_get_default_output_stream (MateMixerBackend *backend)
-{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
-
- return PULSE_BACKEND (backend)->priv->default_sink;
-}
-
static gboolean
pulse_backend_set_default_output_stream (MateMixerBackend *backend,
MateMixerStream *stream)
@@ -601,18 +598,10 @@ pulse_backend_set_default_output_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_sink (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_sink != NULL)
- g_object_unref (pulse->priv->default_sink);
-
- pulse->priv->default_sink = g_object_ref (stream);
-
/* We might be in the process of setting a default sink for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
return TRUE;
}
@@ -633,41 +622,41 @@ on_connection_state_notify (PulseConnection *connection,
* Stream callbacks will unmark available streams and remaining
* unavailable streams will be removed when the CONNECTED state
* is reached. */
- mark_hanging (pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
- if (pulse->priv->connect_source == NULL &&
- pulse_connection_connect (connection, TRUE) == FALSE) {
- pulse->priv->connect_source = g_timeout_source_new (200);
+ if G_UNLIKELY (pulse->priv->connect_tag != 0)
+ break;
- g_source_set_callback (pulse->priv->connect_source,
+ if (pulse_connection_connect (connection, TRUE) == FALSE) {
+ GSource *source;
+
+ source = g_timeout_source_new (200);
+ g_source_set_callback (source,
(GSourceFunc) connect_source_reconnect,
pulse,
- (GDestroyNotify) connect_source_remove);
+ NULL);
+ pulse->priv->connect_tag =
+ g_source_attach (source, g_main_context_get_thread_default ());
- g_source_attach (pulse->priv->connect_source,
- g_main_context_get_thread_default ());
+ g_source_unref (source);
}
break;
}
/* First connection attempt has failed */
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
break;
case PULSE_CONNECTION_CONNECTING:
case PULSE_CONNECTION_AUTHORIZING:
case PULSE_CONNECTION_LOADING:
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
break;
case PULSE_CONNECTION_CONNECTED:
- if (pulse->priv->connected_once == TRUE)
- remove_hanging (pulse);
- else
- pulse->priv->connected_once = TRUE;
+ pulse->priv->connected_once = TRUE;
- change_state (pulse, MATE_MIXER_STATE_READY);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_READY);
break;
}
}
@@ -677,18 +666,17 @@ on_connection_server_info (PulseConnection *connection,
const pa_server_info *info,
PulseBackend *pulse)
{
- const gchar *name_source = NULL;
- const gchar *name_sink = NULL;
+ MateMixerStream *stream;
+ const gchar *name_source = NULL;
+ const gchar *name_sink = NULL;
- if (pulse->priv->default_source != NULL)
- name_source = mate_mixer_stream_get_name (pulse->priv->default_source);
+ stream = PULSE_GET_DEFAULT_SOURCE (pulse);
+ if (stream != NULL)
+ name_source = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_source, info->default_source_name) != 0) {
- if (pulse->priv->default_source != NULL)
- g_clear_object (&pulse->priv->default_source);
-
if (info->default_source_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sources,
compare_stream_names,
(gpointer) info->default_source_name);
@@ -698,20 +686,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to %s", info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
} else {
g_debug ("Default input stream changed to unknown stream %s",
info->default_source_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-source",
- g_strdup (info->default_source_name),
- g_free);
+ PULSE_SET_PENDING_SOURCE (pulse, info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -721,20 +703,16 @@ on_connection_server_info (PulseConnection *connection,
info->default_source_name);
}
} else
- g_debug ("Default input stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
}
- if (pulse->priv->default_sink != NULL)
- name_sink = mate_mixer_stream_get_name (pulse->priv->default_sink);
+ stream = PULSE_GET_DEFAULT_SINK (pulse);
+ if (stream != NULL)
+ name_sink = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_sink, info->default_sink_name) != 0) {
- if (pulse->priv->default_sink != NULL)
- g_clear_object (&pulse->priv->default_sink);
-
if (info->default_sink_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sinks,
compare_stream_names,
(gpointer) info->default_sink_name);
@@ -744,21 +722,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_debug ("Default output stream changed to %s", info->default_sink_name);
-
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
+ PULSE_SET_PENDING_SINK_NULL (pulse);
} else {
g_debug ("Default output stream changed to unknown stream %s",
info->default_sink_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-sink",
- g_strdup (info->default_sink_name),
- g_free);
+ PULSE_SET_PENDING_SINK (pulse, info->default_sink_name);
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -768,12 +739,10 @@ on_connection_server_info (PulseConnection *connection,
info->default_sink_name);
}
} else
- g_debug ("Default output stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
}
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
+ if (mate_mixer_backend_get_state (MATE_MIXER_BACKEND (pulse)) != MATE_MIXER_STATE_READY)
g_debug ("Sound server is %s version %s, running on %s",
info->server_name,
info->server_version,
@@ -790,21 +759,17 @@ on_connection_card_info (PulseConnection *connection,
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->index));
if (device == NULL) {
device = pulse_device_new (connection, info);
- if (G_UNLIKELY (device == NULL))
- return;
- g_hash_table_insert (pulse->priv->devices, GUINT_TO_POINTER (info->index), device);
+ g_hash_table_insert (pulse->priv->devices,
+ GUINT_TO_POINTER (info->index),
+ device);
+ free_list_devices (pulse);
g_signal_emit_by_name (G_OBJECT (pulse),
"device-added",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
- } else {
+ } else
pulse_device_update (device, info);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (device));
- }
}
static void
@@ -813,29 +778,22 @@ on_connection_card_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseDevice *device;
+ gchar *name;
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (index));
- if (G_UNLIKELY (device == NULL))
+ if G_UNLIKELY (device == NULL)
return;
- remove_device (pulse, device);
-}
+ name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-/* PulseAudio uses 32-bit integers as indices for sinks, sink inputs, sources and
- * source inputs, these indices are not unique among the different kinds of streams,
- * but we want to keep all of them in a single hash table. Allow this by using 64-bit
- * hash table keys, use the lower 32 bits for the PulseAudio index and some of the
- * higher bits to indicate what kind of stream it is. */
-enum {
- HASH_BIT_SINK = (1ULL << 63),
- HASH_BIT_SINK_INPUT = (1ULL << 62),
- HASH_BIT_SOURCE = (1ULL << 61),
- HASH_BIT_SOURCE_OUTPUT = (1ULL << 60)
-};
-#define HASH_ID_SINK(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK)
-#define HASH_ID_SINK_INPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK_INPUT)
-#define HASH_ID_SOURCE(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE)
-#define HASH_ID_SOURCE_OUTPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE_OUTPUT)
+ g_hash_table_remove (pulse->priv->devices, GUINT_TO_POINTER (index));
+
+ free_list_devices (pulse);
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-removed",
+ name);
+ g_free (name);
+}
static void
on_connection_sink_info (PulseConnection *connection,
@@ -844,32 +802,36 @@ on_connection_sink_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SINK (info->index);
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_sink_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_sink_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sinks,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this sink to set it as the default */
check_pending_sink (pulse, stream);
- } else {
- pulse_sink_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_sink_update (PULSE_SINK (stream), info);
}
static void
@@ -878,13 +840,38 @@ on_connection_sink_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseStream *stream;
- gint64 index = HASH_ID_SINK (idx);
+ PulseDevice *device;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SINK (pulse)) {
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -892,40 +879,20 @@ on_connection_sink_input_info (PulseConnection *connection,
const pa_sink_input_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
+ PulseSink *sink;
- if (G_LIKELY (info->sink != PA_INVALID_INDEX)) {
- index = HASH_ID_SINK (info->sink);
-
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (parent == NULL))
- g_debug ("Unknown parent %d of PulseAudio sink input %s",
- info->sink,
- info->name);
- }
-
- index = HASH_ID_SINK_INPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_sink_input_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->sink == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ sink = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->sink));
+ if G_UNLIKELY (sink == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_sink_input_update (stream, info, parent);
+ pulse_sink_add_input (sink, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->sink_inputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (sink));
}
static void
@@ -933,14 +900,13 @@ on_connection_sink_input_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SINK_INPUT (idx);
+ PulseSink *sink;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ sink = g_hash_table_lookup (pulse->priv->sink_inputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (sink == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_sink_remove_input (sink, idx);
}
static void
@@ -950,36 +916,40 @@ on_connection_source_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (info->index);
/* Skip monitor streams */
if (info->monitor_of_sink != PA_INVALID_INDEX)
return;
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_source_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_source_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sources,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this source to set it as the default */
check_pending_source (pulse, stream);
- } else {
- pulse_source_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_source_update (PULSE_SOURCE (stream), info);
}
static void
@@ -987,14 +957,39 @@ on_connection_source_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
+ PulseDevice *device;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (idx);
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sources, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SOURCE (pulse)) {
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -1002,39 +997,20 @@ on_connection_source_output_info (PulseConnection *connection,
const pa_source_output_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
-
- if (G_LIKELY (info->source != PA_INVALID_INDEX)) {
- index = HASH_ID_SOURCE (info->source);
-
- /* Most likely a monitor source that we have skipped */
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (parent == NULL)
- return;
- }
+ PulseSource *source;
- index = HASH_ID_SOURCE_OUTPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_source_output_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->source == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ source = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->source));
+ if G_UNLIKELY (source == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_source_output_update (stream, info, parent);
+ pulse_source_add_output (source, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->source_outputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (source));
}
static void
@@ -1042,14 +1018,13 @@ on_connection_source_output_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SOURCE_OUTPUT (idx);
+ PulseSource *source;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ source = g_hash_table_lookup (pulse->priv->source_outputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (source == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_source_remove_output (source, idx);
}
static void
@@ -1057,63 +1032,75 @@ on_connection_ext_stream_info (PulseConnection *connection,
const pa_ext_stream_restore_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
+ PulseExtStream *ext;
+ PulseStream *parent = NULL;
- if (G_LIKELY (info->device != NULL))
- parent = g_hash_table_find (pulse->priv->streams, compare_stream_names,
+ if (info->device != NULL) {
+ parent = g_hash_table_find (pulse->priv->sinks, compare_stream_names,
(gpointer) info->device);
- stream = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
- if (stream == NULL) {
- stream = pulse_ext_stream_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if (parent == NULL)
+ parent = g_hash_table_find (pulse->priv->sources, compare_stream_names,
+ (gpointer) info->device);
+ }
+
+ ext = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
+ if (ext == NULL) {
+ ext = pulse_ext_stream_new (connection, info, parent);
- g_hash_table_insert (pulse->priv->ext_streams, g_strdup (info->name), stream);
+ free_list_ext_streams (pulse);
+ g_hash_table_insert (pulse->priv->ext_streams,
+ g_strdup (info->name),
+ ext);
g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ "stored-control-added",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (ext)));
} else {
- pulse_ext_stream_update (stream, info, parent);
+ pulse_ext_stream_update (ext, info, parent);
/* The object might be hanging if ext-streams are being loaded, remove
* the hanging flag to prevent it from being removed */
- unmark_hanging (pulse, G_OBJECT (stream));
+ PULSE_UNSET_HANGING (ext);
}
}
static void
on_connection_ext_stream_loading (PulseConnection *connection, PulseBackend *pulse)
{
- mark_hanging_hash (pulse->priv->ext_streams);
+ GHashTableIter iter;
+ gpointer ext;
+
+ g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
+
+ while (g_hash_table_iter_next (&iter, NULL, &ext) == TRUE)
+ PULSE_SET_HANGING (ext);
}
static void
on_connection_ext_stream_loaded (PulseConnection *connection, PulseBackend *pulse)
{
GHashTableIter iter;
- gpointer value;
+ gpointer name;
+ gpointer ext;
g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ while (g_hash_table_iter_next (&iter, &name, &ext) == TRUE) {
+ if (PULSE_GET_HANGING (ext) == FALSE)
+ continue;
- if (hanging == 1) {
- gchar *name = g_strdup ((const gchar *) value);
+ free_list_ext_streams (pulse);
+ g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-removed",
- name);
- g_free (name);
- }
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stored-control-removed",
+ name);
}
+ g_debug ("Ext-streams refreshed");
}
+// XXX rename
static gboolean
connect_source_reconnect (PulseBackend *pulse)
{
@@ -1121,16 +1108,10 @@ connect_source_reconnect (PulseBackend *pulse)
* and wait for the connection state notifications, otherwise this function
* will be called again */
if (pulse_connection_connect (pulse->priv->connection, TRUE) == TRUE) {
- connect_source_remove (pulse);
- return FALSE;
+ pulse->priv->connect_tag = 0;
+ return G_SOURCE_REMOVE;
}
- return TRUE;
-}
-
-static void
-connect_source_remove (PulseBackend *pulse)
-{
- g_clear_pointer (&pulse->priv->connect_source, g_source_unref);
+ return G_SOURCE_CONTINUE;
}
static void
@@ -1141,7 +1122,7 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-sink");
+ pending = PULSE_GET_PENDING_SINK (pulse);
if (pending == NULL)
return;
@@ -1149,14 +1130,10 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
+ g_debug ("Setting default output stream to pending stream %s", name);
- g_debug ("Default output stream changed to pending stream %s", name);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
}
static void
@@ -1167,7 +1144,7 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-source");
+ pending = PULSE_GET_PENDING_SOURCE (pulse);
if (pending == NULL)
return;
@@ -1175,160 +1152,43 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to pending stream %s", name);
+ g_debug ("Setting default input stream to pending stream %s", name);
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
}
static void
-mark_hanging (PulseBackend *pulse)
+free_list_devices (PulseBackend *pulse)
{
- /* Mark devices and streams as hanging, ext-streams are handled separately */
- mark_hanging_hash (pulse->priv->devices);
- mark_hanging_hash (pulse->priv->streams);
-}
-
-static void
-mark_hanging_hash (GHashTable *hash)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, hash);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE)
- g_object_set_data (G_OBJECT (value), "backend-hanging", GUINT_TO_POINTER (1));
-}
-
-static void
-unmark_hanging (PulseBackend *pulse, GObject *object)
-{
- if (pulse->priv->connected_once == FALSE)
- return;
- if (pulse->priv->state == MATE_MIXER_STATE_READY)
+ if (pulse->priv->devices_list == NULL)
return;
- g_object_steal_data (object, "backend-hanging");
-}
-
-static void
-remove_hanging (PulseBackend *pulse)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, pulse->priv->devices);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
-
- if (hanging == 1)
- remove_device (pulse, PULSE_DEVICE (value));
- }
-
- g_hash_table_iter_init (&iter, pulse->priv->streams);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ g_list_free_full (pulse->priv->devices_list, g_object_unref);
- if (hanging == 1)
- remove_stream (pulse, PULSE_STREAM (value));
- }
-}
-
-static void
-remove_device (PulseBackend *pulse, PulseDevice *device)
-{
- gchar *name;
-
- name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-
- g_hash_table_remove (pulse->priv->devices,
- GUINT_TO_POINTER (pulse_device_get_index (device)));
-
- g_signal_emit_by_name (G_OBJECT (pulse), "device-removed", name);
- g_free (name);
+ pulse->priv->devices_list = NULL;
}
static void
-remove_stream (PulseBackend *pulse, PulseStream *stream)
+free_list_streams (PulseBackend *pulse)
{
- gchar *name;
- guint32 idx;
- gint64 index;
- gboolean reload = FALSE;
-
- /* The removed stream might be one of the default streams, this happens
- * especially when switching profiles, after which PulseAudio removes the
- * old streams and creates new ones with different names */
- if (MATE_MIXER_STREAM (stream) == pulse->priv->default_sink) {
- g_clear_object (&pulse->priv->default_sink);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
- reload = TRUE;
- }
- else if (MATE_MIXER_STREAM (stream) == pulse->priv->default_source) {
- g_clear_object (&pulse->priv->default_source);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
- reload = TRUE;
- }
-
- idx = pulse_stream_get_index (stream);
-
- if (PULSE_IS_SINK (stream))
- index = HASH_ID_SINK (idx);
- else if (PULSE_IS_SINK_INPUT (stream))
- index = HASH_ID_SINK_INPUT (idx);
- else if (PULSE_IS_SOURCE (stream))
- index = HASH_ID_SOURCE (idx);
- else
- index = HASH_ID_SOURCE_OUTPUT (idx);
-
- name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
-
- g_hash_table_remove (pulse->priv->streams, &index);
+ if (pulse->priv->streams_list == NULL)
+ return;
- /* PulseAudio usually sends a server info update by itself when default
- * stream changes, but there is at least one case when it does not - setting
- * a card profile to off, so to be sure request an update explicitely */
- if (reload == TRUE)
- pulse_connection_load_server_info (pulse->priv->connection);
+ g_list_free_full (pulse->priv->streams_list, g_object_unref);
- g_signal_emit_by_name (G_OBJECT (pulse), "stream-removed", name);
- g_free (name);
+ pulse->priv->streams_list = NULL;
}
static void
-change_state (PulseBackend *backend, MateMixerState state)
+free_list_ext_streams (PulseBackend *pulse)
{
- if (backend->priv->state == state)
+ if (pulse->priv->ext_streams_list == NULL)
return;
- backend->priv->state = state;
-
- g_object_notify (G_OBJECT (backend), "state");
-}
+ g_list_free_full (pulse->priv->ext_streams_list, g_object_unref);
-static gint
-compare_devices (gconstpointer a, gconstpointer b)
-{
- return strcmp (mate_mixer_device_get_name (MATE_MIXER_DEVICE (a)),
- mate_mixer_device_get_name (MATE_MIXER_DEVICE (b)));
-}
-
-static gint
-compare_streams (gconstpointer a, gconstpointer b)
-{
- return strcmp (mate_mixer_stream_get_name (MATE_MIXER_STREAM (a)),
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (b)));
+ pulse->priv->ext_streams_list = NULL;
}
static gboolean
@@ -1336,5 +1196,5 @@ compare_stream_names (gpointer key, gpointer value, gpointer user_data)
{
MateMixerStream *stream = MATE_MIXER_STREAM (value);
- return !strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data);
+ return strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data) == 0;
}