Esempio n. 1
0
/* Called from output thread context */
static void sink_input_attach_cb(pa_sink_input *i) {
    struct userdata *u;

    pa_sink_input_assert_ref(i);
    pa_sink_input_assert_io_context(i);
    pa_assert_se(u = i->userdata);

    u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
            i->sink->thread_info.rtpoll,
            PA_RTPOLL_LATE,
            u->asyncmsgq);

    pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
    pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
}
Esempio n. 2
0
void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop, pa_rtpoll *rtpoll) {
    pa_assert(q);
    pa_assert(mainloop);

    q->mainloop = mainloop;
    pa_assert_se(q->inq = pa_asyncmsgq_new(0));
    pa_assert_se(q->outq = pa_asyncmsgq_new(0));

    pa_assert_se(pa_asyncmsgq_read_before_poll(q->outq) == 0);
    pa_assert_se(q->read_event = mainloop->io_new(mainloop, pa_asyncmsgq_read_fd(q->outq), PA_IO_EVENT_INPUT, asyncmsgq_read_cb, q));

    pa_asyncmsgq_write_before_poll(q->inq);
    pa_assert_se(q->write_event = mainloop->io_new(mainloop, pa_asyncmsgq_write_fd(q->inq), PA_IO_EVENT_INPUT, asyncmsgq_write_cb, q));

    pa_rtpoll_item_new_asyncmsgq_read(rtpoll, PA_RTPOLL_EARLY, q->inq);
    pa_rtpoll_item_new_asyncmsgq_write(rtpoll, PA_RTPOLL_LATE, q->outq);
}
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    jack_status_t status;
    const char *server_name, *client_name;
    uint32_t channels = 0;
    pa_bool_t do_connect = TRUE;
    unsigned i;
    const char **ports = NULL, **p;
    pa_sink_new_data data;

    pa_assert(m);

    jack_set_error_function(jack_error_func);

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

    if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) {
        pa_log("Failed to parse connect= argument.");
        goto fail;
    }

    server_name = pa_modargs_get_value(ma, "server_name", NULL);
    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Sink");

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->saved_frame_time_valid = FALSE;
    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    /* The queue linking the JACK thread and our RT thread */
    u->jack_msgq = pa_asyncmsgq_new(0);

    /* The msgq from the JACK RT thread should have an even higher
     * priority than the normal message queues, to match the guarantee
     * all other drivers make: supplying the audio device with data is
     * the top priority -- and as long as that is possible we don't do
     * anything else */
    u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq_read(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq);

    if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) {
        pa_log("jack_client_open() failed.");
        goto fail;
    }

    ports = jack_get_ports(u->client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsInput);

    channels = 0;
    for (p = ports; *p; p++)
        channels++;

    if (!channels)
        channels = m->core->default_sample_spec.channels;

    if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 ||
        channels <= 0 ||
        channels > PA_CHANNELS_MAX) {
        pa_log("Failed to parse channels= argument.");
        goto fail;
    }

    if (channels == m->core->default_channel_map.channels)
        map = m->core->default_channel_map;
    else
        pa_channel_map_init_extend(&map, channels, PA_CHANNEL_MAP_ALSA);

    if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
        pa_log("Failed to parse channel_map= argument.");
        goto fail;
    }

    pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client));

    u->channels = ss.channels = (uint8_t) channels;
    ss.rate = jack_get_sample_rate(u->client);
    ss.format = PA_SAMPLE_FLOAT32NE;

    pa_assert(pa_sample_spec_valid(&ss));

    for (i = 0; i < ss.channels; i++) {
        if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) {
            pa_log("jack_port_register() failed.");
            goto fail;
        }
    }

    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_sink_new_data_set_channel_map(&data, &map);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "jack");
    if (server_name)
        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, server_name);
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Jack sink (%s)", jack_get_client_name(u->client));
    pa_proplist_sets(data.proplist, "jack.client_name", jack_get_client_name(u->client));

    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_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->userdata = u;

    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
    pa_sink_set_rtpoll(u->sink, u->rtpoll);
    pa_sink_set_max_request(u->sink, jack_get_buffer_size(u->client) * pa_frame_size(&u->sink->sample_spec));

    jack_set_process_callback(u->client, jack_process, u);
    jack_on_shutdown(u->client, jack_shutdown, u);
    jack_set_thread_init_callback(u->client, jack_init, u);
    jack_set_buffer_size_callback(u->client, jack_buffer_size, u);

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

    if (jack_activate(u->client)) {
        pa_log("jack_activate() failed");
        goto fail;
    }

    if (do_connect) {
        for (i = 0, p = ports; i < ss.channels; i++, p++) {

            if (!*p) {
                pa_log("Not enough physical output ports, leaving unconnected.");
                break;
            }

            pa_log_info("Connecting %s to %s", jack_port_name(u->port[i]), *p);

            if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) {
                pa_log("Failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p);
                break;
            }
        }
    }

    pa_sink_put(u->sink);

    free(ports);
    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    free(ports);

    pa__done(m);

    return -1;
}