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