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