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