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