Commit 5daeba34d2aab669aea07abee13d53cd116578fb

Authored by David Dillow
Committed by Jaroslav Kysela
1 parent 8fc6d4186e

ALSA: pcm_lib: avoid timing jitter in snd_pcm_read/write()

When using poll() to wait for the next period -- or avail_min samples --
one gets a consistent delay for each system call that is usually just a
little short of the selected period time. However, When using
snd_pcm_read/write(), one gets a jittery delay that alternates between
less than a millisecond and approximately two period times. This is
caused by snd_pcm_lib_{read,write}1() transferring any available samples
to the user's buffer and adjusting the application pointer prior to
sleeping to the end of the current period. When the next period
interrupt occurs, there is then less than avail_min samples remaining to
be transferred in the period, so we end up sleeping until a second
period occurs.

This is solved by using runtime->twake as the number of samples needed
for a wakeup in addition to selecting the proper wait queue to wake in
snd_pcm_update_state(). This requires twake to be non-zero when used
by snd_pcm_lib_{read,write}1() even if avail_min is zero.

Signed-off-by: Dave Dillow <dave@thedillows.org>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

Showing 2 changed files with 16 additions and 9 deletions Side-by-side Diff

... ... @@ -313,7 +313,7 @@
313 313 struct snd_pcm_mmap_control *control;
314 314  
315 315 /* -- locking / scheduling -- */
316   - unsigned int twake: 1; /* do transfer (!poll) wakeup */
  316 + snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */
317 317 wait_queue_head_t sleep; /* poll sleep */
318 318 wait_queue_head_t tsleep; /* transfer sleep */
319 319 struct fasync_struct *fasync;
sound/core/pcm_lib.c
... ... @@ -287,8 +287,11 @@
287 287 return -EPIPE;
288 288 }
289 289 }
290   - if (avail >= runtime->control->avail_min)
291   - wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep);
  290 + if (runtime->twake) {
  291 + if (avail >= runtime->twake)
  292 + wake_up(&runtime->tsleep);
  293 + } else if (avail >= runtime->control->avail_min)
  294 + wake_up(&runtime->sleep);
292 295 return 0;
293 296 }
294 297  
... ... @@ -1707,7 +1710,7 @@
1707 1710 * The available space is stored on availp. When err = 0 and avail = 0
1708 1711 * on the capture stream, it indicates the stream is in DRAINING state.
1709 1712 */
1710   -static int wait_for_avail_min(struct snd_pcm_substream *substream,
  1713 +static int wait_for_avail(struct snd_pcm_substream *substream,
1711 1714 snd_pcm_uframes_t *availp)
1712 1715 {
1713 1716 struct snd_pcm_runtime *runtime = substream->runtime;
... ... @@ -1757,7 +1760,7 @@
1757 1760 avail = snd_pcm_playback_avail(runtime);
1758 1761 else
1759 1762 avail = snd_pcm_capture_avail(runtime);
1760   - if (avail >= runtime->control->avail_min)
  1763 + if (avail >= runtime->twake)
1761 1764 break;
1762 1765 }
1763 1766 _endloop:
... ... @@ -1820,7 +1823,7 @@
1820 1823 goto _end_unlock;
1821 1824 }
1822 1825  
1823   - runtime->twake = 1;
  1826 + runtime->twake = runtime->control->avail_min ? : 1;
1824 1827 while (size > 0) {
1825 1828 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1826 1829 snd_pcm_uframes_t avail;
... ... @@ -1833,7 +1836,9 @@
1833 1836 err = -EAGAIN;
1834 1837 goto _end_unlock;
1835 1838 }
1836   - err = wait_for_avail_min(substream, &avail);
  1839 + runtime->twake = min_t(snd_pcm_uframes_t, size,
  1840 + runtime->control->avail_min ? : 1);
  1841 + err = wait_for_avail(substream, &avail);
1837 1842 if (err < 0)
1838 1843 goto _end_unlock;
1839 1844 }
... ... @@ -2042,7 +2047,7 @@
2042 2047 goto _end_unlock;
2043 2048 }
2044 2049  
2045   - runtime->twake = 1;
  2050 + runtime->twake = runtime->control->avail_min ? : 1;
2046 2051 while (size > 0) {
2047 2052 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2048 2053 snd_pcm_uframes_t avail;
... ... @@ -2060,7 +2065,9 @@
2060 2065 err = -EAGAIN;
2061 2066 goto _end_unlock;
2062 2067 }
2063   - err = wait_for_avail_min(substream, &avail);
  2068 + runtime->twake = min_t(snd_pcm_uframes_t, size,
  2069 + runtime->control->avail_min ? : 1);
  2070 + err = wait_for_avail(substream, &avail);
2064 2071 if (err < 0)
2065 2072 goto _end_unlock;
2066 2073 if (!avail)