OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 84ad00eb76af34f8a6c6941dc6da80a3f735b207 Mon Sep 17 00:00:00 2001 |
2 | From: wm4 <wm4@nowhere> |
||
3 | Date: Wed, 13 Jan 2016 19:44:47 +0100 |
||
4 | Subject: [PATCH 410/454] bcm2835: interpolate audio delay |
||
5 | |||
6 | It appears the GPU only sends us a message all 10ms to update |
||
7 | the playback progress. Other than this, the playback position |
||
8 | (what SNDRV_PCM_IOCTL_DELAY will return) is not updated at all. |
||
9 | Userspace will see jitter up to 10ms in the audio position. |
||
10 | |||
11 | Make this a bit nicer for userspace by interpolating the |
||
12 | position using the CPU clock. |
||
13 | |||
14 | I'm not sure if setting snd_pcm_runtime.delay is the right |
||
15 | approach for this. Or if there is maybe an already existing |
||
16 | mechanism for position interpolation in the ALSA core. |
||
17 | |||
18 | I only set SNDRV_PCM_INFO_BATCH because this appears to remove |
||
19 | at least one situation snd_pcm_runtime.delay is used, so I have |
||
20 | to worry less in which place I have to update this field, or |
||
21 | how it interacts with the rest of ALSA. |
||
22 | |||
23 | In the future, it might be nice to use VC_AUDIO_MSG_TYPE_LATENCY. |
||
24 | One problem is that it requires sending a videocore message, and |
||
25 | waiting for a reply, which could make the implementation much |
||
26 | harder due to locking and synchronization requirements. |
||
27 | --- |
||
28 | .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 13 +++++++++++-- |
||
29 | .../staging/vc04_services/bcm2835-audio/bcm2835.h | 1 + |
||
30 | 2 files changed, 12 insertions(+), 2 deletions(-) |
||
31 | |||
32 | --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c |
||
33 | +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c |
||
34 | @@ -22,7 +22,7 @@ |
||
35 | /* hardware definition */ |
||
36 | static const struct snd_pcm_hardware snd_bcm2835_playback_hw = { |
||
37 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
||
38 | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), |
||
39 | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH), |
||
40 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, |
||
41 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, |
||
42 | .rate_min = 8000, |
||
43 | @@ -93,6 +93,8 @@ void bcm2835_playback_fifo(struct bcm283 |
||
44 | alsa_stream->pos %= alsa_stream->buffer_size; |
||
45 | } |
||
46 | |||
47 | + alsa_stream->interpolate_start = ktime_get_ns(); |
||
48 | + |
||
49 | if (alsa_stream->substream) { |
||
50 | if (new_period) |
||
51 | snd_pcm_period_elapsed(alsa_stream->substream); |
||
52 | @@ -323,6 +325,7 @@ static int snd_bcm2835_pcm_prepare(struc |
||
53 | alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); |
||
54 | alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); |
||
55 | alsa_stream->pos = 0; |
||
56 | + alsa_stream->interpolate_start = ktime_get_ns(); |
||
57 | |||
58 | audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", |
||
59 | alsa_stream->buffer_size, alsa_stream->period_size, |
||
60 | @@ -415,13 +418,19 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s |
||
61 | { |
||
62 | struct snd_pcm_runtime *runtime = substream->runtime; |
||
63 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; |
||
64 | - |
||
65 | + u64 now = ktime_get_ns(); |
||
66 | |||
67 | audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0, |
||
68 | frames_to_bytes(runtime, runtime->status->hw_ptr), |
||
69 | frames_to_bytes(runtime, runtime->control->appl_ptr), |
||
70 | alsa_stream->pos); |
||
71 | |||
72 | + /* Give userspace better delay reporting by interpolating between GPU |
||
73 | + * notifications, assuming audio speed is close enough to the clock |
||
74 | + * used for ktime */ |
||
75 | + if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now) |
||
76 | + runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000); |
||
77 | + |
||
78 | return snd_pcm_indirect_playback_pointer(substream, |
||
79 | &alsa_stream->pcm_indirect, |
||
80 | alsa_stream->pos); |
||
81 | --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h |
||
82 | +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h |
||
83 | @@ -137,6 +137,7 @@ struct bcm2835_alsa_stream { |
||
84 | unsigned int pos; |
||
85 | unsigned int buffer_size; |
||
86 | unsigned int period_size; |
||
87 | + u64 interpolate_start; |
||
88 | |||
89 | atomic_t retrieved; |
||
90 | struct bcm2835_audio_instance *instance; |