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