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