static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) { pa_context *c = userdata; pa_bool_t is_session; pa_assert(bus); pa_assert(message); pa_assert(c); if (c->state != PA_CONTEXT_CONNECTING) goto finish; if (!c->no_fail) goto finish; /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */ is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus); pa_log_debug("Rock!! PulseAudio might be back on %s bus", is_session ? "session" : "system"); if (is_session) /* The user instance via PF_LOCAL */ c->server_list = prepend_per_user(c->server_list); else /* The system wide instance via PF_LOCAL */ c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); if (!c->client) try_next_connection(c); finish: return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c){ pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) > 0); pa_assert(c->connection); return pa_dbus_wrap_connection_get(c->connection); }
static void context_free(pa_context *c) { pa_assert(c); context_unlink(c); #ifdef HAVE_DBUS if (c->system_bus) { if (c->filter_added) dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c); pa_dbus_wrap_connection_free(c->system_bus); } if (c->session_bus) { if (c->filter_added) dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c); pa_dbus_wrap_connection_free(c->session_bus); } #endif if (c->record_streams) pa_hashmap_free(c->record_streams, NULL, NULL); if (c->playback_streams) pa_hashmap_free(c->playback_streams, NULL, NULL); if (c->mempool) pa_mempool_free(c->mempool); if (c->conf) pa_client_conf_free(c->conf); pa_strlist_free(c->server_list); if (c->proplist) pa_proplist_free(c->proplist); pa_xfree(c->server); pa_xfree(c); }
static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) { DBusError error; pa_assert(c); pa_assert(conn); dbus_error_init(&error); if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message); goto fail; } if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) { pa_log_warn("Failed to add filter function"); goto fail; } c->filter_added = TRUE; if (pa_dbus_add_matches( pa_dbus_wrap_connection_get(*conn), &error, "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) { pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message); goto fail; } return; fail: if (*conn) { pa_dbus_wrap_connection_free(*conn); *conn = NULL; } dbus_error_free(&error); }
static int context_autospawn(pa_context *c) { pid_t pid; int status, r; struct sigaction sa; pa_context_ref(c); if (sigaction(SIGCHLD, NULL, &sa) < 0) { pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } #ifdef SA_NOCLDWAIT if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) { #else if (sa.sa_handler == SIG_IGN) { #endif pa_log_debug("Process disabled waitpid(), cannot autospawn."); pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto fail; } pa_log_debug("Trying to autospawn..."); if (c->spawn_api.prefork) c->spawn_api.prefork(); if ((pid = fork()) < 0) { pa_log_error(_("fork(): %s"), pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); if (c->spawn_api.postfork) c->spawn_api.postfork(); goto fail; } else if (!pid) { /* Child */ const char *state = NULL; const char * argv[32]; unsigned n = 0; if (c->spawn_api.atfork) c->spawn_api.atfork(); /* We leave most of the cleaning up of the process environment * to the executable. We only clean up the file descriptors to * make sure the executable can actually be loaded * correctly. */ pa_close_all(-1); /* Setup argv */ argv[n++] = c->conf->daemon_binary; argv[n++] = "--start"; while (n < PA_ELEMENTSOF(argv)-1) { char *a; if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) break; argv[n++] = a; } argv[n++] = NULL; pa_assert(n <= PA_ELEMENTSOF(argv)); execv(argv[0], (char * const *) argv); _exit(1); } /* Parent */ if (c->spawn_api.postfork) c->spawn_api.postfork(); do { r = waitpid(pid, &status, 0); } while (r < 0 && errno == EINTR); if (r < 0) { if (errno != ESRCH) { pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } /* hmm, something already reaped our child, so we assume * startup worked, even if we cannot know */ } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto fail; } pa_context_unref(c); return 0; fail: pa_context_unref(c); return -1; } #endif /* OS_IS_WIN32 */ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); #ifdef HAVE_DBUS static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) { DBusError error; pa_assert(c); pa_assert(conn); dbus_error_init(&error); if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message); goto fail; } if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) { pa_log_warn("Failed to add filter function"); goto fail; } c->filter_added = true; if (pa_dbus_add_matches( pa_dbus_wrap_connection_get(*conn), &error, "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) { pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message); goto fail; } return; fail: if (*conn) { pa_dbus_wrap_connection_free(*conn); *conn = NULL; } dbus_error_free(&error); }