diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0470-staging-bcm2835-audio-interpolate-audio-delay.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.19/950-0470-staging-bcm2835-audio-interpolate-audio-delay.patch | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0470-staging-bcm2835-audio-interpolate-audio-delay.patch b/target/linux/brcm2708/patches-4.19/950-0470-staging-bcm2835-audio-interpolate-audio-delay.patch new file mode 100644 index 0000000000..44b0218730 --- /dev/null +++ b/target/linux/brcm2708/patches-4.19/950-0470-staging-bcm2835-audio-interpolate-audio-delay.patch @@ -0,0 +1,82 @@ +From 82efe315c1f6ab98ab5d36288648c4373c618220 Mon Sep 17 00:00:00 2001 +From: Mike Brady <mikebrady@eircom.net> +Date: Mon, 22 Oct 2018 20:17:08 +0100 +Subject: [PATCH 470/782] staging: bcm2835-audio: interpolate audio delay + +commit a105a3a72824e0ac685a0711a67e4dbe29de62d0 upstream. + +When the BCM2835 audio output is used, userspace sees a jitter up to 10ms +in the audio position, aka "delay" -- the number of frames that must +be output before a new frame would be played. +Make this a bit nicer for userspace by interpolating the position +using the CPU clock. +The overhead is small -- an extra ktime_get() every time a GPU message +is sent -- and another call and a few calculations whenever the delay +is sought from userland. +At 48,000 frames per second, i.e. approximately 20 microseconds per +frame, it would take a clock inaccuracy of +20 microseconds in 10 milliseconds -- 2,000 parts per million -- +to result in an inaccurate estimate, whereas +crystal- or resonator-based clocks typically have an +inaccuracy of 10s to 100s of parts per million. + +Signed-off-by: Mike Brady <mikebrady@eircom.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 20 +++++++++++++++++++ + .../vc04_services/bcm2835-audio/bcm2835.h | 1 + + 2 files changed, 21 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +@@ -74,6 +74,7 @@ void bcm2835_playback_fifo(struct bcm283 + atomic_set(&alsa_stream->pos, pos); + + alsa_stream->period_offset += bytes; ++ alsa_stream->interpolate_start = ktime_get(); + if (alsa_stream->period_offset >= alsa_stream->period_size) { + alsa_stream->period_offset %= alsa_stream->period_size; + snd_pcm_period_elapsed(substream); +@@ -237,6 +238,7 @@ static int snd_bcm2835_pcm_prepare(struc + atomic_set(&alsa_stream->pos, 0); + alsa_stream->period_offset = 0; + alsa_stream->draining = false; ++ alsa_stream->interpolate_start = ktime_get(); + + return 0; + } +@@ -286,6 +288,24 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s + { + struct snd_pcm_runtime *runtime = substream->runtime; + struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; ++ ktime_t now = ktime_get(); ++ ++ /* Give userspace better delay reporting by interpolating between GPU ++ * notifications, assuming audio speed is close enough to the clock ++ * used for ktime ++ */ ++ ++ if ((ktime_to_ns(alsa_stream->interpolate_start)) && ++ (ktime_compare(alsa_stream->interpolate_start, now) < 0)) { ++ u64 interval = ++ (ktime_to_ns(ktime_sub(now, ++ alsa_stream->interpolate_start))); ++ u64 frames_output_in_interval = ++ div_u64((interval * runtime->rate), 1000000000); ++ snd_pcm_sframes_t frames_output_in_interval_sized = ++ -frames_output_in_interval; ++ runtime->delay = frames_output_in_interval_sized; ++ } + + return snd_pcm_indirect_playback_pointer(substream, + &alsa_stream->pcm_indirect, +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h +@@ -78,6 +78,7 @@ struct bcm2835_alsa_stream { + unsigned int period_offset; + unsigned int buffer_size; + unsigned int period_size; ++ ktime_t interpolate_start; + + struct bcm2835_audio_instance *instance; + int idx; |