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