|
11 | 11 | /* hardware definition */
|
12 | 12 | static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
|
13 | 13 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
14 |
| - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), |
| 14 | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH), |
15 | 15 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
|
16 | 16 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
|
17 | 17 | .rate_min = 8000,
|
@@ -81,6 +81,8 @@ void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
|
81 | 81 | alsa_stream->pos %= alsa_stream->buffer_size;
|
82 | 82 | }
|
83 | 83 |
|
| 84 | + alsa_stream->interpolate_start = ktime_get_ns(); |
| 85 | + |
84 | 86 | if (alsa_stream->substream) {
|
85 | 87 | if (new_period)
|
86 | 88 | snd_pcm_period_elapsed(alsa_stream->substream);
|
@@ -306,6 +308,7 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
|
306 | 308 | alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
|
307 | 309 | alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
|
308 | 310 | alsa_stream->pos = 0;
|
| 311 | + alsa_stream->interpolate_start = ktime_get_ns(); |
309 | 312 |
|
310 | 313 | audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
|
311 | 314 | alsa_stream->buffer_size, alsa_stream->period_size,
|
@@ -397,12 +400,19 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
|
397 | 400 | {
|
398 | 401 | struct snd_pcm_runtime *runtime = substream->runtime;
|
399 | 402 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
|
| 403 | + u64 now = ktime_get_ns(); |
400 | 404 |
|
401 | 405 | audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
|
402 | 406 | frames_to_bytes(runtime, runtime->status->hw_ptr),
|
403 | 407 | frames_to_bytes(runtime, runtime->control->appl_ptr),
|
404 | 408 | alsa_stream->pos);
|
405 | 409 |
|
| 410 | + /* Give userspace better delay reporting by interpolating between GPU |
| 411 | + * notifications, assuming audio speed is close enough to the clock |
| 412 | + * used for ktime */ |
| 413 | + if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now) |
| 414 | + runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000); |
| 415 | + |
406 | 416 | return snd_pcm_indirect_playback_pointer(substream,
|
407 | 417 | &alsa_stream->pcm_indirect,
|
408 | 418 | alsa_stream->pos);
|
|
0 commit comments