]> code.delx.au - pulseaudio/blob - src/pulse/context.c
client-conf: make setting a default server independant from the autospawn setting
[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->system_bus)
815 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
816 if (!c->session_bus)
817 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_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 = 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 try_next_connection(c);
906
907 finish:
908 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
909 }
910 #endif
911
912 int pa_context_connect(
913 pa_context *c,
914 const char *server,
915 pa_context_flags_t flags,
916 const pa_spawn_api *api) {
917
918 int r = -1;
919
920 pa_assert(c);
921 pa_assert(PA_REFCNT_VALUE(c) >= 1);
922
923 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
924 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
925 PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
926 PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
927
928 if (server)
929 c->conf->autospawn = FALSE;
930 else
931 server = c->conf->default_server;
932
933 pa_context_ref(c);
934
935 c->no_fail = flags & PA_CONTEXT_NOFAIL;
936 c->server_specified = !!server;
937 pa_assert(!c->server_list);
938
939 if (server) {
940 if (!(c->server_list = pa_strlist_parse(server))) {
941 pa_context_fail(c, PA_ERR_INVALIDSERVER);
942 goto finish;
943 }
944
945 } else {
946 char *d;
947
948 /* Prepend in reverse order */
949
950 /* Follow the X display */
951 if ((d = getenv("DISPLAY"))) {
952 char *e;
953 d = pa_xstrdup(d);
954 if ((e = strchr(d, ':')))
955 *e = 0;
956
957 if (*d)
958 c->server_list = pa_strlist_prepend(c->server_list, d);
959
960 pa_xfree(d);
961 }
962
963 /* Add TCP/IP on the localhost */
964 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
965 c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
966
967 /* The system wide instance via PF_LOCAL */
968 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
969
970 /* The user instance via PF_LOCAL */
971 c->server_list = prepend_per_user(c->server_list);
972 }
973
974 /* Set up autospawning */
975 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
976
977 if (getuid() == 0)
978 pa_log_debug("Not doing autospawn since we are root.");
979 else {
980 c->do_autospawn = TRUE;
981
982 if (api)
983 c->spawn_api = *api;
984 }
985 }
986
987 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
988 r = try_next_connection(c);
989
990 finish:
991 pa_context_unref(c);
992
993 return r;
994 }
995
996 void pa_context_disconnect(pa_context *c) {
997 pa_assert(c);
998 pa_assert(PA_REFCNT_VALUE(c) >= 1);
999
1000 if (pa_detect_fork())
1001 return;
1002
1003 if (PA_CONTEXT_IS_GOOD(c->state))
1004 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
1005 }
1006
1007 pa_context_state_t pa_context_get_state(pa_context *c) {
1008 pa_assert(c);
1009 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1010
1011 return c->state;
1012 }
1013
1014 int pa_context_errno(pa_context *c) {
1015 pa_assert(c);
1016 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1017
1018 return c->error;
1019 }
1020
1021 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1022 pa_assert(c);
1023 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1024
1025 if (pa_detect_fork())
1026 return;
1027
1028 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1029 return;
1030
1031 c->state_callback = cb;
1032 c->state_userdata = userdata;
1033 }
1034
1035 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1036 pa_assert(c);
1037 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1038
1039 if (pa_detect_fork())
1040 return;
1041
1042 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1043 return;
1044
1045 c->event_callback = cb;
1046 c->event_userdata = userdata;
1047 }
1048
1049 int pa_context_is_pending(pa_context *c) {
1050 pa_assert(c);
1051 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1052
1053 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1054 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1055
1056 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1057 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1058 c->client;
1059 }
1060
1061 static void set_dispatch_callbacks(pa_operation *o);
1062
1063 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1064 set_dispatch_callbacks(userdata);
1065 }
1066
1067 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1068 set_dispatch_callbacks(userdata);
1069 }
1070
1071 static void set_dispatch_callbacks(pa_operation *o) {
1072 int done = 1;
1073
1074 pa_assert(o);
1075 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1076 pa_assert(o->context);
1077 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1078 pa_assert(o->context->state == PA_CONTEXT_READY);
1079
1080 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1081 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1082
1083 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1084 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1085 done = 0;
1086 }
1087
1088 if (pa_pstream_is_pending(o->context->pstream)) {
1089 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1090 done = 0;
1091 }
1092
1093 if (done) {
1094 if (o->callback) {
1095 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1096 cb(o->context, o->userdata);
1097 }
1098
1099 pa_operation_done(o);
1100 pa_operation_unref(o);
1101 }
1102 }
1103
1104 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1105 pa_operation *o;
1106
1107 pa_assert(c);
1108 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1109
1110 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1111 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1112 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1113
1114 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1115 set_dispatch_callbacks(pa_operation_ref(o));
1116
1117 return o;
1118 }
1119
1120 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1121 pa_operation *o = userdata;
1122 int success = 1;
1123
1124 pa_assert(pd);
1125 pa_assert(o);
1126 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1127
1128 if (!o->context)
1129 goto finish;
1130
1131 if (command != PA_COMMAND_REPLY) {
1132 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1133 goto finish;
1134
1135 success = 0;
1136 } else if (!pa_tagstruct_eof(t)) {
1137 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1138 goto finish;
1139 }
1140
1141 if (o->callback) {
1142 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1143 cb(o->context, success, o->userdata);
1144 }
1145
1146 finish:
1147 pa_operation_done(o);
1148 pa_operation_unref(o);
1149 }
1150
1151 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) {
1152 pa_tagstruct *t;
1153 pa_operation *o;
1154 uint32_t tag;
1155
1156 pa_assert(c);
1157 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1158
1159 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1160 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1161
1162 o = pa_operation_new(c, NULL, cb, userdata);
1163
1164 t = pa_tagstruct_command(c, command, &tag);
1165 pa_pstream_send_tagstruct(c->pstream, t);
1166 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1167
1168 return o;
1169 }
1170
1171 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1172 pa_assert(c);
1173 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1174
1175 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1176 }
1177
1178 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1179 pa_tagstruct *t;
1180 pa_operation *o;
1181 uint32_t tag;
1182
1183 pa_assert(c);
1184 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1185
1186 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1187 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1188
1189 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1190 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1191 pa_tagstruct_puts(t, name);
1192 pa_pstream_send_tagstruct(c->pstream, t);
1193 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);
1194
1195 return o;
1196 }
1197
1198 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1199 pa_tagstruct *t;
1200 pa_operation *o;
1201 uint32_t tag;
1202
1203 pa_assert(c);
1204 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1205
1206 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1207 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1208
1209 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1210 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1211 pa_tagstruct_puts(t, name);
1212 pa_pstream_send_tagstruct(c->pstream, t);
1213 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);
1214
1215 return o;
1216 }
1217
1218 int pa_context_is_local(pa_context *c) {
1219 pa_assert(c);
1220 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1221
1222 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1223 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1224
1225 return !!c->is_local;
1226 }
1227
1228 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1229 pa_operation *o;
1230
1231 pa_assert(c);
1232 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1233 pa_assert(name);
1234
1235 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1236 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1237
1238 if (c->version >= 13) {
1239 pa_proplist *p = pa_proplist_new();
1240
1241 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1242 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1243 pa_proplist_free(p);
1244 } else {
1245 pa_tagstruct *t;
1246 uint32_t tag;
1247
1248 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1249 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1250 pa_tagstruct_puts(t, name);
1251 pa_pstream_send_tagstruct(c->pstream, t);
1252 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);
1253 }
1254
1255 return o;
1256 }
1257
1258 const char* pa_get_library_version(void) {
1259 return PACKAGE_VERSION;
1260 }
1261
1262 const char* pa_context_get_server(pa_context *c) {
1263 pa_assert(c);
1264 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1265
1266 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1267 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1268
1269 if (*c->server == '{') {
1270 char *e = strchr(c->server+1, '}');
1271 return e ? e+1 : c->server;
1272 }
1273
1274 return c->server;
1275 }
1276
1277 uint32_t pa_context_get_protocol_version(pa_context *c) {
1278 return PA_PROTOCOL_VERSION;
1279 }
1280
1281 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1282 pa_assert(c);
1283 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1284
1285 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1286 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1287
1288 return c->version;
1289 }
1290
1291 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1292 pa_tagstruct *t;
1293
1294 pa_assert(c);
1295 pa_assert(tag);
1296
1297 t = pa_tagstruct_new(NULL, 0);
1298 pa_tagstruct_putu32(t, command);
1299 pa_tagstruct_putu32(t, *tag = c->ctag++);
1300
1301 return t;
1302 }
1303
1304 uint32_t pa_context_get_index(pa_context *c) {
1305 pa_assert(c);
1306 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1307
1308 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1309 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1310 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1311
1312 return c->client_index;
1313 }
1314
1315 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) {
1316 pa_operation *o;
1317 pa_tagstruct *t;
1318 uint32_t tag;
1319
1320 pa_assert(c);
1321 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1322
1323 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1324 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1325 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1326 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1327
1328 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1329
1330 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1331 pa_tagstruct_putu32(t, (uint32_t) mode);
1332 pa_tagstruct_put_proplist(t, p);
1333
1334 pa_pstream_send_tagstruct(c->pstream, t);
1335 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);
1336
1337 /* Please note that we don't update c->proplist here, because we
1338 * don't export that field */
1339
1340 return o;
1341 }
1342
1343 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1344 pa_operation *o;
1345 pa_tagstruct *t;
1346 uint32_t tag;
1347 const char * const *k;
1348
1349 pa_assert(c);
1350 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1351
1352 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1353 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1354 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1355 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1356
1357 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1358
1359 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1360
1361 for (k = keys; *k; k++)
1362 pa_tagstruct_puts(t, *k);
1363
1364 pa_tagstruct_puts(t, NULL);
1365
1366 pa_pstream_send_tagstruct(c->pstream, t);
1367 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);
1368
1369 /* Please note that we don't update c->proplist here, because we
1370 * don't export that field */
1371
1372 return o;
1373 }
1374
1375 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1376 pa_context *c = userdata;
1377 uint32_t idx;
1378 const char *name;
1379
1380 pa_assert(pd);
1381 pa_assert(command == PA_COMMAND_EXTENSION);
1382 pa_assert(t);
1383 pa_assert(c);
1384 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1385
1386 pa_context_ref(c);
1387
1388 if (c->version < 15) {
1389 pa_context_fail(c, PA_ERR_PROTOCOL);
1390 goto finish;
1391 }
1392
1393 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1394 pa_tagstruct_gets(t, &name) < 0) {
1395 pa_context_fail(c, PA_ERR_PROTOCOL);
1396 goto finish;
1397 }
1398
1399 if (!strcmp(name, "module-stream-restore"))
1400 pa_ext_stream_restore_command(c, tag, t);
1401 else
1402 pa_log(_("Received message for unknown extension '%s'"), name);
1403
1404 finish:
1405 pa_context_unref(c);
1406 }
1407
1408
1409 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1410 pa_context *c = userdata;
1411 pa_proplist *pl = NULL;
1412 const char *event;
1413
1414 pa_assert(pd);
1415 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1416 pa_assert(t);
1417 pa_assert(c);
1418 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1419
1420 pa_context_ref(c);
1421
1422 if (c->version < 15) {
1423 pa_context_fail(c, PA_ERR_PROTOCOL);
1424 goto finish;
1425 }
1426
1427 pl = pa_proplist_new();
1428
1429 if (pa_tagstruct_gets(t, &event) < 0 ||
1430 pa_tagstruct_get_proplist(t, pl) < 0 ||
1431 !pa_tagstruct_eof(t) || !event) {
1432 pa_context_fail(c, PA_ERR_PROTOCOL);
1433 goto finish;
1434 }
1435
1436 if (c->event_callback)
1437 c->event_callback(c, event, pl, c->event_userdata);
1438
1439 finish:
1440 pa_context_unref(c);
1441
1442 if (pl)
1443 pa_proplist_free(pl);
1444 }