2 This file is part of PulseAudio.
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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
30 #include <sys/types.h>
36 #ifdef HAVE_SYS_WAIT_H
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>
52 #include <pulse/client-conf-x11.h>
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>
74 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
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
95 static void context_free(pa_context *c);
98 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata);
101 pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
102 return pa_context_new_with_proplist(mainloop, name, NULL);
105 static void reset_callbacks(pa_context *c) {
108 c->state_callback = NULL;
109 c->state_userdata = NULL;
111 c->subscribe_callback = NULL;
112 c->subscribe_userdata = NULL;
114 c->event_callback = NULL;
115 c->event_userdata = NULL;
117 c->ext_device_manager.callback = NULL;
118 c->ext_device_manager.userdata = NULL;
120 c->ext_device_restore.callback = NULL;
121 c->ext_device_restore.userdata = NULL;
123 c->ext_stream_restore.callback = NULL;
124 c->ext_stream_restore.userdata = NULL;
127 pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
132 if (pa_detect_fork())
137 c = pa_xnew0(pa_context, 1);
140 c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
143 pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
146 c->system_bus = c->session_bus = NULL;
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);
154 PA_LLIST_HEAD_INIT(pa_stream, c->streams);
155 PA_LLIST_HEAD_INIT(pa_operation, c->operations);
158 c->state = PA_CONTEXT_UNCONNECTED;
164 pa_check_signal_is_blocked(SIGPIPE);
168 c->conf = pa_client_conf_new();
169 pa_client_conf_load(c->conf, NULL);
171 pa_client_conf_from_x11(c->conf, NULL);
173 pa_client_conf_env(c->conf);
175 if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
177 if (!c->conf->disable_shm)
178 c->mempool = pa_mempool_new(false, c->conf->shm_size);
189 static void context_unlink(pa_context *c) {
194 s = c->streams ? pa_stream_ref(c->streams) : NULL;
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);
202 while (c->operations)
203 pa_operation_cancel(c->operations);
206 pa_pdispatch_unref(c->pdispatch);
211 pa_pstream_unlink(c->pstream);
212 pa_pstream_unref(c->pstream);
217 pa_socket_client_unref(c->client);
224 static void context_free(pa_context *c) {
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);
236 if (c->session_bus) {
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);
243 if (c->record_streams)
244 pa_hashmap_free(c->record_streams);
245 if (c->playback_streams)
246 pa_hashmap_free(c->playback_streams);
249 pa_mempool_free(c->mempool);
252 pa_client_conf_free(c->conf);
254 pa_strlist_free(c->server_list);
257 pa_proplist_free(c->proplist);
263 pa_context* pa_context_ref(pa_context *c) {
265 pa_assert(PA_REFCNT_VALUE(c) >= 1);
271 void pa_context_unref(pa_context *c) {
273 pa_assert(PA_REFCNT_VALUE(c) >= 1);
275 if (PA_REFCNT_DEC(c) <= 0)
279 void pa_context_set_state(pa_context *c, pa_context_state_t st) {
281 pa_assert(PA_REFCNT_VALUE(c) >= 1);
290 if (c->state_callback)
291 c->state_callback(c, c->state_userdata);
293 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED)
299 int pa_context_set_error(pa_context *c, int error) {
300 pa_assert(error >= 0);
301 pa_assert(error < PA_ERR_MAX);
309 void pa_context_fail(pa_context *c, int error) {
311 pa_assert(PA_REFCNT_VALUE(c) >= 1);
313 pa_context_set_error(c, error);
314 pa_context_set_state(c, PA_CONTEXT_FAILED);
317 static void pstream_die_callback(pa_pstream *p, void *userdata) {
318 pa_context *c = userdata;
323 pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
326 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
327 pa_context *c = userdata;
335 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)
336 pa_context_fail(c, PA_ERR_PROTOCOL);
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;
347 pa_assert(chunk->length > 0);
349 pa_assert(PA_REFCNT_VALUE(c) >= 1);
353 if ((s = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(channel)))) {
355 if (chunk->memblock) {
356 pa_memblockq_seek(s->record_memblockq, offset, seek, true);
357 pa_memblockq_push_align(s->record_memblockq, chunk);
359 pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, true);
361 if (s->read_callback) {
364 if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0)
365 s->read_callback(s, l, s->read_userdata);
372 int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, bool fail) {
375 pa_assert(PA_REFCNT_VALUE(c) >= 1);
377 if (command == PA_COMMAND_ERROR) {
380 if (pa_tagstruct_getu32(t, &err) < 0 ||
381 !pa_tagstruct_eof(t)) {
382 pa_context_fail(c, PA_ERR_PROTOCOL);
386 } else if (command == PA_COMMAND_TIMEOUT)
387 err = PA_ERR_TIMEOUT;
389 pa_context_fail(c, PA_ERR_PROTOCOL);
394 pa_context_fail(c, PA_ERR_PROTOCOL);
398 if (err >= PA_ERR_MAX)
399 err = PA_ERR_UNKNOWN;
402 pa_context_fail(c, (int) err);
406 pa_context_set_error(c, (int) err);
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;
416 pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
420 if (command != PA_COMMAND_REPLY) {
421 pa_context_handle_error(c, command, t, true);
426 case PA_CONTEXT_AUTHORIZING: {
428 bool shm_on_remote = false;
430 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
431 !pa_tagstruct_eof(t)) {
432 pa_context_fail(c, PA_ERR_PROTOCOL);
436 /* Minimum supported version */
437 if (c->version < 8) {
438 pa_context_fail(c, PA_ERR_VERSION);
442 /* Starting with protocol version 13 the MSB of the version
443 tag reflects if shm is available for this connection or
445 if (c->version >= 13) {
446 shm_on_remote = !!(c->version & 0x80000000U);
447 c->version &= 0x7FFFFFFFU;
450 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
452 /* Enable shared memory support if possible */
454 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
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. */
464 const pa_creds *creds;
465 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
470 pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
471 pa_pstream_enable_shm(c->pstream, c->do_shm);
473 reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
475 if (c->version >= 13) {
476 pa_init_proplist(c->proplist);
477 pa_tagstruct_put_proplist(reply, c->proplist);
479 pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));
481 pa_pstream_send_tagstruct(c->pstream, reply);
482 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
484 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
488 case PA_CONTEXT_SETTING_NAME :
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);
497 pa_context_set_state(c, PA_CONTEXT_READY);
501 pa_assert_not_reached();
508 static void setup_context(pa_context *c, pa_iochannel *io) {
517 pa_assert(!c->pstream);
518 c->pstream = pa_pstream_new(c->mainloop, io, c->mempool);
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);
524 pa_assert(!c->pdispatch);
525 c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX);
527 if (!c->conf->cookie_valid)
528 pa_log_info(_("No cookie loaded. Attempting to connect without."));
530 t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
533 pa_mempool_is_shared(c->mempool) &&
536 pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm));
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));
547 if (pa_iochannel_creds_supported(io))
548 pa_iochannel_creds_enable(io);
550 ucred.uid = getuid();
551 ucred.gid = getgid();
553 pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred);
556 pa_pstream_send_tagstruct(c->pstream, t);
559 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
561 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
566 static pa_strlist *prepend_per_user(pa_strlist *l) {
569 /* The per-user instance */
570 if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
571 l = pa_strlist_prepend(l, ufn);
580 static int context_autospawn(pa_context *c) {
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);
594 if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) {
596 if (sa.sa_handler == SIG_IGN) {
598 pa_log_debug("Process disabled waitpid(), cannot autospawn.");
599 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
603 pa_log_debug("Trying to autospawn...");
605 if (c->spawn_api.prefork)
606 c->spawn_api.prefork();
608 if ((pid = fork()) < 0) {
609 pa_log_error(_("fork(): %s"), pa_cstrerror(errno));
610 pa_context_fail(c, PA_ERR_INTERNAL);
612 if (c->spawn_api.postfork)
613 c->spawn_api.postfork();
619 const char *state = NULL;
620 const char * argv[32];
623 if (c->spawn_api.atfork)
624 c->spawn_api.atfork();
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
633 argv[n++] = c->conf->daemon_binary;
634 argv[n++] = "--start";
636 while (n < PA_ELEMENTSOF(argv)-1) {
639 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
646 pa_assert(n <= PA_ELEMENTSOF(argv));
648 execv(argv[0], (char * const *) argv);
654 if (c->spawn_api.postfork)
655 c->spawn_api.postfork();
658 r = waitpid(pid, &status, 0);
659 } while (r < 0 && errno == EINTR);
663 if (errno != ESRCH) {
664 pa_log(_("waitpid(): %s"), pa_cstrerror(errno));
665 pa_context_fail(c, PA_ERR_INTERNAL);
669 /* hmm, something already reaped our child, so we assume
670 * startup worked, even if we cannot know */
672 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
673 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
688 #endif /* OS_IS_WIN32 */
690 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata);
693 static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) {
699 dbus_error_init(&error);
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);
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");
710 c->filter_added = true;
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) {
716 pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message);
724 pa_dbus_wrap_connection_free(*conn);
728 dbus_error_free(&error);
732 static int try_next_connection(pa_context *c) {
737 pa_assert(!c->client);
743 c->server_list = pa_strlist_pop(c->server_list, &u);
748 if (c->do_autospawn) {
750 if ((r = context_autospawn(c)) < 0)
753 /* Autospawn only once */
754 c->do_autospawn = false;
756 /* Connect only to per-user sockets this time */
757 c->server_list = prepend_per_user(c->server_list);
759 /* Retry connection */
765 if (c->no_fail && !c->server_specified) {
767 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
769 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
772 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
777 pa_log_debug("Trying to connect to %s...", u);
780 c->server = pa_xstrdup(u);
782 if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
785 c->is_local = !!pa_socket_client_is_local(c->client);
786 pa_socket_client_set_callback(c->client, on_connection, c);
798 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
799 pa_context *c = userdata;
800 int saved_errno = errno;
804 pa_assert(c->state == PA_CONTEXT_CONNECTING);
808 pa_socket_client_unref(client);
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);
820 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
824 setup_context(c, io);
831 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
832 pa_context *c = userdata;
839 if (c->state != PA_CONTEXT_CONNECTING)
845 /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */
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");
851 /* The user instance via PF_LOCAL */
852 c->server_list = prepend_per_user(c->server_list);
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);
858 try_next_connection(c);
861 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
865 int pa_context_connect(
868 pa_context_flags_t flags,
869 const pa_spawn_api *api) {
874 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
882 c->conf->autospawn = false;
884 server = c->conf->default_server;
888 c->no_fail = !!(flags & PA_CONTEXT_NOFAIL);
889 c->server_specified = !!server;
890 pa_assert(!c->server_list);
893 if (!(c->server_list = pa_strlist_parse(server))) {
894 pa_context_fail(c, PA_ERR_INVALIDSERVER);
901 /* Prepend in reverse order */
903 /* Follow the X display */
904 if (c->conf->auto_connect_display) {
905 if ((d = getenv("DISPLAY"))) {
906 d = pa_xstrndup(d, strcspn(d, ":"));
909 c->server_list = pa_strlist_prepend(c->server_list, d);
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");
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);
924 /* The user instance via PF_LOCAL */
925 c->server_list = prepend_per_user(c->server_list);
928 /* Set up autospawning */
929 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
933 pa_log_debug("Not doing autospawn since we are root.");
935 c->do_autospawn = true;
943 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
944 r = try_next_connection(c);
952 void pa_context_disconnect(pa_context *c) {
954 pa_assert(PA_REFCNT_VALUE(c) >= 1);
956 if (pa_detect_fork())
959 if (PA_CONTEXT_IS_GOOD(c->state))
960 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
963 pa_context_state_t pa_context_get_state(pa_context *c) {
965 pa_assert(PA_REFCNT_VALUE(c) >= 1);
970 int pa_context_errno(pa_context *c) {
973 return PA_ERR_INVALID;
975 pa_assert(PA_REFCNT_VALUE(c) >= 1);
980 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
982 pa_assert(PA_REFCNT_VALUE(c) >= 1);
984 if (pa_detect_fork())
987 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
990 c->state_callback = cb;
991 c->state_userdata = userdata;
994 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
996 pa_assert(PA_REFCNT_VALUE(c) >= 1);
998 if (pa_detect_fork())
1001 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1004 c->event_callback = cb;
1005 c->event_userdata = userdata;
1008 int pa_context_is_pending(pa_context *c) {
1010 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1015 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1016 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1020 static void set_dispatch_callbacks(pa_operation *o);
1022 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1023 set_dispatch_callbacks(userdata);
1026 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1027 set_dispatch_callbacks(userdata);
1030 static void set_dispatch_callbacks(pa_operation *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);
1039 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1040 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1042 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1043 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1047 if (pa_pstream_is_pending(o->context->pstream)) {
1048 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1054 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1055 cb(o->context, o->userdata);
1058 pa_operation_done(o);
1059 pa_operation_unref(o);
1063 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1067 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1073 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1074 set_dispatch_callbacks(pa_operation_ref(o));
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;
1085 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1090 if (command != PA_COMMAND_REPLY) {
1091 if (pa_context_handle_error(o->context, command, t, false) < 0)
1095 } else if (!pa_tagstruct_eof(t)) {
1096 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1101 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1102 cb(o->context, success, o->userdata);
1106 pa_operation_done(o);
1107 pa_operation_unref(o);
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) {
1116 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1121 o = pa_operation_new(c, NULL, cb, userdata);
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);
1130 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1132 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1134 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1137 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1143 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
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);
1157 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1163 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
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);
1177 int pa_context_is_local(pa_context *c) {
1179 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1184 return !!c->is_local;
1187 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1191 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1197 if (c->version >= 13) {
1198 pa_proplist *p = pa_proplist_new();
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);
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);
1217 const char* pa_get_library_version(void) {
1218 return pa_get_headers_version();
1221 const char* pa_context_get_server(pa_context *c) {
1223 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1228 if (*c->server == '{') {
1229 char *e = strchr(c->server+1, '}');
1230 return e ? e+1 : c->server;
1236 uint32_t pa_context_get_protocol_version(pa_context *c) {
1237 return PA_PROTOCOL_VERSION;
1240 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1242 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1250 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1256 t = pa_tagstruct_new(NULL, 0);
1257 pa_tagstruct_putu32(t, command);
1258 pa_tagstruct_putu32(t, *tag = c->ctag++);
1263 uint32_t pa_context_get_index(pa_context *c) {
1265 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1271 return c->client_index;
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) {
1280 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1287 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
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);
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);
1296 /* Please note that we don't update c->proplist here, because we
1297 * don't export that field */
1302 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1306 const char * const *k;
1309 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
1316 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1318 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1320 for (k = keys; *k; k++)
1321 pa_tagstruct_puts(t, *k);
1323 pa_tagstruct_puts(t, NULL);
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);
1328 /* Please note that we don't update c->proplist here, because we
1329 * don't export that field */
1334 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1335 pa_context *c = userdata;
1340 pa_assert(command == PA_COMMAND_EXTENSION);
1343 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1347 if (c->version < 15) {
1348 pa_context_fail(c, PA_ERR_PROTOCOL);
1352 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1353 pa_tagstruct_gets(t, &name) < 0) {
1354 pa_context_fail(c, PA_ERR_PROTOCOL);
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);
1365 pa_log(_("Received message for unknown extension '%s'"), name);
1368 pa_context_unref(c);
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;
1377 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1380 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1384 if (c->version < 15) {
1385 pa_context_fail(c, PA_ERR_PROTOCOL);
1389 pl = pa_proplist_new();
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);
1398 if (c->event_callback)
1399 c->event_callback(c, event, pl, c->event_userdata);
1402 pa_context_unref(c);
1405 pa_proplist_free(pl);
1408 pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
1412 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1413 pa_assert(c->mainloop);
1415 if (usec == PA_USEC_INVALID)
1416 return c->mainloop->time_new(c->mainloop, NULL, cb, userdata);
1418 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1420 return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
1423 void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
1427 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1428 pa_assert(c->mainloop);
1430 if (usec == PA_USEC_INVALID)
1431 c->mainloop->time_restart(e, NULL);
1433 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1434 c->mainloop->time_restart(e, &tv);
1438 size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss) {
1442 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
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);
1452 int pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path) {
1454 pa_assert(cookie_file_path);
1455 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1457 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1458 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
1460 return pa_client_conf_load_cookie_from_file(c->conf, cookie_file_path);