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