Ejemplo n.º 1
0
int pa__init(pa_module*m) {
    pa_modargs *ma = NULL;
    struct userdata *u;

    pa_assert(m);

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

    m->userdata = u = pa_xnew(struct userdata, 1);
    u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
    u->put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) put_hook_callback, u);
    u->unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) unlink_hook_callback, u);
    u->null_module = PA_INVALID_INDEX;
    u->ignore = FALSE;

    pa_modargs_free(ma);

    load_null_sink_if_needed(m->core, NULL, u);

    return 0;
}
Ejemplo n.º 2
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma;
    char *t;
    pa_sink *master;
    pa_sink_input_new_data sink_input_data;
    pa_sink_new_data sink_data;
    const char *plugin, *label;
    LADSPA_Descriptor_Function descriptor_func;
    const char *e, *cdata;
    const LADSPA_Descriptor *d;
    unsigned long input_port, output_port, p, j, n_control;
    unsigned c;
    pa_bool_t *use_default = NULL;

    pa_assert(m);

    pa_assert_cc(sizeof(LADSPA_Data) == sizeof(float));

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

    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) {
        pa_log("Master sink not found");
        goto fail;
    }

    ss = master->sample_spec;
    ss.format = PA_SAMPLE_FLOAT32;
    map = master->channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    if (!(plugin = pa_modargs_get_value(ma, "plugin", NULL))) {
        pa_log("Missing LADSPA plugin name");
        goto fail;
    }

    if (!(label = pa_modargs_get_value(ma, "label", NULL))) {
        pa_log("Missing LADSPA plugin label");
        goto fail;
    }

    cdata = pa_modargs_get_value(ma, "control", NULL);

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;
    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);

    if (!(e = getenv("LADSPA_PATH")))
        e = LADSPA_PATH;

    /* FIXME: This is not exactly thread safe */
    t = pa_xstrdup(lt_dlgetsearchpath());
    lt_dlsetsearchpath(e);
    m->dl = lt_dlopenext(plugin);
    lt_dlsetsearchpath(t);
    pa_xfree(t);

    if (!m->dl) {
        pa_log("Failed to load LADSPA plugin: %s", lt_dlerror());
        goto fail;
    }

    if (!(descriptor_func = (LADSPA_Descriptor_Function) pa_load_sym(m->dl, NULL, "ladspa_descriptor"))) {
        pa_log("LADSPA module lacks ladspa_descriptor() symbol.");
        goto fail;
    }

    for (j = 0;; j++) {

        if (!(d = descriptor_func(j))) {
            pa_log("Failed to find plugin label '%s' in plugin '%s'.", label, plugin);
            goto fail;
        }

        if (strcmp(d->Label, label) == 0)
            break;
    }

    u->descriptor = d;

    pa_log_debug("Module: %s", plugin);
    pa_log_debug("Label: %s", d->Label);
    pa_log_debug("Unique ID: %lu", d->UniqueID);
    pa_log_debug("Name: %s", d->Name);
    pa_log_debug("Maker: %s", d->Maker);
    pa_log_debug("Copyright: %s", d->Copyright);

    input_port = output_port = (unsigned long) -1;
    n_control = 0;

    for (p = 0; p < d->PortCount; p++) {

        if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {

            if (strcmp(d->PortNames[p], "Input") == 0) {
                pa_assert(input_port == (unsigned long) -1);
                input_port = p;
            } else {
                pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]);
                goto fail;
            }

        } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {

            if (strcmp(d->PortNames[p], "Output") == 0) {
                pa_assert(output_port == (unsigned long) -1);
                output_port = p;
            } else {
                pa_log("Found audio output port on plugin we cannot handle: %s", d->PortNames[p]);
                goto fail;
            }

        } else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
            n_control++;
        else {
            pa_assert(LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]));
            pa_log_debug("Ignored control output port \"%s\".", d->PortNames[p]);
        }
    }

    if ((input_port == (unsigned long) -1) || (output_port == (unsigned long) -1)) {
        pa_log("Failed to identify input and output ports. "
               "Right now this module can only deal with plugins which provide an 'Input' and an 'Output' audio port. "
               "Patches welcome!");
        goto fail;
    }

    u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss);

    u->input = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
    if (LADSPA_IS_INPLACE_BROKEN(d->Properties))
        u->output = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
    else
        u->output = u->input;

    u->channels = ss.channels;

    for (c = 0; c < ss.channels; c++) {
        if (!(u->handle[c] = d->instantiate(d, ss.rate))) {
            pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c);
            goto fail;
        }

        d->connect_port(u->handle[c], input_port, u->input);
        d->connect_port(u->handle[c], output_port, u->output);
    }

    if (!cdata && n_control > 0) {
        pa_log("This plugin requires specification of %lu control parameters.", n_control);
        goto fail;
    }

    if (n_control > 0) {
        const char *state = NULL;
        char *k;
        unsigned long h;

        u->control = pa_xnew(LADSPA_Data, (unsigned) n_control);
        use_default = pa_xnew(pa_bool_t, (unsigned) n_control);
        p = 0;

        while ((k = pa_split(cdata, ",", &state)) && p < n_control) {
            double f;

            if (*k == 0) {
                use_default[p++] = TRUE;
                pa_xfree(k);
                continue;
            }

            if (pa_atod(k, &f) < 0) {
                pa_log("Failed to parse control value '%s'", k);
                pa_xfree(k);
                goto fail;
            }

            pa_xfree(k);

            use_default[p] = FALSE;
            u->control[p++] = (LADSPA_Data) f;
        }

        /* The previous loop doesn't take the last control value into account
           if it is left empty, so we do it here. */
        if (*cdata == 0 || cdata[strlen(cdata) - 1] == ',') {
            if (p < n_control)
                use_default[p] = TRUE;
            p++;
        }

        if (p > n_control || k) {
            pa_log("Too many control values passed, %lu expected.", n_control);
            pa_xfree(k);
            goto fail;
        }

        if (p < n_control) {
            pa_log("Not enough control values passed, %lu expected, %lu passed.", n_control, p);
            goto fail;
        }

        h = 0;
        for (p = 0; p < d->PortCount; p++) {
            LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor;

            if (!LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
                continue;

            if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
                for (c = 0; c < ss.channels; c++)
                    d->connect_port(u->handle[c], p, &u->control_out);
                continue;
            }

            pa_assert(h < n_control);

            if (use_default[h]) {
                LADSPA_Data lower, upper;

                if (!LADSPA_IS_HINT_HAS_DEFAULT(hint)) {
                    pa_log("Control port value left empty but plugin defines no default.");
                    goto fail;
                }

                lower = d->PortRangeHints[p].LowerBound;
                upper = d->PortRangeHints[p].UpperBound;

                if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) {
                    lower *= (LADSPA_Data) ss.rate;
                    upper *= (LADSPA_Data) ss.rate;
                }

                switch (hint & LADSPA_HINT_DEFAULT_MASK) {

                    case LADSPA_HINT_DEFAULT_MINIMUM:
                        u->control[h] = lower;
                        break;

                    case LADSPA_HINT_DEFAULT_MAXIMUM:
                        u->control[h] = upper;
                        break;

                    case LADSPA_HINT_DEFAULT_LOW:
                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25);
                        else
                            u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25);
                        break;

                    case LADSPA_HINT_DEFAULT_MIDDLE:
                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5);
                        else
                            u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5);
                        break;

                    case LADSPA_HINT_DEFAULT_HIGH:
                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75);
                        else
                            u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75);
                        break;

                    case LADSPA_HINT_DEFAULT_0:
                        u->control[h] = 0;
                        break;

                    case LADSPA_HINT_DEFAULT_1:
                        u->control[h] = 1;
                        break;

                    case LADSPA_HINT_DEFAULT_100:
                        u->control[h] = 100;
                        break;

                    case LADSPA_HINT_DEFAULT_440:
                        u->control[h] = 440;
                        break;

                    default:
                        pa_assert_not_reached();
                }
            }

            if (LADSPA_IS_HINT_INTEGER(hint))
                u->control[h] = roundf(u->control[h]);

            pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]);

            for (c = 0; c < ss.channels; c++)
                d->connect_port(u->handle[c], p, &u->control[h]);

            h++;
        }

        pa_assert(h == n_control);
    }

    if (d->activate)
        for (c = 0; c < u->channels; c++)
            d->activate(u->handle[c]);

    /* Create sink */
    pa_sink_new_data_init(&sink_data);
    sink_data.driver = __FILE__;
    sink_data.module = m;
    if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
        sink_data.name = pa_sprintf_malloc("%s.ladspa", master->name);
    pa_sink_new_data_set_sample_spec(&sink_data, &ss);
    pa_sink_new_data_set_channel_map(&sink_data, &map);
    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
    pa_proplist_sets(sink_data.proplist, "device.ladspa.module", plugin);
    pa_proplist_sets(sink_data.proplist, "device.ladspa.label", d->Label);
    pa_proplist_sets(sink_data.proplist, "device.ladspa.name", d->Name);
    pa_proplist_sets(sink_data.proplist, "device.ladspa.maker", d->Maker);
    pa_proplist_sets(sink_data.proplist, "device.ladspa.copyright", d->Copyright);
    pa_proplist_setf(sink_data.proplist, "device.ladspa.unique_id", "%lu", (unsigned long) d->UniqueID);

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

    if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
        const char *z;

        z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name);
    }

    u->sink = pa_sink_new(m->core, &sink_data,
                          PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME|
                          (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)));
    pa_sink_new_data_done(&sink_data);

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

    u->sink->parent.process_msg = sink_process_msg_cb;
    u->sink->set_state = sink_set_state_cb;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    u->sink->request_rewind = sink_request_rewind_cb;
    u->sink->set_volume = sink_set_volume_cb;
    u->sink->set_mute = sink_set_mute_cb;
    u->sink->userdata = u;

    pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);

    /* Create sink input */
    pa_sink_input_new_data_init(&sink_input_data);
    sink_input_data.driver = __FILE__;
    sink_input_data.module = m;
    sink_input_data.sink = master;
    pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "LADSPA Stream");
    pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
    pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
    pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);

    pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
    pa_sink_input_new_data_done(&sink_input_data);

    if (!u->sink_input)
        goto fail;

    u->sink_input->pop = sink_input_pop_cb;
    u->sink_input->process_rewind = sink_input_process_rewind_cb;
    u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
    u->sink_input->update_max_request = sink_input_update_max_request_cb;
    u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
    u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
    u->sink_input->kill = sink_input_kill_cb;
    u->sink_input->attach = sink_input_attach_cb;
    u->sink_input->detach = sink_input_detach_cb;
    u->sink_input->state_change = sink_input_state_change_cb;
    u->sink_input->may_move_to = sink_input_may_move_to_cb;
    u->sink_input->moving = sink_input_moving_cb;
    u->sink_input->volume_changed = sink_input_volume_changed_cb;
    u->sink_input->mute_changed = sink_input_mute_changed_cb;
    u->sink_input->userdata = u;

    pa_sink_put(u->sink);
    pa_sink_input_put(u->sink_input);

    pa_modargs_free(ma);

    pa_xfree(use_default);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa_xfree(use_default);

    pa__done(m);

    return -1;
}
Ejemplo n.º 3
0
pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
                           pa_sample_spec *source_ss, pa_channel_map *source_map,
                           pa_sample_spec *sink_ss, pa_channel_map *sink_map,
                           uint32_t *nframes, const char *args)
{
    int rate;
    uint32_t y, frame_size_ms, filter_size_ms;
    pa_modargs *ma;

    if (!(ma = pa_modargs_new(args, valid_modargs))) {
        pa_log("Failed to parse submodule arguments.");
        goto fail;
    }

    filter_size_ms = DEFAULT_FILTER_SIZE_MS;
    if (pa_modargs_get_value_u32(ma, "filter_size_ms", &filter_size_ms) < 0 || filter_size_ms < 1 || filter_size_ms > 2000) {
        pa_log("Invalid filter_size_ms specification");
        goto fail;
    }

    frame_size_ms = DEFAULT_FRAME_SIZE_MS;
    if (pa_modargs_get_value_u32(ma, "frame_size_ms", &frame_size_ms) < 0 || frame_size_ms < 1 || frame_size_ms > 200) {
        pa_log("Invalid frame_size_ms specification");
        goto fail;
    }

    pa_speex_ec_fixate_spec(source_ss, source_map, sink_ss, sink_map);

    rate = source_ss->rate;
    *nframes = (rate * frame_size_ms) / 1000;
    /* nframes should be a power of 2, round down to nearest power of two */
    y = 1 << ((8 * sizeof (uint32_t)) - 2);
    while (y > *nframes)
      y >>= 1;
    *nframes = y;

    pa_log_debug ("Using nframes %d, channels %d, rate %d", *nframes, source_ss->channels, source_ss->rate);

    ec->params.priv.speex.state = speex_echo_state_init_mc (*nframes, (rate * filter_size_ms) / 1000, source_ss->channels, source_ss->channels);

    if (!ec->params.priv.speex.state)
        goto fail;

    speex_echo_ctl(ec->params.priv.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);

    if (!pa_speex_ec_preprocessor_init(ec, source_ss, *nframes, ma))
        goto fail;

    pa_modargs_free(ma);
    return TRUE;

fail:
    if (ma)
        pa_modargs_free(ma);
    if (ec->params.priv.speex.pp_state) {
        speex_preprocess_state_destroy(ec->params.priv.speex.pp_state);
        ec->params.priv.speex.pp_state = NULL;
    }
    if (ec->params.priv.speex.state) {
        speex_echo_state_destroy(ec->params.priv.speex.state);
        ec->params.priv.speex.state = NULL;
    }
    return FALSE;
}
int pa__init(pa_module *m) {
    pa_modargs *ma = NULL;
    struct userdata *u;
    pa_sink *sink = NULL;
    pa_sink_input_new_data sink_input_data;
    pa_bool_t sink_dont_move;
    pa_source *source = NULL;
    pa_source_output_new_data source_output_data;
    pa_bool_t source_dont_move;
    uint32_t latency_msec;
    pa_sample_spec ss;
    pa_channel_map map;
    bool format_set = false;
    bool rate_set = false;
    bool channels_set = false;
    pa_memchunk silence;
    uint32_t adjust_time_sec;
    const char *n;
    pa_bool_t remix = TRUE;

    pa_assert(m);

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

    n = pa_modargs_get_value(ma, "source", NULL);
    if (n && !(source = pa_namereg_get(m->core, n, PA_NAMEREG_SOURCE))) {
        pa_log("No such source.");
        goto fail;
    }

    n = pa_modargs_get_value(ma, "sink", NULL);
    if (n && !(sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK))) {
        pa_log("No such sink.");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
        pa_log("Invalid boolean remix parameter");
        goto fail;
    }

    if (sink) {
        ss = sink->sample_spec;
        map = sink->channel_map;
        format_set = true;
        rate_set = true;
        channels_set = true;
    } else if (source) {
        ss = source->sample_spec;
        map = source->channel_map;
        format_set = true;
        rate_set = true;
        channels_set = true;
    } else {
        /* FIXME: Dummy stream format, needed because pa_sink_input_new()
         * requires valid sample spec and channel map even when all the FIX_*
         * stream flags are specified. pa_sink_input_new() should be changed
         * to ignore the sample spec and channel map when the FIX_* flags are
         * present. */
        ss.format = PA_SAMPLE_U8;
        ss.rate = 8000;
        ss.channels = 1;
        map.channels = 1;
        map.map[0] = PA_CHANNEL_POSITION_MONO;
    }

    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    if (pa_modargs_get_value(ma, "format", NULL))
        format_set = true;

    if (pa_modargs_get_value(ma, "rate", NULL))
        rate_set = true;

    if (pa_modargs_get_value(ma, "channels", NULL) || pa_modargs_get_value(ma, "channel_map", NULL))
        channels_set = true;

    latency_msec = DEFAULT_LATENCY_MSEC;
    if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
        pa_log("Invalid latency specification");
        goto fail;
    }

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;

    adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
    if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
        pa_log("Failed to parse adjust_time value");
        goto fail;
    }

    if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
        u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
    else
        u->adjust_time = DEFAULT_ADJUST_TIME_USEC;

    pa_sink_input_new_data_init(&sink_input_data);
    sink_input_data.driver = __FILE__;
    sink_input_data.module = m;

    if (sink)
        pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE);

    if (pa_modargs_get_proplist(ma, "sink_input_properties", sink_input_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Failed to parse the sink_input_properties value.");
        pa_sink_input_new_data_done(&sink_input_data);
        goto fail;
    }

    if (!pa_proplist_contains(sink_input_data.proplist, PA_PROP_MEDIA_ROLE))
        pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");

    pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
    pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
    sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE | PA_SINK_INPUT_START_CORKED;

    if (!remix)
        sink_input_data.flags |= PA_SINK_INPUT_NO_REMIX;

    if (!format_set)
        sink_input_data.flags |= PA_SINK_INPUT_FIX_FORMAT;

    if (!rate_set)
        sink_input_data.flags |= PA_SINK_INPUT_FIX_RATE;

    if (!channels_set)
        sink_input_data.flags |= PA_SINK_INPUT_FIX_CHANNELS;

    sink_dont_move = FALSE;
    if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) {
        pa_log("sink_dont_move= expects a boolean argument.");
        goto fail;
    }

    if (sink_dont_move)
        sink_input_data.flags |= PA_SINK_INPUT_DONT_MOVE;

    pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
    pa_sink_input_new_data_done(&sink_input_data);

    if (!u->sink_input)
        goto fail;

    /* If format, rate or channels were originally unset, they are set now
     * after the pa_sink_input_new() call. */
    ss = u->sink_input->sample_spec;
    map = u->sink_input->channel_map;

    u->sink_input->parent.process_msg = sink_input_process_msg_cb;
    u->sink_input->pop = sink_input_pop_cb;
    u->sink_input->process_rewind = sink_input_process_rewind_cb;
    u->sink_input->kill = sink_input_kill_cb;
    u->sink_input->state_change = sink_input_state_change_cb;
    u->sink_input->attach = sink_input_attach_cb;
    u->sink_input->detach = sink_input_detach_cb;
    u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
    u->sink_input->update_max_request = sink_input_update_max_request_cb;
    u->sink_input->may_move_to = sink_input_may_move_to_cb;
    u->sink_input->moving = sink_input_moving_cb;
    u->sink_input->suspend = sink_input_suspend_cb;
    u->sink_input->userdata = u;

    pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);

    pa_source_output_new_data_init(&source_output_data);
    source_output_data.driver = __FILE__;
    source_output_data.module = m;
    if (source)
        pa_source_output_new_data_set_source(&source_output_data, source, FALSE);

    if (pa_modargs_get_proplist(ma, "source_output_properties", source_output_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Failed to parse the source_output_properties value.");
        pa_source_output_new_data_done(&source_output_data);
        goto fail;
    }

    if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_ROLE))
        pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");

    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
    pa_source_output_new_data_set_channel_map(&source_output_data, &map);
    source_output_data.flags = PA_SOURCE_OUTPUT_START_CORKED;

    if (!remix)
        source_output_data.flags |= PA_SOURCE_OUTPUT_NO_REMIX;

    source_dont_move = FALSE;
    if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
        pa_log("source_dont_move= expects a boolean argument.");
        goto fail;
    }

    if (source_dont_move)
        source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;

    pa_source_output_new(&u->source_output, m->core, &source_output_data);
    pa_source_output_new_data_done(&source_output_data);

    if (!u->source_output)
        goto fail;

    u->source_output->parent.process_msg = source_output_process_msg_cb;
    u->source_output->push = source_output_push_cb;
    u->source_output->process_rewind = source_output_process_rewind_cb;
    u->source_output->kill = source_output_kill_cb;
    u->source_output->attach = source_output_attach_cb;
    u->source_output->detach = source_output_detach_cb;
    u->source_output->state_change = source_output_state_change_cb;
    u->source_output->may_move_to = source_output_may_move_to_cb;
    u->source_output->moving = source_output_moving_cb;
    u->source_output->suspend = source_output_suspend_cb;
    u->source_output->userdata = u;

    pa_source_output_set_requested_latency(u->source_output, u->latency/3);

    pa_sink_input_get_silence(u->sink_input, &silence);
    u->memblockq = pa_memblockq_new(
            "module-loopback memblockq",
            0,                      /* idx */
            MEMBLOCKQ_MAXLENGTH,    /* maxlength */
            MEMBLOCKQ_MAXLENGTH,    /* tlength */
            &ss,                    /* sample_spec */
            0,                      /* prebuf */
            0,                      /* minreq */
            0,                      /* maxrewind */
            &silence);              /* silence frame */
    pa_memblock_unref(silence.memblock);

    u->asyncmsgq = pa_asyncmsgq_new(0);

    if (!pa_proplist_contains(u->source_output->proplist, PA_PROP_MEDIA_NAME))
        pa_proplist_setf(u->source_output->proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
                         pa_strnull(pa_proplist_gets(u->sink_input->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));

    if (!pa_proplist_contains(u->source_output->proplist, PA_PROP_MEDIA_ICON_NAME)
            && (n = pa_proplist_gets(u->sink_input->sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
        pa_proplist_sets(u->source_output->proplist, PA_PROP_MEDIA_ICON_NAME, n);

    if (!pa_proplist_contains(u->sink_input->proplist, PA_PROP_MEDIA_NAME))
        pa_proplist_setf(u->sink_input->proplist, PA_PROP_MEDIA_NAME, "Loopback from %s",
                         pa_strnull(pa_proplist_gets(u->source_output->source->proplist, PA_PROP_DEVICE_DESCRIPTION)));

    if (source && !pa_proplist_contains(u->sink_input->proplist, PA_PROP_MEDIA_ICON_NAME)
            && (n = pa_proplist_gets(u->source_output->source->proplist, PA_PROP_DEVICE_ICON_NAME)))
        pa_proplist_sets(u->sink_input->proplist, PA_PROP_MEDIA_ICON_NAME, n);

    pa_sink_input_put(u->sink_input);
    pa_source_output_put(u->source_output);

    if (pa_source_get_state(u->source_output->source) != PA_SOURCE_SUSPENDED)
	    pa_sink_input_cork(u->sink_input, FALSE);

    if (pa_sink_get_state(u->sink_input->sink) != PA_SINK_SUSPENDED)
	    pa_source_output_cork(u->source_output, FALSE);

    update_adjust_timer(u);

    pa_modargs_free(ma);
    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_modargs *ma;
    pa_source_new_data data;
    uint32_t frequency;
    pa_sample_spec ss;

    pa_assert(m);

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

    ss.format = PA_SAMPLE_FLOAT32;
    ss.channels = 1;
    ss.rate = 44100;

    if (pa_modargs_get_value_u32(ma, "rate", &ss.rate) < 0 || ss.rate <= 1) {
        pa_log("Invalid rate specification");
        goto fail;
    }

    frequency = 440;
    if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) {
        pa_log("Invalid frequency specification");
        goto fail;
    }

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

    u->peek_index = 0;
    pa_memchunk_sine(&u->memchunk, m->core->mempool, ss.rate, frequency);

    pa_source_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Sine source at %u Hz", (unsigned) frequency);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
    pa_proplist_setf(data.proplist, "sine.hz", "%u", frequency);
    pa_source_new_data_set_sample_spec(&data, &ss);

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

    u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY);
    pa_source_new_data_done(&data);

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

    u->source->parent.process_msg = source_process_msg;
    u->source->update_requested_latency = source_update_requested_latency_cb;
    u->source->userdata = u;

    u->block_usec = BLOCK_USEC;

    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
    pa_source_set_rtpoll(u->source, u->rtpoll);
    pa_source_set_fixed_latency(u->source, u->block_usec);

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

    pa_source_put(u->source);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
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;
}
Ejemplo n.º 7
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_modargs *ma = NULL;
    const char *dst_addr;
    const char *src_addr;
    uint32_t port = DEFAULT_PORT, mtu;
    uint32_t ttl = DEFAULT_TTL;
    sa_family_t af;
    int fd = -1, sap_fd = -1;
    pa_source *s;
    pa_sample_spec ss;
    pa_channel_map cm;
    struct sockaddr_in dst_sa4, dst_sap_sa4, src_sa4, src_sap_sa4;
#ifdef HAVE_IPV6
    struct sockaddr_in6 dst_sa6, dst_sap_sa6, src_sa6, src_sap_sa6;
#endif
    struct sockaddr_storage sa_dst;
    pa_source_output *o = NULL;
    uint8_t payload;
    char *p;
    int r, j;
    socklen_t k;
    char hn[128], *n;
    bool loop = false;
    enum inhibit_auto_suspend inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES;
    const char *inhibit_auto_suspend_str;
    pa_source_output_new_data data;

    pa_assert(m);

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

    if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
        pa_log("Source does not exist.");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) {
        pa_log("Failed to parse \"loop\" parameter.");
        goto fail;
    }

    if ((inhibit_auto_suspend_str = pa_modargs_get_value(ma, "inhibit_auto_suspend", NULL))) {
        if (pa_streq(inhibit_auto_suspend_str, "always"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ALWAYS;
        else if (pa_streq(inhibit_auto_suspend_str, "never"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_NEVER;
        else if (pa_streq(inhibit_auto_suspend_str, "only_with_non_monitor_sources"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES;
        else {
            pa_log("Failed to parse the \"inhibit_auto_suspend\" parameter.");
            goto fail;
        }
    }

    ss = s->sample_spec;
    pa_rtp_sample_spec_fixup(&ss);
    cm = s->channel_map;
    if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
        pa_log("Failed to parse sample specification");
        goto fail;
    }

    if (!pa_rtp_sample_spec_valid(&ss)) {
        pa_log("Specified sample type not compatible with RTP");
        goto fail;
    }

    if (ss.channels != cm.channels)
        pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AIFF);

    payload = pa_rtp_payload_from_sample_spec(&ss);

    mtu = (uint32_t) pa_frame_align(DEFAULT_MTU, &ss);

    if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) {
        pa_log("Invalid MTU.");
        goto fail;
    }

    port = DEFAULT_PORT + ((uint32_t) (rand() % 512) << 1);
    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
        pa_log("port= expects a numerical argument between 1 and 65535.");
        goto fail;
    }

    if (port & 1)
        pa_log_warn("Port number not even as suggested in RFC3550!");

    if (pa_modargs_get_value_u32(ma, "ttl", &ttl) < 0 || ttl < 1 || ttl > 0xFF) {
        pa_log("ttl= expects a numerical argument between 1 and 255.");
        goto fail;
    }

    src_addr = pa_modargs_get_value(ma, "source_ip", DEFAULT_SOURCE_IP);

    if (inet_pton(AF_INET, src_addr, &src_sa4.sin_addr) > 0) {
        src_sa4.sin_family = af = AF_INET;
        src_sa4.sin_port = htons(0);
        memset(&src_sa4.sin_zero, 0, sizeof(src_sa4.sin_zero));
        src_sap_sa4 = src_sa4;
#ifdef HAVE_IPV6
    } else if (inet_pton(AF_INET6, src_addr, &src_sa6.sin6_addr) > 0) {
        src_sa6.sin6_family = af = AF_INET6;
        src_sa6.sin6_port = htons(0);
        src_sa6.sin6_flowinfo = 0;
        src_sa6.sin6_scope_id = 0;
        src_sap_sa6 = src_sa6;
#endif
    } else {
        pa_log("Invalid source address '%s'", src_addr);
        goto fail;
    }

    dst_addr = pa_modargs_get_value(ma, "destination", NULL);
    if (dst_addr == NULL)
        dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP);

    if (inet_pton(AF_INET, dst_addr, &dst_sa4.sin_addr) > 0) {
        dst_sa4.sin_family = af = AF_INET;
        dst_sa4.sin_port = htons((uint16_t) port);
        memset(&dst_sa4.sin_zero, 0, sizeof(dst_sa4.sin_zero));
        dst_sap_sa4 = dst_sa4;
        dst_sap_sa4.sin_port = htons(SAP_PORT);
#ifdef HAVE_IPV6
    } else if (inet_pton(AF_INET6, dst_addr, &dst_sa6.sin6_addr) > 0) {
        dst_sa6.sin6_family = af = AF_INET6;
        dst_sa6.sin6_port = htons((uint16_t) port);
        dst_sa6.sin6_flowinfo = 0;
        dst_sa6.sin6_scope_id = 0;
        dst_sap_sa6 = dst_sa6;
        dst_sap_sa6.sin6_port = htons(SAP_PORT);
#endif
    } else {
        pa_log("Invalid destination '%s'", dst_addr);
        goto fail;
    }

    if ((fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) {
        pa_log("socket() failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (af == AF_INET && bind(fd, (struct sockaddr*) &src_sa4, sizeof(src_sa4)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && bind(fd, (struct sockaddr*) &src_sa6, sizeof(src_sa6)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && connect(fd, (struct sockaddr*) &dst_sa6, sizeof(dst_sa6)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if ((sap_fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) {
        pa_log("socket() failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (af == AF_INET && bind(sap_fd, (struct sockaddr*) &src_sap_sa4, sizeof(src_sap_sa4)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && bind(sap_fd, (struct sockaddr*) &src_sap_sa6, sizeof(src_sap_sa6)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if (af == AF_INET && connect(sap_fd, (struct sockaddr*) &dst_sap_sa4, sizeof(dst_sap_sa4)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && connect(sap_fd, (struct sockaddr*) &dst_sap_sa6, sizeof(dst_sap_sa6)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    j = loop;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0 ||
        setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0) {
        pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (ttl != DEFAULT_TTL) {
        int _ttl = (int) ttl;

        if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) {
            pa_log("IP_MULTICAST_TTL failed: %s", pa_cstrerror(errno));
            goto fail;
        }

        if (setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) {
            pa_log("IP_MULTICAST_TTL (sap) failed: %s", pa_cstrerror(errno));
            goto fail;
        }
    }

    /* If the socket queue is full, let's drop packets */
    pa_make_fd_nonblock(fd);
    pa_make_udp_socket_low_delay(fd);

    pa_source_output_new_data_init(&data);
    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream");
    pa_proplist_sets(data.proplist, "rtp.source", src_addr);
    pa_proplist_sets(data.proplist, "rtp.destination", dst_addr);
    pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
    pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port);
    pa_proplist_setf(data.proplist, "rtp.ttl", "%lu", (unsigned long) ttl);
    data.driver = __FILE__;
    data.module = m;
    pa_source_output_new_data_set_source(&data, s, false, true);
    pa_source_output_new_data_set_sample_spec(&data, &ss);
    pa_source_output_new_data_set_channel_map(&data, &cm);
    data.flags |= get_dont_inhibit_auto_suspend_flag(s, inhibit_auto_suspend);

    pa_source_output_new(&o, m->core, &data);
    pa_source_output_new_data_done(&data);

    if (!o) {
        pa_log("failed to create source output.");
        goto fail;
    }

    o->parent.process_msg = source_output_process_msg;
    o->push = source_output_push_cb;
    o->moving = source_output_moving_cb;
    o->kill = source_output_kill_cb;

    pa_log_info("Configured source latency of %llu ms.",
                (unsigned long long) pa_source_output_set_requested_latency(o, pa_bytes_to_usec(mtu, &o->sample_spec)) / PA_USEC_PER_MSEC);

    m->userdata = o->userdata = u = pa_xnew(struct userdata, 1);
    u->module = m;
    u->source_output = o;

    u->memblockq = pa_memblockq_new(
            "module-rtp-send memblockq",
            0,
            MEMBLOCKQ_MAXLENGTH,
            MEMBLOCKQ_MAXLENGTH,
            &ss,
            1,
            0,
            0,
            NULL);

    u->mtu = mtu;

    k = sizeof(sa_dst);
    pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0);

    n = pa_xstrdup(pa_modargs_get_value(ma, "stream_name", NULL));
    if (n == NULL)
        n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn)));

    if (af == AF_INET) {
        p = pa_sdp_build(af,
                     (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr,
                     (void*) &dst_sa4.sin_addr,
                     n, (uint16_t) port, payload, &ss);
#ifdef HAVE_IPV6
    } else {
        p = pa_sdp_build(af,
                     (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr,
                     (void*) &dst_sa6.sin6_addr,
                     n, (uint16_t) port, payload, &ss);
#endif
    }

    pa_xfree(n);

    pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss));
    pa_sap_context_init_send(&u->sap_context, sap_fd, p);

    pa_log_info("RTP stream initialized with mtu %u on %s:%u from %s ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, src_addr, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
    pa_log_info("SDP-Data:\n%s\nEOF", p);

    pa_sap_send(&u->sap_context, 0);

    u->sap_event = pa_core_rttime_new(m->core, pa_rtclock_now() + SAP_INTERVAL, sap_event_cb, u);
    u->inhibit_auto_suspend = inhibit_auto_suspend;

    pa_source_output_put(u->source_output);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    if (fd >= 0)
        pa_close(fd);

    if (sap_fd >= 0)
        pa_close(sap_fd);

    return -1;
}
int pa__init(pa_module *m) {
    struct userdata *u = NULL;
    pa_modargs *ma;
    struct udev_enumerate *enumerate = NULL;
    struct udev_list_entry *item = NULL, *first = NULL;
    int fd;
    bool use_tsched = true, fixed_latency_range = false, ignore_dB = false, deferred_volume = m->core->deferred_volume;
    bool use_ucm = true;

    pa_assert(m);

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

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) device_free);
    u->inotify_fd = -1;

    if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) {
        pa_log("Failed to parse tsched= argument.");
        goto fail;
    }
    u->use_tsched = use_tsched;

    if (pa_modargs_get_value(ma, "tsched_buffer_size", NULL)) {
        if (pa_modargs_get_value_u32(ma, "tsched_buffer_size", &u->tsched_buffer_size) < 0) {
            pa_log("Failed to parse tsched_buffer_size= argument.");
            goto fail;
        }

        u->tsched_buffer_size_valid = true;
    }

    if (pa_modargs_get_value_boolean(ma, "fixed_latency_range", &fixed_latency_range) < 0) {
        pa_log("Failed to parse fixed_latency_range= argument.");
        goto fail;
    }
    u->fixed_latency_range = fixed_latency_range;

    if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) {
        pa_log("Failed to parse ignore_dB= argument.");
        goto fail;
    }
    u->ignore_dB = ignore_dB;

    if (pa_modargs_get_value_boolean(ma, "deferred_volume", &deferred_volume) < 0) {
        pa_log("Failed to parse deferred_volume= argument.");
        goto fail;
    }
    u->deferred_volume = deferred_volume;

    if (pa_modargs_get_value_boolean(ma, "use_ucm", &use_ucm) < 0) {
        pa_log("Failed to parse use_ucm= argument.");
        goto fail;
    }
    u->use_ucm = use_ucm;

    if (!(u->udev = udev_new())) {
        pa_log("Failed to initialize udev library.");
        goto fail;
    }

    if (setup_inotify(u) < 0)
        goto fail;

    if (!(u->monitor = udev_monitor_new_from_netlink(u->udev, "udev"))) {
        pa_log("Failed to initialize monitor.");
        goto fail;
    }

    if (udev_monitor_filter_add_match_subsystem_devtype(u->monitor, "sound", NULL) < 0) {
        pa_log("Failed to subscribe to sound devices.");
        goto fail;
    }

    errno = 0;
    if (udev_monitor_enable_receiving(u->monitor) < 0) {
        pa_log("Failed to enable monitor: %s", pa_cstrerror(errno));
        if (errno == EPERM)
            pa_log_info("Most likely your kernel is simply too old and "
                        "allows only privileged processes to listen to device events. "
                        "Please upgrade your kernel to at least 2.6.30.");
        goto fail;
    }

    if ((fd = udev_monitor_get_fd(u->monitor)) < 0) {
        pa_log("Failed to get udev monitor fd.");
        goto fail;
    }

    pa_assert_se(u->udev_io = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, monitor_cb, u));

    if (!(enumerate = udev_enumerate_new(u->udev))) {
        pa_log("Failed to initialize udev enumerator.");
        goto fail;
    }

    if (udev_enumerate_add_match_subsystem(enumerate, "sound") < 0) {
        pa_log("Failed to match to subsystem.");
        goto fail;
    }

    if (udev_enumerate_scan_devices(enumerate) < 0) {
        pa_log("Failed to scan for devices.");
        goto fail;
    }

    first = udev_enumerate_get_list_entry(enumerate);
    udev_list_entry_foreach(item, first)
        process_path(u, udev_list_entry_get_name(item));

    udev_enumerate_unref(enumerate);

    pa_log_info("Found %u cards.", pa_hashmap_size(u->devices));

    pa_modargs_free(ma);

    return 0;

fail:

    if (enumerate)
        udev_enumerate_unref(enumerate);

    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 9
0
int pa__init(pa_module*m) {
    pa_iochannel *io;
    pa_modargs *ma;
    bool exit_on_eof = false;
#ifndef OS_IS_WIN32
    int fd;
#endif

    pa_assert(m);

    if (m->core->running_as_daemon) {
        pa_log_info("Running as daemon, refusing to load this module.");
        return 0;
    }

    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, "exit_on_eof", &exit_on_eof) < 0) {
        pa_log("exit_on_eof= expects boolean argument.");
        goto fail;
    }

    if (pa_stdio_acquire() < 0) {
        pa_log("STDIN/STDOUT already in use.");
        goto fail;
    }

    /* We try to open the controlling tty anew here. This has the
     * benefit of giving us a new fd that doesn't share the O_NDELAY
     * flag with fds 0, 1, or 2. Since pa_iochannel_xxx needs O_NDELAY
     * on its fd using those fds directly could set O_NDELAY which
     * fprintf() doesn't really like, resulting in truncated output
     * of log messages, particularly because if stdout and stderr are
     * dup'ed they share the same O_NDELAY, too. */

#ifndef OS_IS_WIN32
    if ((fd = pa_open_cloexec("/dev/tty", O_RDWR|O_NONBLOCK, 0)) >= 0) {
        io = pa_iochannel_new(m->core->mainloop, fd, fd);
        pa_log_debug("Managed to open /dev/tty.");
    }
    else
#endif
    {
        io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO);
        pa_iochannel_set_noclose(io, true);
        pa_log_debug("Failed to open /dev/tty, using stdin/stdout fds instead.");
    }

    m->userdata = pa_cli_new(m->core, io, m);
    pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m);

    pa_modargs_free(ma);

    return 0;

fail:

    if (ma)
        pa_modargs_free(ma);

    return -1;
}
Ejemplo n.º 10
0
int pa__init(pa_module *m) {
    struct userdata *u = NULL;
    const char *p;
    int fd = -1;
    int buffer_size;
    int mode;
    int record = 1, playback = 1;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    char *t;
    struct pollfd *pollfd;

    pa_assert(m);

    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, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
        pa_log("record= and playback= expect numeric argument.");
        goto fail;
    }

    if (!playback && !record) {
        pa_log("neither playback nor record enabled for device.");
        goto fail;
    }

    mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));

    buffer_size = 16384;
    if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
        pa_log("failed to parse buffer size argument");
        goto fail;
    }

    ss = m->core->default_sample_spec;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("failed to parse sample specification");
        goto fail;
    }

    if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
        goto fail;

    pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));

    if (pa_solaris_auto_format(fd, mode, &ss) < 0)
        goto fail;

    if (pa_solaris_set_buffer(fd, buffer_size) < 0)
        goto fail;

    u = pa_xmalloc(sizeof(struct userdata));
    u->core = m->core;

    u->fd = fd;

    pa_memchunk_reset(&u->memchunk);

    /* We use this to get a reasonable chunk size */
    u->page_size = PA_PAGE_SIZE;

    u->frame_size = pa_frame_size(&ss);
    u->buffer_size = buffer_size;

    u->written_bytes = 0;
    u->read_bytes = 0;

    u->module = m;
    m->userdata = u;

    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);

    u->rtpoll = pa_rtpoll_new();
    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);

    pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss));

    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
    pollfd->fd = fd;
    pollfd->events = 0;
    pollfd->revents = 0;

    if (mode != O_WRONLY) {
        u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
        pa_assert(u->source);

        u->source->userdata = u;
        u->source->parent.process_msg = source_process_msg;

        pa_source_set_module(u->source, m);
        pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
        pa_xfree(t);
        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
        pa_source_set_rtpoll(u->source, u->rtpoll);

        u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
        u->source->refresh_volume = 1;
    } else
        u->source = NULL;

    if (mode != O_RDONLY) {
        u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
        pa_assert(u->sink);

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

        pa_sink_set_module(u->sink, m);
        pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
        pa_xfree(t);
        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
        pa_sink_set_rtpoll(u->sink, u->rtpoll);

        u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL;
        u->sink->refresh_volume = 1;
        u->sink->refresh_mute = 1;
    } else
        u->sink = NULL;

    pa_assert(u->source || u->sink);

    u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
    pa_assert(u->sig);
    ioctl(u->fd, I_SETSIG, S_MSG);

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

    /* Read mixer settings */
    if (u->source)
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);
    if (u->sink) {
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL);
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL);
    }

    if (u->sink)
        pa_sink_put(u->sink);
    if (u->source)
        pa_source_put(u->source);

    pa_modargs_free(ma);

    return 0;

fail:
    if (u)
        pa__done(m);
    else if (fd >= 0)
        close(fd);

    if (ma)
        pa_modargs_free(ma);

    return -1;
}
Ejemplo n.º 11
0
int pa__init(pa_module*m) {

    struct userdata *u;
    pa_modargs *ma;
    pa_sink_new_data data;
    int backend_state;
    int ret;
    char strbuf[100];

    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;
    map = m->core->default_channel_map;

    /* user arguments override these */
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        return 1;
    }

    /* Xen Basic init */
    xsh = xs_domain_open();
    if (xsh==NULL) {
        pa_log("xs_domain_open failed");
        goto fail;
    }
    set_state(XenbusStateUnknown);

    xch = xc_interface_open(NULL, NULL, 0);
    if (xch==0) {
        pa_log("xc_interface_open failed");
        goto fail;
    }

    xce = xc_evtchn_open(NULL, 0);
    if (xce==0) {
        pa_log("xc_evtchn_open failed");
        goto fail;
    }

    /* use only dom0 as the backend for now */
    xen_evtchn_port = xc_evtchn_bind_unbound_port(xce, 0);
    if (xen_evtchn_port == 0) {
        pa_log("xc_evtchn_bind_unbound_port failed");
    }

    /* get grant reference & map locally */
    if (alloc_gref(&gref, (void**)&ioring)) {
       pa_log("alloc_gref failed");
    };
    device_id = 0; /* hardcoded for now */

    if (register_backend_state_watch()) {
        pa_log("Xen sink: register xenstore watch failed");
    };

    publish_param_int("event-channel", xen_evtchn_port);
    publish_param_int("ring-ref", gref.gref_ids[0]);

    /* let's ask for something absurd and deal with rejection */
    ss.rate = 192000;

    publish_spec(&ss);

    ret=0;
    while (!ret) {
        backend_state = wait_for_backend_state_change();
        if (backend_state == STATE_UNDEFINED) {
            pa_log("Xen Backend is taking long to respond, still waiting...");
            continue;
        } else if (backend_state == -1) {
            pa_log("Error while waiting for backend: %s", strerror(errno));
            break;
            goto fail;
        }
        ret = state_callbacks[backend_state]();
    }
    if (ret!=NEGOTIATION_OK) {
        pa_log("Negotiation with Xen backend failed!");
        return 1;
    }

    pa_sample_spec_snprint(strbuf, 100, &ss);
    pa_log_debug("Negotiation ended, the result was: %s", strbuf);

    /* End of Phase 2, begin playback cycle */

    u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    m->userdata = u;
    pa_memchunk_reset(&u->memchunk);
    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
    u->write_type = 0;

    /* init ring buffer */
    ioring->prod_indx = ioring->cons_indx = 0;
    ioring->usable_buffer_space = BUFSIZE - BUFSIZE % pa_frame_size(&ss);

    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_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, "xensink");
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Xen PV audio sink");
    pa_sink_new_data_set_sample_spec(&data, &ss);
    pa_sink_new_data_set_channel_map(&data, &map);

    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, ioring->usable_buffer_space);
    pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(ioring->usable_buffer_space, &u->sink->sample_spec));

    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);

    if (!(u->thread = pa_thread_new("xenpv-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;
}
Ejemplo n.º 12
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    pa_sink_new_data data;
    size_t nbytes;

    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;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map,
                         PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

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

    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_DESCRIPTION, "xrdp sink");
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");

    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_DYNAMIC_LATENCY);
    pa_sink_new_data_done(&data);

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

    u->sink->parent.process_msg = sink_process_msg;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    u->sink->userdata = u;

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

    u->block_usec = BLOCK_USEC;
    pa_log_debug("3 block_usec %d", u->block_usec);
    nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
    pa_sink_set_max_rewind(u->sink, nbytes);
    pa_sink_set_max_request(u->sink, nbytes);

    u->display_num = get_display_num_from_display(getenv("DISPLAY"));

#if defined(PA_CHECK_VERSION)
#if PA_CHECK_VERSION(0, 9, 22)
    if (!(u->thread = pa_thread_new("xrdp-sink", thread_func, u))) {
#else
    if (!(u->thread = pa_thread_new(thread_func, u))) {
#endif
#else
    if (!(u->thread = pa_thread_new(thread_func, u))) {
#endif
        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;
}

int pa__get_n_used(pa_module *m) {
    struct userdata *u;

    pa_assert(m);
    pa_assert_se(u = m->userdata);

    return pa_sink_linked_by(u->sink);
}

void pa__done(pa_module*m) {
    struct userdata *u;

    pa_assert(m);

    if (!(u = m->userdata)) {
        return;
    }

    if (u->sink) {
        pa_sink_unlink(u->sink);
    }

    if (u->thread) {
        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN,
                          NULL, 0, NULL);
        pa_thread_free(u->thread);
    }

    pa_thread_mq_done(&u->thread_mq);

    if (u->sink) {
        pa_sink_unref(u->sink);
    }

    if (u->rtpoll) {
        pa_rtpoll_free(u->rtpoll);
    }

    pa_xfree(u);
}
Ejemplo n.º 13
0
int pa__init(pa_module *m) {
    struct userdata *u = NULL;
    bool record = true, playback = true;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    uint32_t buffer_length_msec;
    int fd = -1;
    pa_sink_new_data sink_new_data;
    pa_source_new_data source_new_data;
    char const *name;
    char *name_buf;
    bool namereg_fail;

    pa_assert(m);

    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, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
        pa_log("record= and playback= expect a boolean argument.");
        goto fail;
    }

    if (!playback && !record) {
        pa_log("neither playback nor record enabled for device.");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);

    if (!(u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC * 2, true, true, 10, pa_rtclock_now(), true)))
        goto fail;

    /*
     * For a process (or several processes) to use the same audio device for both
     * record and playback at the same time, the device's mixer must be enabled.
     * See mixerctl(1). It may be turned off for playback only or record only.
     */
    u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));

    ss = m->core->default_sample_spec;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("failed to parse sample specification");
        goto fail;
    }
    u->frame_size = pa_frame_size(&ss);

    u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);

    buffer_length_msec = 100;
    if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) {
        pa_log("failed to parse buffer_length argument");
        goto fail;
    }
    u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss);
    if (u->buffer_size < 2 * u->minimum_request) {
        pa_log("buffer_length argument cannot be smaller than %u",
               (unsigned)(pa_bytes_to_usec(2 * u->minimum_request, &ss) / 1000));
        goto fail;
    }
    if (u->buffer_size > MAX_BUFFER_SIZE) {
        pa_log("buffer_length argument cannot be greater than %u",
               (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE, &ss) / 1000));
        goto fail;
    }

    u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));

    if ((fd = open_audio_device(u, &ss)) < 0)
        goto fail;

    u->core = m->core;
    u->module = m;
    m->userdata = u;

    pa_memchunk_reset(&u->memchunk);

    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    u->rtpoll_item = NULL;
    build_pollfd(u);

    if (u->mode != O_WRONLY) {
        name_buf = NULL;
        namereg_fail = true;

        if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
            name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
            namereg_fail = false;
        }

        pa_source_new_data_init(&source_new_data);
        source_new_data.driver = __FILE__;
        source_new_data.module = m;
        pa_source_new_data_set_name(&source_new_data, name);
        source_new_data.namereg_fail = namereg_fail;
        pa_source_new_data_set_sample_spec(&source_new_data, &ss);
        pa_source_new_data_set_channel_map(&source_new_data, &map);
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);

        if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
            pa_log("Invalid properties");
            pa_source_new_data_done(&source_new_data);
            goto fail;
        }

        u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
        pa_source_new_data_done(&source_new_data);
        pa_xfree(name_buf);

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

        u->source->userdata = u;
        u->source->parent.process_msg = source_process_msg;

        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
        pa_source_set_rtpoll(u->source, u->rtpoll);
        pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec));

        pa_source_set_get_volume_callback(u->source, source_get_volume);
        pa_source_set_set_volume_callback(u->source, source_set_volume);
        u->source->refresh_volume = true;
    } else
        u->source = NULL;

    if (u->mode != O_RDONLY) {
        name_buf = NULL;
        namereg_fail = true;
        if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
            name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
            namereg_fail = false;
        }

        pa_sink_new_data_init(&sink_new_data);
        sink_new_data.driver = __FILE__;
        sink_new_data.module = m;
        pa_sink_new_data_set_name(&sink_new_data, name);
        sink_new_data.namereg_fail = namereg_fail;
        pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
        pa_sink_new_data_set_channel_map(&sink_new_data, &map);
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");

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

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

        pa_assert(u->sink);
        u->sink->userdata = u;
        u->sink->parent.process_msg = sink_process_msg;

        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
        pa_sink_set_rtpoll(u->sink, u->rtpoll);
        pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec));
        pa_sink_set_max_request(u->sink, u->buffer_size);
        pa_sink_set_max_rewind(u->sink, u->buffer_size);

        pa_sink_set_get_volume_callback(u->sink, sink_get_volume);
        pa_sink_set_set_volume_callback(u->sink, sink_set_volume);
        pa_sink_set_get_mute_callback(u->sink, sink_get_mute);
        pa_sink_set_set_mute_callback(u->sink, sink_set_mute);
        u->sink->refresh_volume = u->sink->refresh_muted = true;
    } else
        u->sink = NULL;

    pa_assert(u->source || u->sink);

    u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
    if (u->sig)
        ioctl(u->fd, I_SETSIG, S_MSG);
    else
        pa_log_warn("Could not register SIGPOLL handler");

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

    /* Read mixer settings */
    if (u->sink) {
        if (sink_new_data.volume_is_set)
            u->sink->set_volume(u->sink);
        else
            u->sink->get_volume(u->sink);

        if (sink_new_data.muted_is_set)
            u->sink->set_mute(u->sink);
        else
            u->sink->get_mute(u->sink);

        pa_sink_put(u->sink);
    }

    if (u->source) {
        if (source_new_data.volume_is_set)
            u->source->set_volume(u->source);
        else
            u->source->get_volume(u->source);

        pa_source_put(u->source);
    }

    pa_modargs_free(ma);

    return 0;

fail:
    if (u)
        pa__done(m);
    else if (fd >= 0)
        close(fd);

    if (ma)
        pa_modargs_free(ma);

    return -1;
}
Ejemplo n.º 14
0
int pa__init(pa_module*m) {

    pa_modargs *ma = NULL;
    struct userdata *u;
    int version;
    struct input_id input_id;
    char name[256];
    uint8_t evtype_bitmask[EV_MAX/8 + 1];
    pa_volume_t volume_limit = PA_VOLUME_NORM*3/2;
    pa_volume_t volume_step = PA_VOLUME_NORM/20;

    pa_assert(m);

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

    if (pa_modargs_get_value_u32(ma, "volume_limit", &volume_limit) < 0) {
        pa_log("Failed to parse volume limit");
        goto fail;
    }

    if (pa_modargs_get_value_u32(ma, "volume_step", &volume_step) < 0) {
        pa_log("Failed to parse volume step");
        goto fail;
    }

    m->userdata = u = pa_xnew(struct userdata, 1);
    u->module = m;
    u->io = NULL;
    u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
    u->fd = -1;
    u->fd_type = 0;
    u->volume_limit = PA_CLAMP_VOLUME(volume_limit);
    u->volume_step = PA_CLAMP_VOLUME(volume_step);

    if ((u->fd = pa_open_cloexec(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY, 0)) < 0) {
        pa_log("Failed to open evdev device: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) {
        pa_log("EVIOCGVERSION failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    pa_log_info("evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff);

    if (ioctl(u->fd, EVIOCGID, &input_id)) {
        pa_log("EVIOCGID failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    pa_log_info("evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u",
                input_id.vendor, input_id.product, input_id.version, input_id.bustype);

    memset(name, 0, sizeof(name));
    if (ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
        pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    pa_log_info("evdev device name: %s", name);

    memset(evtype_bitmask, 0, sizeof(evtype_bitmask));
    if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) {
        pa_log("EVIOCGBIT failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (!test_bit(EV_KEY, evtype_bitmask)) {
        pa_log("Device has no keys.");
        goto fail;
    }

    u->io = m->core->mainloop->io_new(m->core->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);

    pa_modargs_free(ma);

    return 0;

fail:

    if (ma)
        pa_modargs_free(ma);

    pa__done(m);
    return -1;
}
Ejemplo n.º 15
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;

    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();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
    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->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);

    /* Prepare the initial request */
    u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t));
    if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 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;
}
Ejemplo n.º 16
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma;
    pa_sink *master=NULL;
    pa_sink_input_new_data sink_input_data;
    pa_sink_new_data sink_data;
    pa_bool_t use_volume_sharing = TRUE;
    pa_bool_t force_flat_volume = FALSE;
    pa_memchunk silence;

    pa_assert(m);

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

    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) {
        pa_log("Master sink not found");
        goto fail;
    }

    pa_assert(master);

    ss = master->sample_spec;
    ss.format = PA_SAMPLE_FLOAT32;
    map = master->channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
        pa_log("use_volume_sharing= expects a boolean argument");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
        pa_log("force_flat_volume= expects a boolean argument");
        goto fail;
    }

    if (use_volume_sharing && force_flat_volume) {
        pa_log("Flat volume can't be forced when using volume sharing.");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;
    u->channels = ss.channels;

    /* Create sink */
    pa_sink_new_data_init(&sink_data);
    sink_data.driver = __FILE__;
    sink_data.module = m;
    if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
        sink_data.name = pa_sprintf_malloc("%s.vsink", master->name);
    pa_sink_new_data_set_sample_spec(&sink_data, &ss);
    pa_sink_new_data_set_channel_map(&sink_data, &map);
    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
    pa_proplist_sets(sink_data.proplist, "device.vsink.name", sink_data.name);

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

    if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
        const char *z;

        z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s", sink_data.name, z ? z : master->name);
    }

    u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))
                                               | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
    pa_sink_new_data_done(&sink_data);

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

    u->sink->parent.process_msg = sink_process_msg_cb;
    u->sink->set_state = sink_set_state_cb;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    u->sink->request_rewind = sink_request_rewind_cb;
    pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
    if (!use_volume_sharing) {
        pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
        pa_sink_enable_decibel_volume(u->sink, TRUE);
    }
    /* Normally this flag would be enabled automatically be we can force it. */
    if (force_flat_volume)
        u->sink->flags |= PA_SINK_FLAT_VOLUME;
    u->sink->userdata = u;

    pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);

    /* Create sink input */
    pa_sink_input_new_data_init(&sink_input_data);
    sink_input_data.driver = __FILE__;
    sink_input_data.module = m;
    pa_sink_input_new_data_set_sink(&sink_input_data, master, FALSE);
    sink_input_data.origin_sink = u->sink;
    pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
    pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
    pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
    pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);

    pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
    pa_sink_input_new_data_done(&sink_input_data);

    if (!u->sink_input)
        goto fail;

    u->sink_input->pop = sink_input_pop_cb;
    u->sink_input->process_rewind = sink_input_process_rewind_cb;
    u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
    u->sink_input->update_max_request = sink_input_update_max_request_cb;
    u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
    u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
    u->sink_input->kill = sink_input_kill_cb;
    u->sink_input->attach = sink_input_attach_cb;
    u->sink_input->detach = sink_input_detach_cb;
    u->sink_input->state_change = sink_input_state_change_cb;
    u->sink_input->moving = sink_input_moving_cb;
    u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb;
    u->sink_input->mute_changed = sink_input_mute_changed_cb;
    u->sink_input->userdata = u;

    u->sink->input_to_master = u->sink_input;

    pa_sink_input_get_silence(u->sink_input, &silence);
    u->memblockq = pa_memblockq_new("module-virtual-sink memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
    pa_memblock_unref(silence.memblock);

    /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */

    pa_sink_put(u->sink);
    pa_sink_input_put(u->sink_input);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 17
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    pa_sink_new_data data;
    size_t nbytes;

    pa_assert(m);

    pa_web_debug_func_t func = pa_get_user_data(PA_USER_WEB_FUNC);
    if (!func) {
        pa_log_error("Failed to get user web func from user data");
        goto fail;
    }

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

    ss = m->core->default_sample_spec;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    pa_modargs_get_value_u32(ma, "fixed_rate", &ss.rate);
    uint32_t c = 0;
    pa_modargs_get_value_u32(ma, "fixed_channels", &c);
    if (c)
        ss.channels = c;
    const char* fixed_fmt = pa_modargs_get_value(ma, "fixed_format", NULL);
    if (fixed_fmt)
        ss.format = pa_parse_sample_format(fixed_fmt);

    if (ss.channels != map.channels) {
        pa_log_error("sample_spec channels[%d] != channel_map channels[%d]", ss.channels, map.channels);
        pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
        pa_log_debug("after init extend mmap.channels=%d", map.channels);
    }

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->rtpoll = pa_rtpoll_new();
    u->data_func = web_data_func;

    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    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_DESCRIPTION, _("Remote Output"));
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");

    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_DYNAMIC_LATENCY);
    pa_sink_new_data_done(&data);

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

    u->sink->parent.process_msg = sink_process_msg;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    u->sink->userdata = u;

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

    u->block_usec = BLOCK_USEC;
    nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
    pa_sink_set_max_rewind(u->sink, nbytes);
    pa_sink_set_max_request(u->sink, nbytes);

    // call websocket to start
    func(1, NULL, ss.rate, ss.format);

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

    pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC);

    pa_sink_put(u->sink);

    pa_modargs_free(ma);

    return 0;

fail:

    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 18
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma;
    pa_source *master=NULL;
    pa_source_output_new_data source_output_data;
    pa_source_new_data source_data;
    pa_bool_t *use_default = NULL;

    /* optional for uplink_sink */
    pa_sink_new_data sink_data;
    size_t nbytes;

    pa_assert(m);

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

    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
        pa_log("Master source not found");
        goto fail;
    }

    pa_assert(master);

    ss = master->sample_spec;
    ss.format = PA_SAMPLE_FLOAT32;
    map = master->channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }


    u = pa_xnew0(struct userdata, 1);
    if (!u) {
        pa_log("Failed to alloc userdata");
        goto fail;
    }
    u->module = m;
    m->userdata = u;
    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
    if (!u->memblockq) {
        pa_log("Failed to create source memblockq.");
        goto fail;
    }
    u->channels = ss.channels;

    /* Create source */
    pa_source_new_data_init(&source_data);
    source_data.driver = __FILE__;
    source_data.module = m;
    if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
        source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
    pa_source_new_data_set_sample_spec(&source_data, &ss);
    pa_source_new_data_set_channel_map(&source_data, &map);
    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
    pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);

    if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Invalid properties");
        pa_source_new_data_done(&source_data);
        goto fail;
    }

    if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
        const char *z;

        z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
    }

    u->source = pa_source_new(m->core, &source_data,
                          PA_SOURCE_HW_MUTE_CTRL|PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_DECIBEL_VOLUME|
                          (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY)));
    pa_source_new_data_done(&source_data);

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

    u->source->parent.process_msg = source_process_msg_cb;
    u->source->set_state = source_set_state_cb;
    u->source->update_requested_latency = source_update_requested_latency_cb;
    u->source->set_volume = source_set_volume_cb;
    u->source->set_mute = source_set_mute_cb;
    u->source->get_volume = source_get_volume_cb;
    u->source->get_mute = source_get_mute_cb;
    u->source->userdata = u;

    pa_source_set_asyncmsgq(u->source, master->asyncmsgq);

    /* Create source output */
    pa_source_output_new_data_init(&source_output_data);
    source_output_data.driver = __FILE__;
    source_output_data.module = m;
    source_output_data.source = master;
    /* FIXME
       source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */

    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream");
    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
    pa_source_output_new_data_set_channel_map(&source_output_data, &map);

    pa_source_output_new(&u->source_output, m->core, &source_output_data);
    pa_source_output_new_data_done(&source_output_data);

    if (!u->source_output)
        goto fail;

    u->source_output->parent.process_msg = source_output_process_msg_cb;
    u->source_output->push = source_output_push_cb;
    u->source_output->process_rewind = source_output_process_rewind_cb;
    u->source_output->kill = source_output_kill_cb;
    u->source_output->attach = source_output_attach_cb;
    u->source_output->detach = source_output_detach_cb;
    u->source_output->state_change = source_output_state_change_cb;
    u->source_output->may_move_to = source_output_may_move_to_cb;
    u->source_output->moving = source_output_moving_cb;
    u->source_output->userdata = u;

    pa_source_put(u->source);
    pa_source_output_put(u->source_output);

    /* Create optional uplink sink */
    pa_sink_new_data_init(&sink_data);
    sink_data.driver = __FILE__;
    sink_data.module = m;
    if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
        pa_sink_new_data_set_sample_spec(&sink_data, &ss);
        pa_sink_new_data_set_channel_map(&sink_data, &map);
        pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
        pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
        pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);

        if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
            const char *z;

            z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
            pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
        }

        u->sink_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
        if (!u->sink_memblockq) {
            pa_log("Failed to create sink memblockq.");
            goto fail;
        }

        u->sink = pa_sink_new(m->core, &sink_data, 0);  /* FIXME, sink has no capabilities */
        pa_sink_new_data_done(&sink_data);

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

        u->sink->parent.process_msg = sink_process_msg_cb;
        u->sink->update_requested_latency = sink_update_requested_latency_cb;
        u->sink->request_rewind = sink_request_rewind_cb;
        u->sink->set_state = sink_set_state_cb;
        u->sink->userdata = u;

        pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);

        /* FIXME: no idea what I am doing here */
        u->block_usec = BLOCK_USEC;
        nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
        pa_sink_set_max_rewind(u->sink, nbytes);
        pa_sink_set_max_request(u->sink, nbytes);

        pa_sink_put(u->sink);
    } else {
        /* optional uplink sink not enabled */
        u->sink = NULL;
    }

    pa_modargs_free(ma);

    pa_xfree(use_default);

    return 0;

 fail:
    if (ma)
        pa_modargs_free(ma);

    pa_xfree(use_default);

    pa__done(m);

    return -1;
}
int pa__init(pa_module *m) {
    struct userdata *u = NULL;
    pa_modargs *ma = NULL;
    pa_sink_new_data sink_data;
    pa_sample_spec ss;
    pa_channel_map map;
    const char *remote_server = NULL;
    const char *sink_name = NULL;
    const char *compression = NULL;
    char *default_sink_name = NULL;

    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;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    remote_server = pa_modargs_get_value(ma, "server", NULL);
    if (!remote_server) {
        pa_log("No server given!");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;
    u->remote_server = pa_xstrdup(remote_server);
    u->thread_mainloop = pa_mainloop_new();
    if (u->thread_mainloop == NULL) {
        pa_log("Failed to create mainloop");
        goto fail;
    }
    u->thread_mainloop_api = pa_mainloop_get_api(u->thread_mainloop);
    u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
    u->remote_sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));

    u->thread_mq = pa_xnew0(pa_thread_mq, 1);
    pa_thread_mq_init_thread_mainloop(u->thread_mq, m->core->mainloop, u->thread_mainloop_api);

    /* Create sink */
    pa_sink_new_data_init(&sink_data);
    sink_data.driver = __FILE__;
    sink_data.module = m;

    default_sink_name = pa_sprintf_malloc("tunnel-sink-new.%s", remote_server);
    sink_name = pa_modargs_get_value(ma, "sink_name", default_sink_name);

    compression = pa_modargs_get_value(ma, "compression", NULL);
    if (compression) {
        pa_log("compression activated");
        memset(&u->transcode, 0, sizeof(pa_transcode));

        if(strcmp(compression, "opus") == 0 && pa_transcode_supported(PA_ENCODING_OPUS)){

             compression = pa_modargs_get_value(ma, "compression-frame_size", NULL);
             if(compression) u->transcode.frame_size = atoi(compression);
             compression = pa_modargs_get_value(ma, "compression-bitrate", NULL);
             if(compression) u->transcode.bitrate = atoi(compression);

             pa_transcode_init(&u->transcode, PA_ENCODING_OPUS, PA_TRANSCODE_ENCODER, NULL, &ss);

         }
    }
    else u->transcode.encoding = -1;
        
    pa_sink_new_data_set_name(&sink_data, sink_name);
    pa_sink_new_data_set_sample_spec(&sink_data, &ss);
    pa_sink_new_data_set_channel_map(&sink_data, &map);

    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
    pa_proplist_setf(sink_data.proplist,
                     PA_PROP_DEVICE_DESCRIPTION,
                     _("Tunnel to %s/%s"),
                     remote_server,
                     pa_strempty(u->remote_sink_name));

    if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Invalid properties");
        pa_sink_new_data_done(&sink_data);
        goto fail;
    }
    if (!(u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY | PA_SINK_NETWORK))) {
        pa_log("Failed to create sink.");
        pa_sink_new_data_done(&sink_data);
        goto fail;
    }

    pa_sink_new_data_done(&sink_data);
    u->sink->userdata = u;
    u->sink->parent.process_msg = sink_process_msg_cb;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    pa_sink_set_latency_range(u->sink, 0, MAX_LATENCY_USEC);

    /* set thread message queue */
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq->inq);

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

    pa_sink_put(u->sink);
    pa_modargs_free(ma);
    pa_xfree(default_sink_name);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    if (default_sink_name)
        pa_xfree(default_sink_name);

    pa__done(m);

    return -1;
}
Ejemplo n.º 20
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_modargs *ma = NULL;
    const char *server;
    pa_sink_new_data data;

    pa_assert(m);

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

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

    if ((ss.format != PA_SAMPLE_S16NE) ||
            (ss.channels > 2)) {
        pa_log("sample type support is limited to mono/stereo and 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->raw_memchunk);
    pa_memchunk_reset(&u->encoded_memchunk);
    u->offset = 0;
    u->encoding_overhead = 0;
    u->next_encoding_overhead = 0;
    u->encoding_ratio = 1.0;

    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
    u->rtpoll_item = NULL;

    /*u->format =
        (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) |
        (ss.channels == 2 ? ESD_STEREO : ESD_MONO);*/
    u->rate = 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 (!(server = pa_modargs_get_value(ma, "server", NULL))) {
        pa_log("No server argument given.");
        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_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, server);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "music");
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "RAOP sink '%s'", server);

    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->userdata = u;
    pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
    pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
    u->sink->flags = PA_SINK_LATENCY|PA_SINK_NETWORK;

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

    if (!(u->raop = pa_raop_client_new(u->core, server))) {
        pa_log("Failed to connect to server.");
        goto fail;
    }

    pa_raop_client_set_callback(u->raop, on_connection, u);
    pa_raop_client_set_closed_callback(u->raop, on_close, u);

    if (!(u->thread = pa_thread_new("raop-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;
}
int pa__init(pa_module *m)
{
  pa_modargs *ma;
  const char *master_sink_name;
  const char *master_source_name;
  const char *max_hw_frag_size_str;
  const char *aep_runtime;
  pa_source *master_source;
  struct userdata *u;
  pa_proplist *p;
  pa_sink *master_sink;
  const char *raw_sink_name;
  const char *raw_source_name;
  const char *voice_sink_name;
  const char *voice_source_name;
  const char *dbus_type;
  int max_hw_frag_size = 3840;

  pa_assert(m);

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

  voice_turn_sidetone_down();
  master_sink_name = pa_modargs_get_value(ma, "master_sink", NULL);
  master_source_name = pa_modargs_get_value(ma, "master_source", NULL);
  raw_sink_name = pa_modargs_get_value(ma, "raw_sink_name", "sink.voice.raw");
  raw_source_name = pa_modargs_get_value(ma, "raw_source_name",
                                         "source.voice.raw");
  voice_sink_name = pa_modargs_get_value(ma, "voice_sink_name", "sink.voice");
  voice_source_name = pa_modargs_get_value(ma, "voice_source_name",
                                           "source.voice");
  dbus_type = pa_modargs_get_value(ma, "dbus_type", "session");
  max_hw_frag_size_str = pa_modargs_get_value(ma, "max_hw_frag_size", "3840");
  aep_runtime = pa_modargs_get_value(ma, "aep_runtime",
                                     "bbaid1n-wr0-h9a22b--dbxpb--");
  voice_set_aep_runtime_switch(aep_runtime);
  pa_log_debug("Got arguments: master_sink=\"%s\" master_source=\"%s\" raw_sink_name=\"%s\" raw_source_name=\"%s\" dbus_type=\"%s\" max_hw_frag_size=\"%s\". ",
               master_sink_name, master_source_name, raw_sink_name,
               raw_source_name, dbus_type, max_hw_frag_size_str);

  if (!(master_sink = pa_namereg_get(m->core, master_sink_name, PA_NAMEREG_SINK)))
  {
    pa_log("Master sink \"%s\" not found", master_sink_name);
    goto fail;
  }

  if (!(master_source = pa_namereg_get(m->core, master_source_name, PA_NAMEREG_SOURCE)))
  {
    pa_log( "Master source \"%s\" not found", master_source_name);
    goto fail;
  }

  if (master_sink->sample_spec.format != master_source->sample_spec.format &&
      master_sink->sample_spec.rate != master_source->sample_spec.rate &&
      master_sink->sample_spec.channels != master_source->sample_spec.channels)
  {
    pa_log("Master source and sink must have same sample spec");
    goto fail;
  }

  if (pa_atoi(max_hw_frag_size_str, &max_hw_frag_size) < 0 ||
      max_hw_frag_size < 960 ||
      max_hw_frag_size > 128*960)
  {
    pa_log("Bad value for max_hw_frag_size: %s", max_hw_frag_size_str);
    goto fail;
  }

  m->userdata = u = pa_xnew0(struct userdata, 1);
  u->core = m->core;
  u->module = m;
  u->modargs = ma;
  u->master_sink = master_sink;
  u->master_source = master_source;
  u->mainloop_handler = voice_mainloop_handler_new(u);;
  u->ul_timing_advance = 500;  // = 500 micro seconds, seems to be a good default value

  pa_channel_map_init_mono(&u->mono_map);
  pa_channel_map_init_stereo(&u->stereo_map);

  u->hw_sample_spec.format = PA_SAMPLE_S16NE;
  u->hw_sample_spec.rate = SAMPLE_RATE_HW_HZ;
  u->hw_sample_spec.channels = 2;

  u->hw_mono_sample_spec.format = PA_SAMPLE_S16NE;
  u->hw_mono_sample_spec.rate = SAMPLE_RATE_HW_HZ;
  u->hw_mono_sample_spec.channels = 1;

  u->aep_sample_spec.format = PA_SAMPLE_S16NE;
  u->aep_sample_spec.rate = SAMPLE_RATE_AEP_HZ;
  u->aep_sample_spec.channels = 1;
  pa_channel_map_init_mono(&u->aep_channel_map);

  // The result is rounded down incorrectly thus +1
  u->aep_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->aep_sample_spec);
  u->aep_hw_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->hw_sample_spec);
  u->hw_fragment_size = pa_usec_to_bytes(PERIOD_MASTER_USECS+1, &u->hw_sample_spec);
  u->hw_fragment_size_max = max_hw_frag_size;
  if (0 != (u->hw_fragment_size_max % u->hw_fragment_size))
      u->hw_fragment_size_max += u->hw_fragment_size - (u->hw_fragment_size_max % u->hw_fragment_size);
  u->aep_hw_mono_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->hw_mono_sample_spec);
  u->hw_mono_fragment_size = pa_usec_to_bytes(PERIOD_MASTER_USECS+1, &u->hw_mono_sample_spec);

  u->voice_ul_fragment_size = pa_usec_to_bytes(PERIOD_CMT_USECS+1, &u->aep_sample_spec);

  pa_silence_memchunk_get(&u->core->silence_cache,
                          u->core->mempool,
                          &u->aep_silence_memchunk,
                          &u->aep_sample_spec,
                          u->aep_fragment_size);
  voice_memchunk_pool_load(u);

  if (voice_init_raw_sink(u, raw_sink_name))
    goto fail;

  pa_sink_put(u->raw_sink);

  if (voice_init_voip_sink(u, voice_sink_name))
    goto fail;

  pa_sink_put(u->voip_sink);

  if (voice_init_aep_sink_input(u))
    goto fail;

  pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI);
  u->alt_mixer_compensation = PA_VOLUME_NORM;

  if (voice_init_hw_sink_input(u))
    goto fail;

  u->sink_temp_buff = pa_xmalloc(2 * u->hw_fragment_size_max);
  u->sink_temp_buff_len = 2 * u->hw_fragment_size_max;

  u->dl_memblockq =
          pa_memblockq_new(0, 2 * u->voice_ul_fragment_size, 0,
                           pa_frame_size(&u->aep_sample_spec), 0, 0, 0, NULL);

  if (voice_init_raw_source(u, raw_source_name))
    goto fail;

  pa_source_put(u->raw_source);

  if (voice_init_voip_source(u, voice_source_name))
    goto fail;

  pa_source_put(u->voip_source);

  if (voice_init_hw_source_output(u))
    goto fail;

  u->hw_source_memblockq =
      pa_memblockq_new(0, 2 * u->hw_fragment_size_max, 0,
                       pa_frame_size(&u->hw_sample_spec), 0, 0, 0, NULL);

  u->ul_memblockq =
      pa_memblockq_new(0, 2 * u->voice_ul_fragment_size, 0,
                       pa_frame_size(&u->aep_sample_spec), 0, 0, 0, NULL);

  u->cs_call_sink_input = 0;
  u->dl_sideinfo_queue = pa_queue_new();

  u->linear_q15_master_volume_L = INT16_MAX;
  u->linear_q15_master_volume_R = INT16_MAX;
  u->field_2CC = 0;

  voice_aep_ear_ref_init(u);

  if (voice_convert_init(u))
    goto fail;

  if (voice_init_event_forwarder(u, dbus_type) || voice_init_cmtspeech(u))
    goto fail;

  if (!(u->wb_mic_iir_eq = iir_eq_new(u->hw_fragment_size / 2,
                              master_source->sample_spec.channels)))
      goto fail;

  if (!(u->nb_mic_iir_eq = iir_eq_new( u->aep_fragment_size / 2, 1)))
    goto fail;

  if (!(u->wb_ear_iir_eq = fir_eq_new(master_sink->sample_spec.rate,
                                      master_sink->sample_spec.channels)))
    goto fail;

  if (!(u->nb_ear_iir_eq = iir_eq_new(u->aep_fragment_size / 2, 1)))
    goto fail;

  u->input_task_active = FALSE;
  u->xprot_watchdog = TRUE;
  u->ambient_temp = 30;
  if (!(u->xprot = xprot_new()))
    goto fail;

  u->aep_enable = FALSE;
  u->wb_meq_enable = FALSE;
  u->wb_eeq_enable = FALSE;
  u->nb_meq_enable = FALSE;
  u->nb_eeq_enable = FALSE;
  u->xprot_enable = FALSE;
  u->updating_parameters = FALSE;

  u->sink_proplist_changed_slot =
      pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED],
                              0, (pa_hook_cb_t)sink_proplist_changed_cb, u);;

  u->source_proplist_changed_slot =
      pa_hook_connect( &m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], 0,
              (pa_hook_cb_t)source_proplist_changed_cb, u);
  u->mode_accessory_hwid_hash = 0;

  p = pa_proplist_new();
  pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_MODE, "ihf");
  pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID, "");

  pa_sink_update_proplist( master_sink, PA_UPDATE_REPLACE, p);

  pa_proplist_free(p);

  pa_source_output_put(u->hw_source_output);
  pa_sink_input_put(u->hw_sink_input);
  pa_sink_input_put(u->aep_sink_input);

  u->sink_subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK,
                                             sink_subscribe_cb, u);

  return 0;

fail:
  if (ma)
    pa_modargs_free(ma);

  pa__done(m);

  return -1;
}
Ejemplo n.º 22
0
int pa__init(pa_module*m) {
    pa_modargs *ma = NULL;
    struct userdata *u = NULL;

#if defined(USE_TCP_SOCKETS)
    uint32_t port = IPV4_PORT;
    pa_bool_t port_fallback = TRUE;
    const char *listen_on;
#else
    int r;
#endif

#if defined(USE_PROTOCOL_NATIVE) || defined(USE_PROTOCOL_HTTP)
    char t[256];
#endif

    pa_assert(m);

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

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->module = m;

#if defined(USE_PROTOCOL_SIMPLE)
    u->simple_protocol = pa_simple_protocol_get(m->core);

    u->simple_options = pa_simple_options_new();
    if (pa_simple_options_parse(u->simple_options, m->core, ma) < 0)
        goto fail;
    u->simple_options->module = m;
#elif defined(USE_PROTOCOL_CLI)
    u->cli_protocol = pa_cli_protocol_get(m->core);
#elif defined(USE_PROTOCOL_HTTP)
    u->http_protocol = pa_http_protocol_get(m->core);
#elif defined(USE_PROTOCOL_NATIVE)
    u->native_protocol = pa_native_protocol_get(m->core);

    u->native_options = pa_native_options_new();
    if (pa_native_options_parse(u->native_options, m->core, ma) < 0)
        goto fail;
    u->native_options->module = m;
#else
    u->esound_protocol = pa_esound_protocol_get(m->core);

    u->esound_options = pa_esound_options_new();
    if (pa_esound_options_parse(u->esound_options, m->core, ma) < 0)
        goto fail;
    u->esound_options->module = m;
#endif

#if defined(USE_TCP_SOCKETS)

    if (pa_in_system_mode() || pa_modargs_get_value(ma, "port", NULL))
        port_fallback = FALSE;

    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
        pa_log("port= expects a numerical argument between 1 and 65535.");
        goto fail;
    }

    listen_on = pa_modargs_get_value(ma, "listen", NULL);

    if (listen_on) {
#  ifdef HAVE_IPV6
        u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
#  endif
        u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
    } else {
#  ifdef HAVE_IPV6
        u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
#  endif
        u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
    }

#  ifdef HAVE_IPV6
    if (!u->socket_server_ipv4 && !u->socket_server_ipv6)
#  else
    if (!u->socket_server_ipv4)
#  endif
        goto fail;

    if (u->socket_server_ipv4)
        pa_socket_server_set_callback(u->socket_server_ipv4, socket_server_on_connection_cb, u);
#  ifdef HAVE_IPV6
    if (u->socket_server_ipv6)
        pa_socket_server_set_callback(u->socket_server_ipv6, socket_server_on_connection_cb, u);
#  endif

#else

#  if defined(USE_PROTOCOL_ESOUND)

#    if defined(USE_PER_USER_ESOUND_SOCKET)
    u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
#    else
    u->socket_path = pa_xstrdup("/tmp/.esd/socket");
#    endif

    /* This socket doesn't reside in our own runtime dir but in
     * /tmp/.esd/, hence we have to create the dir first */

    if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755U : 0700U, (uid_t)-1, (gid_t)-1) < 0) {
        pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
        goto fail;
    }

#  else
    if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
        pa_log("Failed to generate socket path.");
        goto fail;
    }
#  endif

    if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
        pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
        goto fail;
    } else if (r > 0)
        pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);

    if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
        goto fail;

    pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u);

#endif

#if defined(USE_PROTOCOL_NATIVE)
#  if defined(USE_TCP_SOCKETS)
    if (u->socket_server_ipv4)
        if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
            pa_native_protocol_add_server_string(u->native_protocol, t);

#    ifdef HAVE_IPV6
    if (u->socket_server_ipv6)
        if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
            pa_native_protocol_add_server_string(u->native_protocol, t);
#    endif
#  else
    if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
        pa_native_protocol_add_server_string(u->native_protocol, t);

#  endif
#endif

#if defined(USE_PROTOCOL_HTTP)
#if defined(USE_TCP_SOCKETS)
    if (u->socket_server_ipv4)
        if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
            pa_http_protocol_add_server_string(u->http_protocol, t);

#ifdef HAVE_IPV6
    if (u->socket_server_ipv6)
        if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
            pa_http_protocol_add_server_string(u->http_protocol, t);
#endif /* HAVE_IPV6 */
#else /* USE_TCP_SOCKETS */
    if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
        pa_http_protocol_add_server_string(u->http_protocol, t);

#endif /* USE_TCP_SOCKETS */
#endif /* USE_PROTOCOL_HTTP */

    if (ma)
        pa_modargs_free(ma);

    return 0;

fail:

    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 23
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;

    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_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    m->userdata = u;
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
    u->rtpoll = pa_rtpoll_new();
    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);

    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
        pa_log("Failed to create sink.");
        goto fail;
    }

    u->sink->parent.process_msg = sink_process_msg;
    u->sink->userdata = u;
    u->sink->flags = PA_SINK_LATENCY;

    pa_sink_set_module(u->sink, m);
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
    pa_sink_set_rtpoll(u->sink, u->rtpoll);
    pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));

    u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
    if (u->block_size <= 0)
        u->block_size = pa_frame_size(&ss);

    if (!(u->thread = pa_thread_new(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;
}
Ejemplo n.º 24
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    pa_source_new_data data;
    uint32_t latency_time = DEFAULT_LATENCY_TIME;

    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;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

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

    pa_source_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
    pa_source_new_data_set_sample_spec(&data, &ss);
    pa_source_new_data_set_channel_map(&data, &map);
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Input"));
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");

    u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY);
    pa_source_new_data_done(&data);

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

    u->latency_time = DEFAULT_LATENCY_TIME;
    if (pa_modargs_get_value_u32(ma, "latency_time", &latency_time) < 0) {
        pa_log("Failed to parse latency_time value.");
        goto fail;
    }
    u->latency_time = latency_time;

    u->source->parent.process_msg = source_process_msg;
    u->source->update_requested_latency = source_update_requested_latency_cb;
    u->source->userdata = u;

    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
    pa_source_set_rtpoll(u->source, u->rtpoll);

    pa_source_set_latency_range(u->source, 0, MAX_LATENCY_USEC);
    u->block_usec = u->source->thread_info.max_latency;

    u->source->thread_info.max_rewind =
        pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);

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

    pa_source_put(u->source);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_sample_spec ss;
    pa_channel_map source_map, stream_map;
    pa_modargs *ma;
    pa_source *master;
    pa_source_output_new_data source_output_data;
    pa_source_new_data source_data;
    bool remix = true;

    pa_assert(m);

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

    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
        pa_log("Master source not found.");
        goto fail;
    }

    ss = master->sample_spec;
    source_map = master->channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &source_map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map.");
        goto fail;
    }

    stream_map = source_map;
    if (pa_modargs_get_channel_map(ma, "master_channel_map", &stream_map) < 0) {
        pa_log("Invalid master channel map.");
        goto fail;
    }

    if (stream_map.channels != ss.channels) {
        pa_log("Number of channels doesn't match.");
        goto fail;
    }

    if (pa_channel_map_equal(&stream_map, &master->channel_map))
        pa_log_warn("No remapping configured, proceeding nonetheless!");

    if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
        pa_log("Invalid boolean remix parameter.");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;

    /* Create source */
    pa_source_new_data_init(&source_data);
    source_data.driver = __FILE__;
    source_data.module = m;
    if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
        source_data.name = pa_sprintf_malloc("%s.remapped", master->name);
    pa_source_new_data_set_sample_spec(&source_data, &ss);
    pa_source_new_data_set_channel_map(&source_data, &source_map);
    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");

    if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Invalid properties.");
        pa_source_new_data_done(&source_data);
        goto fail;
    }

    if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
        const char *k;

        k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name);
    }

    u->source = pa_source_new(m->core, &source_data, master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY));
    pa_source_new_data_done(&source_data);

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

    u->source->parent.process_msg = source_process_msg_cb;
    u->source->set_state = source_set_state_cb;
    u->source->update_requested_latency = source_update_requested_latency_cb;

    u->source->userdata = u;

    pa_source_set_asyncmsgq(u->source, master->asyncmsgq);

    /* Create source output */
    pa_source_output_new_data_init(&source_output_data);
    source_output_data.driver = __FILE__;
    source_output_data.module = m;
    pa_source_output_new_data_set_source(&source_output_data, master, false);
    source_output_data.destination_source = u->source;

    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream");
    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
    pa_source_output_new_data_set_channel_map(&source_output_data, &stream_map);
    source_output_data.flags = remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX;

    pa_source_output_new(&u->source_output, m->core, &source_output_data);
    pa_source_output_new_data_done(&source_output_data);

    if (!u->source_output)
        goto fail;

    u->source_output->push = source_output_push_cb;
    u->source_output->process_rewind = source_output_process_rewind_cb;
    u->source_output->kill = source_output_kill_cb;
    u->source_output->attach = source_output_attach_cb;
    u->source_output->detach = source_output_detach_cb;
    u->source_output->state_change = source_output_state_change_cb;
    u->source_output->moving = source_output_moving_cb;
    u->source_output->userdata = u;

    u->source->output_from_master = u->source_output;

    pa_source_put(u->source);
    pa_source_output_put(u->source_output);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 26
0
int pa__init(pa_module*m) {
    struct userdata *u = NULL;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    pa_sink_new_data data;
    size_t nbytes;

    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;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

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

    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_DESCRIPTION, _("Null Output"));
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");

    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_DYNAMIC_LATENCY);
    pa_sink_new_data_done(&data);

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

    u->sink->parent.process_msg = sink_process_msg;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    u->sink->userdata = u;

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

    u->block_usec = BLOCK_USEC;
    nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
    pa_sink_set_max_rewind(u->sink, nbytes);
    pa_sink_set_max_request(u->sink, nbytes);

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

    pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC);

    pa_sink_put(u->sink);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 27
0
int pa__init(pa_module* m)
{
    pa_assert(m);

    /* this example uses fixed sample spec and channel map
     *
     * however, usually we to the following instead:
     *  - set sample spec and chennel map to default values:
     *      m->core->default_sample_spec
     *      m->core->default_channel_map
     *
     *  - overwrite them with pa_modargs_get_sample_spec_and_channel_map()
     *    if module was loaded with corresponding arguments
     *
     *  - finally adjust values to nearest supported form
     */
    pa_sample_spec sample_spec;
    sample_spec.format = PA_SAMPLE_FLOAT32LE;
    sample_spec.rate = 44100;
    sample_spec.channels = 2;

    pa_channel_map channel_map;
    pa_channel_map_init_stereo(&channel_map);

    /* get module arguments (key-value list passed to load-module) */
    pa_modargs *args;
    if (!(args = pa_modargs_new(m->argument, example_sink_modargs))) {
        pa_log("[example sink] failed to parse module arguments");
        goto error;
    }

    /* create and initialize module-specific data */
    struct example_sink_userdata *u = pa_xnew0(struct example_sink_userdata, 1);
    pa_assert(u);
    m->userdata = u;

    u->module = m;
    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    u->output_file = pa_modargs_get_value(args, "output_file", "/dev/null");
    u->output_fd = open(u->output_file, O_WRONLY | O_CREAT | O_TRUNC);
    if (u->output_fd == -1) {
        pa_log("[example sink] can't open output file %s", u->output_file);
        goto error;
    }

    /* create and initialize sink */
    pa_sink_new_data data;
    pa_sink_new_data_init(&data);
    data.driver = "example_sink";
    data.module = m;
    pa_sink_new_data_set_name(
        &data,
        pa_modargs_get_value(args, "sink_name", "example_sink"));
    pa_sink_new_data_set_sample_spec(&data, &sample_spec);
    pa_sink_new_data_set_channel_map(&data, &channel_map);

    if (pa_modargs_get_proplist(
            args,
            "sink_properties",
            data.proplist,
            PA_UPDATE_REPLACE) < 0) {
        pa_log("[example sink] invalid sink properties");
        pa_sink_new_data_done(&data);
        goto error;
    }

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

    if (!u->sink) {
        pa_log("[example sink] failed to create sink");
        goto error;
    }

    /* setup sink callbacks */
    u->sink->parent.process_msg = process_message;
    u->sink->userdata = u;

    /* setup sink event loop */
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
    pa_sink_set_rtpoll(u->sink, u->rtpoll);

    /* start thread for sink event loop and sample reader */
    if (!(u->thread = pa_thread_new("example_sink", thread_loop, u))) {
        pa_log("[example sink] failed to create thread");
        goto error;
    }

    pa_sink_put(u->sink);
    pa_modargs_free(args);

    return 0;

error:
    if (args) {
        pa_modargs_free(args);
    }
    pa__done(m);

    return -1;
}
int pa__init (pa_module *m) 
{
    struct userdata *u;
    pa_channel_map map;
    pa_sample_spec ss;
    pa_modargs *ma = NULL;
    pa_sink_new_data data;
    size_t nbytes;

    pa_assert(m);

    ma = pa_modargs_new(m->argument, valid_modargs);
    if (!ma) {
        pa_log ("failed to parse module arguments.");
        goto fail;
    }
    
    ss = m->core->default_sample_spec;
    map = m->core->default_channel_map;
    
    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->rtpoll = pa_rtpoll_new();
    /* Init message queueu */
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    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);
    
    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;

    /* set message queue and rtopoll to sink */
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
    pa_sink_set_rtpoll(u->sink, u->rtpoll);

    u->block_usec = BLOCK_USEC;
    nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
    pa_sink_set_max_rewind(u->sink, nbytes);
    pa_sink_set_max_request(u->sink, nbytes);

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

    /* this called only when sink latency is set to dynamic */
    //pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC);

    pa_sink_put(u->sink); /* sink given to core */

    pa_modargs_free(ma);

    return 0;     
    
fail:
    return -1;
}
Ejemplo n.º 29
0
int pa__init(pa_module *m) {
    struct userdata *u;
    struct stat st;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma;
    struct pollfd *pollfd;
    pa_source_new_data data;

    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;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    pa_memchunk_reset(&u->memchunk);
    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->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));

    if (mkfifo(u->filename, 0666) < 0) {
        pa_log("mkfifo('%s'): %s", u->filename, pa_cstrerror(errno));
        goto fail;
    }
    if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) {
        pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno));
        goto fail;
    }

    pa_make_fd_nonblock(u->fd);

    if (fstat(u->fd, &st) < 0) {
        pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno));
        goto fail;
    }

    if (!S_ISFIFO(st.st_mode)) {
        pa_log("'%s' is not a FIFO.", u->filename);
        goto fail;
    }

    pa_source_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->filename);
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Unix FIFO source %s", u->filename);
    pa_source_new_data_set_sample_spec(&data, &ss);
    pa_source_new_data_set_channel_map(&data, &map);

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

    u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY);
    pa_source_new_data_done(&data);

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

    u->source->parent.process_msg = source_process_msg;
    u->source->userdata = u;

    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
    pa_source_set_rtpoll(u->source, u->rtpoll);
    pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(pa_pipe_buf(u->fd), &u->source->sample_spec));

    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
    pollfd->fd = u->fd;
    pollfd->events = pollfd->revents = 0;

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

    pa_source_put(u->source);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);

    return -1;
}
Ejemplo n.º 30
0
int pa__init(pa_module*m) {
    pa_modargs *ma = NULL;
    struct userdata *u;
    pa_sink *sink;
    pa_sample_spec ss;
    uint32_t frequency;
    pa_sink_input_new_data data;

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

    if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
        pa_log("No such sink.");
        goto fail;
    }

    ss.format = PA_SAMPLE_FLOAT32;
    ss.rate = sink->sample_spec.rate;
    ss.channels = 1;

    frequency = 440;
    if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) {
        pa_log("Invalid frequency specification");
        goto fail;
    }

    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->sink_input = NULL;

    u->peek_index = 0;
    pa_memchunk_sine(&u->memchunk, m->core->mempool, ss.rate, frequency);

    pa_sink_input_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_sink_input_new_data_set_sink(&data, sink, false);
    pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, "%u Hz Sine", frequency);
    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
    pa_proplist_setf(data.proplist, "sine.hz", "%u", frequency);
    pa_sink_input_new_data_set_sample_spec(&data, &ss);

    pa_sink_input_new(&u->sink_input, m->core, &data);
    pa_sink_input_new_data_done(&data);

    if (!u->sink_input)
        goto fail;

    u->sink_input->pop = sink_input_pop_cb;
    u->sink_input->process_rewind = sink_input_process_rewind_cb;
    u->sink_input->kill = sink_input_kill_cb;
    u->sink_input->state_change = sink_input_state_change_cb;
    u->sink_input->userdata = u;

    pa_sink_input_put(u->sink_input);

    pa_modargs_free(ma);
    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    pa__done(m);
    return -1;
}