[alsa-devel] [PATCH]fix mmap emulation bug of recording doesn't work
Takashi Iwai
tiwai at suse.de
Wed Jul 4 19:13:29 CEST 2007
At Wed, 4 Jul 2007 22:18:24 +0800,
Roy Huang wrote:
>
> Record doesn't work if enabling mmap emulation and rate conversion
> needed, this patch fix this bug.
Thanks for the patch. I need to check your changes in detail as it's
not so obvious. What is the problem with rate plugin and
mmap-emulation? From what I find in your patch, it's something to do
with the hw_ptr update mismatch.
Takashi
> diff -uNr alsa-lib-1.0.14a/src/pcm/pcm_hw.c alsa-lib-new/src/pcm/pcm_hw.c
> --- alsa-lib-1.0.14a/src/pcm/pcm_hw.c 2007-06-11 16:53:13.000000000 +0800
> +++ alsa-lib-new/src/pcm/pcm_hw.c 2007-07-04 12:16:31.000000000 +0800
> @@ -96,6 +96,7 @@
> int shadow_appl_ptr: 1,
> avail_update_flag: 1,
> mmap_shm: 1;
> + snd_pcm_uframes_t hw_ptr;
> snd_pcm_uframes_t appl_ptr;
> /* restricted parameters */
> snd_pcm_format_t format;
> @@ -373,7 +374,9 @@
> if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
> if (hw->mmap_shm) {
> hw->shadow_appl_ptr = 1;
> + hw->hw_ptr = 0;
> hw->appl_ptr = 0;
> + snd_pcm_set_hw_ptr(pcm, &hw->hw_ptr, -1, 0);
> snd_pcm_set_appl_ptr(pcm, &hw->appl_ptr, -1, 0);
> } else {
> hw->shadow_appl_ptr = 0;
> @@ -949,28 +952,91 @@
> return size;
> }
>
> +static inline snd_pcm_uframes_t snd_pcm_hw_capture_avail(snd_pcm_t *pcm)
> +{
> + snd_pcm_sframes_t avail;
> + snd_pcm_hw_t *hw = pcm->private_data;
> +
> + avail = hw->mmap_status->hw_ptr - hw->mmap_control->appl_ptr;
> + if (avail < 0)
> + avail += pcm->boundary;
> + return avail;
> +}
> +
> +static snd_pcm_sframes_t snd_pcm_hw_read_mmap(snd_pcm_t *pcm,
> snd_pcm_uframes_t size)
> +{
> + snd_pcm_uframes_t xfer = 0;
> + snd_pcm_sframes_t err = 0;
> + snd_pcm_hw_t *hw = pcm->private_data;
> + if (! size)
> + return 0;
> + while (xfer < size) {
> + snd_pcm_uframes_t frames = size - xfer;
> + snd_pcm_uframes_t appl_offset = hw->mmap_control->appl_ptr %
> pcm->buffer_size;
> + snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
> + if (cont < frames)
> + frames = cont;
> + switch (pcm->access) {
> + case SND_PCM_ACCESS_MMAP_INTERLEAVED:
> + {
> + const snd_pcm_channel_area_t *a =
> snd_pcm_mmap_areas(pcm);
> + char *buf = snd_pcm_channel_area_addr(a, appl_offset);
> + err = _snd_pcm_readi(pcm, buf, frames);
> + if (err >= 0)
> + frames = err;
> + break;
> + }
> + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
> + {
> + snd_pcm_uframes_t channels = pcm->channels;
> + unsigned int c;
> + void *bufs[channels];
> + const snd_pcm_channel_area_t *areas =
> snd_pcm_mmap_areas(pcm);
> + for (c = 0; c < channels; ++c) {
> + const snd_pcm_channel_area_t *a = &areas[c];
> + bufs[c] = snd_pcm_channel_area_addr(a,
> appl_offset);
> + }
> + err = _snd_pcm_readn(pcm->fast_op_arg, bufs, frames);
> + if (err >= 0)
> + frames = err;
> + }
> + default:
> + SNDMSG("invalid access type %d", pcm->access);
> + return -EINVAL;
> + }
> + if (err < 0)
> + break;
> + xfer += frames;
> + }
> + if (xfer > 0)
> + return xfer;
> + return err;
> +}
> +
> static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
> {
> snd_pcm_hw_t *hw = pcm->private_data;
> - snd_pcm_uframes_t avail;
> + snd_pcm_uframes_t avail, xfer_avail;
>
> sync_ptr(hw, 0);
> if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
> avail = snd_pcm_mmap_playback_avail(pcm);
> } else {
> avail = snd_pcm_mmap_capture_avail(pcm);
> - if (avail > 0 && hw->mmap_shm) {
> + if (avail < pcm->avail_min && hw->mmap_shm) {
> snd_pcm_sframes_t err;
> - snd_pcm_hw_t *hw = pcm->private_data;
> - hw->avail_update_flag = 1;
> - err = snd_pcm_read_mmap(pcm, avail);
> - hw->avail_update_flag = 0;
> - if (err < 0)
> - return err;
> - if ((snd_pcm_uframes_t)err != avail)
> - SNDMSG("short read %ld for avail %ld",
> err, avail);
> - return err;
> - }
> + xfer_avail = snd_pcm_hw_capture_avail(pcm);
> + xfer_avail -= xfer_avail % pcm->xfer_align;
> + if (xfer_avail > 0) {
> + hw->avail_update_flag = 1;
> + err = snd_pcm_hw_read_mmap(pcm, xfer_avail);
> + hw->avail_update_flag = 0;
> + if (err < 0)
> + return err;
> + hw->hw_ptr += err;
> + avail = snd_pcm_mmap_capture_avail(pcm);
> + }
> + }
> }
> switch (FAST_PCM_STATE(hw)) {
> case SNDRV_PCM_STATE_RUNNING:
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list