/* hardware definition */
static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
alsa_stream->pos %= alsa_stream->buffer_size;
}
+ alsa_stream->interpolate_start = ktime_get_ns();
+
if (alsa_stream->substream) {
if (new_period)
snd_pcm_period_elapsed(alsa_stream->substream);
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->interpolate_start = ktime_get_ns();
audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
alsa_stream->buffer_size, alsa_stream->period_size,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ u64 now = ktime_get_ns();
audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
frames_to_bytes(runtime, runtime->status->hw_ptr),
frames_to_bytes(runtime, runtime->control->appl_ptr),
alsa_stream->pos);
+ /* Give userspace better delay reporting by interpolating between GPU
+ * notifications, assuming audio speed is close enough to the clock
+ * used for ktime */
+ if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now)
+ runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000);
+
return snd_pcm_indirect_playback_pointer(substream,
&alsa_stream->pcm_indirect,
alsa_stream->pos);