From b6deb0cc4c169b5ef9450586fc66b0b823ef249c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jan 2009 18:29:16 +0100 Subject: add new pa_card object as a way to logically combine multiple sinks and sources --- src/Makefile.am | 1 + src/pulse/def.h | 8 +- src/pulsecore/card.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/card.h | 91 ++++++++++++++++++++++ src/pulsecore/core.c | 4 + src/pulsecore/core.h | 5 +- src/pulsecore/namereg.c | 2 +- src/pulsecore/namereg.h | 3 +- src/pulsecore/sink.c | 8 ++ src/pulsecore/sink.h | 3 + src/pulsecore/source.c | 7 ++ src/pulsecore/source.h | 3 + 12 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 src/pulsecore/card.c create mode 100644 src/pulsecore/card.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index dd9035b5..e570a6d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -716,6 +716,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/cli-command.c pulsecore/cli-command.h \ pulsecore/cli-text.c pulsecore/cli-text.h \ pulsecore/client.c pulsecore/client.h \ + pulsecore/card.c pulsecore/card.h \ pulsecore/core-scache.c pulsecore/core-scache.h \ pulsecore/core-subscribe.c pulsecore/core-subscribe.h \ pulsecore/core.c pulsecore/core.h \ diff --git a/src/pulse/def.h b/src/pulse/def.h index a2e29143..03e8416e 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -391,7 +391,10 @@ typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_AUTOLOAD = 0x0100U, /**< Autoload table events. */ - PA_SUBSCRIPTION_MASK_ALL = 0x01ffU + PA_SUBSCRIPTION_MASK_CARD = 0x0200U, + /**< Card events. \since 0.9.15 */ + + PA_SUBSCRIPTION_MASK_ALL = 0x03ffU /**< Catch all events */ } pa_subscription_mask_t; @@ -424,6 +427,9 @@ typedef enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_AUTOLOAD = 0x0008U, /**< Event type: Autoload table changes. */ + PA_SUBSCRIPTION_EVENT_CARD = 0x0009U, + /**< Event type: Card \since 0.9.15 */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 0x000FU, /**< A mask to extract the event type from an event value */ diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c new file mode 100644 index 00000000..4f3548b4 --- /dev/null +++ b/src/pulsecore/card.c @@ -0,0 +1,196 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "card.h" + +pa_card_config *pa_card_config_new(const char *name) { + pa_card_config *c; + + pa_assert(name); + + c = pa_xnew0(pa_card_config, 1); + c->name = pa_xstrdup(name); + + return c; +} + +void pa_card_config_free(pa_card_config *c) { + pa_assert(c); + + pa_xfree(c->name); + pa_xfree(c); +} + +pa_card_new_data* pa_card_new_data_init(pa_card_new_data *data) { + pa_assert(data); + + memset(data, 0, sizeof(*data)); + data->proplist = pa_proplist_new(); + + return data; +} + +void pa_card_new_data_set_name(pa_card_new_data *data, const char *name) { + pa_assert(data); + + pa_xfree(data->name); + data->name = pa_xstrdup(name); +} + +void pa_card_new_data_done(pa_card_new_data *data) { + + pa_assert(data); + + pa_proplist_free(data->proplist); + + if (data->configs) { + pa_card_config *c; + + while ((c = pa_hashmap_steal_first(data->configs))) + pa_card_config_free(c); + + pa_hashmap_free(data->configs, NULL, NULL); + } + + pa_xfree(data->name); +} + +pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) { + pa_card *c; + const char *name; + + pa_core_assert_ref(core); + pa_assert(data); + pa_assert(data->name); + + c = pa_xnew(pa_card, 1); + + if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_CARD, c, data->namereg_fail))) { + pa_xfree(c); + return NULL; + } + + pa_card_new_data_set_name(data, name); + + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_NEW], data) < 0) { + pa_xfree(c); + pa_namereg_unregister(core, name); + return NULL; + } + + c->core = core; + c->name = pa_xstrdup(data->name); + c->proplist = pa_proplist_copy(data->proplist); + c->driver = pa_xstrdup(data->driver); + c->module = data->module; + + c->sinks = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + c->sources = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + + c->configs = data->configs; + data->configs = NULL; + c->active_config = data->active_config; + data->active_config = NULL; + + c->userdata = NULL; + c->set_config = NULL; + + pa_assert_se(pa_idxset_put(core->cards, c, &c->index) >= 0); + + pa_log_info("Created %u \"%s\"", c->index, c->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, c->index); + + pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_PUT], c); + return c; +} + +void pa_card_free(pa_card *c) { + pa_core *core; + pa_card_config *config; + + pa_assert(c); + pa_assert(c->core); + + core = c->core; + + pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_UNLINK], c); + + pa_namereg_unregister(core, c->name); + + pa_idxset_remove_by_data(c->core->cards, c, NULL); + + pa_log_info("Freed %u \"%s\"", c->index, c->name); + + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); + + pa_idxset_free(c->sinks, NULL, NULL); + pa_idxset_free(c->sources, NULL, NULL); + + while ((config = pa_hashmap_steal_first(c->configs))) + pa_card_config_free(config); + + pa_hashmap_free(c->configs, NULL, NULL); + + pa_proplist_free(c->proplist); + pa_xfree(c->driver); + pa_xfree(c->name); + pa_xfree(c); + + pa_core_check_idle(core); +} + +int pa_card_set_config(pa_card *c, const char *name) { + pa_card_config *config; + pa_assert(c); + + if (!c->set_config) { + pa_log_warn("set_config() operation not implemented for card %u", c->index); + return -1; + } + + if (!c->configs) + return -1; + + if (!(config = pa_hashmap_get(c->configs, name))) + return -1; + + if (c->set_config(c, config) < 0) + return -1; + + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); + + return 0; +} diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h new file mode 100644 index 00000000..40e4a3ee --- /dev/null +++ b/src/pulsecore/card.h @@ -0,0 +1,91 @@ +#ifndef foopulsecardhfoo +#define foopulsecardhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_card pa_card; + +#include +#include +#include +#include + +typedef struct pa_card_config { + char *name; + + pa_bool_t optical_sink:1; + pa_bool_t optical_source:1; + + unsigned n_sinks; + unsigned n_sources; + + unsigned max_sink_channels; + unsigned max_source_channels; +} pa_card_config; + +struct pa_card { + uint32_t index; + pa_core *core; + + char *name; + + pa_proplist *proplist; + pa_module *module; + char *driver; + + pa_idxset *sinks; + pa_idxset *sources; + + pa_hashmap *configs; + pa_card_config *active_config; + + void *userdata; + + int (*set_config)(pa_card *c, pa_card_config *config); +}; + +typedef struct pa_card_new_data { + char *name; + + pa_proplist *proplist; + const char *driver; + pa_module *module; + + pa_hashmap *configs; + pa_card_config *active_config; + + pa_bool_t namereg_fail:1; +} pa_card_new_data; + +pa_card_config *pa_card_config_new(const char *name); +void pa_card_config_free(pa_card_config *c); + +pa_card_new_data *pa_card_new_data_init(pa_card_new_data *data); +void pa_card_new_data_set_name(pa_card_new_data *data, const char *name); +void pa_card_new_data_done(pa_card_new_data *data); + +pa_card *pa_card_new(pa_core *c, pa_card_new_data *data); +void pa_card_free(pa_card *c); + +int pa_card_set_config(pa_card *c, const char *name); + +#endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 5761bbc7..20764325 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -97,6 +97,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) { c->sources = pa_idxset_new(NULL, NULL); c->source_outputs = pa_idxset_new(NULL, NULL); c->sink_inputs = pa_idxset_new(NULL, NULL); + c->cards = pa_idxset_new(NULL, NULL); c->default_source_name = c->default_sink_name = NULL; @@ -167,6 +168,9 @@ static void core_free(pa_object *o) { pa_assert(pa_idxset_isempty(c->clients)); pa_idxset_free(c->clients, NULL, NULL); + pa_assert(pa_idxset_isempty(c->cards)); + pa_idxset_free(c->cards, NULL, NULL); + pa_assert(pa_idxset_isempty(c->sinks)); pa_idxset_free(c->sinks, NULL, NULL); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index f1f38ef1..87ea4ab6 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -79,6 +79,9 @@ typedef enum pa_core_hook { PA_CORE_HOOK_CLIENT_NEW, PA_CORE_HOOK_CLIENT_PUT, PA_CORE_HOOK_CLIENT_UNLINK, + PA_CORE_HOOK_CARD_NEW, + PA_CORE_HOOK_CARD_PUT, + PA_CORE_HOOK_CARD_UNLINK, PA_CORE_HOOK_MAX } pa_core_hook_t; @@ -96,7 +99,7 @@ struct pa_core { pa_mainloop_api *mainloop; /* idxset of all kinds of entities */ - pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; + pa_idxset *clients, *cards, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; /* Some hashmaps for all sorts of entities */ pa_hashmap *namereg, *autoload_hashmap, *shared; diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index ecd8def8..c1a434ae 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -109,7 +109,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t if (!*name) return NULL; - if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) && + if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) && !pa_namereg_is_valid_name(name)) { if (fail) diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index f4581006..8ce548a7 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -30,7 +30,8 @@ typedef enum pa_namereg_type { PA_NAMEREG_SINK, PA_NAMEREG_SOURCE, - PA_NAMEREG_SAMPLE + PA_NAMEREG_SAMPLE, + PA_NAMEREG_CARD } pa_namereg_type_t; void pa_namereg_free(pa_core *c); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 3a662383..dbc72fb4 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -183,6 +183,7 @@ pa_sink* pa_sink_new( s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(data->driver); s->module = data->module; + s->card = data->card; s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; @@ -223,6 +224,9 @@ pa_sink* pa_sink_new( pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); + if (s->card) + pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0); + pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s", s->index, s->name, @@ -235,6 +239,7 @@ pa_sink* pa_sink_new( source_data.name = pa_sprintf_malloc("%s.monitor", name); source_data.driver = data->driver; source_data.module = data->module; + source_data.card = data->card; dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION); pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name); @@ -358,6 +363,9 @@ void pa_sink_unlink(pa_sink* s) { pa_namereg_unregister(s->core, s->name); pa_idxset_remove_by_data(s->core->sinks, s, NULL); + if (s->card) + pa_idxset_remove_by_data(s->card->sinks, s, NULL); + while ((i = pa_idxset_first(s->inputs, NULL))) { pa_assert(i != j); pa_sink_input_kill(i); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 092e30f2..2bd83b63 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -38,6 +38,7 @@ typedef struct pa_sink pa_sink; #include #include #include +#include #define PA_MAX_INPUTS_PER_SINK 32 @@ -70,6 +71,7 @@ struct pa_sink { pa_proplist *proplist; pa_module *module; /* may be NULL */ + pa_card *card; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -186,6 +188,7 @@ typedef struct pa_sink_new_data { const char *driver; pa_module *module; + pa_card *card; pa_sample_spec sample_spec; pa_channel_map channel_map; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index dee6f3d5..676a6b40 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -174,6 +174,7 @@ pa_source* pa_source_new( s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(data->driver); s->module = data->module; + s->card = data->card; s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; @@ -212,6 +213,9 @@ pa_source* pa_source_new( pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0); + if (s->card) + pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0); + pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s", s->index, s->name, @@ -314,6 +318,9 @@ void pa_source_unlink(pa_source *s) { pa_namereg_unregister(s->core, s->name); pa_idxset_remove_by_data(s->core->sources, s, NULL); + if (s->card) + pa_idxset_remove_by_data(s->card->sinks, s, NULL); + while ((o = pa_idxset_first(s->outputs, NULL))) { pa_assert(o != j); pa_source_output_kill(o); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index fd8c4bd6..48240996 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -41,6 +41,7 @@ typedef struct pa_source pa_source; #include #include #include +#include #define PA_MAX_OUTPUTS_PER_SOURCE 32 @@ -73,6 +74,7 @@ struct pa_source { pa_proplist *proplist; pa_module *module; /* may be NULL */ + pa_card *card; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -174,6 +176,7 @@ typedef struct pa_source_new_data { const char *driver; pa_module *module; + pa_card *card; pa_sample_spec sample_spec; pa_channel_map channel_map; -- cgit