1 /*
2 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <glib.h>
21 #include <glib-object.h>
22
23 #include <pulse/pulseaudio.h>
24 #include <pulse/glib-mainloop.h>
25 #include <pulse/ext-stream-restore.h>
26
27 #include "pulse-connection.h"
28 #include "pulse-enums.h"
29 #include "pulse-enum-types.h"
30 #include "pulse-monitor.h"
31
32 struct _PulseConnectionPrivate
33 {
34 gchar *server;
35 guint outstanding;
36 pa_context *context;
37 pa_proplist *proplist;
38 pa_glib_mainloop *mainloop;
39 gboolean ext_streams_loading;
40 gboolean ext_streams_dirty;
41 PulseConnectionState state;
42 };
43
44 enum {
45 PROP_0,
46 PROP_SERVER,
47 PROP_STATE,
48 N_PROPERTIES
49 };
50
51 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
52
53 enum {
54 SERVER_INFO,
55 CARD_INFO,
56 CARD_REMOVED,
57 SINK_INFO,
58 SINK_REMOVED,
59 SOURCE_INFO,
60 SOURCE_REMOVED,
61 SINK_INPUT_INFO,
62 SINK_INPUT_REMOVED,
63 SOURCE_OUTPUT_INFO,
64 SOURCE_OUTPUT_REMOVED,
65 EXT_STREAM_LOADING,
66 EXT_STREAM_LOADED,
67 EXT_STREAM_INFO,
68 N_SIGNALS
69 };
70
71 static guint signals[N_SIGNALS] = { 0, };
72
73 static void pulse_connection_get_property (GObject *object,
74 guint param_id,
75 GValue *value,
76 GParamSpec *pspec);
77 static void pulse_connection_set_property (GObject *object,
78 guint param_id,
79 const GValue *value,
80 GParamSpec *pspec);
81
82 static void pulse_connection_finalize (GObject *object);
83
84 G_DEFINE_TYPE_WITH_PRIVATE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
85
86 static gchar *create_app_name (void);
87
88 static gboolean load_lists (PulseConnection *connection);
89 static gboolean load_list_finished (PulseConnection *connection);
90
91 static void pulse_state_cb (pa_context *c,
92 void *userdata);
93 static void pulse_subscribe_cb (pa_context *c,
94 pa_subscription_event_type_t t,
95 uint32_t idx,
96 void *userdata);
97
98 static void pulse_restore_subscribe_cb (pa_context *c,
99 void *userdata);
100 static void pulse_server_info_cb (pa_context *c,
101 const pa_server_info *info,
102 void *userdata);
103 static void pulse_card_info_cb (pa_context *c,
104 const pa_card_info *info,
105 int eol,
106 void *userdata);
107 static void pulse_sink_info_cb (pa_context *c,
108 const pa_sink_info *info,
109 int eol,
110 void *userdata);
111 static void pulse_source_info_cb (pa_context *c,
112 const pa_source_info *info,
113 int eol,
114 void *userdata);
115 static void pulse_sink_input_info_cb (pa_context *c,
116 const pa_sink_input_info *info,
117 int eol,
118 void *userdata);
119 static void pulse_source_output_info_cb (pa_context *c,
120 const pa_source_output_info *info,
121 int eol,
122 void *userdata);
123 static void pulse_ext_stream_restore_cb (pa_context *c,
124 const pa_ext_stream_restore_info *info,
125 int eol,
126 void *userdata);
127
128 static void change_state (PulseConnection *connection,
129 PulseConnectionState state);
130
131 static gboolean process_pulse_operation (PulseConnection *connection,
132 pa_operation *op);
133
134 static void
pulse_connection_class_init(PulseConnectionClass * klass)135 pulse_connection_class_init (PulseConnectionClass *klass)
136 {
137 GObjectClass *object_class;
138
139 object_class = G_OBJECT_CLASS (klass);
140 object_class->finalize = pulse_connection_finalize;
141 object_class->get_property = pulse_connection_get_property;
142 object_class->set_property = pulse_connection_set_property;
143
144 properties[PROP_SERVER] =
145 g_param_spec_string ("server",
146 "Server",
147 "PulseAudio server to connect to",
148 NULL,
149 G_PARAM_CONSTRUCT_ONLY |
150 G_PARAM_READWRITE |
151 G_PARAM_STATIC_STRINGS);
152
153 properties[PROP_STATE] =
154 g_param_spec_enum ("state",
155 "State",
156 "Connection state",
157 PULSE_TYPE_CONNECTION_STATE,
158 PULSE_CONNECTION_DISCONNECTED,
159 G_PARAM_READABLE |
160 G_PARAM_STATIC_STRINGS);
161
162 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
163
164 signals[SERVER_INFO] =
165 g_signal_new ("server-info",
166 G_TYPE_FROM_CLASS (object_class),
167 G_SIGNAL_RUN_LAST,
168 G_STRUCT_OFFSET (PulseConnectionClass, server_info),
169 NULL,
170 NULL,
171 g_cclosure_marshal_VOID__POINTER,
172 G_TYPE_NONE,
173 1,
174 G_TYPE_POINTER);
175
176 signals[CARD_INFO] =
177 g_signal_new ("card-info",
178 G_TYPE_FROM_CLASS (object_class),
179 G_SIGNAL_RUN_LAST,
180 G_STRUCT_OFFSET (PulseConnectionClass, card_info),
181 NULL,
182 NULL,
183 g_cclosure_marshal_VOID__POINTER,
184 G_TYPE_NONE,
185 1,
186 G_TYPE_POINTER);
187
188 signals[CARD_REMOVED] =
189 g_signal_new ("card-removed",
190 G_TYPE_FROM_CLASS (object_class),
191 G_SIGNAL_RUN_LAST,
192 G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
193 NULL,
194 NULL,
195 g_cclosure_marshal_VOID__UINT,
196 G_TYPE_NONE,
197 1,
198 G_TYPE_UINT);
199
200 signals[SINK_INFO] =
201 g_signal_new ("sink-info",
202 G_TYPE_FROM_CLASS (object_class),
203 G_SIGNAL_RUN_LAST,
204 G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
205 NULL,
206 NULL,
207 g_cclosure_marshal_VOID__POINTER,
208 G_TYPE_NONE,
209 1,
210 G_TYPE_POINTER);
211
212 signals[SINK_REMOVED] =
213 g_signal_new ("sink-removed",
214 G_TYPE_FROM_CLASS (object_class),
215 G_SIGNAL_RUN_LAST,
216 G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
217 NULL,
218 NULL,
219 g_cclosure_marshal_VOID__UINT,
220 G_TYPE_NONE,
221 1,
222 G_TYPE_UINT);
223
224 signals[SINK_INPUT_INFO] =
225 g_signal_new ("sink-input-info",
226 G_TYPE_FROM_CLASS (object_class),
227 G_SIGNAL_RUN_LAST,
228 G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
229 NULL,
230 NULL,
231 g_cclosure_marshal_VOID__POINTER,
232 G_TYPE_NONE,
233 1,
234 G_TYPE_POINTER);
235
236 signals[SINK_INPUT_REMOVED] =
237 g_signal_new ("sink-input-removed",
238 G_TYPE_FROM_CLASS (object_class),
239 G_SIGNAL_RUN_LAST,
240 G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
241 NULL,
242 NULL,
243 g_cclosure_marshal_VOID__UINT,
244 G_TYPE_NONE,
245 1,
246 G_TYPE_UINT);
247
248 signals[SOURCE_INFO] =
249 g_signal_new ("source-info",
250 G_TYPE_FROM_CLASS (object_class),
251 G_SIGNAL_RUN_LAST,
252 G_STRUCT_OFFSET (PulseConnectionClass, source_info),
253 NULL,
254 NULL,
255 g_cclosure_marshal_VOID__POINTER,
256 G_TYPE_NONE,
257 1,
258 G_TYPE_POINTER);
259
260 signals[SOURCE_REMOVED] =
261 g_signal_new ("source-removed",
262 G_TYPE_FROM_CLASS (object_class),
263 G_SIGNAL_RUN_LAST,
264 G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
265 NULL,
266 NULL,
267 g_cclosure_marshal_VOID__UINT,
268 G_TYPE_NONE,
269 1,
270 G_TYPE_UINT);
271
272 signals[SOURCE_OUTPUT_INFO] =
273 g_signal_new ("source-output-info",
274 G_TYPE_FROM_CLASS (object_class),
275 G_SIGNAL_RUN_LAST,
276 G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
277 NULL,
278 NULL,
279 g_cclosure_marshal_VOID__POINTER,
280 G_TYPE_NONE,
281 1,
282 G_TYPE_POINTER);
283
284 signals[SOURCE_OUTPUT_REMOVED] =
285 g_signal_new ("source-output-removed",
286 G_TYPE_FROM_CLASS (object_class),
287 G_SIGNAL_RUN_LAST,
288 G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
289 NULL,
290 NULL,
291 g_cclosure_marshal_VOID__UINT,
292 G_TYPE_NONE,
293 1,
294 G_TYPE_UINT);
295
296 signals[EXT_STREAM_LOADING] =
297 g_signal_new ("ext-stream-loading",
298 G_TYPE_FROM_CLASS (object_class),
299 G_SIGNAL_RUN_LAST,
300 G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_loading),
301 NULL,
302 NULL,
303 g_cclosure_marshal_VOID__VOID,
304 G_TYPE_NONE,
305 0,
306 G_TYPE_NONE);
307
308 signals[EXT_STREAM_LOADED] =
309 g_signal_new ("ext-stream-loaded",
310 G_TYPE_FROM_CLASS (object_class),
311 G_SIGNAL_RUN_LAST,
312 G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_loaded),
313 NULL,
314 NULL,
315 g_cclosure_marshal_VOID__VOID,
316 G_TYPE_NONE,
317 0,
318 G_TYPE_NONE);
319
320 signals[EXT_STREAM_INFO] =
321 g_signal_new ("ext-stream-info",
322 G_TYPE_FROM_CLASS (object_class),
323 G_SIGNAL_RUN_LAST,
324 G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_info),
325 NULL,
326 NULL,
327 g_cclosure_marshal_VOID__POINTER,
328 G_TYPE_NONE,
329 1,
330 G_TYPE_POINTER);
331 }
332
333 static void
pulse_connection_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)334 pulse_connection_get_property (GObject *object,
335 guint param_id,
336 GValue *value,
337 GParamSpec *pspec)
338 {
339 PulseConnection *connection;
340
341 connection = PULSE_CONNECTION (object);
342
343 switch (param_id) {
344 case PROP_SERVER:
345 g_value_set_string (value, connection->priv->server);
346 break;
347 case PROP_STATE:
348 g_value_set_enum (value, connection->priv->state);
349 break;
350 default:
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
352 break;
353 }
354 }
355
356 static void
pulse_connection_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)357 pulse_connection_set_property (GObject *object,
358 guint param_id,
359 const GValue *value,
360 GParamSpec *pspec)
361 {
362 PulseConnection *connection;
363
364 connection = PULSE_CONNECTION (object);
365
366 switch (param_id) {
367 case PROP_SERVER:
368 /* Construct-only string */
369 connection->priv->server = g_strdup (g_value_get_string (value));
370 break;
371 default:
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
373 break;
374 }
375 }
376
377 static void
pulse_connection_init(PulseConnection * connection)378 pulse_connection_init (PulseConnection *connection)
379 {
380 connection->priv = pulse_connection_get_instance_private (connection);
381 }
382
383 static void
pulse_connection_finalize(GObject * object)384 pulse_connection_finalize (GObject *object)
385 {
386 PulseConnection *connection;
387
388 connection = PULSE_CONNECTION (object);
389
390 g_free (connection->priv->server);
391
392 if (connection->priv->context != NULL)
393 pa_context_unref (connection->priv->context);
394
395 pa_proplist_free (connection->priv->proplist);
396 pa_glib_mainloop_free (connection->priv->mainloop);
397
398 G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
399 }
400
401 PulseConnection *
pulse_connection_new(const gchar * app_name,const gchar * app_id,const gchar * app_version,const gchar * app_icon,const gchar * server_address)402 pulse_connection_new (const gchar *app_name,
403 const gchar *app_id,
404 const gchar *app_version,
405 const gchar *app_icon,
406 const gchar *server_address)
407 {
408 pa_glib_mainloop *mainloop;
409 pa_proplist *proplist;
410 PulseConnection *connection;
411
412 mainloop = pa_glib_mainloop_new (g_main_context_get_thread_default ());
413 if (G_UNLIKELY (mainloop == NULL)) {
414 g_warning ("Failed to create PulseAudio main loop");
415 return NULL;
416 }
417
418 /* Create a property list to hold information about the application,
419 * the list will be kept with the connection as it will be reused later
420 * when creating PulseAudio contexts and streams */
421 proplist = pa_proplist_new ();
422 if (app_name != NULL) {
423 pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, app_name);
424 } else {
425 /* Set a sensible default name when application does not provide one */
426 gchar *name = create_app_name ();
427
428 pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, name);
429 g_free (name);
430 }
431 if (app_id != NULL)
432 pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, app_id);
433 if (app_icon != NULL)
434 pa_proplist_sets (proplist, PA_PROP_APPLICATION_ICON_NAME, app_icon);
435 if (app_version != NULL)
436 pa_proplist_sets (proplist, PA_PROP_APPLICATION_VERSION, app_version);
437
438 connection = g_object_new (PULSE_TYPE_CONNECTION,
439 "server", server_address,
440 NULL);
441
442 connection->priv->mainloop = mainloop;
443 connection->priv->proplist = proplist;
444
445 return connection;
446 }
447
448 gboolean
pulse_connection_connect(PulseConnection * connection,gboolean wait_for_daemon)449 pulse_connection_connect (PulseConnection *connection, gboolean wait_for_daemon)
450 {
451 pa_context *context;
452 pa_context_flags_t flags = PA_CONTEXT_NOFLAGS;
453 pa_mainloop_api *mainloop;
454
455 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
456
457 if (connection->priv->state != PULSE_CONNECTION_DISCONNECTED)
458 return TRUE;
459
460 mainloop = pa_glib_mainloop_get_api (connection->priv->mainloop);
461 context = pa_context_new_with_proplist (mainloop,
462 NULL,
463 connection->priv->proplist);
464 if (G_UNLIKELY (context == NULL)) {
465 g_warning ("Failed to create PulseAudio context");
466 return FALSE;
467 }
468
469 /* Set function to monitor status changes */
470 pa_context_set_state_callback (context,
471 pulse_state_cb,
472 connection);
473 if (wait_for_daemon == TRUE)
474 flags = PA_CONTEXT_NOFAIL;
475
476 /* Initiate a connection, state changes will be delivered asynchronously */
477 if (pa_context_connect (context,
478 connection->priv->server,
479 flags,
480 NULL) == 0) {
481 connection->priv->context = context;
482 change_state (connection, PULSE_CONNECTION_CONNECTING);
483 return TRUE;
484 }
485
486 pa_context_unref (context);
487 return FALSE;
488 }
489
490 void
pulse_connection_disconnect(PulseConnection * connection)491 pulse_connection_disconnect (PulseConnection *connection)
492 {
493 g_return_if_fail (PULSE_IS_CONNECTION (connection));
494
495 if (connection->priv->state == PULSE_CONNECTION_DISCONNECTED)
496 return;
497
498 if (connection->priv->context)
499 pa_context_unref (connection->priv->context);
500
501 connection->priv->context = NULL;
502 connection->priv->outstanding = 0;
503 connection->priv->ext_streams_loading = FALSE;
504 connection->priv->ext_streams_dirty = FALSE;
505
506 change_state (connection, PULSE_CONNECTION_DISCONNECTED);
507 }
508
509 PulseConnectionState
pulse_connection_get_state(PulseConnection * connection)510 pulse_connection_get_state (PulseConnection *connection)
511 {
512 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), PULSE_CONNECTION_DISCONNECTED);
513
514 return connection->priv->state;
515 }
516
517 gboolean
pulse_connection_load_server_info(PulseConnection * connection)518 pulse_connection_load_server_info (PulseConnection *connection)
519 {
520 pa_operation *op;
521
522 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
523
524 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
525 connection->priv->state != PULSE_CONNECTION_CONNECTED)
526 return FALSE;
527
528 op = pa_context_get_server_info (connection->priv->context,
529 pulse_server_info_cb,
530 connection);
531
532 return process_pulse_operation (connection, op);
533 }
534
535 gboolean
pulse_connection_load_card_info(PulseConnection * connection,guint32 index)536 pulse_connection_load_card_info (PulseConnection *connection, guint32 index)
537 {
538 pa_operation *op;
539
540 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
541
542 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
543 connection->priv->state != PULSE_CONNECTION_CONNECTED)
544 return FALSE;
545
546 if (index == PA_INVALID_INDEX)
547 op = pa_context_get_card_info_by_index (connection->priv->context,
548 index,
549 pulse_card_info_cb,
550 connection);
551 else
552 op = pa_context_get_card_info_list (connection->priv->context,
553 pulse_card_info_cb,
554 connection);
555
556 return process_pulse_operation (connection, op);
557 }
558
559 gboolean
pulse_connection_load_card_info_name(PulseConnection * connection,const gchar * name)560 pulse_connection_load_card_info_name (PulseConnection *connection, const gchar *name)
561 {
562 pa_operation *op;
563
564 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
565 g_return_val_if_fail (name != NULL, FALSE);
566
567 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
568 connection->priv->state != PULSE_CONNECTION_CONNECTED)
569 return FALSE;
570
571 op = pa_context_get_card_info_by_name (connection->priv->context,
572 name,
573 pulse_card_info_cb,
574 connection);
575
576 return process_pulse_operation (connection, op);
577 }
578
579 gboolean
pulse_connection_load_sink_info(PulseConnection * connection,guint32 index)580 pulse_connection_load_sink_info (PulseConnection *connection, guint32 index)
581 {
582 pa_operation *op;
583
584 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
585
586 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
587 connection->priv->state != PULSE_CONNECTION_CONNECTED)
588 return FALSE;
589
590 if (index == PA_INVALID_INDEX)
591 op = pa_context_get_sink_info_by_index (connection->priv->context,
592 index,
593 pulse_sink_info_cb,
594 connection);
595 else
596 op = pa_context_get_sink_info_list (connection->priv->context,
597 pulse_sink_info_cb,
598 connection);
599
600 return process_pulse_operation (connection, op);
601 }
602
603 gboolean
pulse_connection_load_sink_info_name(PulseConnection * connection,const gchar * name)604 pulse_connection_load_sink_info_name (PulseConnection *connection, const gchar *name)
605 {
606 pa_operation *op;
607
608 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
609 g_return_val_if_fail (name != NULL, FALSE);
610
611 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
612 connection->priv->state != PULSE_CONNECTION_CONNECTED)
613 return FALSE;
614
615 op = pa_context_get_sink_info_by_name (connection->priv->context,
616 name,
617 pulse_sink_info_cb,
618 connection);
619
620 return process_pulse_operation (connection, op);
621 }
622
623 gboolean
pulse_connection_load_sink_input_info(PulseConnection * connection,guint32 index)624 pulse_connection_load_sink_input_info (PulseConnection *connection, guint32 index)
625 {
626 pa_operation *op;
627
628 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
629
630 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
631 connection->priv->state != PULSE_CONNECTION_CONNECTED)
632 return FALSE;
633
634 if (index == PA_INVALID_INDEX)
635 op = pa_context_get_sink_input_info (connection->priv->context,
636 index,
637 pulse_sink_input_info_cb,
638 connection);
639 else
640 op = pa_context_get_sink_input_info_list (connection->priv->context,
641 pulse_sink_input_info_cb,
642 connection);
643
644 return process_pulse_operation (connection, op);
645 }
646
647 gboolean
pulse_connection_load_source_info(PulseConnection * connection,guint32 index)648 pulse_connection_load_source_info (PulseConnection *connection, guint32 index)
649 {
650 pa_operation *op;
651
652 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
653
654 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
655 connection->priv->state != PULSE_CONNECTION_CONNECTED)
656 return FALSE;
657
658 if (index == PA_INVALID_INDEX)
659 op = pa_context_get_source_info_by_index (connection->priv->context,
660 index,
661 pulse_source_info_cb,
662 connection);
663 else
664 op = pa_context_get_source_info_list (connection->priv->context,
665 pulse_source_info_cb,
666 connection);
667
668 return process_pulse_operation (connection, op);
669 }
670
671 gboolean
pulse_connection_load_source_info_name(PulseConnection * connection,const gchar * name)672 pulse_connection_load_source_info_name (PulseConnection *connection, const gchar *name)
673 {
674 pa_operation *op;
675
676 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
677 g_return_val_if_fail (name != NULL, FALSE);
678
679 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
680 connection->priv->state != PULSE_CONNECTION_CONNECTED)
681 return FALSE;
682
683 op = pa_context_get_source_info_by_name (connection->priv->context,
684 name,
685 pulse_source_info_cb,
686 connection);
687
688 return process_pulse_operation (connection, op);
689 }
690
691 gboolean
pulse_connection_load_source_output_info(PulseConnection * connection,guint32 index)692 pulse_connection_load_source_output_info (PulseConnection *connection, guint32 index)
693 {
694 pa_operation *op;
695
696 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
697
698 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
699 connection->priv->state != PULSE_CONNECTION_CONNECTED)
700 return FALSE;
701
702 if (index == PA_INVALID_INDEX)
703 op = pa_context_get_source_output_info (connection->priv->context,
704 index,
705 pulse_source_output_info_cb,
706 connection);
707 else
708 op = pa_context_get_source_output_info_list (connection->priv->context,
709 pulse_source_output_info_cb,
710 connection);
711
712 return process_pulse_operation (connection, op);
713 }
714
715 gboolean
pulse_connection_load_ext_stream_info(PulseConnection * connection)716 pulse_connection_load_ext_stream_info (PulseConnection *connection)
717 {
718 pa_operation *op;
719
720 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
721
722 if (connection->priv->state != PULSE_CONNECTION_LOADING &&
723 connection->priv->state != PULSE_CONNECTION_CONNECTED)
724 return FALSE;
725
726 /* When we receive a request to load the list of ext-streams, see if
727 * loading is already in progress and if it is, wait until the current
728 * loading finishes.
729 * The PulseBackend class relies on this behaviour to ensure it always
730 * contains a correct list of ext-streams, also PulseAudio always sends
731 * a list of all streams in the database and these requests may arrive
732 * very often, so this also optimizaes the amount of traffic. */
733 if (connection->priv->ext_streams_loading == TRUE) {
734 connection->priv->ext_streams_dirty = TRUE;
735 return TRUE;
736 }
737
738 connection->priv->ext_streams_dirty = FALSE;
739 connection->priv->ext_streams_loading = TRUE;
740 g_signal_emit (G_OBJECT (connection),
741 signals[EXT_STREAM_LOADING],
742 0);
743
744 op = pa_ext_stream_restore_read (connection->priv->context,
745 pulse_ext_stream_restore_cb,
746 connection);
747
748 if (process_pulse_operation (connection, op) == FALSE) {
749 connection->priv->ext_streams_loading = FALSE;
750
751 g_signal_emit (G_OBJECT (connection),
752 signals[EXT_STREAM_LOADED],
753 0);
754 return FALSE;
755 }
756 return TRUE;
757 }
758
759 PulseMonitor *
pulse_connection_create_monitor(PulseConnection * connection,guint32 index_source,guint32 index_sink_input)760 pulse_connection_create_monitor (PulseConnection *connection,
761 guint32 index_source,
762 guint32 index_sink_input)
763 {
764 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
765
766 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
767 return NULL;
768
769 return pulse_monitor_new (connection->priv->context,
770 connection->priv->proplist,
771 index_source,
772 index_sink_input);
773 }
774
775 gboolean
pulse_connection_set_default_sink(PulseConnection * connection,const gchar * name)776 pulse_connection_set_default_sink (PulseConnection *connection,
777 const gchar *name)
778 {
779 pa_operation *op;
780
781 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
782 g_return_val_if_fail (name != NULL, FALSE);
783
784 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
785 return FALSE;
786
787 op = pa_context_set_default_sink (connection->priv->context,
788 name,
789 NULL, NULL);
790
791 return process_pulse_operation (connection, op);
792 }
793
794 gboolean
pulse_connection_set_default_source(PulseConnection * connection,const gchar * name)795 pulse_connection_set_default_source (PulseConnection *connection,
796 const gchar *name)
797 {
798 pa_operation *op;
799
800 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
801 g_return_val_if_fail (name != NULL, FALSE);
802
803 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
804 return FALSE;
805
806 op = pa_context_set_default_source (connection->priv->context,
807 name,
808 NULL, NULL);
809
810 return process_pulse_operation (connection, op);
811 }
812
813 gboolean
pulse_connection_set_card_profile(PulseConnection * connection,const gchar * card,const gchar * profile)814 pulse_connection_set_card_profile (PulseConnection *connection,
815 const gchar *card,
816 const gchar *profile)
817 {
818 pa_operation *op;
819
820 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
821 g_return_val_if_fail (card != NULL, FALSE);
822 g_return_val_if_fail (profile != NULL, FALSE);
823
824 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
825 return FALSE;
826
827 op = pa_context_set_card_profile_by_name (connection->priv->context,
828 card,
829 profile,
830 NULL, NULL);
831
832 return process_pulse_operation (connection, op);
833 }
834
835 gboolean
pulse_connection_set_sink_mute(PulseConnection * connection,guint32 index,gboolean mute)836 pulse_connection_set_sink_mute (PulseConnection *connection,
837 guint32 index,
838 gboolean mute)
839 {
840 pa_operation *op;
841
842 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
843
844 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
845 return FALSE;
846
847 op = pa_context_set_sink_mute_by_index (connection->priv->context,
848 index,
849 (int) mute,
850 NULL, NULL);
851
852 return process_pulse_operation (connection, op);
853 }
854
855 gboolean
pulse_connection_set_sink_volume(PulseConnection * connection,guint32 index,const pa_cvolume * volume)856 pulse_connection_set_sink_volume (PulseConnection *connection,
857 guint32 index,
858 const pa_cvolume *volume)
859 {
860 pa_operation *op;
861
862 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
863 g_return_val_if_fail (volume != NULL, FALSE);
864
865 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
866 return FALSE;
867
868 op = pa_context_set_sink_volume_by_index (connection->priv->context,
869 index,
870 volume,
871 NULL, NULL);
872
873 return process_pulse_operation (connection, op);
874 }
875
876 gboolean
pulse_connection_set_sink_port(PulseConnection * connection,guint32 index,const gchar * port)877 pulse_connection_set_sink_port (PulseConnection *connection,
878 guint32 index,
879 const gchar *port)
880 {
881 pa_operation *op;
882
883 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
884 g_return_val_if_fail (port != NULL, FALSE);
885
886 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
887 return FALSE;
888
889 op = pa_context_set_sink_port_by_index (connection->priv->context,
890 index,
891 port,
892 NULL, NULL);
893
894 return process_pulse_operation (connection, op);
895 }
896
897 gboolean
pulse_connection_set_sink_input_mute(PulseConnection * connection,guint32 index,gboolean mute)898 pulse_connection_set_sink_input_mute (PulseConnection *connection,
899 guint32 index,
900 gboolean mute)
901 {
902 pa_operation *op;
903
904 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
905
906 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
907 return FALSE;
908
909 op = pa_context_set_sink_input_mute (connection->priv->context,
910 index,
911 (int) mute,
912 NULL, NULL);
913
914 return process_pulse_operation (connection, op);
915 }
916
917 gboolean
pulse_connection_set_sink_input_volume(PulseConnection * connection,guint32 index,const pa_cvolume * volume)918 pulse_connection_set_sink_input_volume (PulseConnection *connection,
919 guint32 index,
920 const pa_cvolume *volume)
921 {
922 pa_operation *op;
923
924 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
925 g_return_val_if_fail (volume != NULL, FALSE);
926
927 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
928 return FALSE;
929
930 op = pa_context_set_sink_input_volume (connection->priv->context,
931 index,
932 volume,
933 NULL, NULL);
934
935 return process_pulse_operation (connection, op);
936 }
937
938 gboolean
pulse_connection_set_source_mute(PulseConnection * connection,guint32 index,gboolean mute)939 pulse_connection_set_source_mute (PulseConnection *connection,
940 guint32 index,
941 gboolean mute)
942 {
943 pa_operation *op;
944
945 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
946
947 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
948 return FALSE;
949
950 op = pa_context_set_source_mute_by_index (connection->priv->context,
951 index,
952 (int) mute,
953 NULL, NULL);
954
955 return process_pulse_operation (connection, op);
956 }
957
958 gboolean
pulse_connection_set_source_volume(PulseConnection * connection,guint32 index,const pa_cvolume * volume)959 pulse_connection_set_source_volume (PulseConnection *connection,
960 guint32 index,
961 const pa_cvolume *volume)
962 {
963 pa_operation *op;
964
965 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
966 g_return_val_if_fail (volume != NULL, FALSE);
967
968 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
969 return FALSE;
970
971 op = pa_context_set_source_volume_by_index (connection->priv->context,
972 index,
973 volume,
974 NULL, NULL);
975
976 return process_pulse_operation (connection, op);
977 }
978
979 gboolean
pulse_connection_set_source_port(PulseConnection * connection,guint32 index,const gchar * port)980 pulse_connection_set_source_port (PulseConnection *connection,
981 guint32 index,
982 const gchar *port)
983 {
984 pa_operation *op;
985
986 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
987 g_return_val_if_fail (port != NULL, FALSE);
988
989 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
990 return FALSE;
991
992 op = pa_context_set_source_port_by_index (connection->priv->context,
993 index,
994 port,
995 NULL, NULL);
996
997 return process_pulse_operation (connection, op);
998 }
999
1000 gboolean
pulse_connection_set_source_output_mute(PulseConnection * connection,guint32 index,gboolean mute)1001 pulse_connection_set_source_output_mute (PulseConnection *connection,
1002 guint32 index,
1003 gboolean mute)
1004 {
1005 pa_operation *op;
1006
1007 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1008
1009 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1010 return FALSE;
1011
1012 op = pa_context_set_source_output_mute (connection->priv->context,
1013 index,
1014 (int) mute,
1015 NULL, NULL);
1016
1017 return process_pulse_operation (connection, op);
1018 }
1019
1020 gboolean
pulse_connection_set_source_output_volume(PulseConnection * connection,guint32 index,const pa_cvolume * volume)1021 pulse_connection_set_source_output_volume (PulseConnection *connection,
1022 guint32 index,
1023 const pa_cvolume *volume)
1024 {
1025 pa_operation *op;
1026
1027 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1028 g_return_val_if_fail (volume != NULL, FALSE);
1029
1030 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1031 return FALSE;
1032
1033 op = pa_context_set_source_output_volume (connection->priv->context,
1034 index,
1035 volume,
1036 NULL, NULL);
1037
1038 return process_pulse_operation (connection, op);
1039 }
1040
1041 gboolean
pulse_connection_suspend_sink(PulseConnection * connection,guint32 index,gboolean suspend)1042 pulse_connection_suspend_sink (PulseConnection *connection,
1043 guint32 index,
1044 gboolean suspend)
1045 {
1046 pa_operation *op;
1047
1048 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1049
1050 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1051 return FALSE;
1052
1053 op = pa_context_suspend_sink_by_index (connection->priv->context,
1054 index,
1055 (int) suspend,
1056 NULL, NULL);
1057
1058 return process_pulse_operation (connection, op);
1059 }
1060
1061 gboolean
pulse_connection_suspend_source(PulseConnection * connection,guint32 index,gboolean suspend)1062 pulse_connection_suspend_source (PulseConnection *connection,
1063 guint32 index,
1064 gboolean suspend)
1065 {
1066 pa_operation *op;
1067
1068 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1069
1070 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1071 return FALSE;
1072
1073 op = pa_context_suspend_source_by_index (connection->priv->context,
1074 index,
1075 (int) suspend,
1076 NULL, NULL);
1077
1078 return process_pulse_operation (connection, op);
1079 }
1080
1081 gboolean
pulse_connection_move_sink_input(PulseConnection * connection,guint32 index,guint32 sink_index)1082 pulse_connection_move_sink_input (PulseConnection *connection,
1083 guint32 index,
1084 guint32 sink_index)
1085 {
1086 pa_operation *op;
1087
1088 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1089
1090 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1091 return FALSE;
1092
1093 op = pa_context_move_sink_input_by_index (connection->priv->context,
1094 index,
1095 sink_index,
1096 NULL, NULL);
1097
1098 return process_pulse_operation (connection, op);
1099 }
1100
1101 gboolean
pulse_connection_move_source_output(PulseConnection * connection,guint32 index,guint32 source_index)1102 pulse_connection_move_source_output (PulseConnection *connection,
1103 guint32 index,
1104 guint32 source_index)
1105 {
1106 pa_operation *op;
1107
1108 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1109
1110 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1111 return FALSE;
1112
1113 op = pa_context_move_source_output_by_index (connection->priv->context,
1114 index,
1115 source_index,
1116 NULL, NULL);
1117
1118 return process_pulse_operation (connection, op);
1119 }
1120
1121 gboolean
pulse_connection_kill_sink_input(PulseConnection * connection,guint32 index)1122 pulse_connection_kill_sink_input (PulseConnection *connection,
1123 guint32 index)
1124 {
1125 pa_operation *op;
1126
1127 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1128
1129 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1130 return FALSE;
1131
1132 op = pa_context_kill_sink_input (connection->priv->context,
1133 index,
1134 NULL, NULL);
1135
1136 return process_pulse_operation (connection, op);
1137 }
1138
1139 gboolean
pulse_connection_kill_source_output(PulseConnection * connection,guint32 index)1140 pulse_connection_kill_source_output (PulseConnection *connection,
1141 guint32 index)
1142 {
1143 pa_operation *op;
1144
1145 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1146
1147 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1148 return FALSE;
1149
1150 op = pa_context_kill_source_output (connection->priv->context,
1151 index,
1152 NULL, NULL);
1153
1154 return process_pulse_operation (connection, op);
1155 }
1156
1157 gboolean
pulse_connection_write_ext_stream(PulseConnection * connection,const pa_ext_stream_restore_info * info)1158 pulse_connection_write_ext_stream (PulseConnection *connection,
1159 const pa_ext_stream_restore_info *info)
1160 {
1161 pa_operation *op;
1162
1163 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1164 g_return_val_if_fail (info != NULL, FALSE);
1165
1166 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1167 return FALSE;
1168
1169 op = pa_ext_stream_restore_write (connection->priv->context,
1170 PA_UPDATE_REPLACE,
1171 info, 1,
1172 TRUE,
1173 NULL, NULL);
1174
1175 return process_pulse_operation (connection, op);
1176 }
1177
1178 gboolean
pulse_connection_delete_ext_stream(PulseConnection * connection,const gchar * name)1179 pulse_connection_delete_ext_stream (PulseConnection *connection,
1180 const gchar *name)
1181 {
1182 pa_operation *op;
1183 gchar **names;
1184
1185 g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
1186 g_return_val_if_fail (name != NULL, FALSE);
1187
1188 if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
1189 return FALSE;
1190
1191 names = g_new (gchar *, 2);
1192 names[0] = (gchar *) name;
1193 names[1] = NULL;
1194
1195 op = pa_ext_stream_restore_delete (connection->priv->context,
1196 (const char * const *) names,
1197 NULL, NULL);
1198
1199 g_strfreev (names);
1200
1201 return process_pulse_operation (connection, op);
1202 }
1203
1204 static gchar *
create_app_name(void)1205 create_app_name (void)
1206 {
1207 const gchar *name_app;
1208 char name_buf[256];
1209
1210 /* Inspired by GStreamer's pulse plugin */
1211 name_app = g_get_application_name ();
1212 if (name_app != NULL)
1213 return g_strdup (name_app);
1214
1215 if (pa_get_binary_name (name_buf, sizeof (name_buf)) != NULL)
1216 return g_strdup (name_buf);
1217
1218 return g_strdup_printf ("libmatemixer-%lu", (gulong) getpid ());
1219 }
1220
1221 static gboolean
load_lists(PulseConnection * connection)1222 load_lists (PulseConnection *connection)
1223 {
1224 GSList *ops = NULL;
1225 pa_operation *op;
1226
1227 if (G_UNLIKELY (connection->priv->outstanding > 0)) {
1228 g_warn_if_reached ();
1229 return FALSE;
1230 }
1231
1232 op = pa_context_get_card_info_list (connection->priv->context,
1233 pulse_card_info_cb,
1234 connection);
1235 if (G_UNLIKELY (op == NULL))
1236 goto error;
1237
1238 ops = g_slist_prepend (ops, op);
1239
1240 op = pa_context_get_sink_info_list (connection->priv->context,
1241 pulse_sink_info_cb,
1242 connection);
1243 if (G_UNLIKELY (op == NULL))
1244 goto error;
1245
1246 ops = g_slist_prepend (ops, op);
1247
1248 op = pa_context_get_sink_input_info_list (connection->priv->context,
1249 pulse_sink_input_info_cb,
1250 connection);
1251 if (G_UNLIKELY (op == NULL))
1252 goto error;
1253
1254 ops = g_slist_prepend (ops, op);
1255
1256 op = pa_context_get_source_info_list (connection->priv->context,
1257 pulse_source_info_cb,
1258 connection);
1259 if (G_UNLIKELY (op == NULL))
1260 goto error;
1261
1262 ops = g_slist_prepend (ops, op);
1263
1264 op = pa_context_get_source_output_info_list (connection->priv->context,
1265 pulse_source_output_info_cb,
1266 connection);
1267 if (G_UNLIKELY (op == NULL))
1268 goto error;
1269
1270 ops = g_slist_prepend (ops, op);
1271
1272 connection->priv->outstanding = 5;
1273
1274 /* This might not always be supported */
1275 op = pa_ext_stream_restore_read (connection->priv->context,
1276 pulse_ext_stream_restore_cb,
1277 connection);
1278 if (op != NULL) {
1279 ops = g_slist_prepend (ops, op);
1280 connection->priv->outstanding++;
1281 }
1282
1283 g_slist_foreach (ops, (GFunc) pa_operation_unref, NULL);
1284 g_slist_free (ops);
1285
1286 return TRUE;
1287
1288 error:
1289 g_slist_foreach (ops, (GFunc) pa_operation_cancel, NULL);
1290 g_slist_foreach (ops, (GFunc) pa_operation_unref, NULL);
1291 g_slist_free (ops);
1292 return FALSE;
1293 }
1294
1295 static gboolean
load_list_finished(PulseConnection * connection)1296 load_list_finished (PulseConnection *connection)
1297 {
1298 /* Decrement the number of outstanding requests as a list has just been
1299 * downloaded; when the number reaches 0, server information is requested
1300 * as the final step in the connection process */
1301 connection->priv->outstanding--;
1302
1303 if (G_UNLIKELY (connection->priv->outstanding < 0)) {
1304 g_warn_if_reached ();
1305 connection->priv->outstanding = 0;
1306 }
1307
1308 if (connection->priv->outstanding == 0) {
1309 gboolean ret = pulse_connection_load_server_info (connection);
1310
1311 if (G_UNLIKELY (ret == FALSE)) {
1312 pulse_connection_disconnect (connection);
1313 return FALSE;
1314 }
1315 }
1316
1317 return TRUE;
1318 }
1319
1320 static void
pulse_state_cb(pa_context * c,void * userdata)1321 pulse_state_cb (pa_context *c, void *userdata)
1322 {
1323 PulseConnection *connection;
1324 pa_context_state_t state;
1325
1326 connection = PULSE_CONNECTION (userdata);
1327
1328 state = pa_context_get_state (c);
1329
1330 if (state == PA_CONTEXT_READY) {
1331 pa_operation *op;
1332
1333 if (connection->priv->state == PULSE_CONNECTION_LOADING ||
1334 connection->priv->state == PULSE_CONNECTION_CONNECTED) {
1335 g_warn_if_reached ();
1336 return;
1337 }
1338
1339 /* We are connected, let's subscribe to notifications and load the
1340 * initial lists */
1341 pa_context_set_subscribe_callback (connection->priv->context,
1342 pulse_subscribe_cb,
1343 connection);
1344 pa_ext_stream_restore_set_subscribe_cb (connection->priv->context,
1345 pulse_restore_subscribe_cb,
1346 connection);
1347
1348 op = pa_ext_stream_restore_subscribe (connection->priv->context,
1349 TRUE,
1350 NULL, NULL);
1351
1352 /* Keep going if this operation fails */
1353 process_pulse_operation (connection, op);
1354
1355 op = pa_context_subscribe (connection->priv->context,
1356 PA_SUBSCRIPTION_MASK_SERVER |
1357 PA_SUBSCRIPTION_MASK_CARD |
1358 PA_SUBSCRIPTION_MASK_SINK |
1359 PA_SUBSCRIPTION_MASK_SOURCE |
1360 PA_SUBSCRIPTION_MASK_SINK_INPUT |
1361 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
1362 NULL, NULL);
1363
1364 if (process_pulse_operation (connection, op) == TRUE) {
1365 change_state (connection, PULSE_CONNECTION_LOADING);
1366
1367 if (load_lists (connection) == FALSE)
1368 state = PA_CONTEXT_FAILED;
1369 } else
1370 state = PA_CONTEXT_FAILED;
1371 }
1372
1373 if (state == PA_CONTEXT_TERMINATED || state == PA_CONTEXT_FAILED) {
1374 /* We do not distinguish between failure and clean connection termination */
1375 pulse_connection_disconnect (connection);
1376 return;
1377 }
1378
1379 if (state == PA_CONTEXT_CONNECTING)
1380 change_state (connection, PULSE_CONNECTION_CONNECTING);
1381 else if (state == PA_CONTEXT_AUTHORIZING ||
1382 state == PA_CONTEXT_SETTING_NAME)
1383 change_state (connection, PULSE_CONNECTION_AUTHORIZING);
1384 }
1385
1386 static void
pulse_subscribe_cb(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)1387 pulse_subscribe_cb (pa_context *c,
1388 pa_subscription_event_type_t t,
1389 uint32_t idx,
1390 void *userdata)
1391 {
1392 PulseConnection *connection;
1393
1394 connection = PULSE_CONNECTION (userdata);
1395
1396 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
1397 case PA_SUBSCRIPTION_EVENT_SERVER:
1398 pulse_connection_load_server_info (connection);
1399 break;
1400
1401 case PA_SUBSCRIPTION_EVENT_CARD:
1402 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
1403 g_signal_emit (G_OBJECT (connection),
1404 signals[CARD_REMOVED],
1405 0,
1406 idx);
1407 else
1408 pulse_connection_load_card_info (connection, idx);
1409 break;
1410
1411 case PA_SUBSCRIPTION_EVENT_SINK:
1412 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
1413 g_signal_emit (G_OBJECT (connection),
1414 signals[SINK_REMOVED],
1415 0,
1416 idx);
1417 else
1418 pulse_connection_load_sink_info (connection, idx);
1419 break;
1420
1421 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
1422 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
1423 g_signal_emit (G_OBJECT (connection),
1424 signals[SINK_INPUT_REMOVED],
1425 0,
1426 idx);
1427 else
1428 pulse_connection_load_sink_input_info (connection, idx);
1429 break;
1430
1431 case PA_SUBSCRIPTION_EVENT_SOURCE:
1432 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
1433 g_signal_emit (G_OBJECT (connection),
1434 signals[SOURCE_REMOVED],
1435 0,
1436 idx);
1437 else
1438 pulse_connection_load_source_info (connection, idx);
1439 break;
1440
1441 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
1442 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
1443 g_signal_emit (G_OBJECT (connection),
1444 signals[SOURCE_OUTPUT_REMOVED],
1445 0,
1446 idx);
1447 else
1448 pulse_connection_load_source_output_info (connection, idx);
1449 break;
1450 }
1451 }
1452
1453 static void
pulse_restore_subscribe_cb(pa_context * c,void * userdata)1454 pulse_restore_subscribe_cb (pa_context *c, void *userdata)
1455 {
1456 PulseConnection *connection;
1457
1458 connection = PULSE_CONNECTION (userdata);
1459
1460 pulse_connection_load_ext_stream_info (connection);
1461 }
1462
1463 static void
pulse_server_info_cb(pa_context * c,const pa_server_info * info,void * userdata)1464 pulse_server_info_cb (pa_context *c,
1465 const pa_server_info *info,
1466 void *userdata)
1467 {
1468 PulseConnection *connection;
1469
1470 connection = PULSE_CONNECTION (userdata);
1471
1472 g_signal_emit (G_OBJECT (connection),
1473 signals[SERVER_INFO],
1474 0,
1475 info);
1476
1477 /* This notification may arrive at any time, but it also finalizes the
1478 * connection process */
1479 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1480 change_state (connection, PULSE_CONNECTION_CONNECTED);
1481 }
1482
1483 static void
pulse_card_info_cb(pa_context * c,const pa_card_info * info,int eol,void * userdata)1484 pulse_card_info_cb (pa_context *c,
1485 const pa_card_info *info,
1486 int eol,
1487 void *userdata)
1488 {
1489 PulseConnection *connection;
1490
1491 connection = PULSE_CONNECTION (userdata);
1492
1493 if (eol) {
1494 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1495 load_list_finished (connection);
1496 return;
1497 }
1498
1499 g_signal_emit (G_OBJECT (connection),
1500 signals[CARD_INFO],
1501 0,
1502 info);
1503 }
1504
1505 static void
pulse_sink_info_cb(pa_context * c,const pa_sink_info * info,int eol,void * userdata)1506 pulse_sink_info_cb (pa_context *c,
1507 const pa_sink_info *info,
1508 int eol,
1509 void *userdata)
1510 {
1511 PulseConnection *connection;
1512
1513 connection = PULSE_CONNECTION (userdata);
1514
1515 if (eol) {
1516 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1517 load_list_finished (connection);
1518 return;
1519 }
1520
1521 g_signal_emit (G_OBJECT (connection),
1522 signals[SINK_INFO],
1523 0,
1524 info);
1525 }
1526
1527 static void
pulse_sink_input_info_cb(pa_context * c,const pa_sink_input_info * info,int eol,void * userdata)1528 pulse_sink_input_info_cb (pa_context *c,
1529 const pa_sink_input_info *info,
1530 int eol,
1531 void *userdata)
1532 {
1533 PulseConnection *connection;
1534
1535 connection = PULSE_CONNECTION (userdata);
1536
1537 if (eol) {
1538 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1539 load_list_finished (connection);
1540 return;
1541 }
1542
1543 g_signal_emit (G_OBJECT (connection),
1544 signals[SINK_INPUT_INFO],
1545 0,
1546 info);
1547 }
1548
1549 static void
pulse_source_info_cb(pa_context * c,const pa_source_info * info,int eol,void * userdata)1550 pulse_source_info_cb (pa_context *c,
1551 const pa_source_info *info,
1552 int eol,
1553 void *userdata)
1554 {
1555 PulseConnection *connection;
1556
1557 connection = PULSE_CONNECTION (userdata);
1558
1559 if (eol) {
1560 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1561 load_list_finished (connection);
1562 return;
1563 }
1564
1565 g_signal_emit (G_OBJECT (connection),
1566 signals[SOURCE_INFO],
1567 0,
1568 info);
1569 }
1570
1571 static void
pulse_source_output_info_cb(pa_context * c,const pa_source_output_info * info,int eol,void * userdata)1572 pulse_source_output_info_cb (pa_context *c,
1573 const pa_source_output_info *info,
1574 int eol,
1575 void *userdata)
1576 {
1577 PulseConnection *connection;
1578
1579 connection = PULSE_CONNECTION (userdata);
1580
1581 if (eol) {
1582 if (connection->priv->state == PULSE_CONNECTION_LOADING)
1583 load_list_finished (connection);
1584 return;
1585 }
1586
1587 g_signal_emit (G_OBJECT (connection),
1588 signals[SOURCE_OUTPUT_INFO],
1589 0,
1590 info);
1591 }
1592
1593 static void
pulse_ext_stream_restore_cb(pa_context * c,const pa_ext_stream_restore_info * info,int eol,void * userdata)1594 pulse_ext_stream_restore_cb (pa_context *c,
1595 const pa_ext_stream_restore_info *info,
1596 int eol,
1597 void *userdata)
1598 {
1599 PulseConnection *connection;
1600
1601 connection = PULSE_CONNECTION (userdata);
1602
1603 if (eol) {
1604 connection->priv->ext_streams_loading = FALSE;
1605 g_signal_emit (G_OBJECT (connection),
1606 signals[EXT_STREAM_LOADED],
1607 0);
1608
1609 if (connection->priv->state == PULSE_CONNECTION_LOADING) {
1610 if (load_list_finished (connection) == FALSE)
1611 return;
1612 }
1613
1614 if (connection->priv->ext_streams_dirty == TRUE)
1615 pulse_connection_load_ext_stream_info (connection);
1616
1617 return;
1618 }
1619
1620 g_signal_emit (G_OBJECT (connection),
1621 signals[EXT_STREAM_INFO],
1622 0,
1623 info);
1624 }
1625
1626 static void
change_state(PulseConnection * connection,PulseConnectionState state)1627 change_state (PulseConnection *connection, PulseConnectionState state)
1628 {
1629 if (connection->priv->state == state)
1630 return;
1631
1632 connection->priv->state = state;
1633
1634 g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
1635 }
1636
1637 static gboolean
process_pulse_operation(PulseConnection * connection,pa_operation * op)1638 process_pulse_operation (PulseConnection *connection, pa_operation *op)
1639 {
1640 if (G_UNLIKELY (op == NULL)) {
1641 g_warning ("PulseAudio operation failed: %s",
1642 pa_strerror (pa_context_errno (connection->priv->context)));
1643 return FALSE;
1644 }
1645
1646 pa_operation_unref (op);
1647 return TRUE;
1648 }
1649