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