summaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/alsa/alsa-util.c297
-rw-r--r--src/modules/alsa/alsa-util.h19
-rw-r--r--src/modules/alsa/module-alsa-card.c196
-rw-r--r--src/modules/alsa/module-alsa-sink.c16
-rw-r--r--src/modules/alsa/module-alsa-source.c14
5 files changed, 406 insertions, 136 deletions
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 04d23e0e..65221764 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -314,8 +314,8 @@ int pa_alsa_set_hw_params(
pa_bool_t require_exact_channel_number) {
int ret = -1;
- snd_pcm_uframes_t _period_size = *period_size;
- unsigned int _periods = *periods;
+ snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
+ unsigned int _periods = periods ? *periods : 0;
snd_pcm_uframes_t buffer_size;
unsigned int r = ss->rate;
unsigned int c = ss->channels;
@@ -327,8 +327,6 @@ int pa_alsa_set_hw_params(
pa_assert(pcm_handle);
pa_assert(ss);
- pa_assert(periods);
- pa_assert(period_size);
snd_pcm_hw_params_alloca(&hwparams);
@@ -361,10 +359,6 @@ int pa_alsa_set_hw_params(
if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0)
goto finish;
- /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
- _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
- tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
-
if (require_exact_channel_number) {
if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0)
goto finish;
@@ -373,50 +367,56 @@ int pa_alsa_set_hw_params(
goto finish;
}
- if (_use_tsched) {
- _period_size = tsched_size;
- _periods = 1;
+ if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0)
+ goto finish;
- pa_assert_se(snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size) == 0);
- pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
- }
+ if (_period_size && tsched_size && _periods) {
+ /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
+ _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
+ tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
- buffer_size = _periods * _period_size;
+ if (_use_tsched) {
+ _period_size = tsched_size;
+ _periods = 1;
- if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0)
- goto finish;
+ pa_assert_se(snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size) == 0);
+ pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
+ }
+
+ buffer_size = _periods * _period_size;
- if (_periods > 0) {
+ if (_periods > 0) {
- /* First we pass 0 as direction to get exactly what we asked
- * for. That this is necessary is presumably a bug in ALSA */
+ /* First we pass 0 as direction to get exactly what we asked
+ * for. That this is necessary is presumably a bug in ALSA */
- dir = 0;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
- dir = 1;
+ dir = 0;
if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
- dir = -1;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
- goto finish;
+ dir = 1;
+ if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
+ dir = -1;
+ if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
+ goto finish;
+ }
}
}
- }
- if (_period_size > 0)
- if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
- goto finish;
+ if (_period_size > 0)
+ if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
+ goto finish;
+ }
if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
goto finish;
if (ss->rate != r)
- pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
+ pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
if (ss->channels != c)
- pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
+ pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
if (ss->format != f)
- pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
+ pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
if ((ret = snd_pcm_prepare(pcm_handle)) < 0)
goto finish;
@@ -434,8 +434,11 @@ int pa_alsa_set_hw_params(
pa_assert(_periods > 0);
pa_assert(_period_size > 0);
- *periods = _periods;
- *period_size = _period_size;
+ if (periods)
+ *periods = _periods;
+
+ if (period_size)
+ *period_size = _period_size;
if (use_mmap)
*use_mmap = _use_mmap;
@@ -488,14 +491,7 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) {
return 0;
}
-struct device_info {
- pa_channel_map map;
- const char *alsa_name;
- const char *description;
- const char *name;
-};
-
-static const struct device_info device_table[] = {
+static const struct pa_alsa_profile_info device_table[] = {
{{ 1, { PA_CHANNEL_POSITION_MONO }},
"hw",
"Analog Mono",
@@ -602,7 +598,6 @@ snd_pcm_t *pa_alsa_open_by_device_id(
int i;
int direction = 1;
- int err;
char *d;
snd_pcm_t *pcm_handle;
@@ -622,76 +617,47 @@ snd_pcm_t *pa_alsa_open_by_device_id(
i = 0;
for (;;) {
- pa_sample_spec try_ss;
- pa_bool_t reformat;
if ((direction > 0) == channel_map_superset(&device_table[i].map, map)) {
+ pa_sample_spec try_ss;
+
pa_log_debug("Checking for %s (%s)", device_table[i].name, device_table[i].alsa_name);
d = pa_sprintf_malloc("%s:%s", device_table[i].alsa_name, dev_id);
- reformat = FALSE;
- for (;;) {
- pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
-
- /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <=
- * 1.0.17a would then ignore the SND_PCM_NO_xxx
- * flags. Instead we enable nonblock mode afterwards via
- * snd_pcm_nonblock(). Also see
- * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */
-
- if ((err = snd_pcm_open(&pcm_handle, d, mode,
- /* SND_PCM_NONBLOCK| */
- SND_PCM_NO_AUTO_RESAMPLE|
- SND_PCM_NO_AUTO_CHANNELS|
- (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
- pa_log_info("Couldn't open PCM device %s: %s", d, snd_strerror(err));
- break;
- }
-
- try_ss.channels = device_table[i].map.channels;
- try_ss.rate = ss->rate;
- try_ss.format = ss->format;
-
- if ((err = pa_alsa_set_hw_params(pcm_handle, &try_ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, TRUE)) < 0) {
-
- if (!reformat) {
- reformat = TRUE;
- snd_pcm_close(pcm_handle);
- continue;
- }
-
- if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
- char *t;
-
- t = pa_sprintf_malloc("plug:%s", d);
- pa_xfree(d);
- d = t;
-
- reformat = FALSE;
+ try_ss.channels = device_table[i].map.channels;
+ try_ss.rate = ss->rate;
+ try_ss.format = ss->format;
+
+ pcm_handle = pa_alsa_open_by_device_string(
+ d,
+ dev,
+ &try_ss,
+ map,
+ mode,
+ nfrags,
+ period_size,
+ tsched_size,
+ use_mmap,
+ use_tsched,
+ TRUE);
- snd_pcm_close(pcm_handle);
- continue;
- }
+ pa_xfree(d);
- pa_log_info("PCM device %s refused our hw parameters: %s", d, snd_strerror(err));
- snd_pcm_close(pcm_handle);
- break;
- }
+ if (pcm_handle) {
*ss = try_ss;
*map = device_table[i].map;
pa_assert(map->channels == ss->channels);
- *dev = d;
+
if (config_description)
*config_description = device_table[i].description;
if (config_name)
*config_name = device_table[i].name;
+
return pcm_handle;
}
-
- pa_xfree(d);
}
if (direction > 0) {
@@ -742,7 +708,7 @@ snd_pcm_t *pa_alsa_open_by_device_id(
d = pa_sprintf_malloc("hw:%s", dev_id);
pa_log_debug("Trying %s as last resort...", d);
- pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched);
+ pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE);
pa_xfree(d);
if (pcm_handle) {
@@ -763,7 +729,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
snd_pcm_uframes_t *period_size,
snd_pcm_uframes_t tsched_size,
pa_bool_t *use_mmap,
- pa_bool_t *use_tsched) {
+ pa_bool_t *use_tsched,
+ pa_bool_t require_exact_channel_number) {
int err;
char *d;
@@ -771,11 +738,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
pa_bool_t reformat = FALSE;
pa_assert(device);
- pa_assert(dev);
pa_assert(ss);
pa_assert(map);
- pa_assert(nfrags);
- pa_assert(period_size);
d = pa_xstrdup(device);
@@ -793,12 +757,12 @@ snd_pcm_t *pa_alsa_open_by_device_string(
SND_PCM_NO_AUTO_RESAMPLE|
SND_PCM_NO_AUTO_CHANNELS|
(reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
- pa_log("Error opening PCM device %s: %s", d, snd_strerror(err));
+ pa_log_info("Error opening PCM device %s: %s", d, snd_strerror(err));
pa_xfree(d);
return NULL;
}
- if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE)) < 0) {
+ if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
if (!reformat) {
reformat = TRUE;
@@ -822,13 +786,14 @@ snd_pcm_t *pa_alsa_open_by_device_string(
continue;
}
- pa_log("Failed to set hardware parameters on %s: %s", d, snd_strerror(err));
+ pa_log_info("Failed to set hardware parameters on %s: %s", d, snd_strerror(err));
pa_xfree(d);
snd_pcm_close(pcm_handle);
return NULL;
}
- *dev = d;
+ if (dev)
+ *dev = d;
if (ss->channels != map->channels)
pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
@@ -837,6 +802,94 @@ snd_pcm_t *pa_alsa_open_by_device_string(
}
}
+int pa_alsa_probe_profiles(
+ const char *dev_id,
+ const pa_sample_spec *ss,
+ void (*cb)(const pa_alsa_profile_info *sink, const pa_alsa_profile_info *source, void *userdata),
+ void *userdata) {
+
+ const pa_alsa_profile_info *i;
+
+ pa_assert(dev_id);
+ pa_assert(ss);
+ pa_assert(cb);
+
+ /* We try each combination of playback/capture. We also try to
+ * open only for capture resp. only for sink. Don't get confused
+ * by the trailing entry in device_table we use for this! */
+
+ for (i = device_table; i < device_table + PA_ELEMENTSOF(device_table); i++) {
+ const pa_alsa_profile_info *j;
+ snd_pcm_t *pcm_i = NULL;
+
+ if (i->alsa_name) {
+ char *id;
+ pa_sample_spec try_ss;
+ pa_channel_map try_map;
+
+ pa_log_debug("Checking for playback on %s (%s)", i->name, i->alsa_name);
+ id = pa_sprintf_malloc("%s:%s", i->alsa_name, dev_id);
+
+ try_ss = *ss;
+ try_ss.channels = i->map.channels;
+ try_map = i->map;
+
+ pcm_i = pa_alsa_open_by_device_string(
+ id, NULL,
+ &try_ss, &try_map,
+ SND_PCM_STREAM_PLAYBACK,
+ NULL, NULL, 0, NULL, NULL,
+ TRUE);
+
+ pa_xfree(id);
+
+ if (!pcm_i)
+ continue;
+ }
+
+ for (j = device_table; j < device_table + PA_ELEMENTSOF(device_table); j++) {
+ snd_pcm_t *pcm_j = NULL;
+
+ if (j->alsa_name) {
+ char *jd;
+ pa_sample_spec try_ss;
+ pa_channel_map try_map;
+
+ pa_log_debug("Checking for capture on %s (%s)", j->name, j->alsa_name);
+ jd = pa_sprintf_malloc("%s:%s", j->alsa_name, dev_id);
+
+ try_ss = *ss;
+ try_ss.channels = j->map.channels;
+ try_map = j->map;
+
+ pcm_j = pa_alsa_open_by_device_string(
+ jd, NULL,
+ &try_ss, &try_map,
+ SND_PCM_STREAM_CAPTURE,
+ NULL, NULL, 0, NULL, NULL,
+ TRUE);
+
+ pa_xfree(jd);
+
+ if (!pcm_j)
+ continue;
+ }
+
+ if (pcm_j)
+ snd_pcm_close(pcm_j);
+
+ if (i->alsa_name || j->alsa_name)
+ cb(i->alsa_name ? i : NULL,
+ j->alsa_name ? j : NULL, userdata);
+ }
+
+ if (pcm_i)
+ snd_pcm_close(pcm_i);
+ }
+
+ return TRUE;
+}
+
int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) {
int err;
@@ -1151,7 +1204,26 @@ void pa_alsa_redirect_errors_dec(void) {
snd_lib_error_set_handler(NULL);
}
-void pa_alsa_init_proplist(pa_proplist *p, snd_pcm_info_t *pcm_info) {
+void pa_alsa_init_proplist_card(pa_proplist *p, int card) {
+ char *cn, *lcn;
+
+ pa_assert(p);
+ pa_assert(card >= 0);
+
+ pa_proplist_setf(p, "alsa.card", "%i", card);
+
+ if (snd_card_get_name(card, &cn) >= 0) {
+ pa_proplist_sets(p, "alsa.card_name", cn);
+ free(cn);
+ }
+
+ if (snd_card_get_longname(card, &lcn) >= 0) {
+ pa_proplist_sets(p, "alsa.long_card_name", lcn);
+ free(lcn);
+ }
+}
+
+void pa_alsa_init_proplist_pcm(pa_proplist *p, snd_pcm_info_t *pcm_info) {
static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
[SND_PCM_CLASS_GENERIC] = "generic",
@@ -1172,8 +1244,7 @@ void pa_alsa_init_proplist(pa_proplist *p, snd_pcm_info_t *pcm_info) {
snd_pcm_class_t class;
snd_pcm_subclass_t subclass;
- const char *n, *id, *sdn;
- char *cn = NULL, *lcn = NULL;
+ const char *n, *id, *sdn, *cn;
int card;
pa_assert(p);
@@ -1206,13 +1277,8 @@ void pa_alsa_init_proplist(pa_proplist *p, snd_pcm_info_t *pcm_info) {
pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
if ((card = snd_pcm_info_get_card(pcm_info)) >= 0) {
- pa_proplist_setf(p, "alsa.card", "%i", card);
-
- if (snd_card_get_name(card, &cn) >= 0)
- pa_proplist_sets(p, "alsa.card_name", cn);
-
- if (snd_card_get_longname(card, &lcn) >= 0)
- pa_proplist_sets(p, "alsa.long_card_name", lcn);
+ pa_alsa_init_proplist_card(p, card);
+ cn = pa_proplist_gets(p, "alsa.card_name");
}
if (cn && n)
@@ -1221,9 +1287,6 @@ void pa_alsa_init_proplist(pa_proplist *p, snd_pcm_info_t *pcm_info) {
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, cn);
else if (n)
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, n);
-
- free(lcn);
- free(cn);
}
int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index ce5f0eb6..f58ec8e0 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -78,7 +78,21 @@ snd_pcm_t *pa_alsa_open_by_device_string(
snd_pcm_uframes_t *period_size,
snd_pcm_uframes_t tsched_size,
pa_bool_t *use_mmap,
- pa_bool_t *use_tsched);
+ pa_bool_t *use_tsched,
+ pa_bool_t require_exact_channel_number);
+
+typedef struct pa_alsa_profile_info {
+ pa_channel_map map;
+ const char *alsa_name;
+ const char *description;
+ const char *name;
+} pa_alsa_profile_info;
+
+int pa_alsa_probe_profiles(
+ const char *dev_id,
+ const pa_sample_spec *ss,
+ void (*cb)(const pa_alsa_profile_info *sink, const pa_alsa_profile_info *source, void *userdata),
+ void *userdata);
int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback);
@@ -88,7 +102,8 @@ void pa_alsa_dump_status(snd_pcm_t *pcm);
void pa_alsa_redirect_errors_inc(void);
void pa_alsa_redirect_errors_dec(void);
-void pa_alsa_init_proplist(pa_proplist *p, snd_pcm_info_t *pcm_info);
+void pa_alsa_init_proplist_pcm(pa_proplist *p, snd_pcm_info_t *pcm_info);
+void pa_alsa_init_proplist_card(pa_proplist *p, int card);
int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
new file mode 100644
index 00000000..2cc8a151
--- /dev/null
+++ b/src/modules/alsa/module-alsa-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 <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"
+
+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) {
+
+ 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_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/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c
index dfa20557..62ce89cb 100644
--- a/src/modules/alsa/module-alsa-sink.c
+++ b/src/modules/alsa/module-alsa-sink.c
@@ -1308,10 +1308,9 @@ int pa__init(pa_module*m) {
use_tsched = FALSE;
}
- u = pa_xnew0(struct userdata, 1);
+ m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
- m->userdata = u;
u->use_mmap = use_mmap;
u->use_tsched = use_tsched;
u->first = TRUE;
@@ -1351,7 +1350,7 @@ int pa__init(pa_module*m) {
&ss, &map,
SND_PCM_STREAM_PLAYBACK,
&nfrags, &period_frames, tsched_frames,
- &b, &d)))
+ &b, &d, FALSE)))
goto fail;
}
@@ -1439,7 +1438,7 @@ int pa__init(pa_module*m) {
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
- pa_alsa_init_proplist(data.proplist, pcm_info);
+ pa_alsa_init_proplist_pcm(data.proplist, pcm_info);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
@@ -1633,10 +1632,8 @@ void pa__done(pa_module*m) {
pa_assert(m);
- if (!(u = m->userdata)) {
- pa_alsa_redirect_errors_dec();
- return;
- }
+ if (!(u = m->userdata))
+ goto finish;
if (u->sink)
pa_sink_unlink(u->sink);
@@ -1677,7 +1674,8 @@ void pa__done(pa_module*m) {
pa_xfree(u->device_name);
pa_xfree(u);
- snd_config_update_free_global();
+finish:
+ snd_config_update_free_global();
pa_alsa_redirect_errors_dec();
}
diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c
index f89b6e2e..7ca305f5 100644
--- a/src/modules/alsa/module-alsa-source.c
+++ b/src/modules/alsa/module-alsa-source.c
@@ -1142,10 +1142,9 @@ int pa__init(pa_module*m) {
use_tsched = FALSE;
}
- u = pa_xnew0(struct userdata, 1);
+ m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
- m->userdata = u;
u->use_mmap = use_mmap;
u->use_tsched = use_tsched;
u->rtpoll = pa_rtpoll_new();
@@ -1179,7 +1178,7 @@ int pa__init(pa_module*m) {
&ss, &map,
SND_PCM_STREAM_CAPTURE,
&nfrags, &period_frames, tsched_frames,
- &b, &d)))
+ &b, &d, FALSE)))
goto fail;
}
@@ -1266,7 +1265,7 @@ int pa__init(pa_module*m) {
pa_source_new_data_set_sample_spec(&data, &ss);
pa_source_new_data_set_channel_map(&data, &map);
- pa_alsa_init_proplist(data.proplist, pcm_info);
+ pa_alsa_init_proplist_pcm(data.proplist, pcm_info);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
@@ -1454,10 +1453,8 @@ void pa__done(pa_module*m) {
pa_assert(m);
- if (!(u = m->userdata)) {
- pa_alsa_redirect_errors_dec();
- return;
- }
+ if (!(u = m->userdata))
+ goto finish;
if (u->source)
pa_source_unlink(u->source);
@@ -1495,6 +1492,7 @@ void pa__done(pa_module*m) {
pa_xfree(u->device_name);
pa_xfree(u);
+finish:
snd_config_update_free_global();
pa_alsa_redirect_errors_dec();
}