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