]> code.delx.au - pulseaudio/blob - src/pulse/context.c
Merge commit 'origin/master-tx'
[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
58 #include <pulsecore/winsock.h>
59 #include <pulsecore/core-error.h>
60
61 #include <pulsecore/native-common.h>
62 #include <pulsecore/pdispatch.h>
63 #include <pulsecore/pstream.h>
64 #include <pulsecore/dynarray.h>
65 #include <pulsecore/socket-client.h>
66 #include <pulsecore/pstream-util.h>
67 #include <pulsecore/core-util.h>
68 #include <pulsecore/log.h>
69 #include <pulsecore/socket-util.h>
70 #include <pulsecore/creds.h>
71 #include <pulsecore/macro.h>
72 #include <pulsecore/proplist-util.h>
73
74 #include "internal.h"
75
76 #include "client-conf.h"
77 #include "fork-detect.h"
78
79 #ifdef HAVE_X11
80 #include "client-conf-x11.h"
81 #endif
82
83 #include "context.h"
84
85 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
86
87 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
88 [PA_COMMAND_REQUEST] = pa_command_request,
89 [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow,
90 [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow,
91 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed,
92 [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed,
93 [PA_COMMAND_PLAYBACK_STREAM_MOVED] = pa_command_stream_moved,
94 [PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved,
95 [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended,
96 [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended,
97 [PA_COMMAND_STARTED] = pa_command_stream_started,
98 [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event,
99 [PA_COMMAND_EXTENSION] = pa_command_extension,
100 [PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event,
101 [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
102 [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
103 [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
104 [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr
105 };
106 static void context_free(pa_context *c);
107 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata);
108
109 pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
110 return pa_context_new_with_proplist(mainloop, name, NULL);
111 }
112
113 static void reset_callbacks(pa_context *c) {
114 pa_assert(c);
115
116 c->state_callback = NULL;
117 c->state_userdata = NULL;
118
119 c->subscribe_callback = NULL;
120 c->subscribe_userdata = NULL;
121
122 c->event_callback = NULL;
123 c->event_userdata = NULL;
124
125 c->ext_stream_restore.callback = NULL;
126 c->ext_stream_restore.userdata = NULL;
127 }
128
129 pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
130 pa_context *c;
131
132 pa_assert(mainloop);
133
134 if (pa_detect_fork())
135 return NULL;
136
137 pa_init_i18n();
138
139 c = pa_xnew(pa_context, 1);
140 PA_REFCNT_INIT(c);
141
142 c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
143
144 if (name)
145 pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
146
147 c->system_bus = c->session_bus = NULL;
148 c->mainloop = mainloop;
149 c->client = NULL;
150 c->pstream = NULL;
151 c->pdispatch = NULL;
152 c->playback_streams = pa_dynarray_new();
153 c->record_streams = pa_dynarray_new();
154 c->client_index = PA_INVALID_INDEX;
155
156 PA_LLIST_HEAD_INIT(pa_stream, c->streams);
157 PA_LLIST_HEAD_INIT(pa_operation, c->operations);
158
159 c->error = PA_OK;
160 c->state = PA_CONTEXT_UNCONNECTED;
161 c->ctag = 0;
162 c->csyncid = 0;
163
164 reset_callbacks(c);
165
166 c->is_local = FALSE;
167 c->server_list = NULL;
168 c->server = NULL;
169
170 c->do_shm = FALSE;
171
172 c->server_specified = FALSE;
173 c->no_fail = FALSE;
174 c->do_autospawn = FALSE;
175 memset(&c->spawn_api, 0, sizeof(c->spawn_api));
176
177 #ifndef MSG_NOSIGNAL
178 #ifdef SIGPIPE
179 pa_check_signal_is_blocked(SIGPIPE);
180 #endif
181 #endif
182
183 c->conf = pa_client_conf_new();
184 #ifdef HAVE_X11
185 pa_client_conf_from_x11(c->conf, NULL);
186 #endif
187 pa_client_conf_load(c->conf, NULL);
188 pa_client_conf_env(c->conf);
189
190 if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
191
192 if (!c->conf->disable_shm)
193 c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);
194
195 if (!c->mempool) {
196 context_free(c);
197 return NULL;
198 }
199 }
200
201 return c;
202 }
203
204 static void context_unlink(pa_context *c) {
205 pa_stream *s;
206
207 pa_assert(c);
208
209 s = c->streams ? pa_stream_ref(c->streams) : NULL;
210 while (s) {
211 pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
212 pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
213 pa_stream_unref(s);
214 s = n;
215 }
216
217 while (c->operations)
218 pa_operation_cancel(c->operations);
219
220 if (c->pdispatch) {
221 pa_pdispatch_unref(c->pdispatch);
222 c->pdispatch = NULL;
223 }
224
225 if (c->pstream) {
226 pa_pstream_unlink(c->pstream);
227 pa_pstream_unref(c->pstream);
228 c->pstream = NULL;
229 }
230
231 if (c->client) {
232 pa_socket_client_unref(c->client);
233 c->client = NULL;
234 }
235
236 reset_callbacks(c);
237 }
238
239 static void context_free(pa_context *c) {
240 pa_assert(c);
241
242 context_unlink(c);
243
244 if (c->system_bus) {
245 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c);
246 pa_dbus_wrap_connection_free(c->system_bus);
247 }
248
249 if (c->session_bus) {
250 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c);
251 pa_dbus_wrap_connection_free(c->session_bus);
252 }
253
254 if (c->record_streams)
255 pa_dynarray_free(c->record_streams, NULL, NULL);
256 if (c->playback_streams)
257 pa_dynarray_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_dynarray_get(c->record_streams, 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, 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
661 pa_log_debug("Trying to autospawn...");
662
663 pa_context_ref(c);
664
665 if (c->spawn_api.prefork)
666 c->spawn_api.prefork();
667
668 if ((pid = fork()) < 0) {
669 pa_log_error(_("fork(): %s"), pa_cstrerror(errno));
670 pa_context_fail(c, PA_ERR_INTERNAL);
671
672 if (c->spawn_api.postfork)
673 c->spawn_api.postfork();
674
675 goto fail;
676 } else if (!pid) {
677 /* Child */
678
679 const char *state = NULL;
680 #define MAX_ARGS 64
681 const char * argv[MAX_ARGS+1];
682 int n;
683
684 if (c->spawn_api.atfork)
685 c->spawn_api.atfork();
686
687 pa_close_all(-1);
688
689 /* Setup argv */
690
691 n = 0;
692
693 argv[n++] = c->conf->daemon_binary;
694 argv[n++] = "--start";
695
696 while (n < MAX_ARGS) {
697 char *a;
698
699 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
700 break;
701
702 argv[n++] = a;
703 }
704
705 argv[n++] = NULL;
706
707 execv(argv[0], (char * const *) argv);
708 _exit(1);
709 #undef MAX_ARGS
710 }
711
712 /* Parent */
713
714 if (c->spawn_api.postfork)
715 c->spawn_api.postfork();
716
717 do {
718 r = waitpid(pid, &status, 0);
719 } while (r < 0 && errno == EINTR);
720
721 if (r < 0) {
722 pa_log(_("waitpid(): %s"), pa_cstrerror(errno));
723 pa_context_fail(c, PA_ERR_INTERNAL);
724 goto fail;
725 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
726 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
727 goto fail;
728 }
729
730 pa_context_unref(c);
731
732 return 0;
733
734 fail:
735
736 pa_context_unref(c);
737
738 return -1;
739 }
740
741 #endif /* OS_IS_WIN32 */
742
743 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata);
744
745 static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) {
746 DBusError error;
747
748 pa_assert(c);
749 pa_assert(conn);
750
751 dbus_error_init(&error);
752 if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, type, &error)) || dbus_error_is_set(&error)) {
753 pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
754 goto finish;
755 }
756
757 if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) {
758 pa_log_warn("Failed to add filter function");
759 goto finish;
760 }
761
762 if (pa_dbus_add_matches(
763 pa_dbus_wrap_connection_get(*conn), &error,
764 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0)
765 pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message);
766
767 finish:
768 dbus_error_free(&error);
769 }
770
771 static int try_next_connection(pa_context *c) {
772 char *u = NULL;
773 int r = -1;
774
775 pa_assert(c);
776 pa_assert(!c->client);
777
778 for (;;) {
779 pa_xfree(u);
780 u = NULL;
781
782 c->server_list = pa_strlist_pop(c->server_list, &u);
783
784 if (!u) {
785
786 #ifndef OS_IS_WIN32
787 if (c->do_autospawn) {
788
789 if ((r = context_autospawn(c)) < 0)
790 goto finish;
791
792 /* Autospawn only once */
793 c->do_autospawn = FALSE;
794
795 /* Connect only to per-user sockets this time */
796 c->server_list = prepend_per_user(c->server_list);
797
798 /* Retry connection */
799 continue;
800 }
801 #endif
802
803 if (c->no_fail && !c->server_specified) {
804 if (!c->system_bus)
805 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
806 if (!c->session_bus)
807 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
808 } else
809 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
810
811 goto finish;
812 }
813
814 pa_log_debug("Trying to connect to %s...", u);
815
816 pa_xfree(c->server);
817 c->server = pa_xstrdup(u);
818
819 if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
820 continue;
821
822 c->is_local = !!pa_socket_client_is_local(c->client);
823 pa_socket_client_set_callback(c->client, on_connection, c);
824 break;
825 }
826
827 r = 0;
828
829 finish:
830 pa_xfree(u);
831
832 return r;
833 }
834
835 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
836 pa_context *c = userdata;
837 int saved_errno = errno;
838
839 pa_assert(client);
840 pa_assert(c);
841 pa_assert(c->state == PA_CONTEXT_CONNECTING);
842
843 pa_context_ref(c);
844
845 pa_socket_client_unref(client);
846 c->client = NULL;
847
848 if (!io) {
849 /* Try the item in the list */
850 if (saved_errno == ECONNREFUSED ||
851 saved_errno == ETIMEDOUT ||
852 saved_errno == EHOSTUNREACH) {
853 try_next_connection(c);
854 goto finish;
855 }
856
857 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
858 goto finish;
859 }
860
861 setup_context(c, io);
862
863 finish:
864 pa_context_unref(c);
865 }
866
867 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
868 pa_context *c = userdata;
869 pa_bool_t is_session;
870
871 pa_assert(bus);
872 pa_assert(message);
873 pa_assert(c);
874
875 if (c->state != PA_CONTEXT_CONNECTING)
876 goto finish;
877
878 if (!c->no_fail)
879 goto finish;
880
881 /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */
882
883 is_session = bus == pa_dbus_wrap_connection_get(c->session_bus);
884 pa_log_debug("Rock!! PulseAudio is back on %s bus", is_session ? "session" : "system");
885
886 if (is_session)
887 /* The user instance via PF_LOCAL */
888 c->server_list = prepend_per_user(c->server_list);
889 else
890 /* The system wide instance via PF_LOCAL */
891 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
892
893 try_next_connection(c);
894
895 finish:
896 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
897 }
898
899 int pa_context_connect(
900 pa_context *c,
901 const char *server,
902 pa_context_flags_t flags,
903 const pa_spawn_api *api) {
904
905 int r = -1;
906
907 pa_assert(c);
908 pa_assert(PA_REFCNT_VALUE(c) >= 1);
909
910 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
911 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
912 PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
913 PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
914
915 if (!server)
916 server = c->conf->default_server;
917
918 pa_context_ref(c);
919
920 c->no_fail = flags & PA_CONTEXT_NOFAIL;
921 c->server_specified = !!server;
922 pa_assert(!c->server_list);
923
924 if (server) {
925 if (!(c->server_list = pa_strlist_parse(server))) {
926 pa_context_fail(c, PA_ERR_INVALIDSERVER);
927 goto finish;
928 }
929
930 } else {
931 char *d;
932
933 /* Prepend in reverse order */
934
935 /* Follow the X display */
936 if ((d = getenv("DISPLAY"))) {
937 char *e;
938 d = pa_xstrdup(d);
939 if ((e = strchr(d, ':')))
940 *e = 0;
941
942 if (*d)
943 c->server_list = pa_strlist_prepend(c->server_list, d);
944
945 pa_xfree(d);
946 }
947
948 /* Add TCP/IP on the localhost */
949 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
950 c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
951
952 /* The system wide instance via PF_LOCAL */
953 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
954
955 /* The user instance via PF_LOCAL */
956 c->server_list = prepend_per_user(c->server_list);
957
958 /* Set up autospawning */
959 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
960
961 if (getuid() == 0)
962 pa_log_debug("Not doing autospawn since we are root.");
963 else {
964 c->do_autospawn = TRUE;
965
966 if (api)
967 c->spawn_api = *api;
968 }
969 }
970 }
971
972 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
973 r = try_next_connection(c);
974
975 finish:
976 pa_context_unref(c);
977
978 return r;
979 }
980
981 void pa_context_disconnect(pa_context *c) {
982 pa_assert(c);
983 pa_assert(PA_REFCNT_VALUE(c) >= 1);
984
985 if (pa_detect_fork())
986 return;
987
988 if (PA_CONTEXT_IS_GOOD(c->state))
989 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
990 }
991
992 pa_context_state_t pa_context_get_state(pa_context *c) {
993 pa_assert(c);
994 pa_assert(PA_REFCNT_VALUE(c) >= 1);
995
996 return c->state;
997 }
998
999 int pa_context_errno(pa_context *c) {
1000 pa_assert(c);
1001 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1002
1003 return c->error;
1004 }
1005
1006 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1007 pa_assert(c);
1008 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1009
1010 if (pa_detect_fork())
1011 return;
1012
1013 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1014 return;
1015
1016 c->state_callback = cb;
1017 c->state_userdata = userdata;
1018 }
1019
1020 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1021 pa_assert(c);
1022 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1023
1024 if (pa_detect_fork())
1025 return;
1026
1027 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1028 return;
1029
1030 c->event_callback = cb;
1031 c->event_userdata = userdata;
1032 }
1033
1034 int pa_context_is_pending(pa_context *c) {
1035 pa_assert(c);
1036 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1037
1038 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1039 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1040
1041 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1042 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1043 c->client;
1044 }
1045
1046 static void set_dispatch_callbacks(pa_operation *o);
1047
1048 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1049 set_dispatch_callbacks(userdata);
1050 }
1051
1052 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1053 set_dispatch_callbacks(userdata);
1054 }
1055
1056 static void set_dispatch_callbacks(pa_operation *o) {
1057 int done = 1;
1058
1059 pa_assert(o);
1060 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1061 pa_assert(o->context);
1062 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1063 pa_assert(o->context->state == PA_CONTEXT_READY);
1064
1065 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1066 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1067
1068 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1069 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1070 done = 0;
1071 }
1072
1073 if (pa_pstream_is_pending(o->context->pstream)) {
1074 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1075 done = 0;
1076 }
1077
1078 if (done) {
1079 if (o->callback) {
1080 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1081 cb(o->context, o->userdata);
1082 }
1083
1084 pa_operation_done(o);
1085 pa_operation_unref(o);
1086 }
1087 }
1088
1089 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1090 pa_operation *o;
1091
1092 pa_assert(c);
1093 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1094
1095 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1096 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1097 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1098
1099 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1100 set_dispatch_callbacks(pa_operation_ref(o));
1101
1102 return o;
1103 }
1104
1105 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1106 pa_operation *o = userdata;
1107 int success = 1;
1108
1109 pa_assert(pd);
1110 pa_assert(o);
1111 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1112
1113 if (!o->context)
1114 goto finish;
1115
1116 if (command != PA_COMMAND_REPLY) {
1117 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1118 goto finish;
1119
1120 success = 0;
1121 } else if (!pa_tagstruct_eof(t)) {
1122 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1123 goto finish;
1124 }
1125
1126 if (o->callback) {
1127 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1128 cb(o->context, success, o->userdata);
1129 }
1130
1131 finish:
1132 pa_operation_done(o);
1133 pa_operation_unref(o);
1134 }
1135
1136 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) {
1137 pa_tagstruct *t;
1138 pa_operation *o;
1139 uint32_t tag;
1140
1141 pa_assert(c);
1142 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1143
1144 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1145 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1146
1147 o = pa_operation_new(c, NULL, cb, userdata);
1148
1149 t = pa_tagstruct_command(c, command, &tag);
1150 pa_pstream_send_tagstruct(c->pstream, t);
1151 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1152
1153 return o;
1154 }
1155
1156 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1157 pa_assert(c);
1158 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1159
1160 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1161 }
1162
1163 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1164 pa_tagstruct *t;
1165 pa_operation *o;
1166 uint32_t tag;
1167
1168 pa_assert(c);
1169 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1170
1171 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1172 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1173
1174 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1175 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1176 pa_tagstruct_puts(t, name);
1177 pa_pstream_send_tagstruct(c->pstream, t);
1178 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);
1179
1180 return o;
1181 }
1182
1183 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1184 pa_tagstruct *t;
1185 pa_operation *o;
1186 uint32_t tag;
1187
1188 pa_assert(c);
1189 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1190
1191 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1192 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1193
1194 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1195 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1196 pa_tagstruct_puts(t, name);
1197 pa_pstream_send_tagstruct(c->pstream, t);
1198 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1199
1200 return o;
1201 }
1202
1203 int pa_context_is_local(pa_context *c) {
1204 pa_assert(c);
1205 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1206
1207 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1208 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1209
1210 return !!c->is_local;
1211 }
1212
1213 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1214 pa_operation *o;
1215
1216 pa_assert(c);
1217 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1218 pa_assert(name);
1219
1220 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1221 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1222
1223 if (c->version >= 13) {
1224 pa_proplist *p = pa_proplist_new();
1225
1226 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1227 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1228 pa_proplist_free(p);
1229 } else {
1230 pa_tagstruct *t;
1231 uint32_t tag;
1232
1233 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1234 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1235 pa_tagstruct_puts(t, name);
1236 pa_pstream_send_tagstruct(c->pstream, t);
1237 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);
1238 }
1239
1240 return o;
1241 }
1242
1243 const char* pa_get_library_version(void) {
1244 return PACKAGE_VERSION;
1245 }
1246
1247 const char* pa_context_get_server(pa_context *c) {
1248 pa_assert(c);
1249 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1250
1251 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1252 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1253
1254 if (*c->server == '{') {
1255 char *e = strchr(c->server+1, '}');
1256 return e ? e+1 : c->server;
1257 }
1258
1259 return c->server;
1260 }
1261
1262 uint32_t pa_context_get_protocol_version(pa_context *c) {
1263 return PA_PROTOCOL_VERSION;
1264 }
1265
1266 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1267 pa_assert(c);
1268 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1269
1270 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1271 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1272
1273 return c->version;
1274 }
1275
1276 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1277 pa_tagstruct *t;
1278
1279 pa_assert(c);
1280 pa_assert(tag);
1281
1282 t = pa_tagstruct_new(NULL, 0);
1283 pa_tagstruct_putu32(t, command);
1284 pa_tagstruct_putu32(t, *tag = c->ctag++);
1285
1286 return t;
1287 }
1288
1289 uint32_t pa_context_get_index(pa_context *c) {
1290 pa_assert(c);
1291 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1292
1293 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1294 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1295 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1296
1297 return c->client_index;
1298 }
1299
1300 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) {
1301 pa_operation *o;
1302 pa_tagstruct *t;
1303 uint32_t tag;
1304
1305 pa_assert(c);
1306 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1307
1308 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1309 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1310 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1311 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1312
1313 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1314
1315 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1316 pa_tagstruct_putu32(t, (uint32_t) mode);
1317 pa_tagstruct_put_proplist(t, p);
1318
1319 pa_pstream_send_tagstruct(c->pstream, t);
1320 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);
1321
1322 /* Please note that we don't update c->proplist here, because we
1323 * don't export that field */
1324
1325 return o;
1326 }
1327
1328 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1329 pa_operation *o;
1330 pa_tagstruct *t;
1331 uint32_t tag;
1332 const char * const *k;
1333
1334 pa_assert(c);
1335 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1336
1337 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1338 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1339 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1340 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1341
1342 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1343
1344 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1345
1346 for (k = keys; *k; k++)
1347 pa_tagstruct_puts(t, *k);
1348
1349 pa_tagstruct_puts(t, NULL);
1350
1351 pa_pstream_send_tagstruct(c->pstream, t);
1352 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);
1353
1354 /* Please note that we don't update c->proplist here, because we
1355 * don't export that field */
1356
1357 return o;
1358 }
1359
1360 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1361 pa_context *c = userdata;
1362 uint32_t idx;
1363 const char *name;
1364
1365 pa_assert(pd);
1366 pa_assert(command == PA_COMMAND_EXTENSION);
1367 pa_assert(t);
1368 pa_assert(c);
1369 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1370
1371 pa_context_ref(c);
1372
1373 if (c->version < 15) {
1374 pa_context_fail(c, PA_ERR_PROTOCOL);
1375 goto finish;
1376 }
1377
1378 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1379 pa_tagstruct_gets(t, &name) < 0) {
1380 pa_context_fail(c, PA_ERR_PROTOCOL);
1381 goto finish;
1382 }
1383
1384 if (!strcmp(name, "module-stream-restore"))
1385 pa_ext_stream_restore_command(c, tag, t);
1386 else
1387 pa_log(_("Received message for unknown extension '%s'"), name);
1388
1389 finish:
1390 pa_context_unref(c);
1391 }
1392
1393
1394 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1395 pa_context *c = userdata;
1396 pa_proplist *pl = NULL;
1397 const char *event;
1398
1399 pa_assert(pd);
1400 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1401 pa_assert(t);
1402 pa_assert(c);
1403 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1404
1405 pa_context_ref(c);
1406
1407 if (c->version < 15) {
1408 pa_context_fail(c, PA_ERR_PROTOCOL);
1409 goto finish;
1410 }
1411
1412 pl = pa_proplist_new();
1413
1414 if (pa_tagstruct_gets(t, &event) < 0 ||
1415 pa_tagstruct_get_proplist(t, pl) < 0 ||
1416 !pa_tagstruct_eof(t) || !event) {
1417 pa_context_fail(c, PA_ERR_PROTOCOL);
1418 goto finish;
1419 }
1420
1421 if (c->event_callback)
1422 c->event_callback(c, event, pl, c->event_userdata);
1423
1424 finish:
1425 pa_context_unref(c);
1426
1427 if (pl)
1428 pa_proplist_free(pl);
1429 }