[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