]> code.delx.au - pulseaudio/blob - src/pulse/context.c
context: don't fail if session bus is not there
[pulseaudio] / src / pulse / context.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <limits.h>
36 #include <locale.h>
37
38 #ifdef HAVE_SYS_WAIT_H
39 #include <sys/wait.h>
40 #endif
41
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
45 #ifdef HAVE_SYS_UN_H
46 #include <sys/un.h>
47 #endif
48 #ifdef HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
51
52 #include <pulse/version.h>
53 #include <pulse/xmalloc.h>
54 #include <pulse/utf8.h>
55 #include <pulse/util.h>
56 #include <pulse/i18n.h>
57
58 #include <pulsecore/winsock.h>
59 #include <pulsecore/core-error.h>
60
61 #include <pulsecore/native-common.h>
62 #include <pulsecore/pdispatch.h>
63 #include <pulsecore/pstream.h>
64 #include <pulsecore/dynarray.h>
65 #include <pulsecore/socket-client.h>
66 #include <pulsecore/pstream-util.h>
67 #include <pulsecore/core-util.h>
68 #include <pulsecore/log.h>
69 #include <pulsecore/socket-util.h>
70 #include <pulsecore/creds.h>
71 #include <pulsecore/macro.h>
72 #include <pulsecore/proplist-util.h>
73
74 #include "internal.h"
75
76 #include "client-conf.h"
77 #include "fork-detect.h"
78
79 #ifdef HAVE_X11
80 #include "client-conf-x11.h"
81 #endif
82
83 #include "context.h"
84
85 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
86
87 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
88 [PA_COMMAND_REQUEST] = pa_command_request,
89 [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow,
90 [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow,
91 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed,
92 [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed,
93 [PA_COMMAND_PLAYBACK_STREAM_MOVED] = pa_command_stream_moved,
94 [PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved,
95 [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended,
96 [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended,
97 [PA_COMMAND_STARTED] = pa_command_stream_started,
98 [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event,
99 [PA_COMMAND_EXTENSION] = pa_command_extension,
100 [PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event,
101 [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
102 [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
103 [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
104 [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr
105 };
106 static void context_free(pa_context *c);
107
108 #ifdef HAVE_DBUS
109 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata);
110 #endif
111
112 pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
113 return pa_context_new_with_proplist(mainloop, name, NULL);
114 }
115
116 static void reset_callbacks(pa_context *c) {
117 pa_assert(c);
118
119 c->state_callback = NULL;
120 c->state_userdata = NULL;
121
122 c->subscribe_callback = NULL;
123 c->subscribe_userdata = NULL;
124
125 c->event_callback = NULL;
126 c->event_userdata = NULL;
127
128 c->ext_stream_restore.callback = NULL;
129 c->ext_stream_restore.userdata = NULL;
130 }
131
132 pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
133 pa_context *c;
134
135 pa_assert(mainloop);
136
137 if (pa_detect_fork())
138 return NULL;
139
140 pa_init_i18n();
141
142 c = pa_xnew(pa_context, 1);
143 PA_REFCNT_INIT(c);
144
145 c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
146
147 if (name)
148 pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
149
150 #ifdef HAVE_DBUS
151 c->system_bus = c->session_bus = NULL;
152 #endif
153 c->mainloop = mainloop;
154 c->client = NULL;
155 c->pstream = NULL;
156 c->pdispatch = NULL;
157 c->playback_streams = pa_dynarray_new();
158 c->record_streams = pa_dynarray_new();
159 c->client_index = PA_INVALID_INDEX;
160
161 PA_LLIST_HEAD_INIT(pa_stream, c->streams);
162 PA_LLIST_HEAD_INIT(pa_operation, c->operations);
163
164 c->error = PA_OK;
165 c->state = PA_CONTEXT_UNCONNECTED;
166 c->ctag = 0;
167 c->csyncid = 0;
168
169 reset_callbacks(c);
170
171 c->is_local = FALSE;
172 c->server_list = NULL;
173 c->server = NULL;
174
175 c->do_shm = FALSE;
176
177 c->server_specified = FALSE;
178 c->no_fail = FALSE;
179 c->do_autospawn = FALSE;
180 memset(&c->spawn_api, 0, sizeof(c->spawn_api));
181
182 #ifndef MSG_NOSIGNAL
183 #ifdef SIGPIPE
184 pa_check_signal_is_blocked(SIGPIPE);
185 #endif
186 #endif
187
188 c->conf = pa_client_conf_new();
189 pa_client_conf_load(c->conf, NULL);
190 #ifdef HAVE_X11
191 pa_client_conf_from_x11(c->conf, NULL);
192 #endif
193 pa_client_conf_env(c->conf);
194
195 if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
196
197 if (!c->conf->disable_shm)
198 c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);
199
200 if (!c->mempool) {
201 context_free(c);
202 return NULL;
203 }
204 }
205
206 return c;
207 }
208
209 static void context_unlink(pa_context *c) {
210 pa_stream *s;
211
212 pa_assert(c);
213
214 s = c->streams ? pa_stream_ref(c->streams) : NULL;
215 while (s) {
216 pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
217 pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
218 pa_stream_unref(s);
219 s = n;
220 }
221
222 while (c->operations)
223 pa_operation_cancel(c->operations);
224
225 if (c->pdispatch) {
226 pa_pdispatch_unref(c->pdispatch);
227 c->pdispatch = NULL;
228 }
229
230 if (c->pstream) {
231 pa_pstream_unlink(c->pstream);
232 pa_pstream_unref(c->pstream);
233 c->pstream = NULL;
234 }
235
236 if (c->client) {
237 pa_socket_client_unref(c->client);
238 c->client = NULL;
239 }
240
241 reset_callbacks(c);
242 }
243
244 static void context_free(pa_context *c) {
245 pa_assert(c);
246
247 context_unlink(c);
248
249 #ifdef HAVE_DBUS
250 if (c->system_bus) {
251 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c);
252 pa_dbus_wrap_connection_free(c->system_bus);
253 }
254
255 if (c->session_bus) {
256 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c);
257 pa_dbus_wrap_connection_free(c->session_bus);
258 }
259 #endif
260
261 if (c->record_streams)
262 pa_dynarray_free(c->record_streams, NULL, NULL);
263 if (c->playback_streams)
264 pa_dynarray_free(c->playback_streams, NULL, NULL);
265
266 if (c->mempool)
267 pa_mempool_free(c->mempool);
268
269 if (c->conf)
270 pa_client_conf_free(c->conf);
271
272 pa_strlist_free(c->server_list);
273
274 if (c->proplist)
275 pa_proplist_free(c->proplist);
276
277 pa_xfree(c->server);
278 pa_xfree(c);
279 }
280
281 pa_context* pa_context_ref(pa_context *c) {
282 pa_assert(c);
283 pa_assert(PA_REFCNT_VALUE(c) >= 1);
284
285 PA_REFCNT_INC(c);
286 return c;
287 }
288
289 void pa_context_unref(pa_context *c) {
290 pa_assert(c);
291 pa_assert(PA_REFCNT_VALUE(c) >= 1);
292
293 if (PA_REFCNT_DEC(c) <= 0)
294 context_free(c);
295 }
296
297 void pa_context_set_state(pa_context *c, pa_context_state_t st) {
298 pa_assert(c);
299 pa_assert(PA_REFCNT_VALUE(c) >= 1);
300
301 if (c->state == st)
302 return;
303
304 pa_context_ref(c);
305
306 c->state = st;
307
308 if (c->state_callback)
309 c->state_callback(c, c->state_userdata);
310
311 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED)
312 context_unlink(c);
313
314 pa_context_unref(c);
315 }
316
317 int pa_context_set_error(pa_context *c, int error) {
318 pa_assert(error >= 0);
319 pa_assert(error < PA_ERR_MAX);
320
321 if (c)
322 c->error = error;
323
324 return error;
325 }
326
327 void pa_context_fail(pa_context *c, int error) {
328 pa_assert(c);
329 pa_assert(PA_REFCNT_VALUE(c) >= 1);
330
331 pa_context_set_error(c, error);
332 pa_context_set_state(c, PA_CONTEXT_FAILED);
333 }
334
335 static void pstream_die_callback(pa_pstream *p, void *userdata) {
336 pa_context *c = userdata;
337
338 pa_assert(p);
339 pa_assert(c);
340
341 pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
342 }
343
344 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
345 pa_context *c = userdata;
346
347 pa_assert(p);
348 pa_assert(packet);
349 pa_assert(c);
350
351 pa_context_ref(c);
352
353 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)
354 pa_context_fail(c, PA_ERR_PROTOCOL);
355
356 pa_context_unref(c);
357 }
358
359 static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
360 pa_context *c = userdata;
361 pa_stream *s;
362
363 pa_assert(p);
364 pa_assert(chunk);
365 pa_assert(chunk->length > 0);
366 pa_assert(c);
367 pa_assert(PA_REFCNT_VALUE(c) >= 1);
368
369 pa_context_ref(c);
370
371 if ((s = pa_dynarray_get(c->record_streams, channel))) {
372
373 if (chunk->memblock) {
374 pa_memblockq_seek(s->record_memblockq, offset, seek, TRUE);
375 pa_memblockq_push_align(s->record_memblockq, chunk);
376 } else
377 pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, TRUE);
378
379 if (s->read_callback) {
380 size_t l;
381
382 if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0)
383 s->read_callback(s, l, s->read_userdata);
384 }
385 }
386
387 pa_context_unref(c);
388 }
389
390 int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa_bool_t fail) {
391 uint32_t err;
392 pa_assert(c);
393 pa_assert(PA_REFCNT_VALUE(c) >= 1);
394
395 if (command == PA_COMMAND_ERROR) {
396 pa_assert(t);
397
398 if (pa_tagstruct_getu32(t, &err) < 0 ||
399 !pa_tagstruct_eof(t)) {
400 pa_context_fail(c, PA_ERR_PROTOCOL);
401 return -1;
402 }
403
404 } else if (command == PA_COMMAND_TIMEOUT)
405 err = PA_ERR_TIMEOUT;
406 else {
407 pa_context_fail(c, PA_ERR_PROTOCOL);
408 return -1;
409 }
410
411 if (err == PA_OK) {
412 pa_context_fail(c, PA_ERR_PROTOCOL);
413 return -1;
414 }
415
416 if (err >= PA_ERR_MAX)
417 err = PA_ERR_UNKNOWN;
418
419 if (fail) {
420 pa_context_fail(c, (int) err);
421 return -1;
422 }
423
424 pa_context_set_error(c, (int) err);
425
426 return 0;
427 }
428
429 static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
430 pa_context *c = userdata;
431
432 pa_assert(pd);
433 pa_assert(c);
434 pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
435
436 pa_context_ref(c);
437
438 if (command != PA_COMMAND_REPLY) {
439 pa_context_handle_error(c, command, t, TRUE);
440 goto finish;
441 }
442
443 switch(c->state) {
444 case PA_CONTEXT_AUTHORIZING: {
445 pa_tagstruct *reply;
446 pa_bool_t shm_on_remote = FALSE;
447
448 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
449 !pa_tagstruct_eof(t)) {
450 pa_context_fail(c, PA_ERR_PROTOCOL);
451 goto finish;
452 }
453
454 /* Minimum supported version */
455 if (c->version < 8) {
456 pa_context_fail(c, PA_ERR_VERSION);
457 goto finish;
458 }
459
460 /* Starting with protocol version 13 the MSB of the version
461 tag reflects if shm is available for this connection or
462 not. */
463 if (c->version >= 13) {
464 shm_on_remote = !!(c->version & 0x80000000U);
465 c->version &= 0x7FFFFFFFU;
466 }
467
468 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
469
470 /* Enable shared memory support if possible */
471 if (c->do_shm)
472 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
473 c->do_shm = FALSE;
474
475 if (c->do_shm) {
476
477 /* Only enable SHM if both sides are owned by the same
478 * user. This is a security measure because otherwise
479 * data private to the user might leak. */
480
481 #ifdef HAVE_CREDS
482 const pa_creds *creds;
483 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
484 c->do_shm = FALSE;
485 #endif
486 }
487
488 pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
489 pa_pstream_enable_shm(c->pstream, c->do_shm);
490
491 reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
492
493 if (c->version >= 13) {
494 pa_init_proplist(c->proplist);
495 pa_tagstruct_put_proplist(reply, c->proplist);
496 } else
497 pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));
498
499 pa_pstream_send_tagstruct(c->pstream, reply);
500 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
501
502 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
503 break;
504 }
505
506 case PA_CONTEXT_SETTING_NAME :
507
508 if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
509 c->client_index == PA_INVALID_INDEX)) ||
510 !pa_tagstruct_eof(t)) {
511 pa_context_fail(c, PA_ERR_PROTOCOL);
512 goto finish;
513 }
514
515 pa_context_set_state(c, PA_CONTEXT_READY);
516 break;
517
518 default:
519 pa_assert_not_reached();
520 }
521
522 finish:
523 pa_context_unref(c);
524 }
525
526 static void setup_context(pa_context *c, pa_iochannel *io) {
527 pa_tagstruct *t;
528 uint32_t tag;
529
530 pa_assert(c);
531 pa_assert(io);
532
533 pa_context_ref(c);
534
535 pa_assert(!c->pstream);
536 c->pstream = pa_pstream_new(c->mainloop, io, c->mempool);
537
538 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
539 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
540 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
541
542 pa_assert(!c->pdispatch);
543 c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
544
545 if (!c->conf->cookie_valid)
546 pa_log_info(_("No cookie loaded. Attempting to connect without."));
547
548 t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
549
550 c->do_shm =
551 pa_mempool_is_shared(c->mempool) &&
552 c->is_local;
553
554 pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm));
555
556 /* Starting with protocol version 13 we use the MSB of the version
557 * tag for informing the other side if we could do SHM or not */
558 pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION | (c->do_shm ? 0x80000000U : 0));
559 pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
560
561 #ifdef HAVE_CREDS
562 {
563 pa_creds ucred;
564
565 if (pa_iochannel_creds_supported(io))
566 pa_iochannel_creds_enable(io);
567
568 ucred.uid = getuid();
569 ucred.gid = getgid();
570
571 pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred);
572 }
573 #else
574 pa_pstream_send_tagstruct(c->pstream, t);
575 #endif
576
577 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
578
579 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
580
581 pa_context_unref(c);
582 }
583
584 #ifdef ENABLE_LEGACY_RUNTIME_DIR
585 static char *get_old_legacy_runtime_dir(void) {
586 char *p, u[128];
587 struct stat st;
588
589 if (!pa_get_user_name(u, sizeof(u)))
590 return NULL;
591
592 p = pa_sprintf_malloc("/tmp/pulse-%s", u);
593
594 if (stat(p, &st) < 0) {
595 pa_xfree(p);
596 return NULL;
597 }
598
599 if (st.st_uid != getuid()) {
600 pa_xfree(p);
601 return NULL;
602 }
603
604 return p;
605 }
606
607 static char *get_very_old_legacy_runtime_dir(void) {
608 char *p, h[128];
609 struct stat st;
610
611 if (!pa_get_home_dir(h, sizeof(h)))
612 return NULL;
613
614 p = pa_sprintf_malloc("%s/.pulse", h);
615
616 if (stat(p, &st) < 0) {
617 pa_xfree(p);
618 return NULL;
619 }
620
621 if (st.st_uid != getuid()) {
622 pa_xfree(p);
623 return NULL;
624 }
625
626 return p;
627 }
628 #endif
629
630 static pa_strlist *prepend_per_user(pa_strlist *l) {
631 char *ufn;
632
633 #ifdef ENABLE_LEGACY_RUNTIME_DIR
634 static char *legacy_dir;
635
636 /* The very old per-user instance path (< 0.9.11). This is supported only to ease upgrades */
637 if ((legacy_dir = get_very_old_legacy_runtime_dir())) {
638 char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
639 l = pa_strlist_prepend(l, p);
640 pa_xfree(p);
641 pa_xfree(legacy_dir);
642 }
643
644 /* The old per-user instance path (< 0.9.12). This is supported only to ease upgrades */
645 if ((legacy_dir = get_old_legacy_runtime_dir())) {
646 char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
647 l = pa_strlist_prepend(l, p);
648 pa_xfree(p);
649 pa_xfree(legacy_dir);
650 }
651 #endif
652
653 /* The per-user instance */
654 if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
655 l = pa_strlist_prepend(l, ufn);
656 pa_xfree(ufn);
657 }
658
659 return l;
660 }
661
662 #ifndef OS_IS_WIN32
663
664 static int context_autospawn(pa_context *c) {
665 pid_t pid;
666 int status, r;
667
668 pa_log_debug("Trying to autospawn...");
669
670 pa_context_ref(c);
671
672 if (c->spawn_api.prefork)
673 c->spawn_api.prefork();
674
675 if ((pid = fork()) < 0) {
676 pa_log_error(_("fork(): %s"), pa_cstrerror(errno));
677 pa_context_fail(c, PA_ERR_INTERNAL);
678
679 if (c->spawn_api.postfork)
680 c->spawn_api.postfork();
681
682 goto fail;
683 } else if (!pid) {
684 /* Child */
685
686 const char *state = NULL;
687 #define MAX_ARGS 64
688 const char * argv[MAX_ARGS+1];
689 int n;
690
691 if (c->spawn_api.atfork)
692 c->spawn_api.atfork();
693
694 pa_close_all(-1);
695
696 /* Setup argv */
697
698 n = 0;
699
700 argv[n++] = c->conf->daemon_binary;
701 argv[n++] = "--start";
702
703 while (n < MAX_ARGS) {
704 char *a;
705
706 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
707 break;
708
709 argv[n++] = a;
710 }
711
712 argv[n++] = NULL;
713
714 execv(argv[0], (char * const *) argv);
715 _exit(1);
716 #undef MAX_ARGS
717 }
718
719 /* Parent */
720
721 if (c->spawn_api.postfork)
722 c->spawn_api.postfork();
723
724 do {
725 r = waitpid(pid, &status, 0);
726 } while (r < 0 && errno == EINTR);
727
728 if (r < 0) {
729 pa_log(_("waitpid(): %s"), pa_cstrerror(errno));
730 pa_context_fail(c, PA_ERR_INTERNAL);
731 goto fail;
732 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
733 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
734 goto fail;
735 }
736
737 pa_context_unref(c);
738
739 return 0;
740
741 fail:
742
743 pa_context_unref(c);
744
745 return -1;
746 }
747
748 #endif /* OS_IS_WIN32 */
749
750 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata);
751
752 #ifdef HAVE_DBUS
753 static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) {
754 DBusError error;
755
756 pa_assert(c);
757 pa_assert(conn);
758
759 dbus_error_init(&error);
760 if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, type, &error)) || dbus_error_is_set(&error)) {
761 pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
762 goto finish;
763 }
764
765 if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) {
766 pa_log_warn("Failed to add filter function");
767 goto finish;
768 }
769
770 if (pa_dbus_add_matches(
771 pa_dbus_wrap_connection_get(*conn), &error,
772 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0)
773 pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message);
774
775 finish:
776 dbus_error_free(&error);
777 }
778 #endif
779
780 static int try_next_connection(pa_context *c) {
781 char *u = NULL;
782 int r = -1;
783
784 pa_assert(c);
785 pa_assert(!c->client);
786
787 for (;;) {
788 pa_xfree(u);
789 u = NULL;
790
791 c->server_list = pa_strlist_pop(c->server_list, &u);
792
793 if (!u) {
794
795 #ifndef OS_IS_WIN32
796 if (c->do_autospawn) {
797
798 if ((r = context_autospawn(c)) < 0)
799 goto finish;
800
801 /* Autospawn only once */
802 c->do_autospawn = FALSE;
803
804 /* Connect only to per-user sockets this time */
805 c->server_list = prepend_per_user(c->server_list);
806
807 /* Retry connection */
808 continue;
809 }
810 #endif
811
812 #ifdef HAVE_DBUS
813 if (c->no_fail && !c->server_specified) {
814 if (!c->session_bus)
815 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
816 if (!c->system_bus)
817 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
818 } else
819 #endif
820 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
821
822 goto finish;
823 }
824
825 pa_log_debug("Trying to connect to %s...", u);
826
827 pa_xfree(c->server);
828 c->server = pa_xstrdup(u);
829
830 if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
831 continue;
832
833 c->is_local = !!pa_socket_client_is_local(c->client);
834 pa_socket_client_set_callback(c->client, on_connection, c);
835 break;
836 }
837
838 r = 0;
839
840 finish:
841 pa_xfree(u);
842
843 return r;
844 }
845
846 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
847 pa_context *c = userdata;
848 int saved_errno = errno;
849
850 pa_assert(client);
851 pa_assert(c);
852 pa_assert(c->state == PA_CONTEXT_CONNECTING);
853
854 pa_context_ref(c);
855
856 pa_socket_client_unref(client);
857 c->client = NULL;
858
859 if (!io) {
860 /* Try the item in the list */
861 if (saved_errno == ECONNREFUSED ||
862 saved_errno == ETIMEDOUT ||
863 saved_errno == EHOSTUNREACH) {
864 try_next_connection(c);
865 goto finish;
866 }
867
868 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
869 goto finish;
870 }
871
872 setup_context(c, io);
873
874 finish:
875 pa_context_unref(c);
876 }
877
878 #ifdef HAVE_DBUS
879 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
880 pa_context *c = userdata;
881 pa_bool_t is_session;
882
883 pa_assert(bus);
884 pa_assert(message);
885 pa_assert(c);
886
887 if (c->state != PA_CONTEXT_CONNECTING)
888 goto finish;
889
890 if (!c->no_fail)
891 goto finish;
892
893 /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */
894
895 is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus);
896 pa_log_debug("Rock!! PulseAudio is back on %s bus", is_session ? "session" : "system");
897
898 if (is_session)
899 /* The user instance via PF_LOCAL */
900 c->server_list = prepend_per_user(c->server_list);
901 else
902 /* The system wide instance via PF_LOCAL */
903 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
904
905 if (!c->client)
906 try_next_connection(c);
907
908 finish:
909 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
910 }
911 #endif
912
913 int pa_context_connect(
914 pa_context *c,
915 const char *server,
916 pa_context_flags_t flags,
917 const pa_spawn_api *api) {
918
919 int r = -1;
920
921 pa_assert(c);
922 pa_assert(PA_REFCNT_VALUE(c) >= 1);
923
924 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
925 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
926 PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
927 PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
928
929 if (server)
930 c->conf->autospawn = FALSE;
931 else
932 server = c->conf->default_server;
933
934 pa_context_ref(c);
935
936 c->no_fail = flags & PA_CONTEXT_NOFAIL;
937 c->server_specified = !!server;
938 pa_assert(!c->server_list);
939
940 if (server) {
941 if (!(c->server_list = pa_strlist_parse(server))) {
942 pa_context_fail(c, PA_ERR_INVALIDSERVER);
943 goto finish;
944 }
945
946 } else {
947 char *d;
948
949 /* Prepend in reverse order */
950
951 /* Follow the X display */
952 if ((d = getenv("DISPLAY"))) {
953 char *e;
954 d = pa_xstrdup(d);
955 if ((e = strchr(d, ':')))
956 *e = 0;
957
958 if (*d)
959 c->server_list = pa_strlist_prepend(c->server_list, d);
960
961 pa_xfree(d);
962 }
963
964 /* Add TCP/IP on the localhost */
965 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
966 c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
967
968 /* The system wide instance via PF_LOCAL */
969 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
970
971 /* The user instance via PF_LOCAL */
972 c->server_list = prepend_per_user(c->server_list);
973 }
974
975 /* Set up autospawning */
976 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
977
978 if (getuid() == 0)
979 pa_log_debug("Not doing autospawn since we are root.");
980 else {
981 c->do_autospawn = TRUE;
982
983 if (api)
984 c->spawn_api = *api;
985 }
986 }
987
988 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
989 r = try_next_connection(c);
990
991 finish:
992 pa_context_unref(c);
993
994 return r;
995 }
996
997 void pa_context_disconnect(pa_context *c) {
998 pa_assert(c);
999 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1000
1001 if (pa_detect_fork())
1002 return;
1003
1004 if (PA_CONTEXT_IS_GOOD(c->state))
1005 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
1006 }
1007
1008 pa_context_state_t pa_context_get_state(pa_context *c) {
1009 pa_assert(c);
1010 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1011
1012 return c->state;
1013 }
1014
1015 int pa_context_errno(pa_context *c) {
1016 pa_assert(c);
1017 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1018
1019 return c->error;
1020 }
1021
1022 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1023 pa_assert(c);
1024 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1025
1026 if (pa_detect_fork())
1027 return;
1028
1029 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1030 return;
1031
1032 c->state_callback = cb;
1033 c->state_userdata = userdata;
1034 }
1035
1036 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1037 pa_assert(c);
1038 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1039
1040 if (pa_detect_fork())
1041 return;
1042
1043 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1044 return;
1045
1046 c->event_callback = cb;
1047 c->event_userdata = userdata;
1048 }
1049
1050 int pa_context_is_pending(pa_context *c) {
1051 pa_assert(c);
1052 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1053
1054 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1055 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1056
1057 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1058 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1059 c->client;
1060 }
1061
1062 static void set_dispatch_callbacks(pa_operation *o);
1063
1064 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1065 set_dispatch_callbacks(userdata);
1066 }
1067
1068 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1069 set_dispatch_callbacks(userdata);
1070 }
1071
1072 static void set_dispatch_callbacks(pa_operation *o) {
1073 int done = 1;
1074
1075 pa_assert(o);
1076 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1077 pa_assert(o->context);
1078 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1079 pa_assert(o->context->state == PA_CONTEXT_READY);
1080
1081 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1082 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1083
1084 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1085 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1086 done = 0;
1087 }
1088
1089 if (pa_pstream_is_pending(o->context->pstream)) {
1090 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1091 done = 0;
1092 }
1093
1094 if (done) {
1095 if (o->callback) {
1096 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1097 cb(o->context, o->userdata);
1098 }
1099
1100 pa_operation_done(o);
1101 pa_operation_unref(o);
1102 }
1103 }
1104
1105 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1106 pa_operation *o;
1107
1108 pa_assert(c);
1109 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1110
1111 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1112 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1113 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1114
1115 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1116 set_dispatch_callbacks(pa_operation_ref(o));
1117
1118 return o;
1119 }
1120
1121 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1122 pa_operation *o = userdata;
1123 int success = 1;
1124
1125 pa_assert(pd);
1126 pa_assert(o);
1127 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1128
1129 if (!o->context)
1130 goto finish;
1131
1132 if (command != PA_COMMAND_REPLY) {
1133 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1134 goto finish;
1135
1136 success = 0;
1137 } else if (!pa_tagstruct_eof(t)) {
1138 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1139 goto finish;
1140 }
1141
1142 if (o->callback) {
1143 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1144 cb(o->context, success, o->userdata);
1145 }
1146
1147 finish:
1148 pa_operation_done(o);
1149 pa_operation_unref(o);
1150 }
1151
1152 pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) {
1153 pa_tagstruct *t;
1154 pa_operation *o;
1155 uint32_t tag;
1156
1157 pa_assert(c);
1158 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1159
1160 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1161 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1162
1163 o = pa_operation_new(c, NULL, cb, userdata);
1164
1165 t = pa_tagstruct_command(c, command, &tag);
1166 pa_pstream_send_tagstruct(c->pstream, t);
1167 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1168
1169 return o;
1170 }
1171
1172 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1173 pa_assert(c);
1174 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1175
1176 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1177 }
1178
1179 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1180 pa_tagstruct *t;
1181 pa_operation *o;
1182 uint32_t tag;
1183
1184 pa_assert(c);
1185 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1186
1187 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1188 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1189
1190 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1191 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1192 pa_tagstruct_puts(t, name);
1193 pa_pstream_send_tagstruct(c->pstream, t);
1194 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1195
1196 return o;
1197 }
1198
1199 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1200 pa_tagstruct *t;
1201 pa_operation *o;
1202 uint32_t tag;
1203
1204 pa_assert(c);
1205 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1206
1207 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1208 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1209
1210 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1211 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1212 pa_tagstruct_puts(t, name);
1213 pa_pstream_send_tagstruct(c->pstream, t);
1214 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1215
1216 return o;
1217 }
1218
1219 int pa_context_is_local(pa_context *c) {
1220 pa_assert(c);
1221 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1222
1223 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1224 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1225
1226 return !!c->is_local;
1227 }
1228
1229 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1230 pa_operation *o;
1231
1232 pa_assert(c);
1233 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1234 pa_assert(name);
1235
1236 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1237 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1238
1239 if (c->version >= 13) {
1240 pa_proplist *p = pa_proplist_new();
1241
1242 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1243 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1244 pa_proplist_free(p);
1245 } else {
1246 pa_tagstruct *t;
1247 uint32_t tag;
1248
1249 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1250 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1251 pa_tagstruct_puts(t, name);
1252 pa_pstream_send_tagstruct(c->pstream, t);
1253 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1254 }
1255
1256 return o;
1257 }
1258
1259 const char* pa_get_library_version(void) {
1260 return PACKAGE_VERSION;
1261 }
1262
1263 const char* pa_context_get_server(pa_context *c) {
1264 pa_assert(c);
1265 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1266
1267 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1268 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1269
1270 if (*c->server == '{') {
1271 char *e = strchr(c->server+1, '}');
1272 return e ? e+1 : c->server;
1273 }
1274
1275 return c->server;
1276 }
1277
1278 uint32_t pa_context_get_protocol_version(pa_context *c) {
1279 return PA_PROTOCOL_VERSION;
1280 }
1281
1282 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1283 pa_assert(c);
1284 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1285
1286 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1287 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1288
1289 return c->version;
1290 }
1291
1292 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1293 pa_tagstruct *t;
1294
1295 pa_assert(c);
1296 pa_assert(tag);
1297
1298 t = pa_tagstruct_new(NULL, 0);
1299 pa_tagstruct_putu32(t, command);
1300 pa_tagstruct_putu32(t, *tag = c->ctag++);
1301
1302 return t;
1303 }
1304
1305 uint32_t pa_context_get_index(pa_context *c) {
1306 pa_assert(c);
1307 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1308
1309 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1310 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1311 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1312
1313 return c->client_index;
1314 }
1315
1316 pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
1317 pa_operation *o;
1318 pa_tagstruct *t;
1319 uint32_t tag;
1320
1321 pa_assert(c);
1322 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1323
1324 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1325 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1326 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1327 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1328
1329 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1330
1331 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1332 pa_tagstruct_putu32(t, (uint32_t) mode);
1333 pa_tagstruct_put_proplist(t, p);
1334
1335 pa_pstream_send_tagstruct(c->pstream, t);
1336 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1337
1338 /* Please note that we don't update c->proplist here, because we
1339 * don't export that field */
1340
1341 return o;
1342 }
1343
1344 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1345 pa_operation *o;
1346 pa_tagstruct *t;
1347 uint32_t tag;
1348 const char * const *k;
1349
1350 pa_assert(c);
1351 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1352
1353 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1354 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1355 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1356 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1357
1358 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1359
1360 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1361
1362 for (k = keys; *k; k++)
1363 pa_tagstruct_puts(t, *k);
1364
1365 pa_tagstruct_puts(t, NULL);
1366
1367 pa_pstream_send_tagstruct(c->pstream, t);
1368 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1369
1370 /* Please note that we don't update c->proplist here, because we
1371 * don't export that field */
1372
1373 return o;
1374 }
1375
1376 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1377 pa_context *c = userdata;
1378 uint32_t idx;
1379 const char *name;
1380
1381 pa_assert(pd);
1382 pa_assert(command == PA_COMMAND_EXTENSION);
1383 pa_assert(t);
1384 pa_assert(c);
1385 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1386
1387 pa_context_ref(c);
1388
1389 if (c->version < 15) {
1390 pa_context_fail(c, PA_ERR_PROTOCOL);
1391 goto finish;
1392 }
1393
1394 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1395 pa_tagstruct_gets(t, &name) < 0) {
1396 pa_context_fail(c, PA_ERR_PROTOCOL);
1397 goto finish;
1398 }
1399
1400 if (!strcmp(name, "module-stream-restore"))
1401 pa_ext_stream_restore_command(c, tag, t);
1402 else
1403 pa_log(_("Received message for unknown extension '%s'"), name);
1404
1405 finish:
1406 pa_context_unref(c);
1407 }
1408
1409
1410 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1411 pa_context *c = userdata;
1412 pa_proplist *pl = NULL;
1413 const char *event;
1414
1415 pa_assert(pd);
1416 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1417 pa_assert(t);
1418 pa_assert(c);
1419 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1420
1421 pa_context_ref(c);
1422
1423 if (c->version < 15) {
1424 pa_context_fail(c, PA_ERR_PROTOCOL);
1425 goto finish;
1426 }
1427
1428 pl = pa_proplist_new();
1429
1430 if (pa_tagstruct_gets(t, &event) < 0 ||
1431 pa_tagstruct_get_proplist(t, pl) < 0 ||
1432 !pa_tagstruct_eof(t) || !event) {
1433 pa_context_fail(c, PA_ERR_PROTOCOL);
1434 goto finish;
1435 }
1436
1437 if (c->event_callback)
1438 c->event_callback(c, event, pl, c->event_userdata);
1439
1440 finish:
1441 pa_context_unref(c);
1442
1443 if (pl)
1444 pa_proplist_free(pl);
1445 }