mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
fix mmap emulation bug of recording doesn't work
From: Roy Huang <royhuang9@gmail.com> Record doesn't work if enabling mmap emulation and rate conversion needed, this patch fix this bug.
This commit is contained in:
parent
40415cd180
commit
845d9222b2
1 changed files with 77 additions and 11 deletions
|
|
@ -96,6 +96,7 @@ typedef struct {
|
||||||
int shadow_appl_ptr: 1,
|
int shadow_appl_ptr: 1,
|
||||||
avail_update_flag: 1,
|
avail_update_flag: 1,
|
||||||
mmap_shm: 1;
|
mmap_shm: 1;
|
||||||
|
snd_pcm_uframes_t hw_ptr;
|
||||||
snd_pcm_uframes_t appl_ptr;
|
snd_pcm_uframes_t appl_ptr;
|
||||||
/* restricted parameters */
|
/* restricted parameters */
|
||||||
snd_pcm_format_t format;
|
snd_pcm_format_t format;
|
||||||
|
|
@ -373,7 +374,9 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
||||||
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
||||||
if (hw->mmap_shm) {
|
if (hw->mmap_shm) {
|
||||||
hw->shadow_appl_ptr = 1;
|
hw->shadow_appl_ptr = 1;
|
||||||
|
hw->hw_ptr = 0;
|
||||||
hw->appl_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);
|
snd_pcm_set_appl_ptr(pcm, &hw->appl_ptr, -1, 0);
|
||||||
} else {
|
} else {
|
||||||
hw->shadow_appl_ptr = 0;
|
hw->shadow_appl_ptr = 0;
|
||||||
|
|
@ -949,27 +952,90 @@ static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
|
||||||
return size;
|
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)
|
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
snd_pcm_hw_t *hw = pcm->private_data;
|
snd_pcm_hw_t *hw = pcm->private_data;
|
||||||
snd_pcm_uframes_t avail;
|
snd_pcm_uframes_t avail, xfer_avail;
|
||||||
|
|
||||||
sync_ptr(hw, 0);
|
sync_ptr(hw, 0);
|
||||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||||
avail = snd_pcm_mmap_playback_avail(pcm);
|
avail = snd_pcm_mmap_playback_avail(pcm);
|
||||||
} else {
|
} else {
|
||||||
avail = snd_pcm_mmap_capture_avail(pcm);
|
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_sframes_t err;
|
||||||
snd_pcm_hw_t *hw = pcm->private_data;
|
xfer_avail = snd_pcm_hw_capture_avail(pcm);
|
||||||
hw->avail_update_flag = 1;
|
xfer_avail -= xfer_avail % pcm->xfer_align;
|
||||||
err = snd_pcm_read_mmap(pcm, avail);
|
if (xfer_avail > 0) {
|
||||||
hw->avail_update_flag = 0;
|
hw->avail_update_flag = 1;
|
||||||
if (err < 0)
|
err = snd_pcm_hw_read_mmap(pcm, xfer_avail);
|
||||||
return err;
|
hw->avail_update_flag = 0;
|
||||||
if ((snd_pcm_uframes_t)err != avail)
|
if (err < 0)
|
||||||
SNDMSG("short read %ld for avail %ld", err, avail);
|
return err;
|
||||||
return err;
|
hw->hw_ptr += err;
|
||||||
|
avail = snd_pcm_mmap_capture_avail(pcm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (FAST_PCM_STATE(hw)) {
|
switch (FAST_PCM_STATE(hw)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue