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