示例#1
0
static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) {
    struct rule *r;
    char *name;

    pa_assert(data);

    /* In the FIXATE hook we only adjust the volum. Adjusting the device
     * is left for the NEW hook */

    if (!data->client || !(name = client_name(data->client)))
        return PA_HOOK_OK;

    if ((r = pa_hashmap_get(u->hashmap, name))) {

        if (r->volume_is_set && data->sample_spec.channels == r->volume.channels) {
            pa_log_info("Restoring volume for <%s>", r->name);
            pa_sink_input_new_data_set_volume(data, &r->volume);
        }
    }

    pa_xfree(name);

    return PA_HOOK_OK;
}
示例#2
0
pa_sink_input* pa_memblockq_sink_input_new(
        pa_sink *sink,
        const pa_sample_spec *ss,
        const pa_channel_map *map,
        pa_memblockq *q,
        pa_cvolume *volume,
        pa_proplist *p,
        pa_sink_input_flags_t flags) {

    memblockq_stream *u = NULL;
    pa_sink_input_new_data data;

    pa_assert(sink);
    pa_assert(ss);

    /* We allow creating this stream with no q set, so that it can be
     * filled in later */

    u = pa_msgobject_new(memblockq_stream);
    u->parent.parent.free = memblockq_stream_free;
    u->parent.process_msg = memblockq_stream_process_msg;
    u->core = sink->core;
    u->sink_input = NULL;
    u->memblockq = NULL;

    pa_sink_input_new_data_init(&data);
    pa_sink_input_new_data_set_sink(&data, sink, FALSE);
    data.driver = __FILE__;
    pa_sink_input_new_data_set_sample_spec(&data, ss);
    pa_sink_input_new_data_set_channel_map(&data, map);
    pa_sink_input_new_data_set_volume(&data, volume);
    pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
    data.flags |= flags;

    pa_sink_input_new(&u->sink_input, sink->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->update_max_rewind = sink_input_update_max_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;

    if (q)
        pa_memblockq_sink_input_set_queue(u->sink_input, q);

    /* The reference to u is dangling here, because we want
     * to keep this stream around until it is fully played. */

    /* This sink input is not "put" yet, i.e. pa_sink_input_put() has
     * not been called! */

    return pa_sink_input_ref(u->sink_input);

fail:
    if (u)
        memblockq_stream_unref(u);

    return NULL;
}
示例#3
0
int pa_play_file(
        pa_sink *sink,
        const char *fname,
        const pa_cvolume *volume) {

    file_stream *u = NULL;
    pa_sample_spec ss;
    pa_channel_map cm;
    pa_sink_input_new_data data;
    int fd;
    SF_INFO sfi;
    pa_memchunk silence;

    pa_assert(sink);
    pa_assert(fname);

    u = pa_msgobject_new(file_stream);
    u->parent.parent.free = file_stream_free;
    u->parent.process_msg = file_stream_process_msg;
    u->core = sink->core;
    u->sink_input = NULL;
    u->sndfile = NULL;
    u->readf_function = NULL;
    u->memblockq = NULL;

    if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
        goto fail;
    }

    /* FIXME: For now we just use posix_fadvise to avoid page faults
     * when accessing the file data. Eventually we should move the
     * file reader into the main event loop and pass the data over the
     * asyncmsgq. */

#ifdef HAVE_POSIX_FADVISE
    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
        goto fail;
    } else
        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");

    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) {
        pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno));
        goto fail;
    } else
        pa_log_debug("POSIX_FADV_WILLNEED succeeded.");
#endif

    pa_zero(sfi);
    if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
        pa_log("Failed to open file %s", fname);
        goto fail;
    }

    fd = -1;

    if (pa_sndfile_read_sample_spec(u->sndfile, &ss) < 0) {
        pa_log("Failed to determine file sample format.");
        goto fail;
    }

    if (pa_sndfile_read_channel_map(u->sndfile, &cm) < 0) {
        if (ss.channels > 2)
            pa_log_info("Failed to determine file channel map, synthesizing one.");
        pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
    }

    u->readf_function = pa_sndfile_readf_function(&ss);

    pa_sink_input_new_data_init(&data);
    pa_sink_input_new_data_set_sink(&data, sink, FALSE);
    data.driver = __FILE__;
    pa_sink_input_new_data_set_sample_spec(&data, &ss);
    pa_sink_input_new_data_set_channel_map(&data, &cm);
    pa_sink_input_new_data_set_volume(&data, volume);
    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
    pa_sndfile_init_proplist(u->sndfile, data.proplist);

    pa_sink_input_new(&u->sink_input, sink->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->update_max_rewind = sink_input_update_max_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_get_silence(u->sink_input, &silence);
    u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
    pa_memblock_unref(silence.memblock);

    pa_sink_input_put(u->sink_input);

    /* The reference to u is dangling here, because we want to keep
     * this stream around until it is fully played. */

    return 0;

fail:
    file_stream_unref(u);

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

    return -1;
}