]> code.delx.au - pulseaudio/blob - src/pulse/context.c
Merge branch 'master' into 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 struct sigaction sa;
672
673 pa_context_ref(c);
674
675 if (sigaction(SIGCHLD, NULL, &sa) < 0) {
676 pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno));
677 pa_context_fail(c, PA_ERR_INTERNAL);
678 goto fail;
679 }
680
681 if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) {
682 pa_log_debug("Process disabled waitpid(), cannot autospawn.");
683 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
684 goto fail;
685 }
686
687 pa_log_debug("Trying to autospawn...");
688
689 if (c->spawn_api.prefork)
690 c->spawn_api.prefork();
691
692 if ((pid = fork()) < 0) {
693 pa_log_error(_("fork(): %s"), pa_cstrerror(errno));
694 pa_context_fail(c, PA_ERR_INTERNAL);
695
696 if (c->spawn_api.postfork)
697 c->spawn_api.postfork();
698
699 goto fail;
700 } else if (!pid) {
701 /* Child */
702
703 const char *state = NULL;
704 const char * argv[32];
705 unsigned n = 0;
706
707 if (c->spawn_api.atfork)
708 c->spawn_api.atfork();
709
710 pa_close_all(-1);
711
712 /* Setup argv */
713
714 argv[n++] = c->conf->daemon_binary;
715 argv[n++] = "--start";
716
717 while (n < PA_ELEMENTSOF(argv)-1) {
718 char *a;
719
720 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
721 break;
722
723 argv[n++] = a;
724 }
725
726 argv[n++] = NULL;
727 pa_assert(n <= PA_ELEMENTSOF(argv));
728
729 execv(argv[0], (char * const *) argv);
730 _exit(1);
731 }
732
733 /* Parent */
734
735 if (c->spawn_api.postfork)
736 c->spawn_api.postfork();
737
738 do {
739 r = waitpid(pid, &status, 0);
740 } while (r < 0 && errno == EINTR);
741
742 if (r < 0) {
743
744 if (errno != ESRCH) {
745 pa_log(_("waitpid(): %s"), pa_cstrerror(errno));
746 pa_context_fail(c, PA_ERR_INTERNAL);
747 goto fail;
748 }
749
750 /* hmm, something already reaped our child, so we assume
751 * startup worked, even if we cannot know */
752
753 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
754 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
755 goto fail;
756 }
757
758 pa_context_unref(c);
759
760 return 0;
761
762 fail:
763
764 pa_context_unref(c);
765
766 return -1;
767 }
768
769 #endif /* OS_IS_WIN32 */
770
771 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata);
772
773 #ifdef HAVE_DBUS
774 static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) {
775 DBusError error;
776
777 pa_assert(c);
778 pa_assert(conn);
779
780 dbus_error_init(&error);
781
782 if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) {
783 pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
784 goto fail;
785 }
786
787 if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) {
788 pa_log_warn("Failed to add filter function");
789 goto fail;
790 }
791
792 if (pa_dbus_add_matches(
793 pa_dbus_wrap_connection_get(*conn), &error,
794 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) {
795
796 pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message);
797 goto fail;
798 }
799
800 return;
801
802 fail:
803 if (*conn) {
804 pa_dbus_wrap_connection_free(*conn);
805 *conn = NULL;
806 }
807
808 dbus_error_free(&error);
809 }
810 #endif
811
812 static int try_next_connection(pa_context *c) {
813 char *u = NULL;
814 int r = -1;
815
816 pa_assert(c);
817 pa_assert(!c->client);
818
819 for (;;) {
820 pa_xfree(u);
821 u = NULL;
822
823 c->server_list = pa_strlist_pop(c->server_list, &u);
824
825 if (!u) {
826
827 #ifndef OS_IS_WIN32
828 if (c->do_autospawn) {
829
830 if ((r = context_autospawn(c)) < 0)
831 goto finish;
832
833 /* Autospawn only once */
834 c->do_autospawn = FALSE;
835
836 /* Connect only to per-user sockets this time */
837 c->server_list = prepend_per_user(c->server_list);
838
839 /* Retry connection */
840 continue;
841 }
842 #endif
843
844 #ifdef HAVE_DBUS
845 if (c->no_fail && !c->server_specified) {
846 if (!c->session_bus)
847 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
848 if (!c->system_bus)
849 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
850 } else
851 #endif
852 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
853
854 goto finish;
855 }
856
857 pa_log_debug("Trying to connect to %s...", u);
858
859 pa_xfree(c->server);
860 c->server = pa_xstrdup(u);
861
862 if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
863 continue;
864
865 c->is_local = !!pa_socket_client_is_local(c->client);
866 pa_socket_client_set_callback(c->client, on_connection, c);
867 break;
868 }
869
870 r = 0;
871
872 finish:
873 pa_xfree(u);
874
875 return r;
876 }
877
878 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
879 pa_context *c = userdata;
880 int saved_errno = errno;
881
882 pa_assert(client);
883 pa_assert(c);
884 pa_assert(c->state == PA_CONTEXT_CONNECTING);
885
886 pa_context_ref(c);
887
888 pa_socket_client_unref(client);
889 c->client = NULL;
890
891 if (!io) {
892 /* Try the next item in the list */
893 if (saved_errno == ECONNREFUSED ||
894 saved_errno == ETIMEDOUT ||
895 saved_errno == EHOSTUNREACH) {
896 try_next_connection(c);
897 goto finish;
898 }
899
900 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
901 goto finish;
902 }
903
904 setup_context(c, io);
905
906 finish:
907 pa_context_unref(c);
908 }
909
910 #ifdef HAVE_DBUS
911 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
912 pa_context *c = userdata;
913 pa_bool_t is_session;
914
915 pa_assert(bus);
916 pa_assert(message);
917 pa_assert(c);
918
919 if (c->state != PA_CONTEXT_CONNECTING)
920 goto finish;
921
922 if (!c->no_fail)
923 goto finish;
924
925 /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */
926
927 is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus);
928 pa_log_debug("Rock!! PulseAudio might be back on %s bus", is_session ? "session" : "system");
929
930 if (is_session)
931 /* The user instance via PF_LOCAL */
932 c->server_list = prepend_per_user(c->server_list);
933 else
934 /* The system wide instance via PF_LOCAL */
935 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
936
937 if (!c->client)
938 try_next_connection(c);
939
940 finish:
941 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
942 }
943 #endif
944
945 int pa_context_connect(
946 pa_context *c,
947 const char *server,
948 pa_context_flags_t flags,
949 const pa_spawn_api *api) {
950
951 int r = -1;
952
953 pa_assert(c);
954 pa_assert(PA_REFCNT_VALUE(c) >= 1);
955
956 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
957 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
958 PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
959 PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
960
961 if (server)
962 c->conf->autospawn = FALSE;
963 else
964 server = c->conf->default_server;
965
966 pa_context_ref(c);
967
968 c->no_fail = !!(flags & PA_CONTEXT_NOFAIL);
969 c->server_specified = !!server;
970 pa_assert(!c->server_list);
971
972 if (server) {
973 if (!(c->server_list = pa_strlist_parse(server))) {
974 pa_context_fail(c, PA_ERR_INVALIDSERVER);
975 goto finish;
976 }
977
978 } else {
979 char *d;
980
981 /* Prepend in reverse order */
982
983 /* Follow the X display */
984 if ((d = getenv("DISPLAY"))) {
985 d = pa_xstrndup(d, strcspn(d, ":"));
986
987 if (*d)
988 c->server_list = pa_strlist_prepend(c->server_list, d);
989
990 pa_xfree(d);
991 }
992
993 /* Add TCP/IP on the localhost */
994 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
995 c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
996
997 /* The system wide instance via PF_LOCAL */
998 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
999
1000 /* The user instance via PF_LOCAL */
1001 c->server_list = prepend_per_user(c->server_list);
1002 }
1003
1004 /* Set up autospawning */
1005 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
1006
1007 if (getuid() == 0)
1008 pa_log_debug("Not doing autospawn since we are root.");
1009 else {
1010 c->do_autospawn = TRUE;
1011
1012 if (api)
1013 c->spawn_api = *api;
1014 }
1015 }
1016
1017 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
1018 r = try_next_connection(c);
1019
1020 finish:
1021 pa_context_unref(c);
1022
1023 return r;
1024 }
1025
1026 void pa_context_disconnect(pa_context *c) {
1027 pa_assert(c);
1028 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1029
1030 if (pa_detect_fork())
1031 return;
1032
1033 if (PA_CONTEXT_IS_GOOD(c->state))
1034 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
1035 }
1036
1037 pa_context_state_t pa_context_get_state(pa_context *c) {
1038 pa_assert(c);
1039 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1040
1041 return c->state;
1042 }
1043
1044 int pa_context_errno(pa_context *c) {
1045 pa_assert(c);
1046 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1047
1048 return c->error;
1049 }
1050
1051 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1052 pa_assert(c);
1053 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1054
1055 if (pa_detect_fork())
1056 return;
1057
1058 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1059 return;
1060
1061 c->state_callback = cb;
1062 c->state_userdata = userdata;
1063 }
1064
1065 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1066 pa_assert(c);
1067 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1068
1069 if (pa_detect_fork())
1070 return;
1071
1072 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1073 return;
1074
1075 c->event_callback = cb;
1076 c->event_userdata = userdata;
1077 }
1078
1079 int pa_context_is_pending(pa_context *c) {
1080 pa_assert(c);
1081 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1082
1083 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1084 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1085
1086 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1087 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1088 c->client;
1089 }
1090
1091 static void set_dispatch_callbacks(pa_operation *o);
1092
1093 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1094 set_dispatch_callbacks(userdata);
1095 }
1096
1097 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1098 set_dispatch_callbacks(userdata);
1099 }
1100
1101 static void set_dispatch_callbacks(pa_operation *o) {
1102 int done = 1;
1103
1104 pa_assert(o);
1105 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1106 pa_assert(o->context);
1107 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1108 pa_assert(o->context->state == PA_CONTEXT_READY);
1109
1110 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1111 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1112
1113 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1114 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1115 done = 0;
1116 }
1117
1118 if (pa_pstream_is_pending(o->context->pstream)) {
1119 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1120 done = 0;
1121 }
1122
1123 if (done) {
1124 if (o->callback) {
1125 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1126 cb(o->context, o->userdata);
1127 }
1128
1129 pa_operation_done(o);
1130 pa_operation_unref(o);
1131 }
1132 }
1133
1134 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1135 pa_operation *o;
1136
1137 pa_assert(c);
1138 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1139
1140 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1141 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1142 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1143
1144 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1145 set_dispatch_callbacks(pa_operation_ref(o));
1146
1147 return o;
1148 }
1149
1150 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1151 pa_operation *o = userdata;
1152 int success = 1;
1153
1154 pa_assert(pd);
1155 pa_assert(o);
1156 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1157
1158 if (!o->context)
1159 goto finish;
1160
1161 if (command != PA_COMMAND_REPLY) {
1162 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1163 goto finish;
1164
1165 success = 0;
1166 } else if (!pa_tagstruct_eof(t)) {
1167 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1168 goto finish;
1169 }
1170
1171 if (o->callback) {
1172 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1173 cb(o->context, success, o->userdata);
1174 }
1175
1176 finish:
1177 pa_operation_done(o);
1178 pa_operation_unref(o);
1179 }
1180
1181 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) {
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, cb, userdata);
1193
1194 t = pa_tagstruct_command(c, command, &tag);
1195 pa_pstream_send_tagstruct(c->pstream, t);
1196 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1197
1198 return o;
1199 }
1200
1201 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1202 pa_assert(c);
1203 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1204
1205 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1206 }
1207
1208 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1209 pa_tagstruct *t;
1210 pa_operation *o;
1211 uint32_t tag;
1212
1213 pa_assert(c);
1214 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1215
1216 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1217 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1218
1219 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1220 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1221 pa_tagstruct_puts(t, name);
1222 pa_pstream_send_tagstruct(c->pstream, t);
1223 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);
1224
1225 return o;
1226 }
1227
1228 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1229 pa_tagstruct *t;
1230 pa_operation *o;
1231 uint32_t tag;
1232
1233 pa_assert(c);
1234 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1235
1236 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1237 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1238
1239 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1240 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1241 pa_tagstruct_puts(t, name);
1242 pa_pstream_send_tagstruct(c->pstream, t);
1243 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);
1244
1245 return o;
1246 }
1247
1248 int pa_context_is_local(pa_context *c) {
1249 pa_assert(c);
1250 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1251
1252 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1253 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1254
1255 return !!c->is_local;
1256 }
1257
1258 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1259 pa_operation *o;
1260
1261 pa_assert(c);
1262 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1263 pa_assert(name);
1264
1265 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1266 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1267
1268 if (c->version >= 13) {
1269 pa_proplist *p = pa_proplist_new();
1270
1271 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1272 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1273 pa_proplist_free(p);
1274 } else {
1275 pa_tagstruct *t;
1276 uint32_t tag;
1277
1278 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1279 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1280 pa_tagstruct_puts(t, name);
1281 pa_pstream_send_tagstruct(c->pstream, t);
1282 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);
1283 }
1284
1285 return o;
1286 }
1287
1288 const char* pa_get_library_version(void) {
1289 return PACKAGE_VERSION;
1290 }
1291
1292 const char* pa_context_get_server(pa_context *c) {
1293 pa_assert(c);
1294 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1295
1296 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1297 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1298
1299 if (*c->server == '{') {
1300 char *e = strchr(c->server+1, '}');
1301 return e ? e+1 : c->server;
1302 }
1303
1304 return c->server;
1305 }
1306
1307 uint32_t pa_context_get_protocol_version(pa_context *c) {
1308 return PA_PROTOCOL_VERSION;
1309 }
1310
1311 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1312 pa_assert(c);
1313 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1314
1315 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1316 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1317
1318 return c->version;
1319 }
1320
1321 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1322 pa_tagstruct *t;
1323
1324 pa_assert(c);
1325 pa_assert(tag);
1326
1327 t = pa_tagstruct_new(NULL, 0);
1328 pa_tagstruct_putu32(t, command);
1329 pa_tagstruct_putu32(t, *tag = c->ctag++);
1330
1331 return t;
1332 }
1333
1334 uint32_t pa_context_get_index(pa_context *c) {
1335 pa_assert(c);
1336 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1337
1338 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1339 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1340 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1341
1342 return c->client_index;
1343 }
1344
1345 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) {
1346 pa_operation *o;
1347 pa_tagstruct *t;
1348 uint32_t tag;
1349
1350 pa_assert(c);
1351 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1352
1353 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1354 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1355 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1356 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1357
1358 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1359
1360 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1361 pa_tagstruct_putu32(t, (uint32_t) mode);
1362 pa_tagstruct_put_proplist(t, p);
1363
1364 pa_pstream_send_tagstruct(c->pstream, t);
1365 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);
1366
1367 /* Please note that we don't update c->proplist here, because we
1368 * don't export that field */
1369
1370 return o;
1371 }
1372
1373 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1374 pa_operation *o;
1375 pa_tagstruct *t;
1376 uint32_t tag;
1377 const char * const *k;
1378
1379 pa_assert(c);
1380 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1381
1382 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1383 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1384 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1385 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1386
1387 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1388
1389 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1390
1391 for (k = keys; *k; k++)
1392 pa_tagstruct_puts(t, *k);
1393
1394 pa_tagstruct_puts(t, NULL);
1395
1396 pa_pstream_send_tagstruct(c->pstream, t);
1397 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);
1398
1399 /* Please note that we don't update c->proplist here, because we
1400 * don't export that field */
1401
1402 return o;
1403 }
1404
1405 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1406 pa_context *c = userdata;
1407 uint32_t idx;
1408 const char *name;
1409
1410 pa_assert(pd);
1411 pa_assert(command == PA_COMMAND_EXTENSION);
1412 pa_assert(t);
1413 pa_assert(c);
1414 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1415
1416 pa_context_ref(c);
1417
1418 if (c->version < 15) {
1419 pa_context_fail(c, PA_ERR_PROTOCOL);
1420 goto finish;
1421 }
1422
1423 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1424 pa_tagstruct_gets(t, &name) < 0) {
1425 pa_context_fail(c, PA_ERR_PROTOCOL);
1426 goto finish;
1427 }
1428
1429 if (!strcmp(name, "module-stream-restore"))
1430 pa_ext_stream_restore_command(c, tag, t);
1431 else
1432 pa_log(_("Received message for unknown extension '%s'"), name);
1433
1434 finish:
1435 pa_context_unref(c);
1436 }
1437
1438
1439 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1440 pa_context *c = userdata;
1441 pa_proplist *pl = NULL;
1442 const char *event;
1443
1444 pa_assert(pd);
1445 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1446 pa_assert(t);
1447 pa_assert(c);
1448 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1449
1450 pa_context_ref(c);
1451
1452 if (c->version < 15) {
1453 pa_context_fail(c, PA_ERR_PROTOCOL);
1454 goto finish;
1455 }
1456
1457 pl = pa_proplist_new();
1458
1459 if (pa_tagstruct_gets(t, &event) < 0 ||
1460 pa_tagstruct_get_proplist(t, pl) < 0 ||
1461 !pa_tagstruct_eof(t) || !event) {
1462 pa_context_fail(c, PA_ERR_PROTOCOL);
1463 goto finish;
1464 }
1465
1466 if (c->event_callback)
1467 c->event_callback(c, event, pl, c->event_userdata);
1468
1469 finish:
1470 pa_context_unref(c);
1471
1472 if (pl)
1473 pa_proplist_free(pl);
1474 }
1475
1476 pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
1477 struct timeval tv;
1478
1479 pa_assert(c);
1480 pa_assert(c->mainloop);
1481
1482 if (usec == PA_USEC_INVALID)
1483 return c->mainloop->time_new(c->mainloop, NULL, cb, userdata);
1484
1485 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1486
1487 return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
1488 }
1489
1490 void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
1491 struct timeval tv;
1492
1493 pa_assert(c);
1494 pa_assert(c->mainloop);
1495
1496 if (usec == PA_USEC_INVALID)
1497 c->mainloop->time_restart(e, NULL);
1498 else {
1499 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1500 c->mainloop->time_restart(e, &tv);
1501 }
1502 }