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