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