From e205b25d65ccb380fa158711e24d55b6de5d9bc1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 16 Feb 2006 19:19:58 +0000 Subject: Reorganised the source tree. We now have src/ with a couple of subdirs: * daemon/ - Contains the files specific to the polypaudio daemon. * modules/ - All loadable modules. * polyp/ - Files that are part of the public, application interface or are only used in libpolyp. * polypcore/ - All other shared files. * tests/ - Test programs. * utils/ - Utility programs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@487 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 278 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/modules/module-alsa-source.c (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c new file mode 100644 index 00000000..f03e51ad --- /dev/null +++ b/src/modules/module-alsa-source.c @@ -0,0 +1,278 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio 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. + + polypaudio 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 polypaudio; 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 + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "poll.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-alsa-source-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") + +struct userdata { + snd_pcm_t *pcm_handle; + pa_source *source; + pa_io_event **io_events; + unsigned n_io_events; + + size_t frame_size, fragment_size; + pa_memchunk memchunk; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "device", + "source_name", + "channels", + "rate", + "format", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SOURCE_NAME "alsa_input" +#define DEFAULT_DEVICE "hw:0,0" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void xrun_recovery(struct userdata *u) { + assert(u); + + pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + pa_log(__FILE__": snd_pcm_prepare() failed\n"); +} + +static void do_read(struct userdata *u) { + assert(u); + + update_usage(u); + + for (;;) { + pa_memchunk post_memchunk; + snd_pcm_sframes_t frames; + size_t l; + + if (!u->memchunk.memblock) { + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); + u->memchunk.index = 0; + } + + assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); + return; + } + + l = frames * u->frame_size; + + post_memchunk = u->memchunk; + post_memchunk.length = l; + + pa_source_post(u->source, &post_memchunk); + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length == 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } + + break; + } +} + +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + struct userdata *u = userdata; + assert(u && a && e); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_read(u); +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->source); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + pa_log(__FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + pa_sample_spec ss; + unsigned periods, fragsize; + snd_pcm_uframes_t period_size; + size_t frame_size; + int err; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_frame_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + pa_log(__FILE__": failed to parse buffer metrics\n"); + goto fail; + } + period_size = fragsize; + + u = pa_xmalloc0(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + goto fail; + } + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { + pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + goto fail; + } + + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + + u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { + pa_log(__FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = period_size; + + pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + snd_pcm_start(u->pcm_handle); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa__done(c, m); + + goto finish; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_xfree(u); +} + -- cgit From c75972f54a136eda05ab7cd87966526e026edc5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 22:08:06 +0000 Subject: move alsa-util.[ch], oss-util.[ch] and howl-wrap.[ch] to the modules directory since they are just helper source used exclusively by the modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@489 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index f03e51ad..9453f846 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -41,11 +41,11 @@ #include #include #include -#include #include #include #include "module-alsa-source-symdef.h" +#include "alsa-util.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") -- cgit From 5eda18bf608a325c136a450e58fa154eb0b270f4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 12:10:58 +0000 Subject: Cleaned up the includes after the restructuring. Indicate which headers are public and which are internal through <> vs "". git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@500 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 9453f846..4f281aa7 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -44,8 +44,8 @@ #include #include -#include "module-alsa-source-symdef.h" #include "alsa-util.h" +#include "module-alsa-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") -- cgit From 4a64b0d1167e980d81b798d813f35209895f0674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 02:27:19 +0000 Subject: change pa_log() and friends to not require a trailing \n on all logged strings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@574 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4f281aa7..bf031350 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -85,10 +85,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (capture) ***"); if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed"); } static void do_read(struct userdata *u) { @@ -117,7 +117,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", strerror(-frames)); return; } @@ -157,7 +157,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u && u->source); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay\n"); + pa_log(__FILE__": failed to get delay"); s->get_latency = NULL; return 0; } @@ -177,13 +177,13 @@ int pa__init(pa_core *c, pa_module*m) { int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } frame_size = pa_frame_size(&ss); @@ -191,7 +191,7 @@ int pa__init(pa_core *c, pa_module*m) { periods = 12; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } period_size = fragsize; @@ -202,12 +202,12 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -220,14 +220,14 @@ int pa__init(pa_core *c, pa_module*m) { u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors\n"); + pa_log(__FILE__": failed to obtain file descriptors"); goto fail; } u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From b125e1c9d579d47865fb0e4015b8e1f2d15b152b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 17:57:58 +0000 Subject: Hardware volume support in ALSA modules. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@604 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index bf031350..e2dbc8bf 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -54,9 +54,12 @@ PA_MODULE_USAGE("source_name= device= format=< struct userdata { snd_pcm_t *pcm_handle; + snd_mixer_t *mixer_handle; + snd_mixer_elem_t *mixer_elem; pa_source *source; pa_io_event **io_events; unsigned n_io_events; + long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; pa_memchunk memchunk; @@ -165,6 +168,110 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); } +static int source_get_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + long vol; + int err; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, 0, &vol); + if (err < 0) + goto fail; + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); + if (err < 0) + goto fail; + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int source_set_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err; + pa_volume_t vol; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { + vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); + if (err < 0) + goto fail; + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); + if (err < 0) + goto fail; + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int source_get_hw_mute_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err, sw; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); + if (err) { + pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + s->hw_muted = !sw; + + return 0; +} + +static int source_set_hw_mute_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); + if (err) { + pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + return 0; +} + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; int ret = -1; @@ -211,11 +318,35 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { + pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + goto fail; + } + + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture"))) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; + if (u->mixer_handle) { + assert(u->mixer_elem); + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { + u->source->get_hw_volume = source_get_hw_volume_cb; + u->source->set_hw_volume = source_set_hw_volume_cb; + snd_mixer_selem_get_capture_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } + if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { + u->source->get_hw_mute = source_get_hw_mute_cb; + u->source->set_hw_mute = source_set_hw_mute_cb; + } + } pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); @@ -239,6 +370,12 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + /* Get initial mixer settings */ + if (u->source->get_hw_volume) + u->source->get_hw_volume(u->source); + if (u->source->get_hw_mute) + u->source->get_hw_mute(u->source); return ret; @@ -264,6 +401,9 @@ void pa__done(pa_core *c, pa_module*m) { if (u->io_events) pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); -- cgit From c119996c73e540f0c0579c3a6aa45b9cd27c2509 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 17:58:27 +0000 Subject: Fix correct default device. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@605 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index e2dbc8bf..a3570473 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -78,7 +78,7 @@ static const char* const valid_modargs[] = { }; #define DEFAULT_SOURCE_NAME "alsa_input" -#define DEFAULT_DEVICE "hw:0,0" +#define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { pa_module_set_used(u->module, -- cgit From ae07d5abd5fe680367723cc6913eb759d22d8551 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 19:09:26 +0000 Subject: Handle ALSA file descriptors more correctly. This means a bit more overhead, but following their API properly should avoid problems in the future. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@606 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a3570473..2adefa6a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -57,8 +57,7 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_source *source; - pa_io_event **io_events; - unsigned n_io_events; + struct pa_alsa_fdlist *fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -144,9 +143,9 @@ static void do_read(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void fdl_callback(void *userdata) { struct userdata *u = userdata; - assert(u && a && e); + assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -350,8 +349,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors"); + u->fdl = pa_alsa_fdlist_new(); + assert(u->fdl); + if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } @@ -399,8 +400,8 @@ void pa__done(pa_core *c, pa_module*m) { pa_source_unref(u->source); } - if (u->io_events) - pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + if (u->fdl) + pa_alsa_fdlist_free(u->fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); -- cgit From 1e68539dc41f73722402f4678d002197289e37c5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 21:50:55 +0000 Subject: Get notifications about mixer changes from ALSA. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@607 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 44 ++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2adefa6a..1b7ae7d3 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -57,7 +57,8 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_source *source; - struct pa_alsa_fdlist *fdl; + struct pa_alsa_fdlist *pcm_fdl; + struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -153,6 +154,24 @@ static void fdl_callback(void *userdata) { do_read(u); } +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); + + assert(u && u->mixer_handle); + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + if (u->source->get_hw_volume) + u->source->get_hw_volume(u->source); + if (u->source->get_hw_mute) + u->source->get_hw_mute(u->source); + pa_subscription_post(u->source->core, + PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, + u->source->index); + } + + return 0; +} + static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u = s->userdata; snd_pcm_sframes_t frames; @@ -349,13 +368,24 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - u->fdl = pa_alsa_fdlist_new(); - assert(u->fdl); - if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + u->pcm_fdl = pa_alsa_fdlist_new(); + assert(u->pcm_fdl); + if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } + if (u->mixer_handle) { + u->mixer_fdl = pa_alsa_fdlist_new(); + assert(u->mixer_fdl); + if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); + goto fail; + } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); + snd_mixer_elem_set_callback_private(u->mixer_elem, u); + } + u->frame_size = frame_size; u->fragment_size = period_size; @@ -400,8 +430,10 @@ void pa__done(pa_core *c, pa_module*m) { pa_source_unref(u->source); } - if (u->fdl) - pa_alsa_fdlist_free(u->fdl); + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); -- cgit From 7b6a9c3829fe17dc836a3220bff1f9b4e35d3a57 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 15:42:37 +0000 Subject: Tried to get the volume information even upon init failure. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@626 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 1b7ae7d3..5a6dc144 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -398,15 +398,15 @@ int pa__init(pa_core *c, pa_module*m) { ret = 0; -finish: - if (ma) - pa_modargs_free(ma); - /* Get initial mixer settings */ if (u->source->get_hw_volume) u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); + +finish: + if (ma) + pa_modargs_free(ma); return ret; -- cgit From 53c266f6636afd3b9abb88148d7dd2349b1caf13 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 20:59:57 +0000 Subject: Fetch sound card name into sink/source description. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@631 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 5a6dc144..3343e0b6 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -299,6 +299,7 @@ int pa__init(pa_core *c, pa_module*m) { unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; + snd_pcm_info_t *pcm_info = NULL; int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -331,6 +332,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || + (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + goto fail; + } + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; @@ -366,7 +373,7 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); @@ -407,6 +414,9 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + if (pcm_info) + snd_pcm_info_free(pcm_info); return ret; -- cgit From acb96c96fde93dcd87c6509e7c64b403caa44f30 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 31 Mar 2006 08:54:24 +0000 Subject: Fix some warnings caused by size_t having varying size. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@641 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 3343e0b6..14b35eb8 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -396,7 +396,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From a74253606f4f5556e58cb12336d8900dd73226cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Apr 2006 00:19:52 +0000 Subject: clip volume at PA_VOLUME_NORM for alsa devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@666 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 14b35eb8..2ee16190 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -228,7 +228,12 @@ static int source_set_hw_volume_cb(pa_source *s) { assert(u && u->mixer_elem); if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + vol = pa_cvolume_avg(&s->hw_volume); + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); if (err < 0) @@ -237,7 +242,12 @@ static int source_set_hw_volume_cb(pa_source *s) { int i; for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + vol = s->hw_volume.values[i]; + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); if (err < 0) -- cgit From 69096f27531381b57fa73dc8e85c812089915031 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 25 Apr 2006 07:54:49 +0000 Subject: Fall back to software volume if hardware mixer cannot control all channels. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@796 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 62 +++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 36 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2ee16190..7a365286 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -190,25 +190,18 @@ static int source_get_hw_volume_cb(pa_source *s) { struct userdata *u = s->userdata; long vol; int err; + int i; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, 0, &vol); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); if (err < 0) goto fail; - pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); - if (err < 0) - goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); - } + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); } return 0; @@ -224,35 +217,23 @@ static int source_set_hw_volume_cb(pa_source *s) { struct userdata *u = s->userdata; int err; pa_volume_t vol; + int i; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + vol = s->hw_volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); + err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); if (err < 0) goto fail; - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i]; - - if (vol > PA_VOLUME_NORM) - vol = PA_VOLUME_NORM; - - vol = vol * (u->hw_volume_max - u->hw_volume_min) / - PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); - if (err < 0) - goto fail; - } } return 0; @@ -372,10 +353,19 @@ int pa__init(pa_core *c, pa_module*m) { if (u->mixer_handle) { assert(u->mixer_elem); if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { - u->source->get_hw_volume = source_get_hw_volume_cb; - u->source->set_hw_volume = source_set_hw_volume_cb; - snd_mixer_selem_get_capture_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + int i; + + for (i = 0;i < ss.channels;i++) { + if (!snd_mixer_selem_has_capture_channel(u->mixer_elem, i)) + break; + } + + if (i == ss.channels) { + u->source->get_hw_volume = source_get_hw_volume_cb; + u->source->set_hw_volume = source_set_hw_volume_cb; + snd_mixer_selem_get_capture_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } } if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { u->source->get_hw_mute = source_get_hw_mute_cb; -- cgit From 185a57cadd7b4e8e85c7fbecc866d7c279704e12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:40:14 +0000 Subject: support new channel_map argument in sink/source modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@803 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 7a365286..e4938917 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -50,7 +50,15 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "source_name= " + "device= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size= " + "channel_map=") struct userdata { snd_pcm_t *pcm_handle; @@ -74,6 +82,7 @@ static const char* const valid_modargs[] = { "format", "fragments", "fragment_size", + "channel_map", NULL }; @@ -287,6 +296,7 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; const char *dev; pa_sample_spec ss; + pa_channel_map map; unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; @@ -299,7 +309,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -345,7 +355,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); assert(u->source); u->source->userdata = u; -- cgit From 6060bff186e028dfc2d90ffb69869b93f9ec01f5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 28 Apr 2006 07:29:32 +0000 Subject: When a control is removed, all bits are set so we need to test for that first. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@819 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index e4938917..84ae992b 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -168,6 +168,9 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { assert(u && u->mixer_handle); + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return 0; + if (mask & SND_CTL_EVENT_MASK_VALUE) { if (u->source->get_hw_volume) u->source->get_hw_volume(u->source); -- cgit From b6812029ba32002aea1576339571eafde62f124a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 20:29:32 +0000 Subject: use default alsa channel map for alsa devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@851 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 84ae992b..ad52271c 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -312,10 +312,22 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } + + pa_alsa_channel_map_init_auto(&map, ss.channels); + if ((pa_modargs_get_channel_map(ma, &map) < 0)) { + pa_log(__FILE__": invalid channel map."); + goto fail; + } + + if (ss.channels != map.channels) { + pa_log(__FILE__": channel map and sample specification don't match."); + goto fail; + } + frame_size = pa_frame_size(&ss); periods = 12; -- cgit From 7abf17edcdae7d29231ff6619f22212b0ef9eee7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 20:47:55 +0000 Subject: fix fragment size calculation for module-alsa-source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@852 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index ad52271c..a47e0bc6 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -118,7 +118,11 @@ static void do_read(struct userdata *u) { u->memchunk.index = 0; } - assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + assert(u->memchunk.memblock); + assert(u->memchunk.length); + assert(u->memchunk.memblock->data); + assert(u->memchunk.memblock->length); + assert(u->memchunk.length % u->frame_size == 0); if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) @@ -331,12 +335,12 @@ int pa__init(pa_core *c, pa_module*m) { frame_size = pa_frame_size(&ss); periods = 12; - fragsize = 1024; + fragsize = frame_size*1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } - period_size = fragsize; + period_size = fragsize/frame_size; u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; @@ -419,9 +423,9 @@ int pa__init(pa_core *c, pa_module*m) { } u->frame_size = frame_size; - u->fragment_size = period_size; + u->fragment_size = period_size * frame_size; - pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); + pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From 0f22d63289779931cfc3ddd3d2cdfb579e4be3c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:20:34 +0000 Subject: * set default fragment metrics depending on the sample specs of the device in OSS and ALSA * fix fragment size calculation in module-alsa-sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@855 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a47e0bc6..660bc83b 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -333,9 +333,11 @@ int pa__init(pa_core *c, pa_module*m) { } frame_size = pa_frame_size(&ss); - + + /* Fix latency to 100ms */ periods = 12; - fragsize = frame_size*1024; + fragsize = pa_bytes_per_second(&ss)/128; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; @@ -425,7 +427,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size * frame_size; - pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From 4b6ab291a787ff597c938842b569a35434ab11d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 23:47:38 +0000 Subject: * modify pa_channel_map_init_auto() to take an extra argument specifying the standard to use (ALSA, AIFF, ...) * add some more validity checks to pa_source_new(),pa_sink_new(),pa_sink_input_new(),pa_source_output_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@888 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 660bc83b..d46f8e42 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -316,22 +316,11 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } - pa_alsa_channel_map_init_auto(&map, ss.channels); - if ((pa_modargs_get_channel_map(ma, &map) < 0)) { - pa_log(__FILE__": invalid channel map."); - goto fail; - } - - if (ss.channels != map.channels) { - pa_log(__FILE__": channel map and sample specification don't match."); - goto fail; - } - frame_size = pa_frame_size(&ss); /* Fix latency to 100ms */ -- cgit From d9cc2cfcb97c1b0449bcbfb6ab0301a58d77bd55 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 16:34:18 +0000 Subject: Move xmalloc to the public side (libpolyp). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@908 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index d46f8e42..b9d1ff87 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,6 +34,8 @@ #include +#include + #include #include #include @@ -41,7 +43,6 @@ #include #include #include -#include #include #include "alsa-util.h" -- cgit From c47e937011f00eebab7230cedb58fd59f16487b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:09:57 +0000 Subject: split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@917 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b9d1ff87..654f3e49 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include -- cgit From 4e3dc7ce68561c16254712d713b2ccd472b8afe7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 22 May 2006 15:20:46 +0000 Subject: Wrap strerror() in a function that makes it thread safe and converts the output to UTF-8. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@945 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 654f3e49..c72b0322 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,6 +34,7 @@ #include +#include #include #include @@ -134,7 +135,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", pa_cstrerror(-frames)); return; } -- cgit From 4413b89d7a45587b545a31463ad2196767f45563 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:16:55 +0000 Subject: * split pa_cstrerror() into its own file polypcore/core-error.[ch] * fix building of padsp * remove a warning when compiling padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@972 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c72b0322..414efda8 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,9 +34,9 @@ #include -#include #include +#include #include #include #include -- cgit From bb820db4b5b9e928b4d7fe58bbab2f56b1897f64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:05:07 +0000 Subject: * if an ALSA device doesn't support the channel count requested, use what ALSA suggests instead * if an ALSA device doesn't support the sampling freq requested, use what ALSA suggests and resample if this deviates more than 10% from what we requested * fix segfault freeing an unitialized mixer_fdl field git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@992 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 414efda8..10b98f75 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -335,7 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { } period_size = fragsize/frame_size; - u = pa_xmalloc0(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); m->userdata = u; u->module = m; @@ -356,6 +356,10 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if (ss.channels != map.channels) + /* Seems ALSA didn't like the channel number, so let's fix the channel map */ + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); goto fail; @@ -367,8 +371,10 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); - assert(u->source); + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + pa_log(__FILE__": Failed to create source object"); + goto fail; + } u->source->userdata = u; u->source->get_latency = source_get_latency_cb; @@ -413,7 +419,8 @@ int pa__init(pa_core *c, pa_module*m) { } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); - } + } else + u->mixer_fdl = NULL; u->frame_size = frame_size; u->fragment_size = period_size * frame_size; -- cgit From 64fa5b882f53b24d78fd3c84191150000e79b391 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:48:17 +0000 Subject: * alsa-sink: if "PCM" is not found as mixer track name, fallback to "Master" * alsa-source: if "Capture" is not found as mixer track name, fallback to "Mic" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@993 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 10b98f75..0999c65f 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -366,7 +366,7 @@ int pa__init(pa_core *c, pa_module*m) { } if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture"))) { + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } -- cgit From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 0999c65f..c4e8689c 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + 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. - polypaudio is distributed in the hope that it will be useful, but + 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 polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -34,17 +34,17 @@ #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-source-symdef.h" -- cgit From 84907e6716b83a340c0d5717148d6262fc0f7121 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jun 2006 21:23:10 +0000 Subject: fix segfault when module-alsa-source fails to load git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1049 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c4e8689c..68c61be9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -335,7 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { } period_size = fragsize/frame_size; - u = pa_xnew(struct userdata, 1); + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; -- cgit From b91dd2381bffeb0a4b5450ef4ce1f0031909f79a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:28:41 +0000 Subject: set is_hardware flag for a few hw plugins git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1092 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 68c61be9..ca4ac9d0 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -376,6 +376,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + u->source->is_hardware = 1; u->source->userdata = u; u->source->get_latency = source_get_latency_cb; if (u->mixer_handle) { -- cgit From 5d8ccfd83984c6b0559857e6a0bf13037818ca95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Aug 2006 16:50:15 +0000 Subject: try to reduce volume updates in the ALSA sinks/sources: only touch the shadowed hw volme if necessary git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1189 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index ca4ac9d0..3952a385 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -213,13 +213,18 @@ static int source_get_hw_volume_cb(pa_source *s) { assert(u && u->mixer_elem); for (i = 0;i < s->hw_volume.channels;i++) { + long set_vol; + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); - - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); - if (err < 0) + + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + + set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + + /* Try to avoid superfluous volume changes */ + if (set_vol != vol) + s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; @@ -247,10 +252,9 @@ static int source_set_hw_volume_cb(pa_source *s) { if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - vol = vol * (u->hw_volume_max - u->hw_volume_min) / - PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); - if (err < 0) + vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol)) < 0) goto fail; } -- cgit From 7a4e1c9a0ea6143553d6f63ad4b2f96f3c7bb9be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:08:09 +0000 Subject: ALSA: handle write()/read() errors properly by unloading the driver module. This should fix problems when removing USB audio device while pulseaudio is running. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1194 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 76 +++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 24 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 3952a385..b5cf9c70 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -96,13 +96,50 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } -static void xrun_recovery(struct userdata *u) { +static void clear_up(struct userdata *u) { assert(u); + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); - pa_log(__FILE__": *** ALSA-XRUN (capture) ***"); + u->pcm_fdl = u->mixer_fdl = NULL; + + if (u->mixer_handle) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed"); + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } +} + +static int xrun_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info(__FILE__": *** ALSA-XRUN (capture) ***"); + + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + + clear_up(u); + pa_module_unload_request(u->module); + + return -1; + } + + return 0; } static void do_read(struct userdata *u) { @@ -131,11 +168,16 @@ static void do_read(struct userdata *u) { return; if (frames == -EPIPE) { - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; + continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", pa_cstrerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", snd_strerror(-frames)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -164,7 +206,8 @@ static void fdl_callback(void *userdata) { assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; do_read(u); } @@ -182,6 +225,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); + pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index); @@ -468,24 +512,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); - if (u->mixer_handle) - snd_mixer_close(u->mixer_handle); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); -- cgit From bfff23db10db9fe6370f8bfbc8498d2057030a0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:14:35 +0000 Subject: shorten sink/source device descriptions a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1201 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b5cf9c70..63369e47 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -450,7 +450,7 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); + u->source->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); -- cgit From bfa6604b1ddc5e2c0f1aaa15330363724856359b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 23:58:55 +0000 Subject: don't set the sink/source descriptions manually, use the new functions pa_{sink,source}_set_description() instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1205 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 63369e47..6149224a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -359,6 +359,7 @@ int pa__init(pa_core *c, pa_module*m) { size_t frame_size; snd_pcm_info_t *pcm_info = NULL; int err; + char *t; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); @@ -450,7 +451,8 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); + pa_xfree(t); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); -- cgit From bf79e9759112abfa7be5d01de807b24a68038d26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:26:59 +0000 Subject: generate default sink/source names from the device files they belong to git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1223 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 6149224a..b4ef09d9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -88,7 +88,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SOURCE_NAME "alsa_input" #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { @@ -360,6 +359,9 @@ int pa__init(pa_core *c, pa_module*m) { snd_pcm_info_t *pcm_info = NULL; int err; char *t; + const char *name; + char *name_buf = NULL; + int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); @@ -420,7 +422,14 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); + namereg_fail = 0; + } + + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { pa_log(__FILE__": Failed to create source object"); goto fail; } @@ -492,7 +501,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_mute(u->source); finish: - if (ma) + pa_xfree(name_buf); + + if (ma) pa_modargs_free(ma); if (pcm_info) -- cgit From dbe6bdd2bcd035b0b07d70811593be719c5cc7c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:06:05 +0000 Subject: make use of pa_sink_used_by()/pa_source_used_by() wherever applicable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1227 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b4ef09d9..4a8678c9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -91,8 +91,7 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + pa_module_set_used(u->module, u->source ? pa_source_used_by(u->source) : 0); } static void clear_up(struct userdata *u) { -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4a8678c9..c3979df1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -151,7 +151,7 @@ static void do_read(struct userdata *u) { size_t l; if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); + u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); u->memchunk.index = 0; } -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c3979df1..aa0666f1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -126,10 +126,10 @@ static int xrun_recovery(struct userdata *u) { int ret; assert(u); - pa_log_info(__FILE__": *** ALSA-XRUN (capture) ***"); + pa_log_info("*** ALSA-XRUN (capture) ***"); if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); clear_up(u); pa_module_unload_request(u->module); @@ -172,7 +172,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", snd_strerror(-frames)); + pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); clear_up(u); pa_module_unload_request(u->module); @@ -238,7 +238,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u && u->source); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay"); + pa_log("failed to get delay"); s->get_latency = NULL; return 0; } @@ -272,7 +272,7 @@ static int source_get_hw_volume_cb(pa_source *s) { return 0; fail: - pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + pa_log_error("Unable to read volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -303,7 +303,7 @@ static int source_set_hw_volume_cb(pa_source *s) { return 0; fail: - pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + pa_log_error("Unable to set volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -317,7 +317,7 @@ static int source_get_hw_mute_cb(pa_source *s) { err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); if (err) { - pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + pa_log_error("Unable to get switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -336,7 +336,7 @@ static int source_set_hw_mute_cb(pa_source *s) { err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); if (err) { - pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + pa_log_error("Unable to set switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -363,13 +363,13 @@ int pa__init(pa_core *c, pa_module*m) { int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + pa_log("failed to parse sample specification"); goto fail; } @@ -380,7 +380,7 @@ int pa__init(pa_core *c, pa_module*m) { fragsize = pa_bytes_per_second(&ss)/128; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics"); + pa_log("failed to parse buffer metrics"); goto fail; } period_size = fragsize/frame_size; @@ -391,18 +391,18 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { - pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -411,7 +411,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { - pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + pa_log("Error opening mixer: %s", snd_strerror(err)); goto fail; } @@ -429,7 +429,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { - pa_log(__FILE__": Failed to create source object"); + pa_log("Failed to create source object"); goto fail; } @@ -465,7 +465,7 @@ int pa__init(pa_core *c, pa_module*m) { u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } @@ -473,7 +473,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_fdl = pa_alsa_fdlist_new(); assert(u->mixer_fdl); if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); @@ -484,7 +484,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size * frame_size; - pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); + pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From d210ebbb09daddb2c8c8e8e77243e088b0b19c4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:50:56 +0000 Subject: rework memory block management to be thread-safe and mostly lock-free. pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index aa0666f1..9bde46da 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -149,6 +149,7 @@ static void do_read(struct userdata *u) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; + void *p; if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); @@ -157,11 +158,13 @@ static void do_read(struct userdata *u) { assert(u->memchunk.memblock); assert(u->memchunk.length); - assert(u->memchunk.memblock->data); - assert(u->memchunk.memblock->length); assert(u->memchunk.length % u->frame_size == 0); - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + p = pa_memblock_acquire(u->memchunk.memblock); + + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + pa_memblock_release(u->memchunk.memblock); + if (frames == -EAGAIN) return; @@ -178,6 +181,7 @@ static void do_read(struct userdata *u) { pa_module_unload_request(u->module); return; } + pa_memblock_release(u->memchunk.memblock); l = frames * u->frame_size; -- cgit From 8dc62142765249addf131b058c27f931ede1776b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:06:01 +0000 Subject: Revert r1404 and keep it on a development branch until it is fully tested. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1409 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 9bde46da..aa0666f1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -149,7 +149,6 @@ static void do_read(struct userdata *u) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; - void *p; if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); @@ -158,13 +157,11 @@ static void do_read(struct userdata *u) { assert(u->memchunk.memblock); assert(u->memchunk.length); + assert(u->memchunk.memblock->data); + assert(u->memchunk.memblock->length); assert(u->memchunk.length % u->frame_size == 0); - p = pa_memblock_acquire(u->memchunk.memblock); - - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - pa_memblock_release(u->memchunk.memblock); - + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; @@ -181,7 +178,6 @@ static void do_read(struct userdata *u) { pa_module_unload_request(u->module); return; } - pa_memblock_release(u->memchunk.memblock); l = frames * u->frame_size; -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index aa0666f1..596998d1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + 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 @@ -96,13 +96,13 @@ static void update_usage(struct userdata *u) { static void clear_up(struct userdata *u) { assert(u); - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); u->source = NULL; } - + if (u->pcm_fdl) pa_alsa_fdlist_free(u->pcm_fdl); if (u->mixer_fdl) @@ -114,7 +114,7 @@ static void clear_up(struct userdata *u) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } - + if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); snd_pcm_close(u->pcm_handle); @@ -127,7 +127,7 @@ static int xrun_recovery(struct userdata *u) { assert(u); pa_log_info("*** ALSA-XRUN (capture) ***"); - + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); @@ -144,17 +144,17 @@ static void do_read(struct userdata *u) { assert(u); update_usage(u); - + for (;;) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; - + if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); u->memchunk.index = 0; } - + assert(u->memchunk.memblock); assert(u->memchunk.length); assert(u->memchunk.memblock->data); @@ -164,11 +164,11 @@ static void do_read(struct userdata *u) { if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; - + if (frames == -EPIPE) { if (xrun_recovery(u) < 0) return; - + continue; } @@ -180,7 +180,7 @@ static void do_read(struct userdata *u) { } l = frames * u->frame_size; - + post_memchunk = u->memchunk; post_memchunk.length = l; @@ -188,13 +188,13 @@ static void do_read(struct userdata *u) { u->memchunk.index += l; u->memchunk.length -= l; - + if (u->memchunk.length == 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; } - + break; } } @@ -223,7 +223,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); - + pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index); @@ -256,14 +256,14 @@ static int source_get_hw_volume_cb(pa_source *s) { for (i = 0;i < s->hw_volume.channels;i++) { long set_vol; - + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); - + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - + /* Try to avoid superfluous volume changes */ if (set_vol != vol) s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); @@ -361,7 +361,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -378,17 +378,17 @@ int pa__init(pa_core *c, pa_module*m) { /* Fix latency to 100ms */ periods = 12; fragsize = pa_bytes_per_second(&ss)/128; - + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log("failed to parse buffer metrics"); goto fail; } period_size = fragsize/frame_size; - + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; - + snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); @@ -427,7 +427,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); namereg_fail = 0; } - + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { pa_log("Failed to create source object"); goto fail; @@ -490,7 +490,7 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.index = u->memchunk.length = 0; snd_pcm_start(u->pcm_handle); - + ret = 0; /* Get initial mixer settings */ @@ -507,11 +507,11 @@ finish: if (pcm_info) snd_pcm_info_free(pcm_info); - + return ret; fail: - + if (u) pa__done(c, m); @@ -526,10 +526,10 @@ void pa__done(pa_core *c, pa_module*m) { return; clear_up(u); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - + pa_xfree(u); } -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 596998d1..2ea551cb 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + 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, -- cgit From 2b82336df2eb8cf1c9ae150b1850540a88f68ecf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 2 Mar 2007 09:20:54 +0000 Subject: Handle suspended alsa devices. Based on patch by ranma. (closes #26) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1433 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2ea551cb..4061d668 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -143,6 +143,34 @@ static int xrun_recovery(struct userdata *u) { return 0; } + +static int suspend_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info("*** ALSA-SUSPEND (capture) ***"); + + if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { + if (ret == -EAGAIN) + return -1; + + if (ret != -ENOSYS) + pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); + else { + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + } + + if (ret < 0) { + clear_up(u); + pa_module_unload_request(u->module); + return -1; + } + } + + return ret; +} + static void do_read(struct userdata *u) { assert(u); @@ -175,6 +203,13 @@ static void do_read(struct userdata *u) { continue; } + if (frames == -ESTRPIPE) { + if (suspend_recovery(u) < 0) + return; + + continue; + } + pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); clear_up(u); @@ -210,6 +245,10 @@ static void fdl_callback(void *userdata) { if (xrun_recovery(u) < 0) return; + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) + if (suspend_recovery(u) < 0) + return; + do_read(u); } -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 913 ++++++++++++++++++++++++++++----------- 1 file changed, 651 insertions(+), 262 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4061d668..d840cac3 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -26,18 +26,12 @@ #include #endif -#include #include -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - #include #include +#include #include #include @@ -48,6 +42,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-source-symdef.h" @@ -63,20 +62,35 @@ PA_MODULE_USAGE( "rate= " "fragments= " "fragment_size= " - "channel_map=") + "channel_map= " + "mmap=") + +#define DEFAULT_DEVICE "default" struct userdata { + pa_core *core; + pa_module *module; + pa_source *source; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + snd_pcm_t *pcm_handle; + + pa_alsa_fdlist *mixer_fdl; snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; - pa_source *source; - struct pa_alsa_fdlist *pcm_fdl; - struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; - size_t frame_size, fragment_size; - pa_memchunk memchunk; - pa_module *module; + size_t frame_size, fragment_size, hwbuf_size; + unsigned nfragments; + + char *device_name; + + int use_mmap; + + pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { @@ -88,257 +102,438 @@ static const char* const valid_modargs[] = { "fragments", "fragment_size", "channel_map", + "mmap", NULL }; -#define DEFAULT_DEVICE "default" +static int mmap_read(struct userdata *u) { + int work_done = 0; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, u->source ? pa_source_used_by(u->source) : 0); -} + pa_assert(u); + pa_source_assert_ref(u->source); -static void clear_up(struct userdata *u) { - assert(u); + for (;;) { + snd_pcm_sframes_t n; + int err; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t offset, frames; + pa_memchunk chunk; + void *p; - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) { - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); + if (n == -EPIPE) + pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - u->pcm_fdl = u->mixer_fdl = NULL; + if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) + continue; - if (u->mixer_handle) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; - } + if (err == -EAGAIN) + return work_done; - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - } -} + pa_log("snd_pcm_avail_update: %s", snd_strerror(err)); + return -1; + } -static int xrun_recovery(struct userdata *u) { - int ret; - assert(u); +/* pa_log("Got request for %i samples", (int) n); */ - pa_log_info("*** ALSA-XRUN (capture) ***"); + if (n <= 0) + return work_done; - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + frames = n; - clear_up(u); - pa_module_unload_request(u->module); + if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) { - return -1; - } + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); - return 0; -} + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; + if (err == -EAGAIN) + return work_done; -static int suspend_recovery(struct userdata *u) { - int ret; - assert(u); + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); + return -1; + } - pa_log_info("*** ALSA-SUSPEND (capture) ***"); + /* Check these are multiples of 8 bit */ + pa_assert((areas[0].first & 7) == 0); + pa_assert((areas[0].step & 7)== 0); - if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { - if (ret == -EAGAIN) - return -1; + /* We assume a single interleaved memory buffer */ + pa_assert((areas[0].first >> 3) == 0); + pa_assert((areas[0].step >> 3) == u->frame_size); - if (ret != -ENOSYS) - pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); - else { - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); - } + p = (uint8_t*) areas[0].addr + (offset * u->frame_size); + + chunk.memblock = pa_memblock_new_fixed(u->core->mempool, p, frames * u->frame_size, 1); + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; + + pa_source_post(u->source, &chunk); + + /* FIXME: Maybe we can do something to keep this memory block + * a little bit longer around? */ + pa_memblock_unref_fixed(chunk.memblock); + + if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) { + + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); - if (ret < 0) { - clear_up(u); - pa_module_unload_request(u->module); + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; + + if (err == -EAGAIN) + return work_done; + + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; } - } - return ret; + work_done = 1; + +/* pa_log("wrote %i samples", (int) frames); */ + } } -static void do_read(struct userdata *u) { - assert(u); +static int unix_read(struct userdata *u) { + snd_pcm_status_t *status; + int work_done = 0; - update_usage(u); + snd_pcm_status_alloca(&status); - for (;;) { - pa_memchunk post_memchunk; - snd_pcm_sframes_t frames; - size_t l; + pa_assert(u); + pa_source_assert_ref(u->source); - if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); - u->memchunk.index = 0; + for (;;) { + void *p; + snd_pcm_sframes_t t, k; + ssize_t l; + int err; + pa_memchunk chunk; + + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) { + pa_log("Failed to query DSP status data: %s", snd_strerror(err)); + return -1; } - assert(u->memchunk.memblock); - assert(u->memchunk.length); - assert(u->memchunk.memblock->data); - assert(u->memchunk.memblock->length); - assert(u->memchunk.length % u->frame_size == 0); + if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size) + pa_log_debug("Buffer overrun!"); - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; + l = snd_pcm_status_get_avail(status) * u->frame_size; - if (frames == -EPIPE) { - if (xrun_recovery(u) < 0) - return; + if (l <= 0) + return work_done; - continue; - } + chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1); + + k = pa_memblock_get_length(chunk.memblock); + + if (k > l) + k = l; + + k = (k/u->frame_size)*u->frame_size; - if (frames == -ESTRPIPE) { - if (suspend_recovery(u) < 0) - return; + p = pa_memblock_acquire(chunk.memblock); + t = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, k / u->frame_size); + pa_memblock_release(chunk.memblock); +/* pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l); */ + + pa_assert(t != 0); + + if (t < 0) { + pa_memblock_unref(chunk.memblock); + + if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0) continue; + + if (t == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } else { + pa_log("Failed to read data from DSP: %s", snd_strerror(t)); + return -1; } + } - pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); + chunk.index = 0; + chunk.length = t * u->frame_size; - clear_up(u); - pa_module_unload_request(u->module); - return; - } + pa_source_post(u->source, &chunk); + pa_memblock_unref(chunk.memblock); - l = frames * u->frame_size; + work_done = 1; - post_memchunk = u->memchunk; - post_memchunk.length = l; + if (t * u->frame_size >= (unsigned) l) + return work_done; + } +} - pa_source_post(u->source, &post_memchunk); +static pa_usec_t source_get_latency(struct userdata *u) { + pa_usec_t r = 0; + snd_pcm_status_t *status; + snd_pcm_sframes_t frames = 0; + int err; - u->memchunk.index += l; - u->memchunk.length -= l; + snd_pcm_status_alloca(&status); - if (u->memchunk.length == 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } + pa_assert(u); + pa_assert(u->pcm_handle); - break; + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) + pa_log("Failed to get delay: %s", snd_strerror(err)); + else + frames = snd_pcm_status_get_delay(status); + + if (frames > 0) + r = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec); + + return r; +} + +static int build_pollfd(struct userdata *u) { + int err; + struct pollfd *pollfd; + int n; + + pa_assert(u); + pa_assert(u->pcm_handle); + + if ((n = snd_pcm_poll_descriptors_count(u->pcm_handle)) < 0) { + pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n)); + return -1; } + + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + u->alsa_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, n); + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, NULL); + + if ((err = snd_pcm_poll_descriptors(u->pcm_handle, pollfd, n)) < 0) { + pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err)); + return -1; + } + + return 0; } -static void fdl_callback(void *userdata) { - struct userdata *u = userdata; - assert(u); +static int suspend(struct userdata *u) { + pa_assert(u); + pa_assert(u->pcm_handle); - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - if (xrun_recovery(u) < 0) - return; + /* Let's suspend */ + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) - if (suspend_recovery(u) < 0) - return; + if (u->alsa_rtpoll_item) { + pa_rtpoll_item_free(u->alsa_rtpoll_item); + u->alsa_rtpoll_item = NULL; + } - do_read(u); + pa_log_info("Device suspended..."); + + return 0; } -static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { - struct userdata *u = snd_mixer_elem_get_callback_private(elem); +static int unsuspend(struct userdata *u) { + pa_sample_spec ss; + int err, b; + unsigned nfrags; + snd_pcm_uframes_t period_size; - assert(u && u->mixer_handle); + pa_assert(u); + pa_assert(!u->pcm_handle); - if (mask == SND_CTL_EVENT_MASK_REMOVE) - return 0; + pa_log_info("Trying resume..."); - if (mask & SND_CTL_EVENT_MASK_VALUE) { - if (u->source->get_hw_volume) - u->source->get_hw_volume(u->source); - if (u->source->get_hw_mute) - u->source->get_hw_mute(u->source); + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err)); + goto fail; + } - pa_subscription_post(u->source->core, - PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, - u->source->index); + ss = u->source->sample_spec; + nfrags = u->nfragments; + period_size = u->fragment_size / u->frame_size; + b = u->use_mmap; + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + goto fail; } + if (b != u->use_mmap) { + pa_log_warn("Resume failed, couldn't get original access mode."); + goto fail; + } + + if (!pa_sample_spec_equal(&ss, &u->source->sample_spec)) { + pa_log_warn("Resume failed, couldn't restore original sample settings."); + goto fail; + } + + if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { + pa_log_warn("Resume failed, couldn't restore original fragment settings."); + goto fail; + } + + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); + goto fail; + } + + if (build_pollfd(u) < 0) + goto fail; + + snd_pcm_start(u->pcm_handle); + + /* FIXME: We need to reload the volume somehow */ + + pa_log_info("Resumed successfully..."); + return 0; + +fail: + if (u->pcm_handle) { + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } + + return -1; } -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - assert(s && u && u->source); +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->pcm_handle) + r = source_get_latency(u); + + *((pa_usec_t*) data) = r; + + return 0; + } + + case PA_SOURCE_MESSAGE_SET_STATE: + + switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state)); + + if (suspend(u) < 0) + return -1; + + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + + if (u->source->thread_info.state == PA_SOURCE_INIT) { + if (build_pollfd(u) < 0) + return -1; + + snd_pcm_start(u->pcm_handle); + } + + if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { + if (unsuspend(u) < 0) + return -1; + } + + break; - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log("failed to get delay"); - s->get_latency = NULL; + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + } + + break; + } + + return pa_source_process_msg(o, code, data, offset, chunk); +} + +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); + + pa_assert(u); + pa_assert(u->mixer_handle); + + if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + pa_source_get_volume(u->source); + pa_source_get_mute(u->source); } - return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + return 0; } -static int source_get_hw_volume_cb(pa_source *s) { +static int source_get_volume_cb(pa_source *s) { struct userdata *u = s->userdata; - long vol; int err; int i; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0;i < s->hw_volume.channels;i++) { - long set_vol; + for (i = 0; i < s->sample_spec.channels; i++) { + long set_vol, vol; - assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; /* Try to avoid superfluous volume changes */ if (set_vol != vol) - s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); + s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; fail: pa_log_error("Unable to read volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int source_set_hw_volume_cb(pa_source *s) { +static int source_set_volume_cb(pa_source *s) { struct userdata *u = s->userdata; int err; - pa_volume_t vol; int i; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0;i < s->hw_volume.channels;i++) { - assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + for (i = 0; i < s->sample_spec.channels; i++) { + long alsa_vol; + pa_volume_t vol; - vol = s->hw_volume.values[i]; + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + vol = s->volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol)) < 0) + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, alsa_vol)) < 0) goto fail; } @@ -346,55 +541,159 @@ static int source_set_hw_volume_cb(pa_source *s) { fail: pa_log_error("Unable to set volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int source_get_hw_mute_cb(pa_source *s) { +static int source_get_mute_cb(pa_source *s) { struct userdata *u = s->userdata; int err, sw; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); - if (err) { + if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) { pa_log_error("Unable to get switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } - s->hw_muted = !sw; + s->muted = !sw; return 0; } -static int source_set_hw_mute_cb(pa_source *s) { +static int source_set_mute_cb(pa_source *s) { struct userdata *u = s->userdata; int err; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); - if (err) { + if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) { pa_log_error("Unable to set switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } return 0; } -int pa__init(pa_core *c, pa_module*m) { +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + + /* Read some data and pass it to the sources */ + if (PA_SOURCE_OPENED(u->source->thread_info.state)) { + + if (u->use_mmap) { + if (mmap_read(u) < 0) + goto fail; + + } else { + if (unix_read(u) < 0) + goto fail; + } + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + /* Tell ALSA about this and process its response */ + if (PA_SOURCE_OPENED(u->source->thread_info.state)) { + struct pollfd *pollfd; + unsigned short revents = 0; + int err; + unsigned n; + + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, &n); + + if ((err = snd_pcm_poll_descriptors_revents(u->pcm_handle, pollfd, n, &revents)) < 0) { + pa_log("snd_pcm_poll_descriptors_revents() failed: %s", snd_strerror(err)); + goto fail; + } + + if (revents & (POLLERR|POLLNVAL|POLLHUP)) { + + if (revents & POLLERR) + pa_log_warn("Got POLLERR from ALSA"); + if (revents & POLLNVAL) + pa_log_warn("Got POLLNVAL from ALSA"); + if (revents & POLLHUP) + pa_log_warn("Got POLLHUP from ALSA"); + + /* Try to recover from this error */ + + switch (snd_pcm_state(u->pcm_handle)) { + + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err)); + goto fail; + } + break; + + case SND_PCM_STATE_SUSPENDED: + if ((err = snd_pcm_recover(u->pcm_handle, -ESTRPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err)); + goto fail; + } + break; + + default: + + snd_pcm_drop(u->pcm_handle); + + if ((err = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err)); + goto fail; + } + break; + } + } + } + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; - int ret = -1; struct userdata *u = NULL; - const char *dev; + char *dev; pa_sample_spec ss; pa_channel_map map; - unsigned periods, fragsize; + unsigned nfrags, frag_size; snd_pcm_uframes_t period_size; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -403,64 +702,125 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; + int use_mmap = 1, b; + + snd_pcm_info_alloca(&pcm_info); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log("failed to parse sample specification"); + pa_log("Failed to parse sample specification"); goto fail; } frame_size = pa_frame_size(&ss); - /* Fix latency to 100ms */ - periods = 12; - fragsize = pa_bytes_per_second(&ss)/128; + nfrags = m->core->default_n_fragments; + frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); + if (frag_size <= 0) + frag_size = frame_size; + + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) { + pa_log("Failed to parse buffer metrics"); + goto fail; + } + period_size = frag_size/frame_size; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log("failed to parse buffer metrics"); + if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { + pa_log("Failed to parse mmap argument."); goto fail; } - period_size = fragsize/frame_size; u = pa_xnew0(struct userdata, 1); - m->userdata = u; + u->core = m->core; u->module = m; + m->userdata = u; + u->use_mmap = use_mmap; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + u->alsa_rtpoll_item = NULL; + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); snd_config_update_free_global(); - if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - goto fail; + + dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); + + for (;;) { + + if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + b = use_mmap; + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + + if (err == -EPERM) { + /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ + + if (pa_startswith(dev, "hw:")) { + char *d = pa_sprintf_malloc("plughw:%s", dev+3); + pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); + pa_xfree(dev); + dev = d; + + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + continue; + } + } + + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + break; } - if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || - (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + u->device_name = dev; + + if (use_mmap && !b) { + pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); + u->use_mmap = use_mmap = b; + } + + if (u->use_mmap) + pa_log_info("Successfully enabled mmap() mode."); + + if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); goto fail; } + /* ALSA might tweak the sample spec, so recalculate the frame size */ + frame_size = pa_frame_size(&ss); + if (ss.channels != map.channels) /* Seems ALSA didn't like the channel number, so let's fix the channel map */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log("Error opening mixer: %s", snd_strerror(err)); - goto fail; - } + else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } } if ((name = pa_modargs_get_value(ma, "source_name", NULL))) @@ -470,16 +830,39 @@ int pa__init(pa_core *c, pa_module*m) { namereg_fail = 0; } - if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { + u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + + if (!u->source) { pa_log("Failed to create source object"); goto fail; } - u->source->is_hardware = 1; + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_description(u->source, t = pa_sprintf_malloc( + "ALSA PCM on %s (%s)%s", + dev, + snd_pcm_info_get_name(pcm_info), + use_mmap ? " via DMA" : "")); + pa_xfree(t); + + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; + + u->frame_size = frame_size; + u->fragment_size = frag_size = period_size * frame_size; + u->nfragments = nfrags; + u->hwbuf_size = u->fragment_size * nfrags; + + pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size); + if (u->mixer_handle) { - assert(u->mixer_elem); + pa_assert(u->mixer_elem); + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { int i; @@ -489,89 +872,95 @@ int pa__init(pa_core *c, pa_module*m) { } if (i == ss.channels) { - u->source->get_hw_volume = source_get_hw_volume_cb; - u->source->set_hw_volume = source_set_hw_volume_cb; - snd_mixer_selem_get_capture_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + u->source->get_volume = source_get_volume_cb; + u->source->set_volume = source_set_volume_cb; + snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); } } + if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { - u->source->get_hw_mute = source_get_hw_mute_cb; - u->source->set_hw_mute = source_set_hw_mute_cb; + u->source->get_mute = source_get_mute_cb; + u->source->set_mute = source_set_mute_cb; } - } - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); - pa_xfree(t); - u->pcm_fdl = pa_alsa_fdlist_new(); - assert(u->pcm_fdl); - if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log("failed to initialise file descriptor monitoring"); - goto fail; - } - - if (u->mixer_handle) { u->mixer_fdl = pa_alsa_fdlist_new(); - assert(u->mixer_fdl); - if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + + if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { pa_log("failed to initialise file descriptor monitoring"); goto fail; } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); } else u->mixer_fdl = NULL; - u->frame_size = frame_size; - u->fragment_size = period_size * frame_size; - - pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - snd_pcm_start(u->pcm_handle); - - ret = 0; - + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } /* Get initial mixer settings */ - if (u->source->get_hw_volume) - u->source->get_hw_volume(u->source); - if (u->source->get_hw_mute) - u->source->get_hw_mute(u->source); + if (u->source->get_volume) + u->source->get_volume(u->source); + if (u->source->get_mute) + u->source->get_mute(u->source); -finish: - pa_xfree(name_buf); - - if (ma) - pa_modargs_free(ma); + pa_source_put(u->source); - if (pcm_info) - snd_pcm_info_free(pcm_info); + pa_modargs_free(ma); - return ret; + return 0; fail: - if (u) - pa__done(c, m); + if (ma) + pa_modargs_free(ma); - goto finish; + pa__done(m); + + return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); + if (u->source) + pa_source_unlink(u->source); - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); + + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + pa_xfree(u->device_name); pa_xfree(u); -} + snd_config_update_free_global(); +} -- cgit From 7bfd1b2f01613dd14b9ca478ae530c1641aa46a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 02:58:26 +0000 Subject: make rtprio and nice level actually configurable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2014 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index d840cac3..a862657f 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -592,8 +592,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); -- cgit From e313fe1b3d0d9f9945c41c151d72edbe9cf1ec54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 18:25:40 +0000 Subject: tag modules that may only be loaded once at most especially, and enforce that in the module loader git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2043 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a862657f..1a6113a7 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -51,9 +51,10 @@ #include "alsa-util.h" #include "module-alsa-source-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ALSA Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ALSA Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source_name= " "device= " @@ -63,7 +64,7 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= " "channel_map= " - "mmap=") + "mmap="); #define DEFAULT_DEVICE "default" -- cgit From d17bb53d3ebfbd7046719400264bd87830c140d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:37:44 +0000 Subject: Completely rework ALSA device selection code: choose the device to open depending on the requested number of channels and channel map. In most cases it will now suffice to set default-channels=6 to enable 5.1 sound for all devices that support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2050 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 69 +++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 39 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 1a6113a7..2d2bfa07 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -58,6 +58,7 @@ PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source_name= " "device= " + "device_id= " "format= " "channels= " "rate= " @@ -89,13 +90,14 @@ struct userdata { char *device_name; - int use_mmap; + pa_bool_t use_mmap; pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { "device", + "device_id", "source_name", "channels", "rate", @@ -342,7 +344,8 @@ static int suspend(struct userdata *u) { static int unsuspend(struct userdata *u) { pa_sample_spec ss; - int err, b; + int err; + pa_bool_t b; unsigned nfrags; snd_pcm_uframes_t period_size; @@ -362,7 +365,7 @@ static int unsuspend(struct userdata *u) { period_size = u->fragment_size / u->frame_size; b = u->use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b, TRUE)) < 0) { pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -691,10 +694,10 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; - char *dev; + const char *dev_id; pa_sample_spec ss; pa_channel_map map; - unsigned nfrags, frag_size; + uint32_t nfrags, frag_size; snd_pcm_uframes_t period_size; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -703,7 +706,7 @@ int pa__init(pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - int use_mmap = 1, b; + pa_bool_t use_mmap = TRUE, b; snd_pcm_info_alloca(&pcm_info); @@ -750,43 +753,31 @@ int pa__init(pa_module*m) { snd_config_update_free_global(); - dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); - - for (;;) { + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { - if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - pa_xfree(dev); + if (!(u->pcm_handle = pa_alsa_open_by_device_id( + dev_id, + &u->device_name, + &ss, &map, + SND_PCM_STREAM_CAPTURE, + &nfrags, &period_size, + &b))) goto fail; - } - - b = use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { - - if (err == -EPERM) { - /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ - if (pa_startswith(dev, "hw:")) { - char *d = pa_sprintf_malloc("plughw:%s", dev+3); - pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); - pa_xfree(dev); - dev = d; + } else { - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - continue; - } - } - - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); - pa_xfree(dev); + if (!(u->pcm_handle = pa_alsa_open_by_device_string( + pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), + &u->device_name, + &ss, &map, + SND_PCM_STREAM_CAPTURE, + &nfrags, &period_size, + &b))) goto fail; - } - - break; } - u->device_name = dev; + pa_assert(u->device_name); + pa_log_info("Successfully opened device %s.", u->device_name); if (use_mmap && !b) { pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); @@ -817,7 +808,7 @@ int pa__init(pa_module*m) { pa_log("Error opening mixer: %s", snd_strerror(err)); else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; @@ -827,7 +818,7 @@ int pa__init(pa_module*m) { if ((name = pa_modargs_get_value(ma, "source_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); + name = name_buf = pa_sprintf_malloc("alsa_input.%s", u->device_name); namereg_fail = 0; } @@ -847,7 +838,7 @@ int pa__init(pa_module*m) { pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_description(u->source, t = pa_sprintf_malloc( "ALSA PCM on %s (%s)%s", - dev, + u->device_name, snd_pcm_info_get_name(pcm_info), use_mmap ? " via DMA" : "")); pa_xfree(t); -- cgit From 7462ab1aca6ffb7b1e97834e2a8d0e0129604f6f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 23:42:15 +0000 Subject: Rework ALSA mixer channel detection code. This time we actually care about the channel names the ALSA mixer exports for us git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2055 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 54 ++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2d2bfa07..23a2f921 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -93,6 +93,8 @@ struct userdata { pa_bool_t use_mmap; pa_rtpoll_item *alsa_rtpoll_item; + + snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST]; }; static const char* const valid_modargs[] = { @@ -494,9 +496,9 @@ static int source_get_volume_cb(pa_source *s) { for (i = 0; i < s->sample_spec.channels; i++) { long set_vol, vol; - pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); - if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &vol)) < 0) goto fail; set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; @@ -528,7 +530,7 @@ static int source_set_volume_cb(pa_source *s) { long alsa_vol; pa_volume_t vol; - pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); vol = s->volume.values[i]; @@ -537,7 +539,7 @@ static int source_set_volume_cb(pa_source *s) { alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, alsa_vol)) < 0) + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0) goto fail; } @@ -753,6 +755,8 @@ int pa__init(pa_module*m) { snd_config_update_free_global(); + b = use_mmap; + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { if (!(u->pcm_handle = pa_alsa_open_by_device_id( @@ -800,16 +804,28 @@ int pa__init(pa_module*m) { /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - if (ss.channels != map.channels) - /* Seems ALSA didn't like the channel number, so let's fix the channel map */ - pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log("Error opening mixer: %s", snd_strerror(err)); else { + pa_bool_t found = FALSE; + + if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0) + found = TRUE; + else { + char *md = pa_sprintf_malloc("hw:%s", dev_id); + + if (strcmp(u->device_name, md)) + if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) + found = TRUE; + + pa_xfree(md); + } - if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { + if (found) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) + found = FALSE; + + if (!found) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } @@ -843,7 +859,7 @@ int pa__init(pa_module*m) { use_mmap ? " via DMA" : "")); pa_xfree(t); - u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY; u->frame_size = frame_size; u->fragment_size = frag_size = period_size * frame_size; @@ -855,30 +871,24 @@ int pa__init(pa_module*m) { if (u->mixer_handle) { pa_assert(u->mixer_elem); - if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { - int i; - - for (i = 0;i < ss.channels;i++) { - if (!snd_mixer_selem_has_capture_channel(u->mixer_elem, i)) - break; - } - - if (i == ss.channels) { + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) + if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0) { u->source->get_volume = source_get_volume_cb; u->source->set_volume = source_set_volume_cb; snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; } - } if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { u->source->get_mute = source_get_mute_cb; u->source->set_mute = source_set_mute_cb; + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; } u->mixer_fdl = pa_alsa_fdlist_new(); if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { - pa_log("failed to initialise file descriptor monitoring"); + pa_log("Failed to initialize file descriptor monitoring"); goto fail; } -- cgit