]> code.delx.au - pulseaudio/blob - src/pulse/context.c
dbus: remove filter functions only if they were actually set before
[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/hashmap.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_device_manager.callback = NULL;
132 c->ext_device_manager.userdata = NULL;
133
134 c->ext_stream_restore.callback = NULL;
135 c->ext_stream_restore.userdata = NULL;
136 }
137
138 pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
139 pa_context *c;
140
141 pa_assert(mainloop);
142
143 if (pa_detect_fork())
144 return NULL;
145
146 pa_init_i18n();
147
148 c = pa_xnew0(pa_context, 1);
149 PA_REFCNT_INIT(c);
150
151 c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
152
153 if (name)
154 pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
155
156 #ifdef HAVE_DBUS
157 c->system_bus = c->session_bus = NULL;
158 #endif
159 c->mainloop = mainloop;
160 c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
161 c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
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
171 reset_callbacks(c);
172
173 #ifndef MSG_NOSIGNAL
174 #ifdef SIGPIPE
175 pa_check_signal_is_blocked(SIGPIPE);
176 #endif
177 #endif
178
179 c->conf = pa_client_conf_new();
180 pa_client_conf_load(c->conf, NULL);
181 #ifdef HAVE_X11
182 pa_client_conf_from_x11(c->conf, NULL);
183 #endif
184 pa_client_conf_env(c->conf);
185
186 if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
187
188 if (!c->conf->disable_shm)
189 c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);
190
191 if (!c->mempool) {
192 context_free(c);
193 return NULL;
194 }
195 }
196
197 return c;
198 }
199
200 static void context_unlink(pa_context *c) {
201 pa_stream *s;
202
203 pa_assert(c);
204
205 s = c->streams ? pa_stream_ref(c->streams) : NULL;
206 while (s) {
207 pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
208 pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
209 pa_stream_unref(s);
210 s = n;
211 }
212
213 while (c->operations)
214 pa_operation_cancel(c->operations);
215
216 if (c->pdispatch) {
217 pa_pdispatch_unref(c->pdispatch);
218 c->pdispatch = NULL;
219 }
220
221 if (c->pstream) {
222 pa_pstream_unlink(c->pstream);
223 pa_pstream_unref(c->pstream);
224 c->pstream = NULL;
225 }
226
227 if (c->client) {
228 pa_socket_client_unref(c->client);
229 c->client = NULL;
230 }
231
232 reset_callbacks(c);
233 }
234
235 static void context_free(pa_context *c) {
236 pa_assert(c);
237
238 context_unlink(c);
239
240 #ifdef HAVE_DBUS
241 if (c->system_bus) {
242 if (c->filter_added)
243 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c);
244 pa_dbus_wrap_connection_free(c->system_bus);
245 }
246
247 if (c->session_bus) {
248 if (c->filter_added)
249 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c);
250 pa_dbus_wrap_connection_free(c->session_bus);
251 }
252 #endif
253
254 if (c->record_streams)
255 pa_hashmap_free(c->record_streams, NULL, NULL);
256 if (c->playback_streams)
257 pa_hashmap_free(c->playback_streams, NULL, NULL);
258
259 if (c->mempool)
260 pa_mempool_free(c->mempool);
261
262 if (c->conf)
263 pa_client_conf_free(c->conf);
264
265 pa_strlist_free(c->server_list);
266
267 if (c->proplist)
268 pa_proplist_free(c->proplist);
269
270 pa_xfree(c->server);
271 pa_xfree(c);
272 }
273
274 pa_context* pa_context_ref(pa_context *c) {
275 pa_assert(c);
276 pa_assert(PA_REFCNT_VALUE(c) >= 1);
277
278 PA_REFCNT_INC(c);
279 return c;
280 }
281
282 void pa_context_unref(pa_context *c) {
283 pa_assert(c);
284 pa_assert(PA_REFCNT_VALUE(c) >= 1);
285
286 if (PA_REFCNT_DEC(c) <= 0)
287 context_free(c);
288 }
289
290 void pa_context_set_state(pa_context *c, pa_context_state_t st) {
291 pa_assert(c);
292 pa_assert(PA_REFCNT_VALUE(c) >= 1);
293
294 if (c->state == st)
295 return;
296
297 pa_context_ref(c);
298
299 c->state = st;
300
301 if (c->state_callback)
302 c->state_callback(c, c->state_userdata);
303
304 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED)
305 context_unlink(c);
306
307 pa_context_unref(c);
308 }
309
310 int pa_context_set_error(pa_context *c, int error) {
311 pa_assert(error >= 0);
312 pa_assert(error < PA_ERR_MAX);
313
314 if (c)
315 c->error = error;
316
317 return error;
318 }
319
320 void pa_context_fail(pa_context *c, int error) {
321 pa_assert(c);
322 pa_assert(PA_REFCNT_VALUE(c) >= 1);
323
324 pa_context_set_error(c, error);
325 pa_context_set_state(c, PA_CONTEXT_FAILED);
326 }
327
328 static void pstream_die_callback(pa_pstream *p, void *userdata) {
329 pa_context *c = userdata;
330
331 pa_assert(p);
332 pa_assert(c);
333
334 pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
335 }
336
337 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
338 pa_context *c = userdata;
339
340 pa_assert(p);
341 pa_assert(packet);
342 pa_assert(c);
343
344 pa_context_ref(c);
345
346 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)
347 pa_context_fail(c, PA_ERR_PROTOCOL);
348
349 pa_context_unref(c);
350 }
351
352 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) {
353 pa_context *c = userdata;
354 pa_stream *s;
355
356 pa_assert(p);
357 pa_assert(chunk);
358 pa_assert(chunk->length > 0);
359 pa_assert(c);
360 pa_assert(PA_REFCNT_VALUE(c) >= 1);
361
362 pa_context_ref(c);
363
364 if ((s = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(channel)))) {
365
366 if (chunk->memblock) {
367 pa_memblockq_seek(s->record_memblockq, offset, seek, TRUE);
368 pa_memblockq_push_align(s->record_memblockq, chunk);
369 } else
370 pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, TRUE);
371
372 if (s->read_callback) {
373 size_t l;
374
375 if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0)
376 s->read_callback(s, l, s->read_userdata);
377 }
378 }
379
380 pa_context_unref(c);
381 }
382
383 int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa_bool_t fail) {
384 uint32_t err;
385 pa_assert(c);
386 pa_assert(PA_REFCNT_VALUE(c) >= 1);
387
388 if (command == PA_COMMAND_ERROR) {
389 pa_assert(t);
390
391 if (pa_tagstruct_getu32(t, &err) < 0 ||
392 !pa_tagstruct_eof(t)) {
393 pa_context_fail(c, PA_ERR_PROTOCOL);
394 return -1;
395 }
396
397 } else if (command == PA_COMMAND_TIMEOUT)
398 err = PA_ERR_TIMEOUT;
399 else {
400 pa_context_fail(c, PA_ERR_PROTOCOL);
401 return -1;
402 }
403
404 if (err == PA_OK) {
405 pa_context_fail(c, PA_ERR_PROTOCOL);
406 return -1;
407 }
408
409 if (err >= PA_ERR_MAX)
410 err = PA_ERR_UNKNOWN;
411
412 if (fail) {
413 pa_context_fail(c, (int) err);
414 return -1;
415 }
416
417 pa_context_set_error(c, (int) err);
418
419 return 0;
420 }
421
422 static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
423 pa_context *c = userdata;
424
425 pa_assert(pd);
426 pa_assert(c);
427 pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
428
429 pa_context_ref(c);
430
431 if (command != PA_COMMAND_REPLY) {
432 pa_context_handle_error(c, command, t, TRUE);
433 goto finish;
434 }
435
436 switch(c->state) {
437 case PA_CONTEXT_AUTHORIZING: {
438 pa_tagstruct *reply;
439 pa_bool_t shm_on_remote = FALSE;
440
441 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
442 !pa_tagstruct_eof(t)) {
443 pa_context_fail(c, PA_ERR_PROTOCOL);
444 goto finish;
445 }
446
447 /* Minimum supported version */
448 if (c->version < 8) {
449 pa_context_fail(c, PA_ERR_VERSION);
450 goto finish;
451 }
452
453 /* Starting with protocol version 13 the MSB of the version
454 tag reflects if shm is available for this connection or
455 not. */
456 if (c->version >= 13) {
457 shm_on_remote = !!(c->version & 0x80000000U);
458 c->version &= 0x7FFFFFFFU;
459 }
460
461 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
462
463 /* Enable shared memory support if possible */
464 if (c->do_shm)
465 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
466 c->do_shm = FALSE;
467
468 if (c->do_shm) {
469
470 /* Only enable SHM if both sides are owned by the same
471 * user. This is a security measure because otherwise
472 * data private to the user might leak. */
473
474 #ifdef HAVE_CREDS
475 const pa_creds *creds;
476 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
477 c->do_shm = FALSE;
478 #endif
479 }
480
481 pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
482 pa_pstream_enable_shm(c->pstream, c->do_shm);
483
484 reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
485
486 if (c->version >= 13) {
487 pa_init_proplist(c->proplist);
488 pa_tagstruct_put_proplist(reply, c->proplist);
489 } else
490 pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));
491
492 pa_pstream_send_tagstruct(c->pstream, reply);
493 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
494
495 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
496 break;
497 }
498
499 case PA_CONTEXT_SETTING_NAME :
500
501 if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
502 c->client_index == PA_INVALID_INDEX)) ||
503 !pa_tagstruct_eof(t)) {
504 pa_context_fail(c, PA_ERR_PROTOCOL);
505 goto finish;
506 }
507
508 pa_context_set_state(c, PA_CONTEXT_READY);
509 break;
510
511 default:
512 pa_assert_not_reached();
513 }
514
515 finish:
516 pa_context_unref(c);
517 }
518
519 static void setup_context(pa_context *c, pa_iochannel *io) {
520 pa_tagstruct *t;
521 uint32_t tag;
522
523 pa_assert(c);
524 pa_assert(io);
525
526 pa_context_ref(c);
527
528 pa_assert(!c->pstream);
529 c->pstream = pa_pstream_new(c->mainloop, io, c->mempool);
530
531 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
532 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
533 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
534
535 pa_assert(!c->pdispatch);
536 c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX);
537
538 if (!c->conf->cookie_valid)
539 pa_log_info(_("No cookie loaded. Attempting to connect without."));
540
541 t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
542
543 c->do_shm =
544 pa_mempool_is_shared(c->mempool) &&
545 c->is_local;
546
547 pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm));
548
549 /* Starting with protocol version 13 we use the MSB of the version
550 * tag for informing the other side if we could do SHM or not */
551 pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION | (c->do_shm ? 0x80000000U : 0));
552 pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
553
554 #ifdef HAVE_CREDS
555 {
556 pa_creds ucred;
557
558 if (pa_iochannel_creds_supported(io))
559 pa_iochannel_creds_enable(io);
560
561 ucred.uid = getuid();
562 ucred.gid = getgid();
563
564 pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred);
565 }
566 #else
567 pa_pstream_send_tagstruct(c->pstream, t);
568 #endif
569
570 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
571
572 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
573
574 pa_context_unref(c);
575 }
576
577 #ifdef ENABLE_LEGACY_RUNTIME_DIR
578 static char *get_old_legacy_runtime_dir(void) {
579 char *p, u[128];
580 struct stat st;
581
582 if (!pa_get_user_name(u, sizeof(u)))
583 return NULL;
584
585 p = pa_sprintf_malloc("/tmp/pulse-%s", u);
586
587 if (stat(p, &st) < 0) {
588 pa_xfree(p);
589 return NULL;
590 }
591
592 if (st.st_uid != getuid()) {
593 pa_xfree(p);
594 return NULL;
595 }
596
597 return p;
598 }
599
600 static char *get_very_old_legacy_runtime_dir(void) {
601 char *p, h[128];
602 struct stat st;
603
604 if (!pa_get_home_dir(h, sizeof(h)))
605 return NULL;
606
607 p = pa_sprintf_malloc("%s/.pulse", h);
608
609 if (stat(p, &st) < 0) {
610 pa_xfree(p);
611 return NULL;
612 }
613
614 if (st.st_uid != getuid()) {
615 pa_xfree(p);
616 return NULL;
617 }
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 static 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 if (getuid() == 0)
1005 pa_log_debug("Not doing autospawn since we are root.");
1006 else {
1007 c->do_autospawn = TRUE;
1008
1009 if (api)
1010 c->spawn_api = *api;
1011 }
1012 }
1013
1014 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
1015 r = try_next_connection(c);
1016
1017 finish:
1018 pa_context_unref(c);
1019
1020 return r;
1021 }
1022
1023 void pa_context_disconnect(pa_context *c) {
1024 pa_assert(c);
1025 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1026
1027 if (pa_detect_fork())
1028 return;
1029
1030 if (PA_CONTEXT_IS_GOOD(c->state))
1031 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
1032 }
1033
1034 pa_context_state_t pa_context_get_state(pa_context *c) {
1035 pa_assert(c);
1036 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1037
1038 return c->state;
1039 }
1040
1041 int pa_context_errno(pa_context *c) {
1042
1043 if (!c)
1044 return PA_ERR_INVALID;
1045
1046 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1047
1048 return c->error;
1049 }
1050
1051 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1052 pa_assert(c);
1053 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1054
1055 if (pa_detect_fork())
1056 return;
1057
1058 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1059 return;
1060
1061 c->state_callback = cb;
1062 c->state_userdata = userdata;
1063 }
1064
1065 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1066 pa_assert(c);
1067 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1068
1069 if (pa_detect_fork())
1070 return;
1071
1072 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1073 return;
1074
1075 c->event_callback = cb;
1076 c->event_userdata = userdata;
1077 }
1078
1079 int pa_context_is_pending(pa_context *c) {
1080 pa_assert(c);
1081 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1082
1083 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1084 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1085
1086 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1087 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1088 c->client;
1089 }
1090
1091 static void set_dispatch_callbacks(pa_operation *o);
1092
1093 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1094 set_dispatch_callbacks(userdata);
1095 }
1096
1097 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1098 set_dispatch_callbacks(userdata);
1099 }
1100
1101 static void set_dispatch_callbacks(pa_operation *o) {
1102 int done = 1;
1103
1104 pa_assert(o);
1105 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1106 pa_assert(o->context);
1107 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1108 pa_assert(o->context->state == PA_CONTEXT_READY);
1109
1110 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1111 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1112
1113 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1114 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1115 done = 0;
1116 }
1117
1118 if (pa_pstream_is_pending(o->context->pstream)) {
1119 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1120 done = 0;
1121 }
1122
1123 if (done) {
1124 if (o->callback) {
1125 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1126 cb(o->context, o->userdata);
1127 }
1128
1129 pa_operation_done(o);
1130 pa_operation_unref(o);
1131 }
1132 }
1133
1134 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1135 pa_operation *o;
1136
1137 pa_assert(c);
1138 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1139
1140 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1141 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1142 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1143
1144 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1145 set_dispatch_callbacks(pa_operation_ref(o));
1146
1147 return o;
1148 }
1149
1150 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1151 pa_operation *o = userdata;
1152 int success = 1;
1153
1154 pa_assert(pd);
1155 pa_assert(o);
1156 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1157
1158 if (!o->context)
1159 goto finish;
1160
1161 if (command != PA_COMMAND_REPLY) {
1162 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1163 goto finish;
1164
1165 success = 0;
1166 } else if (!pa_tagstruct_eof(t)) {
1167 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1168 goto finish;
1169 }
1170
1171 if (o->callback) {
1172 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1173 cb(o->context, success, o->userdata);
1174 }
1175
1176 finish:
1177 pa_operation_done(o);
1178 pa_operation_unref(o);
1179 }
1180
1181 pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) {
1182 pa_tagstruct *t;
1183 pa_operation *o;
1184 uint32_t tag;
1185
1186 pa_assert(c);
1187 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1188
1189 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1190 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1191
1192 o = pa_operation_new(c, NULL, cb, userdata);
1193
1194 t = pa_tagstruct_command(c, command, &tag);
1195 pa_pstream_send_tagstruct(c->pstream, t);
1196 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1197
1198 return o;
1199 }
1200
1201 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1202 pa_assert(c);
1203 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1204
1205 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1206 }
1207
1208 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1209 pa_tagstruct *t;
1210 pa_operation *o;
1211 uint32_t tag;
1212
1213 pa_assert(c);
1214 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1215
1216 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1217 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1218
1219 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1220 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1221 pa_tagstruct_puts(t, name);
1222 pa_pstream_send_tagstruct(c->pstream, t);
1223 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1224
1225 return o;
1226 }
1227
1228 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1229 pa_tagstruct *t;
1230 pa_operation *o;
1231 uint32_t tag;
1232
1233 pa_assert(c);
1234 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1235
1236 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1237 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1238
1239 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1240 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1241 pa_tagstruct_puts(t, name);
1242 pa_pstream_send_tagstruct(c->pstream, t);
1243 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1244
1245 return o;
1246 }
1247
1248 int pa_context_is_local(pa_context *c) {
1249 pa_assert(c);
1250 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1251
1252 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1253 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1254
1255 return !!c->is_local;
1256 }
1257
1258 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1259 pa_operation *o;
1260
1261 pa_assert(c);
1262 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1263 pa_assert(name);
1264
1265 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1266 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1267
1268 if (c->version >= 13) {
1269 pa_proplist *p = pa_proplist_new();
1270
1271 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1272 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1273 pa_proplist_free(p);
1274 } else {
1275 pa_tagstruct *t;
1276 uint32_t tag;
1277
1278 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1279 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1280 pa_tagstruct_puts(t, name);
1281 pa_pstream_send_tagstruct(c->pstream, t);
1282 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1283 }
1284
1285 return o;
1286 }
1287
1288 const char* pa_get_library_version(void) {
1289 return PACKAGE_VERSION;
1290 }
1291
1292 const char* pa_context_get_server(pa_context *c) {
1293 pa_assert(c);
1294 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1295
1296 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1297 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1298
1299 if (*c->server == '{') {
1300 char *e = strchr(c->server+1, '}');
1301 return e ? e+1 : c->server;
1302 }
1303
1304 return c->server;
1305 }
1306
1307 uint32_t pa_context_get_protocol_version(pa_context *c) {
1308 return PA_PROTOCOL_VERSION;
1309 }
1310
1311 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1312 pa_assert(c);
1313 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1314
1315 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1316 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1317
1318 return c->version;
1319 }
1320
1321 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1322 pa_tagstruct *t;
1323
1324 pa_assert(c);
1325 pa_assert(tag);
1326
1327 t = pa_tagstruct_new(NULL, 0);
1328 pa_tagstruct_putu32(t, command);
1329 pa_tagstruct_putu32(t, *tag = c->ctag++);
1330
1331 return t;
1332 }
1333
1334 uint32_t pa_context_get_index(pa_context *c) {
1335 pa_assert(c);
1336 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1337
1338 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1339 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1340 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1341
1342 return c->client_index;
1343 }
1344
1345 pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
1346 pa_operation *o;
1347 pa_tagstruct *t;
1348 uint32_t tag;
1349
1350 pa_assert(c);
1351 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1352
1353 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1354 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1355 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1356 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1357
1358 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1359
1360 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1361 pa_tagstruct_putu32(t, (uint32_t) mode);
1362 pa_tagstruct_put_proplist(t, p);
1363
1364 pa_pstream_send_tagstruct(c->pstream, t);
1365 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1366
1367 /* Please note that we don't update c->proplist here, because we
1368 * don't export that field */
1369
1370 return o;
1371 }
1372
1373 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1374 pa_operation *o;
1375 pa_tagstruct *t;
1376 uint32_t tag;
1377 const char * const *k;
1378
1379 pa_assert(c);
1380 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1381
1382 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1383 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1384 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1385 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1386
1387 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1388
1389 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1390
1391 for (k = keys; *k; k++)
1392 pa_tagstruct_puts(t, *k);
1393
1394 pa_tagstruct_puts(t, NULL);
1395
1396 pa_pstream_send_tagstruct(c->pstream, t);
1397 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1398
1399 /* Please note that we don't update c->proplist here, because we
1400 * don't export that field */
1401
1402 return o;
1403 }
1404
1405 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1406 pa_context *c = userdata;
1407 uint32_t idx;
1408 const char *name;
1409
1410 pa_assert(pd);
1411 pa_assert(command == PA_COMMAND_EXTENSION);
1412 pa_assert(t);
1413 pa_assert(c);
1414 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1415
1416 pa_context_ref(c);
1417
1418 if (c->version < 15) {
1419 pa_context_fail(c, PA_ERR_PROTOCOL);
1420 goto finish;
1421 }
1422
1423 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1424 pa_tagstruct_gets(t, &name) < 0) {
1425 pa_context_fail(c, PA_ERR_PROTOCOL);
1426 goto finish;
1427 }
1428
1429 if (!strcmp(name, "module-stream-restore"))
1430 pa_ext_stream_restore_command(c, tag, t);
1431 else if (!strcmp(name, "module-device-manager"))
1432 pa_ext_device_manager_command(c, tag, t);
1433 else
1434 pa_log(_("Received message for unknown extension '%s'"), name);
1435
1436 finish:
1437 pa_context_unref(c);
1438 }
1439
1440
1441 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1442 pa_context *c = userdata;
1443 pa_proplist *pl = NULL;
1444 const char *event;
1445
1446 pa_assert(pd);
1447 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1448 pa_assert(t);
1449 pa_assert(c);
1450 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1451
1452 pa_context_ref(c);
1453
1454 if (c->version < 15) {
1455 pa_context_fail(c, PA_ERR_PROTOCOL);
1456 goto finish;
1457 }
1458
1459 pl = pa_proplist_new();
1460
1461 if (pa_tagstruct_gets(t, &event) < 0 ||
1462 pa_tagstruct_get_proplist(t, pl) < 0 ||
1463 !pa_tagstruct_eof(t) || !event) {
1464 pa_context_fail(c, PA_ERR_PROTOCOL);
1465 goto finish;
1466 }
1467
1468 if (c->event_callback)
1469 c->event_callback(c, event, pl, c->event_userdata);
1470
1471 finish:
1472 pa_context_unref(c);
1473
1474 if (pl)
1475 pa_proplist_free(pl);
1476 }
1477
1478 pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
1479 struct timeval tv;
1480
1481 pa_assert(c);
1482 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1483 pa_assert(c->mainloop);
1484
1485 if (usec == PA_USEC_INVALID)
1486 return c->mainloop->time_new(c->mainloop, NULL, cb, userdata);
1487
1488 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1489
1490 return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
1491 }
1492
1493 void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
1494 struct timeval tv;
1495
1496 pa_assert(c);
1497 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1498 pa_assert(c->mainloop);
1499
1500
1501 if (usec == PA_USEC_INVALID)
1502 c->mainloop->time_restart(e, NULL);
1503 else {
1504 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1505 c->mainloop->time_restart(e, &tv);
1506 }
1507 }
1508
1509 size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss) {
1510 size_t fs, mbs;
1511
1512 pa_assert(c);
1513 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1514
1515 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1);
1516 PA_CHECK_VALIDITY_RETURN_ANY(c, !ss || pa_sample_spec_valid(ss), PA_ERR_INVALID, (size_t) -1);
1517
1518 fs = ss ? pa_frame_size(ss) : 1;
1519 mbs = PA_ROUND_DOWN(pa_mempool_block_size_max(c->mempool), fs);
1520 return PA_MAX(mbs, fs);
1521 }