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