diff mbox series

pcm: rate: fix drain of partial period at end of buffer

Message ID 20220223093740.113617-1-consult.awy@gmail.com
State New
Headers show
Series pcm: rate: fix drain of partial period at end of buffer | expand

Commit Message

Alan Young Feb. 23, 2022, 9:37 a.m. UTC
In the case that:
* the buffer size is not an integer multiple of the period size, and
* drain must flush a partial period located before the end of the buffer
  but without a full period available, where
* these conditions may pertain to the source or slave pcm buffer, and
* because rate conversion is always done on a full period,
it is necessary to check that both a full source period is available
before source pcm buffer wrap and a full slave period is available
before slave pcm buffer wrap in order to use the simple, single-commit
implementation in snd_pcm_rate_commit_area().

The alternative fix would be to change snd_pcm_rate_write_areas1() to
take size and slave_size parameters. This would be more disruptive to
the code base, tricky to get right, and is unnecessary given that
snd_pcm_mmap_commit() only commits the partial period of actually valid
converted samples.

Fixes: 3047f8fa5a3dce0c9775404a2285fb2cff462d96
Signed-off-by: Alan Young <consult.awy@gmail.com>
---
 src/pcm/pcm_rate.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index c45895a9..ba5364c0 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -781,16 +781,25 @@  static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate,
 	snd_pcm_sframes_t result;
 
 	areas = snd_pcm_mmap_areas(pcm);
-	if (cont >= size) {
+	/*
+	 * Because snd_pcm_rate_write_areas1() below will convert a full source period
+	 * then there had better be a full period available in the current buffer.
+	 */
+	if (cont >= pcm->period_size) {
 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
 		if (result < 0)
 			return result;
-		if (slave_frames < slave_size) {
+		/*
+		 * Because snd_pcm_rate_write_areas1() below will convert to a full slave period
+		 * then there had better be a full slave period available in the slave buffer.
+		 */
+		if (slave_frames < rate->gen.slave->period_size) {
 			snd_pcm_rate_write_areas1(pcm, areas, appl_offset, rate->sareas, 0);
 			goto __partial;
 		}
 		snd_pcm_rate_write_areas1(pcm, areas, appl_offset,
 					  slave_areas, slave_offset);
+		/* Only commit the requested slave_size, even if more was actually converted */
 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, slave_size);
 		if (result < (snd_pcm_sframes_t)slave_size) {
 			if (result < 0)