diff options
author | Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> | 2012-05-22 14:54:02 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-05-23 01:50:29 +0200 |
commit | 3509a03f4dcf7fedb8880180fed3f7f791ce5598 (patch) | |
tree | 9be4d6f21e9fe84926b96b39fbb825c537168011 /sound | |
parent | 599ed4b0aeceb6d45ea33f64639e745e3da72766 (diff) | |
download | lwn-3509a03f4dcf7fedb8880180fed3f7f791ce5598.tar.gz lwn-3509a03f4dcf7fedb8880180fed3f7f791ce5598.zip |
ALSA: core: group read of pointer, tstamp and jiffies
Group read of hw_ptr, tstamp and jiffies in a sequence
for better correlation. Previous code took timestamp at the
end, which could introduce delays between audio time and
system time.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/pcm_lib.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index faedb1481b24..8f312fa6c282 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -313,9 +313,22 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; snd_pcm_sframes_t hdelta, delta; unsigned long jdelta; + unsigned long curr_jiffies; + struct timespec curr_tstamp; old_hw_ptr = runtime->status->hw_ptr; + + /* + * group pointer, time and jiffies reads to allow for more + * accurate correlations/corrections. + * The values are stored at the end of this routine after + * corrections for hw_ptr position + */ pos = substream->ops->pointer(substream); + curr_jiffies = jiffies; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); + if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); return -EPIPE; @@ -343,7 +356,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { /* check for double acknowledged interrupts */ - hdelta = jiffies - runtime->hw_ptr_jiffies; + hdelta = curr_jiffies - runtime->hw_ptr_jiffies; if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) @@ -388,7 +401,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, * Without regular period interrupts, we have to check * the elapsed time to detect xruns. */ - jdelta = jiffies - runtime->hw_ptr_jiffies; + jdelta = curr_jiffies - runtime->hw_ptr_jiffies; if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) goto no_delta_check; hdelta = jdelta - delta * HZ / runtime->rate; @@ -430,7 +443,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (hdelta < runtime->delay) goto no_jiffies_check; hdelta -= runtime->delay; - jdelta = jiffies - runtime->hw_ptr_jiffies; + jdelta = curr_jiffies - runtime->hw_ptr_jiffies; if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { delta = jdelta / (((runtime->period_size * HZ) / runtime->rate) @@ -492,9 +505,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; - runtime->hw_ptr_jiffies = jiffies; + runtime->hw_ptr_jiffies = curr_jiffies; if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); + runtime->status->tstamp = curr_tstamp; return snd_pcm_update_state(substream, runtime); } |