summaryrefslogtreecommitdiff
path: root/backends/pulse/pulse-connection.c
diff options
context:
space:
mode:
authorMichal Ratajsky <[email protected]>2014-06-20 00:12:40 +0200
committerMichal Ratajsky <[email protected]>2014-06-20 00:12:40 +0200
commit6be9a89195e0d3bf8408cea661f22cb97b638f24 (patch)
tree745cfec763facc62b6c3bc51cd246e5cad4d9f68 /backends/pulse/pulse-connection.c
parenta2290d5e13ccee88fd9ae66a3895eb4da646f81f (diff)
downloadlibmatemixer-6be9a89195e0d3bf8408cea661f22cb97b638f24.tar.bz2
libmatemixer-6be9a89195e0d3bf8408cea661f22cb97b638f24.tar.xz
Pulse and API updates, fixes
Diffstat (limited to 'backends/pulse/pulse-connection.c')
-rw-r--r--backends/pulse/pulse-connection.c633
1 files changed, 365 insertions, 268 deletions
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index ec172ca..4289660 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -26,14 +26,14 @@
#include "pulse-connection.h"
#include "pulse-enums.h"
#include "pulse-enum-types.h"
+#include "pulse-monitor.h"
struct _PulseConnectionPrivate
{
gchar *server;
guint outstanding;
- gboolean reconnect;
- gboolean connected_once;
pa_context *context;
+ pa_proplist *proplist;
pa_glib_mainloop *mainloop;
PulseConnectionState state;
};
@@ -41,11 +41,12 @@ struct _PulseConnectionPrivate
enum {
PROP_0,
PROP_SERVER,
- PROP_RECONNECT,
PROP_STATE,
N_PROPERTIES
};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
enum {
SERVER_INFO,
CARD_INFO,
@@ -61,55 +62,229 @@ enum {
N_SIGNALS
};
-static gchar *connection_get_app_name (void);
-static gboolean connection_load_lists (PulseConnection *connection);
-
-static void connection_state_cb (pa_context *c,
- void *userdata);
-static void connection_subscribe_cb (pa_context *c,
- pa_subscription_event_type_t t,
- uint32_t idx,
- void *userdata);
-static void connection_server_info_cb (pa_context *c,
- const pa_server_info *info,
- void *userdata);
-static void connection_card_info_cb (pa_context *c,
- const pa_card_info *info,
- int eol,
- void *userdata);
-static void connection_sink_info_cb (pa_context *c,
- const pa_sink_info *info,
- int eol,
- void *userdata);
-static void connection_source_info_cb (pa_context *c,
- const pa_source_info *info,
- int eol,
- void *userdata);
-static void connection_sink_input_info_cb (pa_context *c,
- const pa_sink_input_info *info,
- int eol,
- void *userdata);
-static void connection_source_output_info_cb (pa_context *c,
- const pa_source_output_info *info,
- int eol,
- void *userdata);
-
-static void connection_list_loaded (PulseConnection *connection);
-static gboolean connection_process_operation (PulseConnection *connection,
- pa_operation *op);
+static guint signals[N_SIGNALS] = { 0, };
-G_DEFINE_TYPE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
+static void pulse_connection_class_init (PulseConnectionClass *klass);
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+static void pulse_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
-static guint signals[N_SIGNALS] = { 0, };
+static void pulse_connection_init (PulseConnection *connection);
+static void pulse_connection_finalize (GObject *object);
+
+G_DEFINE_TYPE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
+
+static gchar *connection_get_app_name (void);
+
+static gboolean connection_load_lists (PulseConnection *connection);
+
+static void connection_state_cb (pa_context *c,
+ void *userdata);
+static void connection_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata);
+static void connection_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata);
+static void connection_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata);
+
+static void connection_change_state (PulseConnection *connection,
+ PulseConnectionState state);
+
+static void connection_list_loaded (PulseConnection *connection);
+
+static gboolean connection_process_operation (PulseConnection *connection,
+ pa_operation *op);
static void
-pulse_connection_init (PulseConnection *connection)
+pulse_connection_class_init (PulseConnectionClass *klass)
{
- connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
- PULSE_TYPE_CONNECTION,
- PulseConnectionPrivate);
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pulse_connection_finalize;
+ object_class->get_property = pulse_connection_get_property;
+ object_class->set_property = pulse_connection_set_property;
+
+ properties[PROP_SERVER] =
+ g_param_spec_string ("server",
+ "Server",
+ "PulseAudio server to connect to",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] =
+ g_param_spec_enum ("state",
+ "State",
+ "Connection state",
+ PULSE_TYPE_CONNECTION_STATE,
+ PULSE_CONNECTION_DISCONNECTED,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ signals[SERVER_INFO] =
+ g_signal_new ("server-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, server_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_INFO] =
+ g_signal_new ("card-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_REMOVED] =
+ g_signal_new ("card-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INFO] =
+ g_signal_new ("sink-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_REMOVED] =
+ g_signal_new ("sink-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INPUT_INFO] =
+ g_signal_new ("sink-input-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_INPUT_REMOVED] =
+ g_signal_new ("sink-input-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_INFO] =
+ g_signal_new ("source-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_REMOVED] =
+ g_signal_new ("source-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_OUTPUT_INFO] =
+ g_signal_new ("source-output-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_OUTPUT_REMOVED] =
+ g_signal_new ("source-output-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
}
static void
@@ -126,9 +301,6 @@ pulse_connection_get_property (GObject *object,
case PROP_SERVER:
g_value_set_string (value, connection->priv->server);
break;
- case PROP_RECONNECT:
- g_value_set_boolean (value, connection->priv->reconnect);
- break;
case PROP_STATE:
g_value_set_enum (value, connection->priv->state);
break;
@@ -150,12 +322,8 @@ pulse_connection_set_property (GObject *object,
switch (param_id) {
case PROP_SERVER:
- g_free (connection->priv->server);
-
- connection->priv->server = g_value_dup_string (value);
- break;
- case PROP_RECONNECT:
- connection->priv->reconnect = g_value_get_boolean (value);
+ /* Construct-only string */
+ connection->priv->server = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -164,6 +332,14 @@ pulse_connection_set_property (GObject *object,
}
static void
+pulse_connection_init (PulseConnection *connection)
+{
+ connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
+ PULSE_TYPE_CONNECTION,
+ PulseConnectionPrivate);
+}
+
+static void
pulse_connection_finalize (GObject *object)
{
PulseConnection *connection;
@@ -172,165 +348,12 @@ pulse_connection_finalize (GObject *object)
g_free (connection->priv->server);
- G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
-}
+ pa_context_unref (connection->priv->context);
+ pa_proplist_free (connection->priv->proplist);
-static void
-pulse_connection_class_init (PulseConnectionClass *klass)
-{
- GObjectClass *object_class;
+ pa_glib_mainloop_free (connection->priv->mainloop);
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = pulse_connection_finalize;
- object_class->get_property = pulse_connection_get_property;
- object_class->set_property = pulse_connection_set_property;
-
- properties[PROP_SERVER] = g_param_spec_string ("server",
- "Server",
- "PulseAudio server to connect to",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_RECONNECT] = g_param_spec_boolean ("reconnect",
- "Reconnect",
- "Try to reconnect when connection is lost",
- TRUE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] = g_param_spec_enum ("state",
- "State",
- "Connection state",
- PULSE_TYPE_CONNECTION_STATE,
- PULSE_CONNECTION_DISCONNECTED,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- signals[SERVER_INFO] = g_signal_new ("server-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, server_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[CARD_INFO] = g_signal_new ("card-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[CARD_REMOVED] = g_signal_new ("card-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SINK_INFO] = g_signal_new ("sink-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SINK_REMOVED] = g_signal_new ("sink-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SINK_INPUT_INFO] = g_signal_new ("sink-input-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SINK_INPUT_REMOVED] = g_signal_new ("sink-input-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SOURCE_INFO] = g_signal_new ("source-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SOURCE_OUTPUT_INFO] = g_signal_new ("source-output-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SOURCE_OUTPUT_REMOVED] = g_signal_new ("source-output-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
+ G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
}
PulseConnection *
@@ -351,6 +374,9 @@ pulse_connection_new (const gchar *app_name,
return NULL;
}
+ /* Create a property list to hold information about the application,
+ * the list will be kept with the connection as it may be reused later
+ * when creating PulseAudio streams */
proplist = pa_proplist_new ();
if (app_name)
pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, app_name);
@@ -366,80 +392,90 @@ pulse_connection_new (const gchar *app_name,
app_name,
proplist);
} else {
+ /* Try to set some sensible default name when application does not
+ * provide a name */
gchar *name = connection_get_app_name ();
context = pa_context_new_with_proplist (pa_glib_mainloop_get_api (mainloop),
name,
proplist);
-
g_free (name);
}
- pa_proplist_free (proplist);
if (G_UNLIKELY (context == NULL)) {
g_warning ("Failed to create PulseAudio context");
+
pa_glib_mainloop_free (mainloop);
+ pa_proplist_free (proplist);
return NULL;
}
connection = g_object_new (PULSE_TYPE_CONNECTION,
"server", server_address,
- "reconnect", TRUE,
NULL);
+ /* Set function to monitor status changes */
+ pa_context_set_state_callback (context,
+ connection_state_cb,
+ connection);
+
connection->priv->mainloop = mainloop;
connection->priv->context = context;
+ connection->priv->proplist = proplist;
+
return connection;
}
gboolean
pulse_connection_connect (PulseConnection *connection)
{
- int ret;
-
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
if (connection->priv->state != PULSE_CONNECTION_DISCONNECTED)
return TRUE;
- /* Set function to monitor status changes */
- pa_context_set_state_callback (connection->priv->context,
- connection_state_cb,
- connection);
-
- /* Initiate a connection, this call does not guarantee the connection
- * to be established and usable */
- ret = pa_context_connect (connection->priv->context, NULL, PA_CONTEXT_NOFLAGS, NULL);
- if (ret < 0) {
- g_warning ("Failed to connect to PulseAudio server: %s", pa_strerror (ret));
+ /* Initiate a connection, state changes will be delivered asynchronously */
+ if (pa_context_connect (connection->priv->context,
+ connection->priv->server,
+ PA_CONTEXT_NOFLAGS,
+ NULL) == 0)
+ return TRUE;
+ else
return FALSE;
- }
- return TRUE;
}
void
pulse_connection_disconnect (PulseConnection *connection)
{
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_if_fail (PULSE_IS_CONNECTION (connection));
if (connection->priv->state == PULSE_CONNECTION_DISCONNECTED)
return;
pa_context_disconnect (connection->priv->context);
- connection->priv->state = PULSE_CONNECTION_DISCONNECTED;
-
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ connection_change_state (connection, PULSE_CONNECTION_DISCONNECTED);
}
PulseConnectionState
pulse_connection_get_state (PulseConnection *connection)
{
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), PULSE_CONNECTION_DISCONNECTED);
return connection->priv->state;
}
+PulseMonitor *
+pulse_connection_create_monitor (PulseConnection *connection,
+ guint32 index_source,
+ guint32 index_sink_input)
+{
+ return pulse_monitor_new (connection->priv->context,
+ connection->priv->proplist,
+ index_source,
+ index_sink_input);
+}
+
gboolean
pulse_connection_set_default_sink (PulseConnection *connection,
const gchar *name)
@@ -666,6 +702,40 @@ pulse_connection_set_source_output_volume (PulseConnection *connection,
}
gboolean
+pulse_connection_suspend_sink (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_suspend_sink_by_index (connection->priv->context,
+ index,
+ (int) suspend,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
+
+gboolean
+pulse_connection_suspend_source (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_suspend_source_by_index (connection->priv->context,
+ index,
+ (int) suspend,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
+
+gboolean
pulse_connection_move_sink_input (PulseConnection *connection,
guint32 index,
guint32 sink_index)
@@ -755,19 +825,10 @@ connection_load_lists (PulseConnection *connection)
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
if (G_UNLIKELY (connection->priv->outstanding)) {
- /* This can only mean a bug */
g_warn_if_reached ();
return FALSE;
}
- op = pa_context_get_server_info (connection->priv->context,
- connection_server_info_cb,
- connection);
- if (G_UNLIKELY (op == NULL))
- goto error;
-
- ops = g_list_prepend (ops, op);
-
op = pa_context_get_card_info_list (connection->priv->context,
connection_card_info_cb,
connection);
@@ -834,9 +895,16 @@ connection_state_cb (pa_context *c, void *userdata)
if (state == PA_CONTEXT_READY) {
pa_operation *op;
- // XXX check state
+ if (connection->priv->state == PULSE_CONNECTION_LOADING ||
+ connection->priv->state == PULSE_CONNECTION_CONNECTED) {
+ g_warn_if_reached ();
+ return;
+ }
+ /* We are connected, let's subscribe to notifications and load the
+ * initial lists */
op = pa_context_subscribe (connection->priv->context,
+ PA_SUBSCRIPTION_MASK_SERVER |
PA_SUBSCRIPTION_MASK_CARD |
PA_SUBSCRIPTION_MASK_SINK |
PA_SUBSCRIPTION_MASK_SOURCE |
@@ -844,25 +912,22 @@ connection_state_cb (pa_context *c, void *userdata)
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
NULL, NULL);
if (op) {
- connection->priv->state = PULSE_CONNECTION_LOADING;
- connection->priv->connected_once = TRUE;
-
pa_context_set_subscribe_callback (connection->priv->context,
connection_subscribe_cb,
connection);
pa_operation_unref (op);
connection_load_lists (connection);
+ connection_change_state (connection, PULSE_CONNECTION_LOADING);
+ return;
+ }
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
- } else {
- /* If we could not subscribe to notifications, we consider it the
- * same as a connection failture */
- g_warning ("Failed to subscribe to PulseAudio notifications: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
+ /* If we could not subscribe to notifications, we consider it the
+ * same as a connection failture */
+ g_warning ("Failed to subscribe to PulseAudio notifications: %s",
+ pa_strerror (pa_context_errno (connection->priv->context)));
- state = PA_CONTEXT_FAILED;
- }
+ state = PA_CONTEXT_FAILED;
}
if (state == PA_CONTEXT_TERMINATED || state == PA_CONTEXT_FAILED) {
@@ -870,10 +935,14 @@ connection_state_cb (pa_context *c, void *userdata)
* change which should not normally happen, because the signal subscription
* is cancelled before disconnecting */
pulse_connection_disconnect (connection);
-
- if (connection->priv->connected_once && connection->priv->reconnect)
- pulse_connection_connect (connection);
+ return;
}
+
+ if (state == PA_CONTEXT_CONNECTING)
+ connection_change_state (connection, PULSE_CONNECTION_CONNECTING);
+ else if (state == PA_CONTEXT_AUTHORIZING ||
+ state == PA_CONTEXT_SETTING_NAME)
+ connection_change_state (connection, PULSE_CONNECTION_AUTHORIZING);
}
static void
@@ -970,10 +1039,19 @@ connection_server_info_cb (pa_context *c,
const pa_server_info *info,
void *userdata)
{
- g_signal_emit (G_OBJECT (userdata),
+ PulseConnection *connection;
+
+ connection = PULSE_CONNECTION (userdata);
+
+ g_signal_emit (G_OBJECT (connection),
signals[SERVER_INFO],
0,
info);
+
+ /* This notification may arrive at any time, but it also finalizes the
+ * connection process */
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_change_state (connection, PULSE_CONNECTION_CONNECTED);
}
static void
@@ -1008,13 +1086,16 @@ connection_sink_info_cb (pa_context *c,
connection = PULSE_CONNECTION (userdata);
- if (eol)
- connection_list_loaded (connection);
- else
- g_signal_emit (G_OBJECT (connection),
- signals[SINK_INFO],
- 0,
- info);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
+
+ g_signal_emit (G_OBJECT (connection),
+ signals[SINK_INFO],
+ 0,
+ info);
}
static void
@@ -1084,6 +1165,17 @@ connection_source_output_info_cb (pa_context *c,
}
static void
+connection_change_state (PulseConnection *connection, PulseConnectionState state)
+{
+ if (connection->priv->state == state)
+ return;
+
+ connection->priv->state = state;
+
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+}
+
+static void
connection_list_loaded (PulseConnection *connection)
{
connection->priv->outstanding--;
@@ -1093,9 +1185,14 @@ connection_list_loaded (PulseConnection *connection)
connection->priv->outstanding = 0;
}
if (connection->priv->outstanding == 0) {
- connection->priv->state = PULSE_CONNECTION_CONNECTED;
+ pa_operation *op;
+
+ op = pa_context_get_server_info (connection->priv->context,
+ connection_server_info_cb,
+ connection);
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ if (G_UNLIKELY (!connection_process_operation (connection, op)))
+ pulse_connection_disconnect (connection);
}
}