aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Dillow <dave@thedillows.org>2010-06-26 18:13:20 -0400
committerJaroslav Kysela <perex@perex.cz>2010-06-28 03:42:09 -0400
commit5daeba34d2aab669aea07abee13d53cd116578fb (patch)
tree4213fce45c60b6c16160fa9c777aa923ef562172
parent8fc6d4186e0a60b3755a6b88bf67a3ac3214dcc3 (diff)
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>
-rw-r--r--include/sound/pcm.h2
-rw-r--r--sound/core/pcm_lib.c23
2 files changed, 16 insertions, 9 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index dd76cdede64d..83c6fa6aac43 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -313,7 +313,7 @@ struct snd_pcm_runtime {
313 struct snd_pcm_mmap_control *control; 313 struct snd_pcm_mmap_control *control;
314 314
315 /* -- locking / scheduling -- */ 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 wait_queue_head_t sleep; /* poll sleep */ 317 wait_queue_head_t sleep; /* poll sleep */
318 wait_queue_head_t tsleep; /* transfer sleep */ 318 wait_queue_head_t tsleep; /* transfer sleep */
319 struct fasync_struct *fasync; 319 struct fasync_struct *fasync;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e9d98be190c5..bcf95d3ff5c7 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -287,8 +287,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
287 return -EPIPE; 287 return -EPIPE;
288 } 288 }
289 } 289 }
290 if (avail >= runtime->control->avail_min) 290 if (runtime->twake) {
291 wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); 291 if (avail >= runtime->twake)
292 wake_up(&runtime->tsleep);
293 } else if (avail >= runtime->control->avail_min)
294 wake_up(&runtime->sleep);
292 return 0; 295 return 0;
293} 296}
294 297
@@ -1707,7 +1710,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed);
1707 * The available space is stored on availp. When err = 0 and avail = 0 1710 * The available space is stored on availp. When err = 0 and avail = 0
1708 * on the capture stream, it indicates the stream is in DRAINING state. 1711 * on the capture stream, it indicates the stream is in DRAINING state.
1709 */ 1712 */
1710static int wait_for_avail_min(struct snd_pcm_substream *substream, 1713static int wait_for_avail(struct snd_pcm_substream *substream,
1711 snd_pcm_uframes_t *availp) 1714 snd_pcm_uframes_t *availp)
1712{ 1715{
1713 struct snd_pcm_runtime *runtime = substream->runtime; 1716 struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1757,7 +1760,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
1757 avail = snd_pcm_playback_avail(runtime); 1760 avail = snd_pcm_playback_avail(runtime);
1758 else 1761 else
1759 avail = snd_pcm_capture_avail(runtime); 1762 avail = snd_pcm_capture_avail(runtime);
1760 if (avail >= runtime->control->avail_min) 1763 if (avail >= runtime->twake)
1761 break; 1764 break;
1762 } 1765 }
1763 _endloop: 1766 _endloop:
@@ -1820,7 +1823,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1820 goto _end_unlock; 1823 goto _end_unlock;
1821 } 1824 }
1822 1825
1823 runtime->twake = 1; 1826 runtime->twake = runtime->control->avail_min ? : 1;
1824 while (size > 0) { 1827 while (size > 0) {
1825 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 1828 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1826 snd_pcm_uframes_t avail; 1829 snd_pcm_uframes_t avail;
@@ -1833,7 +1836,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1833 err = -EAGAIN; 1836 err = -EAGAIN;
1834 goto _end_unlock; 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 if (err < 0) 1842 if (err < 0)
1838 goto _end_unlock; 1843 goto _end_unlock;
1839 } 1844 }
@@ -2042,7 +2047,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2042 goto _end_unlock; 2047 goto _end_unlock;
2043 } 2048 }
2044 2049
2045 runtime->twake = 1; 2050 runtime->twake = runtime->control->avail_min ? : 1;
2046 while (size > 0) { 2051 while (size > 0) {
2047 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 2052 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2048 snd_pcm_uframes_t avail; 2053 snd_pcm_uframes_t avail;
@@ -2060,7 +2065,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2060 err = -EAGAIN; 2065 err = -EAGAIN;
2061 goto _end_unlock; 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 if (err < 0) 2071 if (err < 0)
2065 goto _end_unlock; 2072 goto _end_unlock;
2066 if (!avail) 2073 if (!avail)