static pa_hook_result_t servers_changed_cb(void *hook_data, void *call_data, void *slot_data) { pa_strlist *servers = call_data; struct userdata *u = slot_data; char t[256]; int screen; pa_assert(u); screen = DefaultScreen(pa_x11_wrapper_get_display(u->x11_wrapper)); if (!pa_x11_get_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_ID", t, sizeof(t)) || !pa_streq(t, u->id)) { pa_log_warn("PulseAudio information vanished from X11!"); return PA_HOOK_OK; } publish_servers(u, servers); return PA_HOOK_OK; }
void pa__done(pa_module*m) { struct userdata*u; pa_assert(m); if (!(u = m->userdata)) return; if (u->x11_client) pa_x11_client_free(u->x11_client); if (u->x11_wrapper) { char t[256]; int screen = DefaultScreen(pa_x11_wrapper_get_display(u->x11_wrapper)); /* Yes, here is a race condition */ if (!pa_x11_get_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_ID", t, sizeof(t)) || !pa_streq(t, u->id)) pa_log_warn("PulseAudio information vanished from X11!"); else { pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_ID"); pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_SERVER"); pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_SINK"); pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_SOURCE"); pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_COOKIE"); pa_x11_del_prop(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper), screen, "PULSE_SESSION_ID"); xcb_flush(pa_x11_wrapper_get_xcb_connection(u->x11_wrapper)); } pa_x11_wrapper_unref(u->x11_wrapper); } if (u->auth_cookie) pa_auth_cookie_unref(u->auth_cookie); if (u->hook_slot) pa_hook_slot_free(u->hook_slot); if (u->protocol) pa_native_protocol_unref(u->protocol); pa_xfree(u->id); pa_xfree(u); }
int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; int c, ret = 1; Display *d = NULL; enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { switch (c) { case 'D' : dname = optarg; break; case 'h': printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" " -d Show current PulseAudio data attached to X11 display (default)\n" " -e Export local PulseAudio data to X11 display\n" " -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n" " -r Remove PulseAudio data from X11 display\n", pa_path_get_filename(argv[0])); ret = 0; goto finish; case 'd': mode = DUMP; break; case 'e': mode = EXPORT; break; case 'i': mode = IMPORT; break; case 'r': mode = REMOVE; break; case 'c': cookie_file = optarg; break; case 'I': source = optarg; break; case 'O': sink = optarg; break; case 'S': server = optarg; break; default: fprintf(stderr, "Failed to parse command line.\n"); goto finish; } } if (!(d = XOpenDisplay(dname))) { pa_log("XOpenDisplay() failed"); goto finish; } switch (mode) { case DUMP: { char t[1024]; if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("Server: %s\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) printf("Sink: %s\n", t); if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) printf("Cookie: %s\n", t); break; } case IMPORT: { char t[1024]; if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t); if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { fprintf(stderr, "Failed to parse cookie data\n"); goto finish; } if (pa_authkey_save(cookie_file, cookie, l) < 0) { fprintf(stderr, "Failed to save cookie data\n"); goto finish; } } break; } case EXPORT: { pa_client_conf *conf = pa_client_conf_new(); uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; assert(conf); if (pa_client_conf_load(conf, NULL) < 0) { fprintf(stderr, "Failed to load client configuration file.\n"); goto finish; } if (pa_client_conf_env(conf) < 0) { fprintf(stderr, "Failed to read environment configuration data.\n"); goto finish; } pa_x11_del_prop(d, "PULSE_SERVER"); pa_x11_del_prop(d, "PULSE_SINK"); pa_x11_del_prop(d, "PULSE_SOURCE"); pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); if (server) pa_x11_set_prop(d, "PULSE_SERVER", server); else if (conf->default_server) pa_x11_set_prop(d, "PULSE_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { fprintf(stderr, "Failed to get FQDN.\n"); goto finish; } pa_x11_set_prop(d, "PULSE_SERVER", hn); } if (sink) pa_x11_set_prop(d, "PULSE_SINK", sink); else if (conf->default_sink) pa_x11_set_prop(d, "PULSE_SINK", conf->default_sink); if (source) pa_x11_set_prop(d, "PULSE_SOURCE", source); if (conf->default_source) pa_x11_set_prop(d, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { fprintf(stderr, "Failed to load cookie data\n"); goto finish; } pa_x11_set_prop(d, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: pa_x11_del_prop(d, "PULSE_SERVER"); pa_x11_del_prop(d, "PULSE_SINK"); pa_x11_del_prop(d, "PULSE_SOURCE"); pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); break; default: fprintf(stderr, "No yet implemented.\n"); goto finish; } ret = 0; finish: if (d) { XSync(d, False); XCloseDisplay(d); } return ret; }
int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; int c, ret = 1, screen = 0; xcb_connection_t *xcb = NULL; enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { switch (c) { case 'D' : dname = optarg; break; case 'h': printf(_("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" " -d Show current PulseAudio data attached to X11 display (default)\n" " -e Export local PulseAudio data to X11 display\n" " -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n" " -r Remove PulseAudio data from X11 display\n"), pa_path_get_filename(argv[0])); ret = 0; goto finish; case 'd': mode = DUMP; break; case 'e': mode = EXPORT; break; case 'i': mode = IMPORT; break; case 'r': mode = REMOVE; break; case 'c': cookie_file = optarg; break; case 'I': source = optarg; break; case 'O': sink = optarg; break; case 'S': server = optarg; break; default: fprintf(stderr, _("Failed to parse command line.\n")); goto finish; } } if (!(xcb = xcb_connect(dname, &screen))) { pa_log(_("xcb_connect() failed")); goto finish; } if (xcb_connection_has_error(xcb)) { pa_log(_("xcb_connection_has_error() returned true")); goto finish; } switch (mode) { case DUMP: { char t[1024]; if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t))) printf(_("Server: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t))) printf(_("Source: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t))) printf(_("Sink: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t))) printf(_("Cookie: %s\n"), t); break; } case IMPORT: { char t[1024]; if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t))) printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t))) printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t))) printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { fprintf(stderr, _("Failed to parse cookie data\n")); goto finish; } if (pa_authkey_save(cookie_file, cookie, l) < 0) { fprintf(stderr, _("Failed to save cookie data\n")); goto finish; } } break; } case EXPORT: { pa_client_conf *conf = pa_client_conf_new(); uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; assert(conf); pa_client_conf_load(conf, false, true); pa_x11_del_prop(xcb, screen, "PULSE_SERVER"); pa_x11_del_prop(xcb, screen, "PULSE_SINK"); pa_x11_del_prop(xcb, screen, "PULSE_SOURCE"); pa_x11_del_prop(xcb, screen, "PULSE_ID"); pa_x11_del_prop(xcb, screen, "PULSE_COOKIE"); if (server) pa_x11_set_prop(xcb, screen, "PULSE_SERVER", server); else if (conf->default_server) pa_x11_set_prop(xcb, screen, "PULSE_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { fprintf(stderr, _("Failed to get FQDN.\n")); goto finish; } pa_x11_set_prop(xcb, screen, "PULSE_SERVER", hn); } if (sink) pa_x11_set_prop(xcb, screen, "PULSE_SINK", sink); else if (conf->default_sink) pa_x11_set_prop(xcb, screen, "PULSE_SINK", conf->default_sink); if (source) pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", source); if (conf->default_source) pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); if (pa_authkey_load(cookie_file, true, cookie, sizeof(cookie)) < 0) { fprintf(stderr, _("Failed to load cookie data\n")); goto finish; } pa_x11_set_prop(xcb, screen, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: pa_x11_del_prop(xcb, screen, "PULSE_SERVER"); pa_x11_del_prop(xcb, screen, "PULSE_SINK"); pa_x11_del_prop(xcb, screen, "PULSE_SOURCE"); pa_x11_del_prop(xcb, screen, "PULSE_ID"); pa_x11_del_prop(xcb, screen, "PULSE_COOKIE"); pa_x11_del_prop(xcb, screen, "PULSE_SESSION_ID"); break; default: fprintf(stderr, _("Not yet implemented.\n")); goto finish; } ret = 0; finish: if (xcb) { xcb_flush(xcb); xcb_disconnect(xcb); } return ret; }