Esempio n. 1
0
pa_auth_cookie* pa_auth_cookie_get(pa_core *core, const char *cn, bool create, size_t size) {
    pa_auth_cookie *c;
    char *t;

    pa_assert(core);
    pa_assert(size > 0);

    t = pa_sprintf_malloc("auth-cookie%s%s", cn ? "@" : "", cn ? cn : "");

    if ((c = pa_shared_get(core, t))) {

        pa_xfree(t);

        if (c->size != size)
            return NULL;

        return pa_auth_cookie_ref(c);
    }

    c = pa_xmalloc(PA_ALIGN(sizeof(pa_auth_cookie)) + size);
    PA_REFCNT_INIT(c);
    c->core = core;
    c->name = t;
    c->size = size;

    pa_assert_se(pa_shared_set(core, t, c) >= 0);

    if (pa_authkey_load(cn, create, (uint8_t*) c + PA_ALIGN(sizeof(pa_auth_cookie)), size) < 0) {
        pa_auth_cookie_unref(c);
        return NULL;
    }

    return c;
}
Esempio n. 2
0
/* If the specified file path starts with / return it, otherwise
 * return path prepended with home directory */
static char *normalize_path(const char *fn) {

    pa_assert(fn);

#ifndef OS_IS_WIN32
    if (fn[0] != '/') {
#else
    if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
#endif
        char *homedir, *s;

        if (!(homedir = pa_get_home_dir_malloc()))
            return NULL;

        s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
        pa_xfree(homedir);

        return s;
    }

    return pa_xstrdup(fn);
}

/* Load a cookie from a file in the home directory. If the specified
 * path starts with /, use it as absolute path instead. */
int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
    char *p;
    int ret;

    pa_assert(fn);
    pa_assert(data);
    pa_assert(length > 0);

    if (!(p = normalize_path(fn)))
        return -2;

    ret = pa_authkey_load(p, data, length);
    pa_xfree(p);

    return ret;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_modargs *ma = NULL;
    const char *espeaker;
    uint32_t key;
    pa_sink_new_data data;
    char *cookie_path;
    int r;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log("failed to parse module arguments");
        goto fail;
    }

    ss = m->core->default_sample_spec;
    if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
        pa_log("invalid sample format specification");
        goto fail;
    }

    if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) ||
        (ss.channels > 2)) {
        pa_log("esound sample type support is limited to mono/stereo and U8 or S16NE sample data");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    m->userdata = u;
    u->fd = -1;
    u->smoother = pa_smoother_new(
            PA_USEC_PER_SEC,
            PA_USEC_PER_SEC*2,
            true,
            true,
            10,
            0,
            false);
    pa_memchunk_reset(&u->memchunk);
    u->offset = 0;

    u->rtpoll = pa_rtpoll_new();

    if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) {
        pa_log("pa_thread_mq_init() failed.");
        goto fail;
    }

    u->rtpoll_item = NULL;

    u->format =
        (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) |
        (ss.channels == 2 ? ESD_STEREO : ESD_MONO);
    u->rate = (int32_t) ss.rate;
    u->block_size = pa_usec_to_bytes(PA_USEC_PER_SEC/20, &ss);

    u->read_data = u->write_data = NULL;
    u->read_index = u->write_index = u->read_length = u->write_length = 0;

    u->state = STATE_AUTH;
    u->latency = 0;

    if (!(espeaker = getenv("ESPEAKER")))
        espeaker = ESD_UNIX_SOCKET_NAME;

    espeaker = pa_modargs_get_value(ma, "server", espeaker);

    pa_sink_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
    pa_sink_new_data_set_sample_spec(&data, &ss);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, espeaker);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "esd");
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "EsounD Output on %s", espeaker);

    if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Invalid properties");
        pa_sink_new_data_done(&data);
        goto fail;
    }

    u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY|PA_SINK_NETWORK);
    pa_sink_new_data_done(&data);

    if (!u->sink) {
        pa_log("Failed to create sink.");
        goto fail;
    }

    u->sink->parent.process_msg = sink_process_msg;
    u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
    u->sink->userdata = u;

    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
    pa_sink_set_rtpoll(u->sink, u->rtpoll);

    if (!(u->client = pa_socket_client_new_string(u->core->mainloop, true, espeaker, ESD_DEFAULT_PORT))) {
        pa_log("Failed to connect to server.");
        goto fail;
    }

    pa_socket_client_set_callback(u->client, on_connection, u);

    cookie_path = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
    if (!cookie_path) {
        if (pa_append_to_home_dir(".esd_auth", &cookie_path) < 0)
            goto fail;
    }

    /* Prepare the initial request */
    u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t));

    r = pa_authkey_load(cookie_path, true, u->write_data, ESD_KEY_LEN);
    pa_xfree(cookie_path);
    if (r < 0) {
        pa_log("Failed to load cookie");
        goto fail;
    }

    key = ESD_ENDIAN_KEY;
    memcpy((uint8_t*) u->write_data + ESD_KEY_LEN, &key, sizeof(key));

    /* Reserve space for the response */
    u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t));

    if (!(u->thread = pa_thread_new("esound-sink", thread_func, u))) {
        pa_log("Failed to create thread.");
        goto fail;
    }

    pa_sink_put(u->sink);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}