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@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel