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/alsa-util.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/modules/alsa-util.c (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c new file mode 100644 index 00000000..8318f945 --- /dev/null +++ b/src/modules/alsa-util.c @@ -0,0 +1,125 @@ +/* $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 + +#include +#include +#include + +#include "alsa-util.h" + +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period and *period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; + snd_pcm_hw_params_t *hwparams = NULL; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; + assert(pcm_handle && ss && periods && period_size); + + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || + snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || + (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || + (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) + goto finish; + + if (snd_pcm_prepare(pcm_handle) < 0) + goto finish; + + if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || + snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + goto finish; + + assert(buffer_size > 0); + assert(*period_size > 0); + *periods = buffer_size / *period_size; + assert(*periods > 0); + + ret = 0; + +finish: + if (hwparams) + snd_pcm_hw_params_free(hwparams); + + return ret; +} + +/* Allocate an IO event for every ALSA poll descriptor for the + * specified ALSA device. Return a pointer to such an array in + * *io_events. Store the length of that array in *n_io_events. Use the + * specified callback function and userdata. The array has to be freed + * with pa_free_io_events(). */ +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { + unsigned i; + struct pollfd *pfds, *ppfd; + pa_io_event **ios; + assert(pcm_handle && m && io_events && n_io_events && cb); + + *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); + + pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { + pa_xfree(pfds); + return -1; + } + + *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); + + for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { + *ios = m->io_new(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); + assert(*ios); + } + + pa_xfree(pfds); + return 0; +} + +/* Free the memory allocated by pa_create_io_events() */ +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { + unsigned i; + pa_io_event **ios; + assert(m && io_events); + + for (ios = io_events, i = 0; i < n_io_events; i++, ios++) + m->io_free(*ios); + pa_xfree(io_events); +} -- cgit From 9bcb4134137902b886ae4debe34f2d5c372c177b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:47:46 +0000 Subject: fix snd_pcm_hw_params_set_rate_near() usage git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@540 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8318f945..68e9f975 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -38,6 +38,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; + unsigned int r = ss->rate; + static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, @@ -53,12 +55,15 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL) < 0 || snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || snd_pcm_hw_params(pcm_handle, hwparams) < 0) goto finish; + + if (ss->rate != r) + pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.\n", ss->rate, r); if (snd_pcm_prepare(pcm_handle) < 0) goto finish; -- 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/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 68e9f975..1b254f51 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -63,7 +63,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 goto finish; if (ss->rate != r) - pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.\n", ss->rate, r); + pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); if (snd_pcm_prepare(pcm_handle) < 0) goto finish; -- 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/alsa-util.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 1b254f51..4e1db545 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -128,3 +128,42 @@ void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_i m->io_free(*ios); pa_xfree(io_events); } + +int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { + int err; + + assert(mixer && dev); + + if ((err = snd_mixer_attach(mixer, dev)) < 0) { + pa_log_warn(__FILE__": Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + return -1; + } + + if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) { + pa_log_warn(__FILE__": Unable to register mixer: %s", snd_strerror(err)); + return -1; + } + + if ((err = snd_mixer_load(mixer)) < 0) { + pa_log_warn(__FILE__": Unable to load mixer: %s", snd_strerror(err)); + return -1; + } + + return 0; +} + +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + snd_mixer_selem_id_alloca(&sid); + + assert(mixer && name); + + snd_mixer_selem_id_set_name(sid, name); + + elem = snd_mixer_find_selem(mixer, sid); + if (!elem) + pa_log_warn(__FILE__": Cannot find mixer control %s", snd_mixer_selem_id_get_name(sid)); + + return elem; +} -- 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/alsa-util.c | 225 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 182 insertions(+), 43 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 4e1db545..5f4323f8 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -32,6 +32,188 @@ #include "alsa-util.h" +struct pa_alsa_fdlist { + int num_fds; + struct pollfd *fds; + /* This is a temporary buffer used to avoid lots of mallocs */ + struct pollfd *work_fds; + + snd_pcm_t *pcm; + + pa_mainloop_api *m; + pa_defer_event *defer; + pa_io_event **ios; + + int polled; + + void (*cb)(void *userdata); + void *userdata; +}; + +static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { + struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + int err, i; + unsigned short revents; + + assert(a && fdl && fdl->pcm); + + if (fdl->polled) + return; + + fdl->polled = 1; + + memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds); + + for (i = 0;i < fdl->num_fds;i++) { + if (e == fdl->ios[i]) { + if (events & PA_IO_EVENT_INPUT) + fdl->work_fds[i].revents |= POLLIN; + if (events & PA_IO_EVENT_OUTPUT) + fdl->work_fds[i].revents |= POLLOUT; + if (events & PA_IO_EVENT_ERROR) + fdl->work_fds[i].revents |= POLLERR; + if (events & PA_IO_EVENT_HANGUP) + fdl->work_fds[i].revents |= POLLHUP; + break; + } + } + + assert(i != fdl->num_fds); + + err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + if (err < 0) { + pa_log_error(__FILE__": Unable to get poll revent: %s", + snd_strerror(err)); + a->defer_enable(fdl->defer, 0); + return; + } + + if (revents) + fdl->cb(fdl->userdata); +} + +static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { + struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + int num_fds, i, err; + struct pollfd *temp; + + assert(a && fdl && fdl->pcm); + + num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + assert(num_fds > 0); + + if (num_fds != fdl->num_fds) { + if (fdl->fds) + pa_xfree(fdl->fds); + if (fdl->work_fds) + pa_xfree(fdl->work_fds); + fdl->fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + } + + memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); + err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + if (err < 0) { + pa_log_error(__FILE__": Unable to get poll descriptors: %s", + snd_strerror(err)); + a->defer_enable(fdl->defer, 0); + return; + } + + fdl->polled = 0; + + if (memcmp(fdl->fds, fdl->work_fds, sizeof(struct pollfd) * num_fds) == 0) + return; + + if (fdl->ios) { + for (i = 0;i < fdl->num_fds;i++) + a->io_free(fdl->ios[i]); + if (num_fds != fdl->num_fds) { + pa_xfree(fdl->ios); + fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); + assert(fdl->ios); + } + } else { + fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); + assert(fdl->ios); + } + + /* Swap pointers */ + temp = fdl->work_fds; + fdl->work_fds = fdl->fds; + fdl->fds = temp; + + fdl->num_fds = num_fds; + + for (i = 0;i < num_fds;i++) { + fdl->ios[i] = a->io_new(a, fdl->fds[i].fd, + ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), + io_cb, fdl); + assert(fdl->ios[i]); + } +} + +struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { + struct pa_alsa_fdlist *fdl; + + fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); + assert(fdl); + + fdl->num_fds = 0; + fdl->fds = NULL; + fdl->work_fds = NULL; + + fdl->pcm = NULL; + + fdl->m = NULL; + fdl->defer = NULL; + fdl->ios = NULL; + + fdl->polled = 0; + + return fdl; +} + +void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { + assert(fdl); + + if (fdl->defer) { + assert(fdl->m); + fdl->m->defer_free(fdl->defer); + } + + if (fdl->ios) { + int i; + assert(fdl->m); + for (i = 0;i < fdl->num_fds;i++) + fdl->m->io_free(fdl->ios[0]); + pa_xfree(fdl->ios); + } + + if (fdl->fds) + pa_xfree(fdl->fds); + if (fdl->work_fds) + pa_xfree(fdl->work_fds); + + pa_xfree(fdl); +} + +int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata) { + assert(fdl && pcm_handle && m && !fdl->m && cb); + + fdl->pcm = pcm_handle; + fdl->m = m; + + fdl->defer = m->defer_new(m, defer_cb, fdl); + assert(fdl->defer); + + fdl->cb = cb; + fdl->userdata = userdata; + + return 0; +} + /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { @@ -86,49 +268,6 @@ finish: return ret; } -/* Allocate an IO event for every ALSA poll descriptor for the - * specified ALSA device. Return a pointer to such an array in - * *io_events. Store the length of that array in *n_io_events. Use the - * specified callback function and userdata. The array has to be freed - * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { - unsigned i; - struct pollfd *pfds, *ppfd; - pa_io_event **ios; - assert(pcm_handle && m && io_events && n_io_events && cb); - - *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); - - pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { - pa_xfree(pfds); - return -1; - } - - *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); - - for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { - *ios = m->io_new(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); - assert(*ios); - } - - pa_xfree(pfds); - return 0; -} - -/* Free the memory allocated by pa_create_io_events() */ -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { - unsigned i; - pa_io_event **ios; - assert(m && io_events); - - for (ios = io_events, i = 0; i < n_io_events; i++, ios++) - m->io_free(*ios); - pa_xfree(io_events); -} - int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; -- 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/alsa-util.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5f4323f8..adb6f3f1 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -39,6 +39,7 @@ struct pa_alsa_fdlist { struct pollfd *work_fds; snd_pcm_t *pcm; + snd_mixer_t *mixer; pa_mainloop_api *m; pa_defer_event *defer; @@ -55,7 +56,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t int err, i; unsigned short revents; - assert(a && fdl && fdl->pcm); + assert(a && fdl && (fdl->pcm || fdl->mixer) && fdl->fds && fdl->work_fds); if (fdl->polled) return; @@ -80,7 +81,11 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t assert(i != fdl->num_fds); - err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + if (fdl->pcm) + err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + else + err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); + if (err < 0) { pa_log_error(__FILE__": Unable to get poll revent: %s", snd_strerror(err)); @@ -88,8 +93,12 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t return; } - if (revents) - fdl->cb(fdl->userdata); + if (revents) { + if (fdl->pcm) + fdl->cb(fdl->userdata); + else + snd_mixer_handle_events(fdl->mixer); + } } static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { @@ -97,9 +106,12 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { int num_fds, i, err; struct pollfd *temp; - assert(a && fdl && fdl->pcm); + assert(a && fdl && (fdl->pcm || fdl->mixer)); - num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + if (fdl->pcm) + num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + else + num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); assert(num_fds > 0); if (num_fds != fdl->num_fds) { @@ -112,7 +124,12 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { } memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); - err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + + if (fdl->pcm) + err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + else + err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); + if (err < 0) { pa_log_error(__FILE__": Unable to get poll descriptors: %s", snd_strerror(err)); @@ -165,6 +182,7 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { fdl->work_fds = NULL; fdl->pcm = NULL; + fdl->mixer = NULL; fdl->m = NULL; fdl->defer = NULL; @@ -214,6 +232,18 @@ int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, p return 0; } +int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { + assert(fdl && mixer_handle && m && !fdl->m); + + fdl->mixer = mixer_handle; + fdl->m = m; + + fdl->defer = m->defer_new(m, defer_cb, fdl); + assert(fdl->defer); + + return 0; +} + /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { -- cgit From f22d8ab3fe46e971f40bed21b159cf0c54d05f98 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 18:35:45 +0000 Subject: Return the proper error code so that we get a correct error message. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@627 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index adb6f3f1..c7be4790 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -263,25 +263,25 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 }; assert(pcm_handle && ss && periods && period_size); - if (snd_pcm_hw_params_malloc(&hwparams) < 0 || - snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL) < 0 || - snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || - (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) + if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || + (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || + (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || + (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || + (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || + (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || + (*periods > 0 && (ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL)) < 0) || + (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; if (ss->rate != r) pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); - if (snd_pcm_prepare(pcm_handle) < 0) + if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; - if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || - snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + if ((ret = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0 || + (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; assert(buffer_size > 0); -- cgit From 4e56725a60da8a1c80442ab16f7fe21147b143e9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 18:37:13 +0000 Subject: It's safer to set buffer size than to try setting number of periods. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@628 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index c7be4790..683db6c0 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -262,6 +262,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, }; assert(pcm_handle && ss && periods && period_size); + + buffer_size = *periods * *period_size; if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || @@ -269,7 +271,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || - (*periods > 0 && (ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; -- cgit From e75cc68685c598deb71fdd0de4b68d43c595362d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 16 Apr 2006 09:23:27 +0000 Subject: Fix ALSA fd handling to be compatible with blocking deferred events. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@724 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 683db6c0..2f9be07a 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -89,7 +89,6 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t if (err < 0) { pa_log_error(__FILE__": Unable to get poll revent: %s", snd_strerror(err)); - a->defer_enable(fdl->defer, 0); return; } @@ -99,6 +98,8 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t else snd_mixer_handle_events(fdl->mixer); } + + a->defer_enable(fdl->defer, 1); } static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { @@ -108,6 +109,8 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { assert(a && fdl && (fdl->pcm || fdl->mixer)); + a->defer_enable(fdl->defer, 0); + if (fdl->pcm) num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); else @@ -133,7 +136,6 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { if (err < 0) { pa_log_error(__FILE__": Unable to get poll descriptors: %s", snd_strerror(err)); - a->defer_enable(fdl->defer, 0); return; } -- cgit From 746adcfed5dc396bc4820724b2e951369fc63aeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:31:50 +0000 Subject: fix a couple of issues I found when compiling polypaudio with gcc 2.95 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@754 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 2f9be07a..dcc0e020 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -51,7 +51,7 @@ struct pa_alsa_fdlist { void *userdata; }; -static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { +static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; int err, i; unsigned short revents; @@ -102,7 +102,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t a->defer_enable(fdl->defer, 1); } -static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { +static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; int num_fds, i, err; struct pollfd *temp; -- cgit From 53930f4455dddc44fd260b151839aef0c76ce433 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 28 Apr 2006 07:28:48 +0000 Subject: Zero the fd list since we do a memcmp on it later. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@818 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index dcc0e020..8bb33c2f 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -122,7 +122,7 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u pa_xfree(fdl->fds); if (fdl->work_fds) pa_xfree(fdl->work_fds); - fdl->fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->fds = pa_xmalloc0(sizeof(struct pollfd) * num_fds); fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); } -- 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/alsa-util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8bb33c2f..4c9cde9e 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -340,3 +340,47 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { return elem; } + +pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + /* The standard ALSA channel order */ + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } +} -- cgit From 0231e6ea4100ccb6c525012c0dd51dbb88aab189 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:19:02 +0000 Subject: first set buffer size, and afterwards period size git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@854 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 4c9cde9e..a8192165 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -273,8 +273,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || - (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; -- 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/alsa-util.c | 44 -------------------------------------------- 1 file changed, 44 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index a8192165..503b8efb 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -340,47 +340,3 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { return elem; } - -pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - pa_channel_map_init(m); - - m->channels = channels; - - /* The standard ALSA channel order */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } -} -- 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/alsa-util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 503b8efb..122f4419 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -27,7 +27,8 @@ #include #include -#include +#include + #include #include "alsa-util.h" -- 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/alsa-util.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 122f4419..22e623f6 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -249,11 +249,12 @@ int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_han /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; unsigned int r = ss->rate; + unsigned int c = ss->channels; static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, @@ -273,14 +274,24 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || - (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || + (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; - if (ss->rate != r) + if (ss->rate != r) { pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + + /* If the sample rate deviates too much, we need to resample */ + if (r < ss->rate*.9 || r > ss->rate*1.1) + ss->rate = r; + } + + if (ss->channels != c) { + pa_log_info(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + ss->channels = c; + } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; -- 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/alsa-util.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 22e623f6..be0fc064 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -337,18 +337,29 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { return 0; } -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) { snd_mixer_elem_t *elem; - snd_mixer_selem_id_t *sid; + snd_mixer_selem_id_t *sid = NULL; snd_mixer_selem_id_alloca(&sid); - assert(mixer && name); + assert(mixer); + assert(name); snd_mixer_selem_id_set_name(sid, name); - elem = snd_mixer_find_selem(mixer, sid); - if (!elem) - pa_log_warn(__FILE__": Cannot find mixer control %s", snd_mixer_selem_id_get_name(sid)); + if (!(elem = snd_mixer_find_selem(mixer, sid))) { + pa_log_warn(__FILE__": Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + + if (fallback) { + snd_mixer_selem_id_set_name(sid, fallback); + + if (!(elem = snd_mixer_find_selem(mixer, sid))) + pa_log_warn(__FILE__": Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + } + } + + if (elem) + pa_log_warn(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } -- cgit From 9f2026da05582c154b2cd833fce8e877fb9d5375 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:57:41 +0000 Subject: downgrade a log message git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@994 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index be0fc064..99c1cfa3 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -359,7 +359,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const } if (elem) - pa_log_warn(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } -- cgit From 79b6c31f2303e34f016363ced6dad3bc3ff35c54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 31 May 2006 00:05:38 +0000 Subject: decrease maximum allowed sample frequency for ALSA devices to 5%, since 48000 would otherwise match with 44100 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@995 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 99c1cfa3..5b6d72e7 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -284,7 +284,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ - if (r < ss->rate*.9 || r > ss->rate*1.1) + if (r < ss->rate*.95 || r > ss->rate*1.05) ss->rate = r; } -- cgit From a529b281ebe32ee07f80f77aa13e24d65ee15eba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jun 2006 19:33:05 +0000 Subject: if S16NE is not supported, fall back to S16RE. If FLOAT32NE is not supported, fall back to FLOAT32NE. If still nothing is supported, try everything else in order git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1020 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 84 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 14 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5b6d72e7..2ead58c8 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -247,15 +247,8 @@ int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_han return 0; } -/* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { - int ret = -1; - snd_pcm_uframes_t buffer_size; - snd_pcm_hw_params_t *hwparams = NULL; - unsigned int r = ss->rate; - unsigned int c = ss->channels; - +static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) { + static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, @@ -265,15 +258,73 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, }; - assert(pcm_handle && ss && periods && period_size); + + static const pa_sample_format_t try_order[] = { + PA_SAMPLE_S16NE, + PA_SAMPLE_S16RE, + PA_SAMPLE_FLOAT32NE, + PA_SAMPLE_FLOAT32RE, + PA_SAMPLE_ULAW, + PA_SAMPLE_ALAW, + PA_SAMPLE_U8, + PA_SAMPLE_INVALID + }; + + int i, ret; + + assert(pcm_handle); + assert(f); + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + + if (*f == PA_SAMPLE_FLOAT32BE) + *f = PA_SAMPLE_FLOAT32LE; + else if (*f == PA_SAMPLE_FLOAT32LE) + *f = PA_SAMPLE_FLOAT32BE; + else if (*f == PA_SAMPLE_S16BE) + *f = PA_SAMPLE_S16LE; + else if (*f == PA_SAMPLE_S16LE) + *f = PA_SAMPLE_S16BE; + else + goto try_auto; + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + +try_auto: + + for (i = 0; try_order[i] != PA_SAMPLE_INVALID; i++) { + *f = try_order[i]; + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + } + + return -1; +} + +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period and *period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; + unsigned int r = ss->rate; + unsigned int c = ss->channels; + pa_sample_format_t f = ss->format; + snd_pcm_hw_params_t *hwparams; + + assert(pcm_handle); + assert(ss); + assert(periods); + assert(period_size); buffer_size = *periods * *period_size; if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || - (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || - (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || + (ret = set_format(pcm_handle, hwparams, &f)) < 0 || (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || @@ -281,7 +332,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -289,9 +340,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_info(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); ss->channels = c; } + + if (ss->format != f) { + pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + ss->format = f; + } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; -- cgit From e26bd47282e679b384568f4dd916f13277b271fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jun 2006 23:36:03 +0000 Subject: * make hw param settings easier to debug by splitting up long if * actually set the sample rate * disable resampling done by ALSA git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1024 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 2ead58c8..fafcac48 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -323,12 +323,24 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || - (ret = set_format(pcm_handle, hwparams, &f)) < 0 || - (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || - (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || - (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || - (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) + (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || + (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + goto finish; + + if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) + goto finish; + + if ((*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)) + goto finish; + + if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; if (ss->rate != r) { -- 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/alsa-util.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index fafcac48..04a2d849 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.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. ***/ @@ -26,10 +26,10 @@ #include #include -#include -#include +#include +#include -#include +#include #include "alsa-util.h" -- cgit From b0b968df0048a66c9beb76a0c0f42e3264753d4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:06:03 +0000 Subject: change order of the ALSA event dispatch code to make sure that the code survives if the event dispatcher frees the ALSA client git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1193 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 04a2d849..969a3da1 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -93,14 +93,14 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io return; } + a->defer_enable(fdl->defer, 1); + if (revents) { if (fdl->pcm) fdl->cb(fdl->userdata); else snd_mixer_handle_events(fdl->mixer); } - - a->defer_enable(fdl->defer, 1); } static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { -- cgit From e1316f572828257ea788c87aabf4e298101fbaa1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:56:47 +0000 Subject: fix bad memory access and a leak when detructing ALSA fd lists git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1198 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 969a3da1..39ddbfe9 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -178,7 +178,6 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { struct pa_alsa_fdlist *fdl; fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); - assert(fdl); fdl->num_fds = 0; fdl->fds = NULL; @@ -208,7 +207,7 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { int i; assert(fdl->m); for (i = 0;i < fdl->num_fds;i++) - fdl->m->io_free(fdl->ios[0]); + fdl->m->io_free(fdl->ios[i]); pa_xfree(fdl->ios); } -- 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/alsa-util.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 39ddbfe9..d8b6c5cc 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -88,7 +88,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); if (err < 0) { - pa_log_error(__FILE__": Unable to get poll revent: %s", + pa_log_error("Unable to get poll revent: %s", snd_strerror(err)); return; } @@ -135,7 +135,7 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); if (err < 0) { - pa_log_error(__FILE__": Unable to get poll descriptors: %s", + pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err)); return; } @@ -343,7 +343,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_warn(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn("device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -351,12 +351,12 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_warn(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn("device doesn't support %u channels, changed to %u.", ss->channels, c); ss->channels = c; } if (ss->format != f) { - pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } @@ -387,17 +387,17 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { assert(mixer && dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { - pa_log_warn(__FILE__": Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); return -1; } if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) { - pa_log_warn(__FILE__": Unable to register mixer: %s", snd_strerror(err)); + pa_log_warn("Unable to register mixer: %s", snd_strerror(err)); return -1; } if ((err = snd_mixer_load(mixer)) < 0) { - pa_log_warn(__FILE__": Unable to load mixer: %s", snd_strerror(err)); + pa_log_warn("Unable to load mixer: %s", snd_strerror(err)); return -1; } @@ -415,18 +415,18 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const snd_mixer_selem_id_set_name(sid, name); if (!(elem = snd_mixer_find_selem(mixer, sid))) { - pa_log_warn(__FILE__": Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); if (!(elem = snd_mixer_find_selem(mixer, sid))) - pa_log_warn(__FILE__": Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); } } if (elem) - pa_log_info(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } -- 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/alsa-util.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index d8b6c5cc..8023d3ad 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.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 @@ -270,7 +270,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s }; int i, ret; - + assert(pcm_handle); assert(f); @@ -290,12 +290,12 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; - + try_auto: for (i = 0; try_order[i] != PA_SAMPLE_INVALID; i++) { *f = try_order[i]; - + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; } @@ -312,14 +312,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p unsigned int c = ss->channels; pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; - + assert(pcm_handle); assert(ss); assert(periods); assert(period_size); buffer_size = *periods * *period_size; - + if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || @@ -359,25 +359,25 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } - + if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; if ((ret = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0 || (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; - + assert(buffer_size > 0); assert(*period_size > 0); *periods = buffer_size / *period_size; assert(*periods > 0); - + ret = 0; - + finish: if (hwparams) snd_pcm_hw_params_free(hwparams); - + return ret; } @@ -419,7 +419,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); - + if (!(elem = snd_mixer_find_selem(mixer, sid))) pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); } -- 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/alsa-util.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8023d3ad..40be5311 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.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 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/alsa-util.c | 202 ++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 94 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 40be5311..906de58d 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -33,6 +33,7 @@ #include #include +#include #include "alsa-util.h" @@ -42,7 +43,6 @@ struct pa_alsa_fdlist { /* This is a temporary buffer used to avoid lots of mallocs */ struct pollfd *work_fds; - snd_pcm_t *pcm; snd_mixer_t *mixer; pa_mainloop_api *m; @@ -56,11 +56,16 @@ struct pa_alsa_fdlist { }; static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { - struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + + struct pa_alsa_fdlist *fdl = userdata; int err, i; unsigned short revents; - assert(a && fdl && (fdl->pcm || fdl->mixer) && fdl->fds && fdl->work_fds); + pa_assert(a); + pa_assert(fdl); + pa_assert(fdl->mixer); + pa_assert(fdl->fds); + pa_assert(fdl->work_fds); if (fdl->polled) return; @@ -69,7 +74,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds); - for (i = 0;i < fdl->num_fds;i++) { + for (i = 0;i < fdl->num_fds; i++) { if (e == fdl->ios[i]) { if (events & PA_IO_EVENT_INPUT) fdl->work_fds[i].revents |= POLLIN; @@ -83,63 +88,46 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io } } - assert(i != fdl->num_fds); - - if (fdl->pcm) - err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); - else - err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); + pa_assert(i != fdl->num_fds); - if (err < 0) { - pa_log_error("Unable to get poll revent: %s", - snd_strerror(err)); + if ((err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents)) < 0) { + pa_log_error("Unable to get poll revent: %s", snd_strerror(err)); return; } a->defer_enable(fdl->defer, 1); - if (revents) { - if (fdl->pcm) - fdl->cb(fdl->userdata); - else - snd_mixer_handle_events(fdl->mixer); - } + if (revents) + snd_mixer_handle_events(fdl->mixer); } static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { - struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + struct pa_alsa_fdlist *fdl = userdata; int num_fds, i, err; struct pollfd *temp; - assert(a && fdl && (fdl->pcm || fdl->mixer)); + pa_assert(a); + pa_assert(fdl); + pa_assert(fdl->mixer); a->defer_enable(fdl->defer, 0); - if (fdl->pcm) - num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); - else - num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); - assert(num_fds > 0); + num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); + pa_assert(num_fds > 0); if (num_fds != fdl->num_fds) { if (fdl->fds) pa_xfree(fdl->fds); if (fdl->work_fds) pa_xfree(fdl->work_fds); - fdl->fds = pa_xmalloc0(sizeof(struct pollfd) * num_fds); - fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->fds = pa_xnew0(struct pollfd, num_fds); + fdl->work_fds = pa_xnew(struct pollfd, num_fds); } memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); - if (fdl->pcm) - err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); - else - err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); - - if (err < 0) { - pa_log_error("Unable to get poll descriptors: %s", - snd_strerror(err)); + if ((err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds)) < 0) { + pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err)); return; } @@ -149,18 +137,18 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u return; if (fdl->ios) { - for (i = 0;i < fdl->num_fds;i++) + for (i = 0; i < fdl->num_fds; i++) a->io_free(fdl->ios[i]); + if (num_fds != fdl->num_fds) { pa_xfree(fdl->ios); - fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); - assert(fdl->ios); + fdl->ios = NULL; } - } else { - fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); - assert(fdl->ios); } + if (!fdl->ios) + fdl->ios = pa_xnew(pa_io_event*, num_fds); + /* Swap pointers */ temp = fdl->work_fds; fdl->work_fds = fdl->fds; @@ -168,47 +156,41 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u fdl->num_fds = num_fds; - for (i = 0;i < num_fds;i++) { + for (i = 0;i < num_fds;i++) fdl->ios[i] = a->io_new(a, fdl->fds[i].fd, ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), io_cb, fdl); - assert(fdl->ios[i]); - } } struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { struct pa_alsa_fdlist *fdl; - fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); + fdl = pa_xnew0(struct pa_alsa_fdlist, 1); fdl->num_fds = 0; fdl->fds = NULL; fdl->work_fds = NULL; - - fdl->pcm = NULL; fdl->mixer = NULL; - fdl->m = NULL; fdl->defer = NULL; fdl->ios = NULL; - fdl->polled = 0; return fdl; } void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { - assert(fdl); + pa_assert(fdl); if (fdl->defer) { - assert(fdl->m); + pa_assert(fdl->m); fdl->m->defer_free(fdl->defer); } if (fdl->ios) { int i; - assert(fdl->m); + pa_assert(fdl->m); for (i = 0;i < fdl->num_fds;i++) fdl->m->io_free(fdl->ios[i]); pa_xfree(fdl->ios); @@ -222,29 +204,15 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { pa_xfree(fdl); } -int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata) { - assert(fdl && pcm_handle && m && !fdl->m && cb); - - fdl->pcm = pcm_handle; - fdl->m = m; - - fdl->defer = m->defer_new(m, defer_cb, fdl); - assert(fdl->defer); - - fdl->cb = cb; - fdl->userdata = userdata; - - return 0; -} - -int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { - assert(fdl && mixer_handle && m && !fdl->m); +int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { + pa_assert(fdl); + pa_assert(mixer_handle); + pa_assert(m); + pa_assert(!fdl->m); fdl->mixer = mixer_handle; fdl->m = m; - fdl->defer = m->defer_new(m, defer_cb, fdl); - assert(fdl->defer); return 0; } @@ -274,8 +242,8 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s int i, ret; - assert(pcm_handle); - assert(f); + pa_assert(pcm_handle); + pa_assert(f); if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; @@ -308,7 +276,7 @@ try_auto: /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap) { int ret = -1; snd_pcm_uframes_t buffer_size; unsigned int r = ss->rate; @@ -316,17 +284,32 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; - assert(pcm_handle); - assert(ss); - assert(periods); - assert(period_size); + pa_assert(pcm_handle); + pa_assert(ss); + pa_assert(periods); + pa_assert(period_size); + + snd_pcm_hw_params_alloca(&hwparams); buffer_size = *periods * *period_size; - if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || - (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || - (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || + (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) + goto finish; + + if (use_mmap && *use_mmap) { + if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + + /* mmap() didn't work, fall back to interleaved */ + + if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + goto finish; + + if (use_mmap) + *use_mmap = 0; + } + + } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) goto finish; if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) @@ -346,7 +329,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_warn("device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -354,12 +337,12 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_warn("device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); ss->channels = c; } if (ss->format != f) { - pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } @@ -370,24 +353,54 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; - assert(buffer_size > 0); - assert(*period_size > 0); + pa_assert(buffer_size > 0); + pa_assert(*period_size > 0); *periods = buffer_size / *period_size; - assert(*periods > 0); + pa_assert(*periods > 0); ret = 0; finish: - if (hwparams) - snd_pcm_hw_params_free(hwparams); return ret; } +int pa_alsa_set_sw_params(snd_pcm_t *pcm) { + snd_pcm_sw_params_t *swparams; + int err; + + pa_assert(pcm); + + snd_pcm_sw_params_alloca(&swparams); + + if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) { + pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + pa_log_warn("Unable to set start threshold: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) { + pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err)); + return err; + } + + return 0; +} + int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; - assert(mixer && dev); + pa_assert(mixer); + pa_assert(dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); @@ -410,10 +423,11 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) { snd_mixer_elem_t *elem; snd_mixer_selem_id_t *sid = NULL; + snd_mixer_selem_id_alloca(&sid); - assert(mixer); - assert(name); + pa_assert(mixer); + pa_assert(name); snd_mixer_selem_id_set_name(sid, name); -- cgit From 7e0f547f2fd8ddfae1d807334dbc3428a3dfe374 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 02:45:07 +0000 Subject: add support for 32bit integer samples git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2037 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 906de58d..15ae1fc6 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -227,15 +227,19 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE, + [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE, }; static const pa_sample_format_t try_order[] = { - PA_SAMPLE_S16NE, - PA_SAMPLE_S16RE, PA_SAMPLE_FLOAT32NE, PA_SAMPLE_FLOAT32RE, - PA_SAMPLE_ULAW, + PA_SAMPLE_S32NE, + PA_SAMPLE_S32RE, + PA_SAMPLE_S16NE, + PA_SAMPLE_S16RE, PA_SAMPLE_ALAW, + PA_SAMPLE_ULAW, PA_SAMPLE_U8, PA_SAMPLE_INVALID }; @@ -256,6 +260,10 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s *f = PA_SAMPLE_S16LE; else if (*f == PA_SAMPLE_S16LE) *f = PA_SAMPLE_S16BE; + else if (*f == PA_SAMPLE_S32BE) + *f = PA_SAMPLE_S32LE; + else if (*f == PA_SAMPLE_S32LE) + *f = PA_SAMPLE_S32BE; else goto try_auto; -- 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/alsa-util.c | 252 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 234 insertions(+), 18 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 15ae1fc6..5b74c98c 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -34,6 +34,7 @@ #include #include +#include #include "alsa-util.h" @@ -284,13 +285,21 @@ try_auto: /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap) { +int pa_alsa_set_hw_params( + snd_pcm_t *pcm_handle, + pa_sample_spec *ss, + uint32_t *periods, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap, + pa_bool_t require_exact_channel_number) { + int ret = -1; snd_pcm_uframes_t buffer_size; unsigned int r = ss->rate; unsigned int c = ss->channels; pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; + pa_bool_t _use_mmap = use_mmap && *use_mmap; pa_assert(pcm_handle); pa_assert(ss); @@ -305,7 +314,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) goto finish; - if (use_mmap && *use_mmap) { + if (_use_mmap) { if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { /* mmap() didn't work, fall back to interleaved */ @@ -313,8 +322,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) goto finish; - if (use_mmap) - *use_mmap = 0; + _use_mmap = FALSE; } } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) @@ -326,8 +334,13 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) goto finish; - if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) - goto finish; + if (require_exact_channel_number) { + if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) + goto finish; + } else { + if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) + goto finish; + } if ((*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)) @@ -336,23 +349,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; - if (ss->rate != r) { + if (ss->rate != r) pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); - /* If the sample rate deviates too much, we need to resample */ - if (r < ss->rate*.95 || r > ss->rate*1.05) - ss->rate = r; - } - - if (ss->channels != c) { + if (ss->channels != c) pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); - ss->channels = c; - } - if (ss->format != f) { + if (ss->format != f) pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); - ss->format = f; - } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; @@ -361,11 +365,20 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; + /* If the sample rate deviates too much, we need to resample */ + if (r < ss->rate*.95 || r > ss->rate*1.05) + ss->rate = r; + ss->channels = c; + ss->format = f; + pa_assert(buffer_size > 0); pa_assert(*period_size > 0); *periods = buffer_size / *period_size; pa_assert(*periods > 0); + if (use_mmap) + *use_mmap = _use_mmap; + ret = 0; finish: @@ -404,6 +417,209 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm) { return 0; } +struct device_info { + pa_channel_map map; + const char *name; +}; + +static const struct device_info device_table[] = { + {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, "front" }, + + {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "surround40" }, + + {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_LFE }}, "surround41" }, + + {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER }}, "surround50" }, + + {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }}, "surround51" }, + + {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }} , "surround71" }, + + {{ 0, { 0 }}, NULL } +}; + +static pa_bool_t channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { + pa_bool_t in_a[PA_CHANNEL_POSITION_MAX]; + unsigned i; + + pa_assert(a); + pa_assert(b); + + memset(in_a, 0, sizeof(in_a)); + + for (i = 0; i < a->channels; i++) + in_a[a->map[i]] = TRUE; + + for (i = 0; i < b->channels; i++) + if (!in_a[b->map[i]]) + return FALSE; + + return TRUE; +} + +snd_pcm_t *pa_alsa_open_by_device_id( + const char *dev_id, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap) { + + int i; + int direction = 1; + int err; + char *d; + snd_pcm_t *pcm_handle; + + pa_assert(dev_id); + pa_assert(dev); + pa_assert(ss); + pa_assert(map); + pa_assert(nfrags); + pa_assert(period_size); + + /* First we try to find a device string with a superset of the + * requested channel map and open it without the plug: prefix. We + * iterate through our device table from top to bottom and take + * the first that matches. If we didn't find a working device that + * way, we iterate backwards, and check all devices that do not + * provide a superset of the requested channel map.*/ + + for (i = 0;; i += direction) { + pa_sample_spec try_ss; + + if (i < 0) { + pa_assert(direction == -1); + + /* OK, so we iterated backwards, and now are at the + * beginning of our list. */ + + break; + + } else if (!device_table[i].name) { + pa_assert(direction == 1); + + /* OK, so we are at the end of our list. at iterated + * forwards. */ + + i--; + direction = -1; + } + + if ((direction > 0) == !channel_map_superset(&device_table[i].map, map)) + continue; + + d = pa_sprintf_malloc("%s:%s", device_table[i].name, dev_id); + pa_log_debug("Trying %s...", d); + + if ((err = snd_pcm_open(&pcm_handle, d, mode, SND_PCM_NONBLOCK)) < 0) { + pa_log_info("Couldn't open PCM device %s: %s", d, snd_strerror(err)); + pa_xfree(d); + continue; + } + + try_ss.channels = device_table[i].map.channels; + try_ss.rate = ss->rate; + try_ss.format = ss->format; + + if ((err = pa_alsa_set_hw_params(pcm_handle, &try_ss, nfrags, period_size, use_mmap, TRUE)) < 0) { + pa_log_info("PCM device %s refused our hw parameters: %s", d, snd_strerror(err)); + pa_xfree(d); + snd_pcm_close(pcm_handle); + continue; + } + + *ss = try_ss; + *map = device_table[i].map; + pa_assert(map->channels == ss->channels); + *dev = d; + return pcm_handle; + } + + /* OK, we didn't find any good device, so let's try the raw hw: stuff */ + + d = pa_sprintf_malloc("hw:%s", dev_id); + pa_log_debug("Trying %s as last resort...", d); + pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, use_mmap); + pa_xfree(d); + + return pcm_handle; +} + +snd_pcm_t *pa_alsa_open_by_device_string( + const char *device, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap) { + + int err; + char *d; + snd_pcm_t *pcm_handle; + + pa_assert(device); + pa_assert(dev); + pa_assert(ss); + pa_assert(map); + pa_assert(nfrags); + pa_assert(period_size); + + d = pa_xstrdup(device); + + for (;;) { + + if ((err = snd_pcm_open(&pcm_handle, d, mode, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", d, snd_strerror(err)); + pa_xfree(d); + return NULL; + } + + if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, use_mmap, FALSE)) < 0) { + + if (err == -EPERM) { + /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */ + + if (pa_startswith(d, "hw:")) { + char *t = pa_sprintf_malloc("plughw:%s", d+3); + pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", d, t); + pa_xfree(d); + d = t; + + snd_pcm_close(pcm_handle); + continue; + } + + pa_log("Failed to set hardware parameters on %s: %s", d, snd_strerror(err)); + pa_xfree(d); + snd_pcm_close(pcm_handle); + return NULL; + } + } + + *dev = d; + + if (ss->channels != map->channels) + pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA); + + return pcm_handle; + } +} + int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; -- 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/alsa-util.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5b74c98c..40170e9c 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -310,8 +310,10 @@ int pa_alsa_set_hw_params( buffer_size = *periods * *period_size; - if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) + if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) goto finish; if (_use_mmap) { @@ -627,7 +629,7 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { pa_assert(dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { - pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + pa_log_info("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); return -1; } @@ -641,6 +643,8 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { return -1; } + pa_log_info("Successfully attached to mixer '%s'", dev); + return 0; } @@ -656,7 +660,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const snd_mixer_selem_id_set_name(sid, name); if (!(elem = snd_mixer_find_selem(mixer, sid))) { - pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); @@ -671,3 +675,123 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const return elem; } + +static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = { + [PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */ + + [PA_CHANNEL_POSITION_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER, + [PA_CHANNEL_POSITION_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT, + [PA_CHANNEL_POSITION_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT, + + [PA_CHANNEL_POSITION_REAR_CENTER] = SND_MIXER_SCHN_REAR_CENTER, + [PA_CHANNEL_POSITION_REAR_LEFT] = SND_MIXER_SCHN_REAR_LEFT, + [PA_CHANNEL_POSITION_REAR_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT, + + [PA_CHANNEL_POSITION_LFE] = SND_MIXER_SCHN_WOOFER, + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT, + [PA_CHANNEL_POSITION_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT, + + [PA_CHANNEL_POSITION_AUX0] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX1] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX2] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX3] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX4] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX5] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX6] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX7] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX8] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX9] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX10] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX11] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX12] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX13] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX14] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX15] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX16] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX17] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX18] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX19] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX20] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX21] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX22] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX23] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX24] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX25] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX26] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX27] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX28] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX29] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX30] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX31] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SND_MIXER_SCHN_UNKNOWN +}; + + +int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback) { + unsigned i; + pa_bool_t alsa_channel_used[SND_MIXER_SCHN_LAST]; + pa_bool_t mono_used = FALSE; + + pa_assert(elem); + pa_assert(channel_map); + pa_assert(mixer_map); + + memset(&alsa_channel_used, 0, sizeof(alsa_channel_used)); + + if (channel_map->channels > 1 && + ((playback && snd_mixer_selem_has_playback_volume_joined(elem)) || + (!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) { + pa_log_info("ALSA device lacks independant volume controls for each channel, falling back to software volume control."); + return -1; + } + + for (i = 0; i < channel_map->channels; i++) { + snd_mixer_selem_channel_id_t id; + pa_bool_t is_mono; + + is_mono = channel_map->map[i] == PA_CHANNEL_POSITION_MONO; + id = alsa_channel_ids[channel_map->map[i]]; + + if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) { + pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer. Falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if ((is_mono && mono_used) || (!is_mono && alsa_channel_used[id])) { + pa_log_info("Channel map has duplicate channel '%s', failling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) || + (!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) { + + pa_log_info("ALSA device lacks separate volumes control for channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if (is_mono) { + mixer_map[i] = SND_MIXER_SCHN_MONO; + mono_used = TRUE; + } else { + mixer_map[i] = id; + alsa_channel_used[id] = TRUE; + } + } + + pa_log_info("All %u channels can be mapped to mixer channels. Using hardware volume control.", channel_map->channels); + + return 0; +} -- cgit From 86b9ef8c961bed9d3a65f044741bb423c26d8005 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Feb 2008 22:13:44 +0000 Subject: deal with a possibly failing pa_channel_map_init_auto() correctly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2105 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/modules/alsa-util.c') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 40170e9c..6afec3bc 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -615,8 +615,10 @@ snd_pcm_t *pa_alsa_open_by_device_string( *dev = d; - if (ss->channels != map->channels) + if (ss->channels != map->channels) { + pa_assert_se(pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_AUX)); pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA); + } return pcm_handle; } -- cgit