pipewire config: enable bluez modules in pipewire and wireplumber
[AGL/meta-agl-devel.git] / meta-pipewire / recipes-multimedia / pipewire / pipewire / 0007-alsa-make-corrections-on-the-timeout-based-on-how-fa.patch
1 From 05a3a926df4906cdf60f7978843c637bbf37714a Mon Sep 17 00:00:00 2001
2 From: George Kiagiadakis <george.kiagiadakis@collabora.com>
3 Date: Tue, 9 Jul 2019 18:06:18 +0300
4 Subject: [PATCH] alsa: make corrections on the timeout based on how fast ALSA
5  consumes samples
6
7 This feels a bit hacky, but it actually makes huge difference when pipewire is
8 running in qemu.
9
10 The idea is that it keeps track of how much samples are in the device
11 (fill level) and calculates how many are consumed when a timeout occurs.
12 Then it converts that into a time based on the sample rate and compares it to
13 the system clock time that elapsed since the last write to the device.
14 The division between the two gives a rate (drift) that can be used to shorten
15 the timeout window.
16
17 So for instance, if the timeout window was 21.3 ms, but the device actually
18 consumed an equivalent of 28 ms in samples, the drift will be 21.3/28 = 0.76
19 and the next timeout window will be approximately 21.3 * 0.76 = 16.1 ms
20
21 To avoid making things worse, the drift is clamped between 0.6 and 1.0.
22 Min 0.6 was arbitrarily chosen, but sometimes alsa does report strange numbers,
23 causing the drift to be very low, which in turn causes an early wakeup.
24 Max 1.0 basically means that we don't care if the device is consuming samples
25 slower. In that case, the early wakeup mechanism will throttle pipewire.
26
27 Fixes #163
28
29 Upstream-Status: Submitted [https://github.com/PipeWire/pipewire/pull/166]
30 ---
31  spa/plugins/alsa/alsa-utils.c | 31 ++++++++++++++++++++++++++-----
32  spa/plugins/alsa/alsa-utils.h |  2 ++
33  2 files changed, 28 insertions(+), 5 deletions(-)
34
35 diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c
36 index 87582c1c..872969bf 100644
37 --- a/spa/plugins/alsa/alsa-utils.c
38 +++ b/spa/plugins/alsa/alsa-utils.c
39 @@ -593,7 +593,21 @@ static int get_status(struct state *state, snd_pcm_sframes_t *delay)
40  
41  static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t delay, bool slave)
42  {
43 -       double err, corr;
44 +       double err, corr, drift;
45 +       snd_pcm_sframes_t consumed;
46 +
47 +       consumed = state->fill_level - delay;
48 +       if (state->alsa_started && consumed > 0) {
49 +               double sysclk_diff = nsec - state->last_time;
50 +               double devclk_diff = ((double) consumed) * 1e9 / state->rate;
51 +               drift = sysclk_diff / devclk_diff;
52 +               drift = SPA_CLAMP(drift, 0.6, 1.0);
53 +
54 +               spa_log_trace_fp(state->log, "cons:%ld sclk:%f dclk:%f drift:%f",
55 +                       consumed, sysclk_diff, devclk_diff, drift);
56 +       } else {
57 +               drift = 1.0;
58 +       }
59  
60         if (state->stream == SND_PCM_STREAM_PLAYBACK)
61                 err = delay - state->last_threshold;
62 @@ -650,11 +664,11 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del
63                 state->clock->rate_diff = corr;
64         }
65  
66 -       spa_log_trace_fp(state->log, "slave:%d %"PRIu64" %f %ld %f %f %d", slave, nsec,
67 -                       corr, delay, err, state->threshold * corr,
68 +       spa_log_trace_fp(state->log, "slave:%d %"PRIu64" %f %ld %f %f %f %d", slave, nsec,
69 +                       corr, delay, err, state->threshold * corr, drift,
70                         state->threshold);
71  
72 -       state->next_time += state->threshold / corr * 1e9 / state->rate;
73 +       state->next_time += state->threshold / corr * drift * 1e9 / state->rate;
74         state->last_threshold = state->threshold;
75  
76         return 0;
77 @@ -783,6 +797,10 @@ again:
78                 goto again;
79  
80         state->sample_count += total_written;
81 +       state->fill_level += total_written;
82 +
83 +       clock_gettime(CLOCK_MONOTONIC, &state->now);
84 +       state->last_time = SPA_TIMESPEC_TO_NSEC (&state->now);
85  
86         if (!state->alsa_started && total_written > 0) {
87                 spa_log_trace(state->log, "snd_pcm_start %lu", written);
88 @@ -935,7 +953,7 @@ static int handle_play(struct state *state, uint64_t nsec, snd_pcm_sframes_t del
89  {
90         int res;
91  
92 -       if (delay >= state->last_threshold * 2) {
93 +       if (delay > state->last_threshold * 2) {
94                 spa_log_trace(state->log, "early wakeup %ld %d", delay, state->threshold);
95                 state->next_time = nsec + (delay - state->last_threshold) * SPA_NSEC_PER_SEC / state->rate;
96                 return -EAGAIN;
97 @@ -944,6 +962,8 @@ static int handle_play(struct state *state, uint64_t nsec, snd_pcm_sframes_t del
98         if ((res = update_time(state, nsec, delay, false)) < 0)
99                 return res;
100  
101 +       state->fill_level = delay;
102 +
103         if (spa_list_is_empty(&state->ready)) {
104                 struct spa_io_buffers *io = state->io;
105  
106 @@ -1072,6 +1092,7 @@ int spa_alsa_start(struct state *state)
107  
108         state->slaved = is_slaved(state);
109         state->last_threshold = state->threshold;
110 +       state->fill_level = 0;
111  
112         init_loop(state);
113         state->safety = 0.0;
114 diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h
115 index a862873f..b53890b5 100644
116 --- a/spa/plugins/alsa/alsa-utils.h
117 +++ b/spa/plugins/alsa/alsa-utils.h
118 @@ -134,7 +134,9 @@ struct state {
119         int64_t sample_time;
120         uint64_t next_time;
121         uint64_t base_time;
122 +       uint64_t last_time;
123  
124 +       snd_pcm_uframes_t fill_level;
125         uint64_t underrun;
126         double safety;
127  
128 -- 
129 2.20.1
130