From d7f054639f55bf97d783110e64b0f7dd33e32035 Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Wed, 18 Mar 2020 22:28:05 +0100 Subject: [PATCH 1/3] pcm_a52: Determine virtual hardware pointer upon slave pointer Calculate the pointer upon the hardware pointer of the slave by querying its available frames. Thereby we can guarantee that our transfer routine will accept as many frames as the pointer indicates. --- a52/pcm_a52.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/a52/pcm_a52.c b/a52/pcm_a52.c index b005bc2..653de12 100644 --- a/a52/pcm_a52.c +++ b/a52/pcm_a52.c @@ -325,21 +325,18 @@ static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io, /* * pointer callback * - * Calculate the current position from the delay of slave PCM + * Calculate the current position from the available frames of slave PCM */ static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io) { struct a52_ctx *rec = io->private_data; - snd_pcm_sframes_t delay; + snd_pcm_sframes_t avail; snd_pcm_state_t state; - int err; state = snd_pcm_state(rec->slave); switch (state) { case SND_PCM_STATE_RUNNING: case SND_PCM_STATE_DRAINING: - if ((err = snd_pcm_delay(rec->slave, &delay)) < 0) - return err; break; case SND_PCM_STATE_XRUN: case SND_PCM_STATE_SUSPENDED: @@ -348,16 +345,25 @@ static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io) return 0; } - if (delay < 0 || delay >= (snd_pcm_sframes_t)rec->slave_buffer_size) - delay = 0; - delay = (snd_pcm_sframes_t)io->appl_ptr - delay; - if (delay < 0) { - delay += io->buffer_size; - if (delay < 0) - delay = 0; + avail = 0; + + /* Write what we have from outbuf. */ + write_out_pending(io, rec); + + /* If there is anything remaining in outbuf, we can't + * accept any full packets. */ + if (rec->remain == 0) + { + /* Round the slave frames to multiples of the packet size. */ + avail += (snd_pcm_avail_update(rec->slave) / rec->avctx->frame_size) * rec->avctx->frame_size; } - delay %= io->buffer_size; - return delay; + + if (avail < 0) + avail = 0; + else if (avail >= io->buffer_size) + avail = io->buffer_size - 1; + + return (io->appl_ptr + avail) % io->buffer_size; } /* set up the fixed parameters of slave PCM hw_parmas */ From 5992a4f305d15dc77c47324161877ec49188f853 Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Wed, 18 Mar 2020 22:33:44 +0100 Subject: [PATCH 2/3] pcm_a52: Don't pass EAGAIN errors from the slave to the caller EAGAIN can happen when we already could have passed frames to the slave. If we then return EAGAIN to our caller it wrongly indicates that no frames were send. Therefore return the processed frames instead. --- a52/pcm_a52.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/a52/pcm_a52.c b/a52/pcm_a52.c index 653de12..1715751 100644 --- a/a52/pcm_a52.c +++ b/a52/pcm_a52.c @@ -154,6 +154,8 @@ static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec) if (err < 0) { if (err == -EPIPE) io->state = SND_PCM_STATE_XRUN; + if (err == -EAGAIN) + break; return err; } else if (! err) break; @@ -312,7 +314,7 @@ static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io, do { err = fill_data(io, areas, offset, size, interleaved); - if (err < 0) + if (err <= 0) break; offset += (unsigned int)err; size -= (unsigned int)err; From 440ac976450e16e996cc8e7ece4d0280ed7f7344 Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Wed, 18 Mar 2020 22:38:18 +0100 Subject: [PATCH 3/3] pcm_a52: Don't move bytes within the outbuf The output buffer will never be appended, but a new a52 frame will always be written in its entirety to outbuf. Therefore we don't need to move bytes that were not yet sent to the slave to the beginning of the output buffer. Also don't overwrite the output buffer when there are still frames to be sent. --- a52/pcm_a52.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/a52/pcm_a52.c b/a52/pcm_a52.c index 1715751..b6a8f55 100644 --- a/a52/pcm_a52.c +++ b/a52/pcm_a52.c @@ -144,7 +144,7 @@ static void convert_data(struct a52_ctx *rec) /* write pending encoded data to the slave pcm */ static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec) { - int err, ofs = 0; + int err, ofs = (rec->avctx->frame_size - rec->remain) * 4; if (! rec->remain) return 0; @@ -163,8 +163,6 @@ static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec) ofs += (rec->remain - err) * 4; rec->remain -= err; } - if (rec->remain && ofs) - memmove(rec->outbuf, rec->outbuf + ofs, rec->remain * 4); return 0; } @@ -257,6 +255,12 @@ static int fill_data(snd_pcm_ioplug_t *io, if ((err = write_out_pending(io, rec)) < 0) return err; + /* If there are still frames left in outbuf, we can't + * accept a full a52 frame, because this would overwrite + * the frames in outbuf. */ + if (rec->remain && len) + len--; + if (size > len) size = len;