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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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);
}
Пример #6
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;
}
Пример #7
0
int pa__init(pa_module *module)
{
	struct context *context = NULL;

	pa_sample_spec ss;
	pa_channel_map cmap;
	pa_modargs *modargs = NULL;
	pa_sink_new_data data;
	size_t nbytes;

	pa_log("Loading module module-freerds-sink.");

	pa_assert(module);

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

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

	context = pa_xnew0(struct context, 1);

	module->userdata = (void *) context;

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

	pa_sink_new_data_init(&data);
	data.driver = __FILE__;
	data.module = module;
	pa_sink_new_data_set_name(&data,
		pa_modargs_get_value(modargs, "sink_name", DEFAULT_SINK_NAME));
	pa_sink_new_data_set_sample_spec(&data, &ss);
	pa_sink_new_data_set_channel_map(&data, &cmap);
	pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "FreeRDS sink");
	pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");

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

	context->sink = pa_sink_new(module->core, &data,
		PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY);
	pa_sink_new_data_done(&data);

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

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

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

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

#if defined(PA_CHECK_VERSION)
#if PA_CHECK_VERSION(0, 9, 22)
	if (!(context->thread = pa_thread_new("freerds-sink", thread_func, context)))
#else
	if (!(context->thread = pa_thread_new(thread_func, context)))
#endif
#else
	if (!(context->thread = pa_thread_new(thread_func, context)))
#endif
	{
		pa_log("Failed to create thread.");
		goto FAIL;
	}

	pa_sink_put(context->sink);

	pa_modargs_free(modargs);

	return 0;

FAIL:
	if (modargs)
	{
		pa_modargs_free(modargs);
	}

	pa__done(module);

	return -1;
}