]> git.alsa-project.org Git - alsa-lib.git/commitdiff
fix infinite draining of the rate plugin in SND_PCM_NONBLOCK mode
authorsylvain.bertrand@gmail.com <sylvain.bertrand@gmail.com>
Tue, 28 Apr 2020 12:09:18 +0000 (12:09 +0000)
committerJaroslav Kysela <perex@perex.cz>
Thu, 30 Apr 2020 12:25:10 +0000 (14:25 +0200)
The draining function of the rate plugin does not handle properly the
SND_PCM_NONBLOCK case. It can write data to the slave plugin each time the
function is called, but does not update its internal state in order to
reach a stopping condition. Use a last_commit_ptr workaround to reach such
condition.

Signed-off-by: Sylvain BERTRAND <sylvain.bertrand@legeek.net>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/pcm/pcm_rate.c

index 21611f62c370918dbed0bb5a7e3ea2aac8fe1c30..4f99a95b325f580bdd0006f75f3b9f2153d66127 100644 (file)
@@ -1051,6 +1051,7 @@ static int snd_pcm_rate_drain(snd_pcm_t *pcm)
                /* commit the remaining fraction (if any) */
                snd_pcm_uframes_t size, ofs, saved_avail_min;
                snd_pcm_sw_params_t sw_params;
+               int commit_err;
 
                __snd_pcm_lock(pcm);
                /* temporarily set avail_min to one */
@@ -1079,14 +1080,29 @@ static int snd_pcm_rate_drain(snd_pcm_t *pcm)
                                if (! spsize)
                                        break;
                        }
-                       snd_pcm_rate_commit_area(pcm, rate, ofs,
+                       commit_err = snd_pcm_rate_commit_area(pcm, rate, ofs,
                                                 psize, spsize);
+                       if (commit_err == 1) {
+                               rate->last_commit_ptr += psize;
+                               if (rate->last_commit_ptr >= pcm->boundary)
+                                       rate->last_commit_ptr = 0;
+                       } else if (commit_err == 0) {
+                               if (pcm->mode & SND_PCM_NONBLOCK != 0) {
+                                       commit_err = -EAGAIN;
+                                       break;
+                               }
+                               continue;
+                       } else
+                               break;
+
                        ofs = (ofs + psize) % pcm->buffer_size;
                        size -= psize;
                }
                sw_params.avail_min = saved_avail_min;
                snd_pcm_sw_params(rate->gen.slave, &sw_params);
                __snd_pcm_unlock(pcm);
+               if (commit_err < 0)
+                       return commit_err;
        }
        return snd_pcm_drain(rate->gen.slave);
 }