]> code.delx.au - pulseaudio/blob - polyp/polyplib-context.c
62d1ff0d41b83a977caaa277087d3d81f99af0a4
[pulseaudio] / polyp / polyplib-context.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37 #include <signal.h>
38
39 #include "polyplib-internal.h"
40 #include "polyplib-context.h"
41 #include "native-common.h"
42 #include "pdispatch.h"
43 #include "pstream.h"
44 #include "dynarray.h"
45 #include "socket-client.h"
46 #include "pstream-util.h"
47 #include "util.h"
48 #include "xmalloc.h"
49 #include "log.h"
50 #include "client-conf.h"
51 #include "socket-util.h"
52
53 #ifdef HAVE_X11
54 #include "client-conf-x11.h"
55 #endif
56
57 #define AUTOSPAWN_LOCK "autospawn.lock"
58
59
60
61 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
62 [PA_COMMAND_REQUEST] = { pa_command_request },
63 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed },
64 [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed },
65 [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event },
66 };
67
68 static void unlock_autospawn_lock_file(struct pa_context *c) {
69 assert(c);
70
71 if (c->autospawn_lock_fd >= 0) {
72 pa_unlock_lockfile(c->autospawn_lock_fd);
73 c->autospawn_lock_fd = -1;
74 }
75
76 }
77
78 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
79 struct pa_context *c;
80 assert(mainloop && name);
81
82 c = pa_xmalloc(sizeof(struct pa_context));
83 c->ref = 1;
84 c->name = pa_xstrdup(name);
85 c->mainloop = mainloop;
86 c->client = NULL;
87 c->pstream = NULL;
88 c->pdispatch = NULL;
89 c->playback_streams = pa_dynarray_new();
90 c->record_streams = pa_dynarray_new();
91 assert(c->playback_streams && c->record_streams);
92
93 PA_LLIST_HEAD_INIT(struct pa_stream, c->streams);
94 PA_LLIST_HEAD_INIT(struct pa_operation, c->operations);
95
96 c->error = PA_ERROR_OK;
97 c->state = PA_CONTEXT_UNCONNECTED;
98 c->ctag = 0;
99
100 c->state_callback = NULL;
101 c->state_userdata = NULL;
102
103 c->subscribe_callback = NULL;
104 c->subscribe_userdata = NULL;
105
106 c->memblock_stat = pa_memblock_stat_new();
107 c->local = -1;
108 c->server_list = NULL;
109 c->autospawn_lock_fd = -1;
110 memset(&c->spawn_api, 0, sizeof(c->spawn_api));
111 c->do_autospawn = 0;
112
113 pa_check_signal_is_blocked(SIGPIPE);
114
115 c->conf = pa_client_conf_new();
116 pa_client_conf_load(c->conf, NULL);
117 #ifdef HAVE_X11
118 pa_client_conf_from_x11(c->conf, NULL);
119 #endif
120 pa_client_conf_env(c->conf);
121
122 return c;
123 }
124
125 static void context_free(struct pa_context *c) {
126 assert(c);
127
128 unlock_autospawn_lock_file(c);
129
130 while (c->operations)
131 pa_operation_cancel(c->operations);
132
133 while (c->streams)
134 pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
135
136 if (c->client)
137 pa_socket_client_unref(c->client);
138 if (c->pdispatch)
139 pa_pdispatch_unref(c->pdispatch);
140 if (c->pstream) {
141 pa_pstream_close(c->pstream);
142 pa_pstream_unref(c->pstream);
143 }
144
145 if (c->record_streams)
146 pa_dynarray_free(c->record_streams, NULL, NULL);
147 if (c->playback_streams)
148 pa_dynarray_free(c->playback_streams, NULL, NULL);
149
150 pa_memblock_stat_unref(c->memblock_stat);
151
152 if (c->conf)
153 pa_client_conf_free(c->conf);
154
155 pa_strlist_free(c->server_list);
156
157 pa_xfree(c->name);
158 pa_xfree(c);
159 }
160
161 struct pa_context* pa_context_ref(struct pa_context *c) {
162 assert(c && c->ref >= 1);
163 c->ref++;
164 return c;
165 }
166
167 void pa_context_unref(struct pa_context *c) {
168 assert(c && c->ref >= 1);
169
170 if ((--(c->ref)) == 0)
171 context_free(c);
172 }
173
174 void pa_context_set_state(struct pa_context *c, enum pa_context_state st) {
175 assert(c);
176
177 if (c->state == st)
178 return;
179
180 pa_context_ref(c);
181
182 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
183 struct pa_stream *s;
184
185 s = c->streams ? pa_stream_ref(c->streams) : NULL;
186 while (s) {
187 struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
188 pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
189 pa_stream_unref(s);
190 s = n;
191 }
192
193 if (c->pdispatch)
194 pa_pdispatch_unref(c->pdispatch);
195 c->pdispatch = NULL;
196
197 if (c->pstream) {
198 pa_pstream_close(c->pstream);
199 pa_pstream_unref(c->pstream);
200 }
201 c->pstream = NULL;
202
203 if (c->client)
204 pa_socket_client_unref(c->client);
205 c->client = NULL;
206 }
207
208 c->state = st;
209 if (c->state_callback)
210 c->state_callback(c, c->state_userdata);
211
212 pa_context_unref(c);
213 }
214
215 void pa_context_fail(struct pa_context *c, int error) {
216 assert(c);
217 c->error = error;
218 pa_context_set_state(c, PA_CONTEXT_FAILED);
219 }
220
221 static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
222 struct pa_context *c = userdata;
223 assert(p && c);
224 pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED);
225 }
226
227 static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
228 struct pa_context *c = userdata;
229 assert(p && packet && c);
230
231 pa_context_ref(c);
232
233 if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
234 pa_log(__FILE__": invalid packet.\n");
235 pa_context_fail(c, PA_ERROR_PROTOCOL);
236 }
237
238 pa_context_unref(c);
239 }
240
241 static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) {
242 struct pa_context *c = userdata;
243 struct pa_stream *s;
244 assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
245
246 pa_context_ref(c);
247
248 if ((s = pa_dynarray_get(c->record_streams, channel))) {
249 if (s->read_callback) {
250 s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
251 s->counter += chunk->length;
252 }
253 }
254
255 pa_context_unref(c);
256 }
257
258 int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
259 assert(c);
260
261 if (command == PA_COMMAND_ERROR) {
262 assert(t);
263
264 if (pa_tagstruct_getu32(t, &c->error) < 0) {
265 pa_context_fail(c, PA_ERROR_PROTOCOL);
266 return -1;
267
268 }
269 } else if (command == PA_COMMAND_TIMEOUT)
270 c->error = PA_ERROR_TIMEOUT;
271 else {
272 pa_context_fail(c, PA_ERROR_PROTOCOL);
273 return -1;
274 }
275
276 return 0;
277 }
278
279 static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
280 struct pa_context *c = userdata;
281 assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME));
282
283 pa_context_ref(c);
284
285 if (command != PA_COMMAND_REPLY) {
286
287 if (pa_context_handle_error(c, command, t) < 0)
288 pa_context_fail(c, PA_ERROR_PROTOCOL);
289
290 pa_context_fail(c, c->error);
291 goto finish;
292 }
293
294 switch(c->state) {
295 case PA_CONTEXT_AUTHORIZING: {
296 struct pa_tagstruct *t;
297 t = pa_tagstruct_new(NULL, 0);
298 assert(t);
299 pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME);
300 pa_tagstruct_putu32(t, tag = c->ctag++);
301 pa_tagstruct_puts(t, c->name);
302 pa_pstream_send_tagstruct(c->pstream, t);
303 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
304
305 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
306 break;
307 }
308
309 case PA_CONTEXT_SETTING_NAME :
310 pa_context_set_state(c, PA_CONTEXT_READY);
311 break;
312
313 default:
314 assert(0);
315 }
316
317 finish:
318 pa_context_unref(c);
319 }
320
321 static void setup_context(struct pa_context *c, struct pa_iochannel *io) {
322 struct pa_tagstruct *t;
323 uint32_t tag;
324 assert(c && io);
325
326 pa_context_ref(c);
327
328 assert(!c->pstream);
329 c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat);
330 assert(c->pstream);
331
332 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
333 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
334 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
335
336 assert(!c->pdispatch);
337 c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
338 assert(c->pdispatch);
339
340 if (!c->conf->cookie_valid) {
341 pa_context_fail(c, PA_ERROR_AUTHKEY);
342 goto finish;
343 }
344
345 t = pa_tagstruct_new(NULL, 0);
346 assert(t);
347 pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
348 pa_tagstruct_putu32(t, tag = c->ctag++);
349 pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
350 pa_pstream_send_tagstruct(c->pstream, t);
351 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
352
353 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
354
355 finish:
356
357 pa_context_unref(c);
358 }
359
360 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
361
362 static int context_connect_spawn(struct pa_context *c) {
363 pid_t pid;
364 int status, r;
365 int fds[2] = { -1, -1} ;
366 struct pa_iochannel *io;
367
368 pa_context_ref(c);
369
370 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
371 pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno));
372 pa_context_fail(c, PA_ERROR_INTERNAL);
373 goto fail;
374 }
375
376 pa_fd_set_cloexec(fds[0], 1);
377
378 pa_socket_low_delay(fds[0]);
379 pa_socket_low_delay(fds[1]);
380
381 if (c->spawn_api.prefork)
382 c->spawn_api.prefork();
383
384 if ((pid = fork()) < 0) {
385 pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
386 pa_context_fail(c, PA_ERROR_INTERNAL);
387
388 if (c->spawn_api.postfork)
389 c->spawn_api.postfork();
390
391 goto fail;
392 } else if (!pid) {
393 /* Child */
394
395 char t[128];
396 const char *state = NULL;
397 #define MAX_ARGS 64
398 char *argv[MAX_ARGS+1];
399 int n;
400
401 /* Not required, since fds[0] has CLOEXEC enabled anyway */
402 close(fds[0]);
403
404 if (c->spawn_api.atfork)
405 c->spawn_api.atfork();
406
407 /* Setup argv */
408
409 n = 0;
410
411 argv[n++] = c->conf->daemon_binary;
412 argv[n++] = "--daemonize=yes";
413
414 snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
415 argv[n++] = strdup(t);
416
417 while (n < MAX_ARGS) {
418 char *a;
419
420 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
421 break;
422
423 argv[n++] = a;
424 }
425
426 argv[n++] = NULL;
427
428 execv(argv[0], argv);
429 _exit(1);
430 #undef MAX_ARGS
431 }
432
433 /* Parent */
434
435 r = waitpid(pid, &status, 0);
436
437 if (c->spawn_api.postfork)
438 c->spawn_api.postfork();
439
440 if (r < 0) {
441 pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno));
442 pa_context_fail(c, PA_ERROR_INTERNAL);
443 goto fail;
444 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
445 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
446 goto fail;
447 }
448
449 close(fds[1]);
450
451 c->local = 1;
452
453 io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
454
455 setup_context(c, io);
456 unlock_autospawn_lock_file(c);
457
458 pa_context_unref(c);
459
460 return 0;
461
462 fail:
463 if (fds[0] != -1)
464 close(fds[0]);
465 if (fds[1] != -1)
466 close(fds[1]);
467
468 unlock_autospawn_lock_file(c);
469
470 pa_context_unref(c);
471
472 return -1;
473 }
474
475 static int try_next_connection(struct pa_context *c) {
476 char *u = NULL;
477 int r = -1;
478 assert(c && !c->client);
479
480 for (;;) {
481 if (u)
482 pa_xfree(u);
483 u = NULL;
484
485 c->server_list = pa_strlist_pop(c->server_list, &u);
486
487 if (!u) {
488
489 if (c->do_autospawn) {
490 r = context_connect_spawn(c);
491 goto finish;
492 }
493
494 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
495 goto finish;
496 }
497
498 /* pa_log(__FILE__": Trying to connect to %s...\n", u); */
499
500 if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
501 continue;
502
503 c->local = pa_socket_client_is_local(c->client);
504 pa_socket_client_set_callback(c->client, on_connection, c);
505 break;
506 }
507
508 r = 0;
509
510 finish:
511 if (u)
512 pa_xfree(u);
513
514 return r;
515 }
516
517 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
518 struct pa_context *c = userdata;
519 assert(client && c && c->state == PA_CONTEXT_CONNECTING);
520
521 pa_context_ref(c);
522
523 pa_socket_client_unref(client);
524 c->client = NULL;
525
526 if (!io) {
527 /* Try the item in the list */
528 if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) {
529 try_next_connection(c);
530 goto finish;
531 }
532
533 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
534 goto finish;
535 }
536
537 unlock_autospawn_lock_file(c);
538 setup_context(c, io);
539
540 finish:
541 pa_context_unref(c);
542 }
543
544 int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) {
545 int r = -1;
546 assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
547
548 if (!server)
549 server = c->conf->default_server;
550
551
552 pa_context_ref(c);
553
554 assert(!c->server_list);
555
556 if (server) {
557 if (!(c->server_list = pa_strlist_parse(server))) {
558 pa_context_fail(c, PA_ERROR_INVALIDSERVER);
559 goto finish;
560 }
561 } else {
562 char *d;
563 char ufn[PATH_MAX];
564
565 /* Prepend in reverse order */
566
567 if ((d = getenv("DISPLAY")))
568 c->server_list = pa_strlist_prepend(c->server_list, d);
569
570 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost");
571 c->server_list = pa_strlist_prepend(c->server_list, "localhost");
572 c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn)));
573
574 /* Wrap the connection attempts in a single transaction for sane autospwan locking */
575 if (spawn && c->conf->autospawn) {
576 char lf[PATH_MAX];
577
578 pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf));
579 assert(c->autospawn_lock_fd <= 0);
580 c->autospawn_lock_fd = pa_lock_lockfile(lf);
581
582 if (api)
583 c->spawn_api = *api;
584 c->do_autospawn = 1;
585 }
586
587 }
588
589 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
590 r = try_next_connection(c);
591
592 finish:
593 pa_context_unref(c);
594
595 return r;
596 }
597
598 void pa_context_disconnect(struct pa_context *c) {
599 assert(c);
600 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
601 }
602
603 enum pa_context_state pa_context_get_state(struct pa_context *c) {
604 assert(c && c->ref >= 1);
605 return c->state;
606 }
607
608 int pa_context_errno(struct pa_context *c) {
609 assert(c && c->ref >= 1);
610 return c->error;
611 }
612
613 void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
614 assert(c && c->ref >= 1);
615 c->state_callback = cb;
616 c->state_userdata = userdata;
617 }
618
619 int pa_context_is_pending(struct pa_context *c) {
620 assert(c && c->ref >= 1);
621
622 /* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */
623 /* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */
624
625 return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || c->client;
626 }
627
628 static void set_dispatch_callbacks(struct pa_operation *o);
629
630 static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
631 set_dispatch_callbacks(userdata);
632 }
633
634 static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
635 set_dispatch_callbacks(userdata);
636 }
637
638 static void set_dispatch_callbacks(struct pa_operation *o) {
639 int done = 1;
640 assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY);
641
642 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
643 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
644
645 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
646 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
647 done = 0;
648 }
649
650 if (pa_pstream_is_pending(o->context->pstream)) {
651 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
652 done = 0;
653 }
654
655 if (!done)
656 pa_operation_ref(o);
657 else {
658 if (o->callback) {
659 void (*cb)(struct pa_context *c, void *userdata);
660 cb = (void (*)(struct pa_context*, void*)) o->callback;
661 cb(o->context, o->userdata);
662 }
663
664 pa_operation_done(o);
665 }
666
667 pa_operation_unref(o);
668 }
669
670 struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) {
671 struct pa_operation *o;
672 assert(c && c->ref >= 1);
673
674 if (c->state != PA_CONTEXT_READY)
675 return NULL;
676
677 if (!pa_context_is_pending(c))
678 return NULL;
679
680 o = pa_operation_new(c, NULL);
681 assert(o);
682 o->callback = cb;
683 o->userdata = userdata;
684
685 set_dispatch_callbacks(pa_operation_ref(o));
686
687 return o;
688 }
689
690 void pa_context_exit_daemon(struct pa_context *c) {
691 struct pa_tagstruct *t;
692 assert(c && c->ref >= 1);
693
694 t = pa_tagstruct_new(NULL, 0);
695 assert(t);
696 pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
697 pa_tagstruct_putu32(t, c->ctag++);
698 pa_pstream_send_tagstruct(c->pstream, t);
699 }
700
701 void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
702 struct pa_operation *o = userdata;
703 int success = 1;
704 assert(pd && o && o->context && o->ref >= 1);
705
706 if (command != PA_COMMAND_REPLY) {
707 if (pa_context_handle_error(o->context, command, t) < 0)
708 goto finish;
709
710 success = 0;
711 } else if (!pa_tagstruct_eof(t)) {
712 pa_context_fail(o->context, PA_ERROR_PROTOCOL);
713 goto finish;
714 }
715
716 if (o->callback) {
717 void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback;
718 cb(o->context, success, o->userdata);
719 }
720
721 finish:
722 pa_operation_done(o);
723 pa_operation_unref(o);
724 }
725
726 struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) {
727 struct pa_tagstruct *t;
728 struct pa_operation *o;
729 uint32_t tag;
730 assert(c && cb);
731
732 o = pa_operation_new(c, NULL);
733 o->callback = cb;
734 o->userdata = userdata;
735
736 t = pa_tagstruct_new(NULL, 0);
737 pa_tagstruct_putu32(t, command);
738 pa_tagstruct_putu32(t, tag = c->ctag++);
739 pa_pstream_send_tagstruct(c->pstream, t);
740 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o);
741
742 return pa_operation_ref(o);
743 }
744
745 struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) {
746 struct pa_tagstruct *t;
747 struct pa_operation *o;
748 uint32_t tag;
749 assert(c && cb);
750
751 o = pa_operation_new(c, NULL);
752 o->callback = cb;
753 o->userdata = userdata;
754
755 t = pa_tagstruct_new(NULL, 0);
756 pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK);
757 pa_tagstruct_putu32(t, tag = c->ctag++);
758 pa_tagstruct_puts(t, name);
759 pa_pstream_send_tagstruct(c->pstream, t);
760 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
761
762 return pa_operation_ref(o);
763 }
764
765 struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) {
766 struct pa_tagstruct *t;
767 struct pa_operation *o;
768 uint32_t tag;
769 assert(c && cb);
770
771 o = pa_operation_new(c, NULL);
772 o->callback = cb;
773 o->userdata = userdata;
774
775 t = pa_tagstruct_new(NULL, 0);
776 pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE);
777 pa_tagstruct_putu32(t, tag = c->ctag++);
778 pa_tagstruct_puts(t, name);
779 pa_pstream_send_tagstruct(c->pstream, t);
780 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
781
782 return pa_operation_ref(o);
783 }
784
785 int pa_context_is_local(struct pa_context *c) {
786 assert(c);
787 return c->local;
788 }
789
790 struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) {
791 struct pa_tagstruct *t;
792 struct pa_operation *o;
793 uint32_t tag;
794 assert(c && name && cb);
795
796 o = pa_operation_new(c, NULL);
797 o->callback = cb;
798 o->userdata = userdata;
799
800 t = pa_tagstruct_new(NULL, 0);
801 pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME);
802 pa_tagstruct_putu32(t, tag = c->ctag++);
803 pa_tagstruct_puts(t, name);
804 pa_pstream_send_tagstruct(c->pstream, t);
805 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
806
807 return pa_operation_ref(o);
808 }
809
810 const char* pa_get_library_version(void) {
811 return PACKAGE_VERSION;
812 }
813