diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/alsa/alsa-util.c | 297 | ||||
-rw-r--r-- | src/modules/alsa/alsa-util.h | 19 | ||||
-rw-r--r-- | src/modules/alsa/module-alsa-card.c | 196 | ||||
-rw-r--r-- | src/modules/alsa/module-alsa-sink.c | 16 | ||||
-rw-r--r-- | src/modules/alsa/module-alsa-source.c | 14 |
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(); } |