diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/alsa/module-alsa-card.c | 154 | ||||
-rw-r--r-- | src/pulsecore/card.c | 13 | ||||
-rw-r--r-- | src/pulsecore/card.h | 12 |
3 files changed, 165 insertions, 14 deletions
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 64559c4f..2cc8a151 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -23,6 +23,10 @@ #include <config.h> #endif +#include <pulse/xmalloc.h> +#include <pulsecore/core-util.h> +#include <pulsecore/modargs.h> + #include "alsa-util.h" #include "module-alsa-card-symdef.h" @@ -30,27 +34,163 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("ALSA Card"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE( + "name=<name for the sink/source> " + "device_id=<ALSA card index> " + "format=<sample format> " + "rate=<sample rate> " + "fragments=<number of fragments> " + "fragment_size=<fragment size> " + "mmap=<enable memory mapping?> " + "tsched=<enable system timer based scheduling mode?> " + "tsched_buffer_size=<buffer size when using timer based scheduling> " + "tsched_buffer_watermark=<lower fill watermark> " + "profile=<profile name>"); + +static const char* const valid_modargs[] = { + "sink_name", + "device", + "device_id", + "format", + "rate", + "channels", + "channel_map", + "fragments", + "fragment_size", + "mmap", + "tsched", + "tsched_buffer_size", + "tsched_buffer_watermark", + NULL +}; + +#define DEFAULT_DEVICE_ID "0" + +struct userdata { + pa_core *core; + pa_module *module; + + char *device_id; + + pa_card *card; +}; + +struct profile_data { + const pa_alsa_profile_info *sink, *source; +}; static void enumerate_cb( const pa_alsa_profile_info *sink, const pa_alsa_profile_info *source, void *userdata) { - if (sink && source) - pa_log("Found Output %s + Input %s", sink->description, source->description); - else if (sink) - pa_log("Found Output %s", sink->description); - else if (source) - pa_log("Found Input %s", source->description); + pa_hashmap *profiles = (pa_hashmap *) userdata; + char *t, *n; + pa_card_profile *p; + struct profile_data *d; + + if (sink && source) { + n = pa_sprintf_malloc("%s+%s", sink->name, source->name); + t = pa_sprintf_malloc("Output %s + Input %s", sink->description, source->description); + } else if (sink) { + n = pa_xstrdup(sink->name); + t = pa_sprintf_malloc("Output %s", sink->description); + } else { + pa_assert(source); + n = pa_xstrdup(source->name); + t = pa_sprintf_malloc("Input %s", source->description); + } + pa_log_info("Found output profile '%s'", t); + + p = pa_card_profile_new(n, t, sizeof(struct profile_data)); + + pa_xfree(t); + pa_xfree(n); + + p->n_sinks = !!sink; + p->n_sources = !!source; + + if (sink) + p->max_sink_channels = sink->map.channels; + if (source) + p->max_source_channels = source->map.channels; + + d = PA_CARD_PROFILE_DATA(p); + + d->sink = sink; + d->source = source; + + pa_hashmap_put(profiles, p->name, p); } int pa__init(pa_module*m) { + pa_card_new_data data; + pa_modargs *ma; + int alsa_card_index; + struct userdata *u; + pa_alsa_redirect_errors_inc(); - pa_alsa_probe_profiles("1", &m->core->default_sample_spec, enumerate_cb, m); + + 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->module = m; + u->device_id = pa_xstrdup(pa_modargs_get_value(ma, "device_id", DEFAULT_DEVICE_ID)); + + if ((alsa_card_index = snd_card_get_index(u->device_id)) < 0) { + pa_log("Card '%s' doesn't exist: %s", u->device_id, snd_strerror(alsa_card_index)); + goto fail; + } + + pa_card_new_data_init(&data); + data.driver = __FILE__; + data.module = m; + pa_alsa_init_proplist_card(data.proplist, alsa_card_index); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_id); + pa_card_new_data_set_name(&data, pa_modargs_get_value(ma, "name", u->device_id)); + + data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + if (pa_alsa_probe_profiles(u->device_id, &m->core->default_sample_spec, enumerate_cb, data.profiles) < 0) { + pa_card_new_data_done(&data); + goto fail; + } + + u->card = pa_card_new(m->core, &data); + pa_card_new_data_done(&data); + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(m); + return -1; } void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) + goto finish; + + if (u->card) + pa_card_free(u->card); + + pa_xfree(u->device_id); + pa_xfree(u); + +finish: + snd_config_update_free_global(); pa_alsa_redirect_errors_dec(); } diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c index 99c0cc55..ec4a50c5 100644 --- a/src/pulsecore/card.c +++ b/src/pulsecore/card.c @@ -36,13 +36,14 @@ #include "card.h" -pa_card_profile *pa_card_profile_new(const char *name) { +pa_card_profile *pa_card_profile_new(const char *name, const char *description, size_t extra) { pa_card_profile *c; pa_assert(name); - c = pa_xnew0(pa_card_profile, 1); + c = pa_xmalloc(PA_ALIGN(sizeof(pa_card_profile)) + extra); c->name = pa_xstrdup(name); + c->description = pa_xstrdup(description); return c; } @@ -51,6 +52,7 @@ void pa_card_profile_free(pa_card_profile *c) { pa_assert(c); pa_xfree(c->name); + pa_xfree(c->description); pa_xfree(c); } @@ -122,7 +124,9 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) { c->profiles = data->profiles; data->profiles = NULL; - c->active_profile = data->active_profile; + if (!(c->active_profile = data->active_profile)) + if (c->profiles) + c->active_profile = pa_hashmap_first(c->profiles); data->active_profile = NULL; c->userdata = NULL; @@ -189,6 +193,9 @@ int pa_card_set_profile(pa_card *c, const char *name) { if (!(profile = pa_hashmap_get(c->profiles, name))) return -1; + if (c->active_profile == profile) + return 0; + if (c->set_profile(c, profile) < 0) return -1; diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h index e32e8809..b4e68b04 100644 --- a/src/pulsecore/card.h +++ b/src/pulsecore/card.h @@ -31,17 +31,20 @@ typedef struct pa_card pa_card; typedef struct pa_card_profile { char *name; + char *description; - pa_bool_t optical_sink:1; - pa_bool_t optical_source:1; - + /* We probably want to have different properties later on here */ unsigned n_sinks; unsigned n_sources; unsigned max_sink_channels; unsigned max_source_channels; + + /* .. followed by some implementation specific data */ } pa_card_profile; +#define PA_CARD_PROFILE_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_card_profile)))) + struct pa_card { uint32_t index; pa_core *core; @@ -65,6 +68,7 @@ struct pa_card { typedef struct pa_card_new_data { char *name; + char *description; pa_proplist *proplist; const char *driver; @@ -76,7 +80,7 @@ typedef struct pa_card_new_data { pa_bool_t namereg_fail:1; } pa_card_new_data; -pa_card_profile *pa_card_profile_new(const char *name); +pa_card_profile *pa_card_profile_new(const char *name, const char *description, size_t extra); void pa_card_profile_free(pa_card_profile *c); pa_card_new_data *pa_card_new_data_init(pa_card_new_data *data); |