1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "asrc_resampler.h"
18 
19 #include <base/strings/stringprintf.h>
20 #include <bluetooth/log.h>
21 #include <com_android_bluetooth_flags.h>
22 
23 #include <algorithm>
24 #include <cmath>
25 #include <utility>
26 
27 #include "asrc_tables.h"
28 #include "common/repeating_timer.h"
29 #include "hal/link_clocker.h"
30 #include "hci/hci_layer.h"
31 #include "hci/hci_packets.h"
32 #include "main/shim/entry.h"
33 #include "stack/include/main_thread.h"
34 
35 namespace bluetooth::audio::asrc {
36 
37 class SourceAudioHalAsrc::ClockRecovery
38     : public bluetooth::hal::ReadClockHandler {
39   std::mutex mutex_;
40   bluetooth::common::RepeatingTimer read_clock_timer_;
41 
42   enum class StateId { RESET, WARMUP, RUNNING };
43 
44   struct {
45     StateId id;
46 
47     uint32_t t0;
48     uint32_t local_time;
49     uint32_t stream_time;
50     uint32_t last_bt_clock;
51 
52     uint32_t decim_t0;
53     int decim_dt[2];
54 
55     double butter_drift;
56     double butter_s[2];
57   } state_;
58 
59   struct {
60     uint32_t local_time;
61     uint32_t stream_time;
62     double drift;
63   } reference_timing_;
64 
65   struct {
66     double sample_rate;
67     int drift_us;
68   } output_stats_;
69 
OnEvent(uint32_t timestamp_us,uint32_t bt_clock)70   __attribute__((no_sanitize("integer"))) void OnEvent(
71       uint32_t timestamp_us, uint32_t bt_clock) override {
72     auto& state = state_;
73 
74     // Setup the start point of the streaming
75 
76     if (state.id == StateId::RESET) {
77       state.t0 = timestamp_us;
78       state.local_time = state.stream_time = state.t0;
79       state.last_bt_clock = bt_clock;
80 
81       state.decim_t0 = state.t0;
82       state.decim_dt[1] = INT_MAX;
83 
84       state.id = StateId::WARMUP;
85     }
86 
87     // Update timing informations, and compute the minimum deviation
88     // in the interval of the decimation (1 second).
89 
90     // Convert the local clock interval from the last subampling event
91     // into microseconds.
92     uint32_t elapsed_us = ((bt_clock - state.last_bt_clock) * 625) >> 5;
93 
94     uint32_t local_time = state.local_time + elapsed_us;
95     int dt_current = int(timestamp_us - local_time);
96     state.decim_dt[1] = std::min(state.decim_dt[1], dt_current);
97 
98     if (local_time - state.decim_t0 < 1000 * 1000) return;
99 
100     state.decim_t0 += 1000 * 1000;
101 
102     state.last_bt_clock = bt_clock;
103     state.local_time += elapsed_us;
104     state.stream_time += elapsed_us;
105 
106     // The first decimation interval is used to adjust the start point.
107     // The deviation between local time and stream time in this interval can be
108     // ignored.
109 
110     if (state.id == StateId::WARMUP) {
111       state.decim_t0 += state.decim_dt[1];
112       state.local_time += state.decim_dt[1];
113       state.stream_time += state.decim_dt[1];
114 
115       state.decim_dt[0] = 0;
116       state.decim_dt[1] = INT_MAX;
117       state.id = StateId::RUNNING;
118       return;
119     }
120 
121     // Deduct the derive of the deviation, from the difference between
122     // the two consecutives decimated deviations.
123 
124     int drift = state.decim_dt[1] - state.decim_dt[0];
125     state.decim_dt[0] = state.decim_dt[1];
126     state.decim_dt[1] = INT_MAX;
127 
128     // Let's filter the derive, with a low-pass Butterworth filter.
129     // The cut-off frequency is set to 1/60th seconds.
130 
131     const double a1 = -1.9259839697e+00, a2 = 9.2862708612e-01;
132     const double b0 = 6.6077909823e-04, b1 = 1.3215581965e-03, b2 = b0;
133 
134     state.butter_drift = drift * b0 + state.butter_s[0];
135     state.butter_s[0] =
136         state.butter_s[1] + drift * b1 - state.butter_drift * a1;
137     state.butter_s[1] = drift * b2 - state.butter_drift * a2;
138 
139     // The stream time is adjusted with the filtered drift, and the error is
140     // caught up with a gain of 2^-8 (~1/250us). The error is deducted from
141     // the difference between the instant stream time, and the local time
142     // corrected by the decimated deviation.
143 
144     int err = state.stream_time - (state.local_time + state.decim_dt[0]);
145     state.stream_time +=
146         (int(ldexpf(state.butter_drift, 8)) - err + (1 << 7)) >> 8;
147 
148     // Update recovered timing information, and sample the output statistics.
149 
150     decltype(output_stats_) output_stats;
151 
152     {
153       const std::lock_guard<std::mutex> lock(mutex_);
154 
155       auto& ref = reference_timing_;
156       ref.local_time = state.local_time - state.t0;
157       ref.stream_time = state.stream_time - state.t0;
158       ref.drift = state.butter_drift * 1e-6;
159 
160       output_stats = output_stats_;
161     }
162 
163     log::info(
164         "Deviation: {:6} us ({:3.0f} ppm) | Output Fs: {:5.2f} Hz  drift: {:2} "
165         "us",
166         state.stream_time - state.local_time, state.butter_drift,
167         output_stats.sample_rate, output_stats.drift_us);
168   }
169 
170  public:
ClockRecovery(bluetooth::common::MessageLoopThread * thread)171   ClockRecovery(bluetooth::common::MessageLoopThread* thread)
172       : state_{.id = StateId::RESET}, reference_timing_{0, 0, 0} {
173     if (com::android::bluetooth::flags::run_clock_recovery_in_worker_thread()) {
174       read_clock_timer_.SchedulePeriodic(
175           thread->GetWeakPtr(), FROM_HERE,
176           base::BindRepeating(
__anon1887976e0402(void*) 177               [](void*) {
178                 bluetooth::shim::GetHciLayer()->EnqueueCommand(
179                     bluetooth::hci::ReadClockBuilder::Create(
180                         0, bluetooth::hci::WhichClock::LOCAL),
181                     get_main_thread()->BindOnce(
182                         [](bluetooth::hci::CommandCompleteView) {}));
183               },
184               nullptr),
185           std::chrono::milliseconds(100));
186     } else {
187       read_clock_timer_.SchedulePeriodic(
188           get_main_thread()->GetWeakPtr(), FROM_HERE,
189           base::BindRepeating(
__anon1887976e0602(void*) 190               [](void*) {
191                 bluetooth::shim::GetHciLayer()->EnqueueCommand(
192                     bluetooth::hci::ReadClockBuilder::Create(
193                         0, bluetooth::hci::WhichClock::LOCAL),
194                     get_main_thread()->BindOnce(
195                         [](bluetooth::hci::CommandCompleteView) {}));
196               },
197               nullptr),
198           std::chrono::milliseconds(100));
199     }
200 
201     hal::LinkClocker::Register(this);
202   }
203 
~ClockRecovery()204   ~ClockRecovery() override {
205     hal::LinkClocker::Unregister();
206     read_clock_timer_.Cancel();
207   }
208 
Convert(uint32_t stream_time)209   __attribute__((no_sanitize("integer"))) uint32_t Convert(
210       uint32_t stream_time) {
211     // Compute the difference between the stream time and the sampled time
212     // of the clock recovery, and adjust according to the drift.
213     // Then return the sampled local time, modified by this converted gap.
214 
215     const std::lock_guard<std::mutex> lock(mutex_);
216     const auto& ref = reference_timing_;
217 
218     int stream_dt = int(stream_time - ref.stream_time);
219     int local_dt_us = int(round(stream_dt * (1 + ref.drift)));
220     return ref.local_time + local_dt_us;
221   }
222 
UpdateOutputStats(double sample_rate,int drift_us)223   void UpdateOutputStats(double sample_rate, int drift_us) {
224     // Atomically update the output statistics,
225     // this should be used for logging.
226 
227     const std::lock_guard<std::mutex> lock(mutex_);
228 
229     output_stats_ = {sample_rate, drift_us};
230   }
231 };
232 
233 class SourceAudioHalAsrc::Resampler {
234   static const int KERNEL_Q = asrc::ResamplerTables::KERNEL_Q;
235   static const int KERNEL_A = asrc::ResamplerTables::KERNEL_A;
236 
237   const int32_t (*h_)[2 * KERNEL_A];
238   const int16_t (*d_)[2 * KERNEL_A];
239 
240   static const unsigned WSIZE = 64;
241 
242   int32_t win_[2][WSIZE];
243   unsigned out_pos_, in_pos_;
244   const int32_t pcm_min_, pcm_max_;
245 
246   // Apply the transfer coefficients `h`, corrected by linear interpolation,
247   // given fraction position `mu` weigthed by `d` values.
248 
249   inline int32_t Filter(const int32_t* in, const int32_t* h, int16_t mu,
250                         const int16_t* d);
251 
252   // Upsampling loop, the ratio is less than 1.0 in Q26 format,
253   // more output samples are produced compared to input.
254 
255   template <typename T>
Upsample(unsigned ratio,const T * in,int in_stride,size_t in_len,size_t * in_count,T * out,int out_stride,size_t out_len,size_t * out_count)256   __attribute__((no_sanitize("integer"))) void Upsample(
257       unsigned ratio, const T* in, int in_stride, size_t in_len,
258       size_t* in_count, T* out, int out_stride, size_t out_len,
259       size_t* out_count) {
260     int nin = in_len, nout = out_len;
261 
262     while (nin > 0 && nout > 0) {
263       unsigned idx = (in_pos_ >> 26);
264       unsigned phy = (in_pos_ >> 17) & 0x1ff;
265       int16_t mu = (in_pos_ >> 2) & 0x7fff;
266 
267       unsigned wbuf = idx < WSIZE / 2 || idx >= WSIZE + WSIZE / 2;
268       auto w = win_[wbuf] + ((idx + wbuf * WSIZE / 2) % WSIZE) - WSIZE / 2;
269 
270       *out = Filter(w, h_[phy], mu, d_[phy]);
271       out += out_stride;
272       nout--;
273       in_pos_ += ratio;
274 
275       if (in_pos_ - (out_pos_ << 26) >= (1u << 26)) {
276         win_[0][(out_pos_ + WSIZE / 2) % WSIZE] = win_[1][(out_pos_)] = *in;
277 
278         in += in_stride;
279         nin--;
280         out_pos_ = (out_pos_ + 1) % WSIZE;
281       }
282     }
283 
284     *in_count = in_len - nin;
285     *out_count = out_len - nout;
286   }
287 
288   // Downsample loop, the ratio is greater than 1.0 in Q26 format,
289   // less output samples are produced compared to input.
290 
291   template <typename T>
Downsample(unsigned ratio,const T * in,int in_stride,size_t in_len,size_t * in_count,T * out,int out_stride,size_t out_len,size_t * out_count)292   __attribute__((no_sanitize("integer"))) void Downsample(
293       unsigned ratio, const T* in, int in_stride, size_t in_len,
294       size_t* in_count, T* out, int out_stride, size_t out_len,
295       size_t* out_count) {
296     size_t nin = in_len, nout = out_len;
297 
298     while (nin > 0 && nout > 0) {
299       if (in_pos_ - (out_pos_ << 26) < (1u << 26)) {
300         unsigned idx = (in_pos_ >> 26);
301         unsigned phy = (in_pos_ >> 17) & 0x1ff;
302         int16_t mu = (in_pos_ >> 2) & 0x7fff;
303 
304         unsigned wbuf = idx < WSIZE / 2 || idx >= WSIZE + WSIZE / 2;
305         auto w = win_[wbuf] + ((idx + wbuf * WSIZE / 2) % WSIZE) - WSIZE / 2;
306 
307         *out = Filter(w, h_[phy], mu, d_[phy]);
308         out += out_stride;
309         nout--;
310         in_pos_ += ratio;
311       }
312 
313       win_[0][(out_pos_ + WSIZE / 2) % WSIZE] = win_[1][(out_pos_)] = *in;
314 
315       in += in_stride;
316       nin--;
317       out_pos_ = (out_pos_ + 1) % WSIZE;
318     }
319 
320     *in_count = in_len - nin;
321     *out_count = out_len - nout;
322   }
323 
324  public:
Resampler(int bit_depth)325   Resampler(int bit_depth)
326       : h_(asrc::resampler_tables.h),
327         d_(asrc::resampler_tables.d),
328         win_{{0}, {0}},
329         out_pos_(0),
330         in_pos_(0),
331         pcm_min_(-(int32_t(1) << (bit_depth - 1))),
332         pcm_max_((int32_t(1) << (bit_depth - 1)) - 1) {}
333 
334   // Resample from `in` buffer to `out` buffer, until the end of any of
335   // the two buffers. `in_count` returns the number of consumed samples,
336   // and `out_count` the number produced. `in_sub` returns the phase in
337   // the input stream, in Q26 format.
338 
339   template <typename T>
Resample(unsigned ratio_q26,const T * in,int in_stride,size_t in_len,size_t * in_count,T * out,int out_stride,size_t out_len,size_t * out_count,unsigned * in_sub_q26)340   void Resample(unsigned ratio_q26, const T* in, int in_stride, size_t in_len,
341                 size_t* in_count, T* out, int out_stride, size_t out_len,
342                 size_t* out_count, unsigned* in_sub_q26) {
343     auto fn = ratio_q26 < (1u << 26) ? &Resampler::Upsample<T>
344                                      : &Resampler::Downsample<T>;
345 
346     (this->*fn)(ratio_q26, in, in_stride, in_len, in_count, out, out_stride,
347                 out_len, out_count);
348 
349     *in_sub_q26 = in_pos_ & ((1u << 26) - 1);
350   }
351 };
352 
353 //
354 // ARM AArch 64 Neon Resampler Filtering
355 //
356 
357 #if __ARM_NEON && __ARM_ARCH_ISA_A64
358 
359 #include <arm_neon.h>
360 
vmull_low_s16(int16x8_t a,int16x8_t b)361 static inline int32x4_t vmull_low_s16(int16x8_t a, int16x8_t b) {
362   return vmull_s16(vget_low_s16(a), vget_low_s16(b));
363 }
364 
vmull_low_s32(int32x4_t a,int32x4_t b)365 static inline int64x2_t vmull_low_s32(int32x4_t a, int32x4_t b) {
366   return vmull_s32(vget_low_s32(a), vget_low_s32(b));
367 }
368 
vmlal_low_s32(int64x2_t r,int32x4_t a,int32x4_t b)369 static inline int64x2_t vmlal_low_s32(int64x2_t r, int32x4_t a, int32x4_t b) {
370   return vmlal_s32(r, vget_low_s32(a), vget_low_s32(b));
371 }
372 
Filter(const int32_t * x,const int32_t * h,int16_t _mu,const int16_t * d)373 inline int32_t SourceAudioHalAsrc::Resampler::Filter(const int32_t* x,
374                                                      const int32_t* h,
375                                                      int16_t _mu,
376                                                      const int16_t* d) {
377   int64x2_t sx;
378 
379   int16x8_t mu = vdupq_n_s16(_mu);
380 
381   int16x8_t d0 = vld1q_s16(d + 0);
382   int32x4_t h0 = vld1q_s32(h + 0), h4 = vld1q_s32(h + 4);
383   int32x4_t x0 = vld1q_s32(x + 0), x4 = vld1q_s32(x + 4);
384 
385   h0 = vaddq_s32(h0, vrshrq_n_s32(vmull_low_s16(d0, mu), 7));
386   h4 = vaddq_s32(h4, vrshrq_n_s32(vmull_high_s16(d0, mu), 7));
387 
388   sx = vmull_low_s32(x0, h0);
389   sx = vmlal_high_s32(sx, x0, h0);
390   sx = vmlal_low_s32(sx, x4, h4);
391   sx = vmlal_high_s32(sx, x4, h4);
392 
393   for (int i = 8; i < 32; i += 8) {
394     int16x8_t d8 = vld1q_s16(d + i);
395     int32x4_t h8 = vld1q_s32(h + i), h12 = vld1q_s32(h + i + 4);
396     int32x4_t x8 = vld1q_s32(x + i), x12 = vld1q_s32(x + i + 4);
397 
398     h8 = vaddq_s32(h8, vrshrq_n_s32(vmull_low_s16(d8, mu), 7));
399     h12 = vaddq_s32(h12, vrshrq_n_s32(vmull_high_s16(d8, mu), 7));
400 
401     sx = vmlal_low_s32(sx, x8, h8);
402     sx = vmlal_high_s32(sx, x8, h8);
403     sx = vmlal_low_s32(sx, x12, h12);
404     sx = vmlal_high_s32(sx, x12, h12);
405   }
406 
407   int64_t s = (vaddvq_s64(sx) + (1 << 30)) >> 31;
408   return std::clamp(s, int64_t(pcm_min_), int64_t(pcm_max_));
409 }
410 
411 //
412 // Generic Resampler Filtering
413 //
414 
415 #else
416 
Filter(const int32_t * in,const int32_t * h,int16_t mu,const int16_t * d)417 inline int32_t SourceAudioHalAsrc::Resampler::Filter(const int32_t* in,
418                                                      const int32_t* h,
419                                                      int16_t mu,
420                                                      const int16_t* d) {
421   int64_t s = 0;
422   for (int i = 0; i < 2 * KERNEL_A - 1; i++)
423     s += int64_t(in[i]) * (h[i] + ((mu * d[i] + (1 << 6)) >> 7));
424 
425   s = (s + (1 << 30)) >> 31;
426   return std::clamp(s, int64_t(pcm_min_), int64_t(pcm_max_));
427 }
428 
429 #endif
430 
SourceAudioHalAsrc(bluetooth::common::MessageLoopThread * thread,int channels,int sample_rate,int bit_depth,int interval_us,int num_burst_buffers,int burst_delay_ms)431 SourceAudioHalAsrc::SourceAudioHalAsrc(
432     bluetooth::common::MessageLoopThread* thread, int channels, int sample_rate,
433     int bit_depth, int interval_us, int num_burst_buffers, int burst_delay_ms)
434     : sample_rate_(sample_rate),
435       bit_depth_(bit_depth),
436       interval_us_(interval_us),
437       stream_us_(0),
438       drift_us_(0),
439       out_counter_(0),
440       resampler_pos_{0, 0} {
441   buffers_size_ = 0;
442 
443   // Check parameters
444 
__anon1887976e0802(int v, int min, int max) 445   auto check_bounds = [](int v, int min, int max) {
446     return v >= min && v <= max;
447   };
448 
449   if (!check_bounds(channels, 1, 8) ||
450       !check_bounds(sample_rate, 1 * 1000, 100 * 1000) ||
451       !check_bounds(bit_depth, 8, 32) ||
452       !check_bounds(interval_us, 1 * 1000, 100 * 1000) ||
453       !check_bounds(num_burst_buffers, 0, 10) ||
454       !check_bounds(burst_delay_ms, 0, 1000)) {
455     log::error(
456         "Bad parameters: channels: {} sample_rate: {} bit_depth: {} "
457         "interval_us: {} num_burst_buffers: {} burst_delay_ms: {}",
458         channels, sample_rate, bit_depth, interval_us, num_burst_buffers,
459         burst_delay_ms);
460 
461     return;
462   }
463 
464   // Compute filter constants
465 
466   const double drift_release_sec = 3;
467   drift_z0_ = 1. - exp(-3. / (1e6 / interval_us_) / drift_release_sec);
468 
469   // Setup modules, the 32 bits resampler is choosed over the 16 bits resampler
470   // when the PCM bit_depth is higher than 16 bits.
471 
472   clock_recovery_ = std::make_unique<ClockRecovery>(thread);
473   resamplers_ = std::make_unique<std::vector<Resampler>>(channels, bit_depth_);
474 
475   // Deduct from the PCM stream characteristics, the size of the pool buffers
476   // It needs 3 buffers (one almost full, an entire one, and a last which can be
477   // started).
478 
479   auto& buffers = buffers_;
480 
481   int num_interval_samples =
482       channels * (interval_us_ * sample_rate_) / (1000 * 1000);
483   buffers_size_ = num_interval_samples *
484                   (bit_depth_ <= 16 ? sizeof(int16_t) : sizeof(int32_t));
485 
486   for (auto& b : buffers.pool) b.resize(buffers_size_);
487   buffers.index = 0;
488   buffers.offset = 0;
489 
490   // Setup the burst buffers to silence
491 
492   auto silence_buffer = &buffers_.pool[0];
493   std::fill(silence_buffer->begin(), silence_buffer->end(), 0);
494 
495   burst_buffers_.resize(num_burst_buffers);
496   for (auto& b : burst_buffers_) b = silence_buffer;
497 
498   burst_delay_us_ = burst_delay_ms * 1000;
499 }
500 
~SourceAudioHalAsrc()501 SourceAudioHalAsrc::~SourceAudioHalAsrc() {}
502 
503 template <typename T>
Resample(double ratio,const std::vector<uint8_t> & in,std::vector<const std::vector<uint8_t> * > * out,uint32_t * output_us)504 __attribute__((no_sanitize("integer"))) void SourceAudioHalAsrc::Resample(
505     double ratio, const std::vector<uint8_t>& in,
506     std::vector<const std::vector<uint8_t>*>* out, uint32_t* output_us) {
507   auto& resamplers = *resamplers_;
508   auto& buffers = buffers_;
509   auto channels = resamplers.size();
510 
511   // Convert the resampling ration in fixed Q16,
512   // then loop until the input buffer is consumed.
513 
514   auto in_size = in.size() / sizeof(T);
515   auto in_length = in_size / channels;
516 
517   unsigned ratio_q26 = round(ldexp(ratio, 26));
518   unsigned sub_q26;
519 
520   while (in_length > 0) {
521     auto in_data = (const T*)in.data() + (in_size - in_length * channels);
522 
523     // Load from the context the current output buffer, the offset
524     // and deduct the remaning size. Let's resample the interleaved
525     // PCM stream, a separate reampler is used for each channel.
526 
527     auto buffer = &buffers.pool[buffers.index];
528     auto out_data = (T*)buffer->data() + buffers.offset;
529     auto out_size = buffer->size() / sizeof(T);
530     auto out_length = (out_size - buffers.offset) / channels;
531 
532     size_t in_count, out_count;
533 
534     for (auto& r : resamplers)
535       r.Resample<T>(ratio_q26, in_data++, channels, in_length, &in_count,
536                     out_data++, channels, out_length, &out_count, &sub_q26);
537 
538     in_length -= in_count;
539     buffers.offset += out_count * channels;
540 
541     // Update the resampler position, expressed in seconds
542     // and a number of samples in a second. The `sub_q26` variable
543     // returned by the resampler, adds the sub-sample information.
544 
545     resampler_pos_.samples += out_count;
546     for (; resampler_pos_.samples >= sample_rate_;
547          resampler_pos_.samples -= sample_rate_)
548       resampler_pos_.seconds++;
549 
550     // An output buffer has been fulfilled,
551     // select a new buffer in the pool, used as a ring.
552 
553     if (out_count >= out_length) {
554       buffers.index = (buffers.index + 1) % buffers.pool.size();
555       buffers.offset = 0;
556       out->push_back(buffer);
557     }
558   }
559 
560   // Let's convert the resampler position, in a micro-seconds timestamp.
561   // The samples count within a seconds, and sub-sample position, are
562   // converted, then add the number of seconds modulo 2^32.
563 
564   int64_t output_samples_q26 = (int64_t(resampler_pos_.samples) << 26) -
565                                ((int64_t(sub_q26) << 26) / ratio_q26);
566 
567   *output_us = resampler_pos_.seconds * (1000 * 1000) +
568                uint32_t((output_samples_q26 * 1000 * 1000) /
569                         (int64_t(sample_rate_) << 26));
570 }
571 
572 __attribute__((no_sanitize("integer"))) std::vector<const std::vector<uint8_t>*>
Run(const std::vector<uint8_t> & in)573 SourceAudioHalAsrc::Run(const std::vector<uint8_t>& in) {
574   std::vector<const std::vector<uint8_t>*> out;
575 
576   if (in.size() != buffers_size_) {
577     log::error("Inconsistent input buffer size: {} ({} expected)", in.size(),
578                buffers_size_);
579     return out;
580   }
581 
582   // The burst delay has expired, let's generate the burst.
583 
584   if (burst_buffers_.size() && stream_us_ >= burst_delay_us_) {
585     for (size_t i = 0; i < burst_buffers_.size(); i++)
586       out.push_back(burst_buffers_[(out_counter_ + i) % burst_buffers_.size()]);
587 
588     burst_buffers_.clear();
589   }
590 
591   // Convert the stream position to a local time,
592   // and catch up the drift within the next second.
593 
594   stream_us_ += interval_us_;
595   uint32_t local_us = clock_recovery_->Convert(stream_us_);
596 
597   double ratio = 1e6 / (1e6 - drift_us_);
598 
599   // Let's run the resampler,
600   // and update the drift according the output position returned.
601 
602   uint32_t output_us;
603 
604   if (bit_depth_ <= 16)
605     Resample<int16_t>(ratio, in, &out, &output_us);
606   else
607     Resample<int32_t>(ratio, in, &out, &output_us);
608 
609   drift_us_ += drift_z0_ * (int(output_us - local_us) - drift_us_);
610 
611   // Delay the stream, in order to generate a burst when
612   // the associated delay has expired.
613 
614   if (burst_buffers_.size()) {
615     for (size_t i = 0; i < out.size(); i++)
616       std::exchange<const std::vector<uint8_t>*>(
617           out[i], burst_buffers_[(out_counter_ + i) % burst_buffers_.size()]);
618   }
619 
620   // Return the output statistics to the clock recovery module
621 
622   out_counter_ += out.size();
623   clock_recovery_->UpdateOutputStats(ratio * sample_rate_,
624                                      int(output_us - local_us));
625 
626   if (0)
627     log::info("[{:6}.{:06}]  Fs: {:.2f} Hz  drift: {} us",
628               output_us / (1000 * 1000), output_us % (1000 * 1000),
629               ratio * sample_rate_, int(output_us - local_us));
630 
631   return out;
632 }
633 
634 }  // namespace bluetooth::audio::asrc
635