1 /*
2 * Copyright 2021 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 #define LOG_TAG "sco_hci"
18
19 #include <bluetooth/log.h>
20 #include <grp.h>
21 #include <math.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include <cfloat>
26 #include <memory>
27
28 #include "bta/ag/bta_ag_int.h"
29 #include "btif/include/core_callbacks.h"
30 #include "btif/include/stack_manager_t.h"
31 #include "osi/include/allocator.h"
32 #include "stack/btm/btm_sco.h"
33 #include "udrv/include/uipc.h"
34
35 /* Per Bluetooth Core v5.0 and HFP 1.9 specification. */
36 #define BTM_MSBC_H2_HEADER_0 0x01
37 #define BTM_MSBC_H2_HEADER_LEN 2
38 #define BTM_MSBC_PKT_LEN 60
39 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */
40 #define BTM_MSBC_SYNC_WORD 0xAD
41
42 /* Used by PLC */
43 #define BTM_MSBC_SAMPLE_SIZE 2 /* 2 bytes*/
44 #define BTM_MSBC_FS 120 /* Frame Size */
45
46 #define BTM_PLC_WL 256 /* 16ms - Window Length for pattern matching */
47 #define BTM_PLC_TL 64 /* 4ms - Template Length for matching */
48 #define BTM_PLC_HL (BTM_PLC_WL + BTM_MSBC_FS - 1) /* Length of History buffer required */
49 #define BTM_PLC_SBCRL 36 /* SBC Reconvergence sample Length */
50 #define BTM_PLC_OLAL 16 /* OverLap-Add Length */
51
52 /* Disable the PLC when there are more than threshold of lost packets in the
53 * window */
54 #define BTM_PLC_WINDOW_SIZE 5
55 #define BTM_PLC_PL_THRESHOLD 1
56
57 /* LC3 definitions */
58 #define BTM_LC3_H2_HEADER_0 0x01
59 #define BTM_LC3_H2_HEADER_LEN 2
60 #define BTM_LC3_PKT_LEN 60
61 #define BTM_LC3_FS 240 /* Frame Size */
62
63 #if TARGET_FLOSS
64
65 #define SCO_DATA_READ_POLL_MS 10
66 #define SCO_HOST_DATA_PATH "/var/run/bluetooth/audio/.sco_data"
67 // TODO(b/198260375): Make SCO data owner group configurable.
68 #define SCO_HOST_DATA_GROUP "bluetooth-audio"
69
70 namespace {
71
72 std::unique_ptr<tUIPC_STATE> sco_uipc = nullptr;
73
sco_data_cb(tUIPC_CH_ID,tUIPC_EVENT event)74 void sco_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
75 switch (event) {
76 case UIPC_OPEN_EVT:
77 /*
78 * Read directly from media task from here on (keep callback for
79 * connection events.
80 */
81 UIPC_Ioctl(*sco_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
82 UIPC_Ioctl(*sco_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
83 reinterpret_cast<void*>(SCO_DATA_READ_POLL_MS));
84 break;
85 default:
86 break;
87 }
88 }
89
90 } // namespace
91 #endif
92
93 namespace bluetooth {
94 namespace audio {
95 namespace sco {
96
97 #if TARGET_FLOSS
open()98 void open() {
99 if (sco_uipc != nullptr) {
100 log::warn("Re-opening UIPC that is already running");
101 cleanup();
102 }
103
104 sco_uipc = UIPC_Init();
105 if (sco_uipc == nullptr) {
106 log::error("failed to init UIPC");
107 return;
108 }
109
110 UIPC_Open(*sco_uipc, UIPC_CH_ID_AV_AUDIO, sco_data_cb, SCO_HOST_DATA_PATH);
111 struct group* grp = getgrnam(SCO_HOST_DATA_GROUP);
112 chmod(SCO_HOST_DATA_PATH, 0770);
113 if (grp) {
114 int res = chown(SCO_HOST_DATA_PATH, -1, grp->gr_gid);
115 if (res == -1) {
116 log::error("failed: {}", strerror(errno));
117 }
118 }
119 }
120
cleanup()121 void cleanup() {
122 if (sco_uipc == nullptr) {
123 return;
124 }
125 UIPC_Close(*sco_uipc, UIPC_CH_ID_ALL);
126 sco_uipc = nullptr;
127 }
128
read(uint8_t * p_buf,uint32_t len)129 size_t read(uint8_t* p_buf, uint32_t len) {
130 if (sco_uipc == nullptr) {
131 log::warn("Read from uninitialized or closed UIPC");
132 return 0;
133 }
134 return UIPC_Read(*sco_uipc, UIPC_CH_ID_AV_AUDIO, p_buf, len);
135 }
136
write(const uint8_t * p_buf,uint32_t len)137 size_t write(const uint8_t* p_buf, uint32_t len) {
138 if (sco_uipc == nullptr) {
139 log::warn("Write to uninitialized or closed UIPC");
140 return 0;
141 }
142 return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0;
143 }
144 #else
145 void open() {}
146 void cleanup() {}
147
148 size_t read(uint8_t* p_buf, uint32_t len) { return bta_ag_sco_read(p_buf, len); }
149
150 size_t write(const uint8_t* p_buf, uint32_t len) { return bta_ag_sco_write(p_buf, len); }
151 #endif
152
153 enum decode_buf_state {
154 DECODE_BUF_EMPTY,
155 DECODE_BUF_FULL,
156
157 // Neither empty nor full.
158 DECODE_BUF_HALFFULL,
159 };
160
161 namespace wbs {
162
163 /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits
164 * sequence number 0000, 0011, 1100, 1111. */
165 static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
166
167 /* Supported SCO packet sizes for mSBC. The wideband speech mSBC frame parsing
168 * code ties to limited packet size values. Specifically list them out
169 * to check against when setting packet size. The first entry is the default
170 * value as a fallback. */
171 constexpr size_t btm_wbs_supported_pkt_size[] = {BTM_MSBC_PKT_LEN, 72, 24, 0};
172 /* Buffer size should be set to least common multiple of SCO packet size and
173 * BTM_MSBC_PKT_LEN for optimizing buffer copy. */
174 constexpr size_t btm_wbs_msbc_buffer_size[] = {BTM_MSBC_PKT_LEN, 360, 120, 0};
175
176 /* The pre-computed SCO packet per HFP 1.7 spec. This mSBC packet will be
177 * decoded into all-zero input PCM. */
178 static const uint8_t btm_msbc_zero_packet[] = {
179 0x01, 0x08, /* Mock H2 header */
180 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7,
181 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb,
182 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd,
183 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c,
184 /* End of Audio Samples */
185 0x00 /* A padding byte defined by mSBC */};
186
187 /* Raised Cosine table for OLA */
188 static const float rcos[BTM_PLC_OLAL] = {0.99148655f, 0.96623611f, 0.92510857f, 0.86950446f,
189 0.80131732f, 0.72286918f, 0.63683150f, 0.54613418f,
190 0.45386582f, 0.36316850f, 0.27713082f, 0.19868268f,
191 0.13049554f, 0.07489143f, 0.03376389f, 0.00851345f};
192
f_to_s16(float input)193 static int16_t f_to_s16(float input) {
194 return input > INT16_MAX ? INT16_MAX : input < INT16_MIN ? INT16_MIN : (int16_t)input;
195 }
196 /* This structure tracks the packet loss for last PLC_WINDOW_SIZE of packets */
197 struct tBTM_MSBC_BTM_PLC_WINDOW {
198 bool loss_hist[BTM_PLC_WINDOW_SIZE]; /* The packet loss history of receiving
199 packets.*/
200 unsigned int idx; /* The index of the to be updated packet loss status. */
201 unsigned int count; /* The count of lost packets in the window. */
202
203 public:
update_plc_statebluetooth::audio::sco::wbs::tBTM_MSBC_BTM_PLC_WINDOW204 void update_plc_state(bool is_packet_loss) {
205 bool* curr = &loss_hist[idx];
206 if (is_packet_loss != *curr) {
207 count += (is_packet_loss - *curr);
208 *curr = is_packet_loss;
209 }
210 idx = (idx + 1) % BTM_PLC_WINDOW_SIZE;
211 }
212
is_packet_loss_too_highbluetooth::audio::sco::wbs::tBTM_MSBC_BTM_PLC_WINDOW213 bool is_packet_loss_too_high() {
214 /* The packet loss count comes from a time window and we use it as an
215 * indicator of our confidence of the PLC algorithm. It is known to
216 * generate poorer and robotic feeling sounds, when the majority of
217 * samples in the PLC history buffer are from the concealment results.
218 */
219 return count > BTM_PLC_PL_THRESHOLD;
220 }
221 };
222
223 /* The PLC is specifically designed for mSBC. The algorithm searches the
224 * history of receiving samples to find the best match samples and constructs
225 * substitutions for the lost samples. The selection is based on pattern
226 * matching a template, composed of a length of samples preceding to the lost
227 * samples. It then uses the following samples after the best match as the
228 * replacement samples and applies Overlap-Add to reduce the audible
229 * distortion.
230 *
231 * This structure holds related info needed to conduct the PLC algorithm.
232 */
233 struct tBTM_MSBC_PLC {
234 int16_t hist[BTM_PLC_HL + BTM_MSBC_FS + BTM_PLC_SBCRL +
235 BTM_PLC_OLAL]; /* The history buffer for receiving samples, we
236 also use it to buffer the processed
237 replacement samples */
238 unsigned best_lag; /* The index of the best substitution samples in the
239 sample history */
240 int handled_bad_frames; /* Number of bad frames handled since the last good
241 frame */
242 int16_t decoded_buffer[BTM_MSBC_FS]; /* Used for storing the samples from
243 decoding the mSBC zero frame packet and
244 also constructed frames */
245 tBTM_MSBC_BTM_PLC_WINDOW* pl_window; /* Used to monitor how many packets are bad within the recent
246 BTM_PLC_WINDOW_SIZE of packets. We use this to determine
247 if we want to disable the PLC temporarily */
248
249 int num_decoded_frames; /* Number of total read mSBC frames. */
250 int num_lost_frames; /* Number of total lost mSBC frames. */
251
overlap_addbluetooth::audio::sco::wbs::tBTM_MSBC_PLC252 void overlap_add(int16_t* output, float scaler_d, const int16_t* desc, float scaler_a,
253 const int16_t* asc) {
254 for (int i = 0; i < BTM_PLC_OLAL; i++) {
255 output[i] = f_to_s16(scaler_d * desc[i] * rcos[i] +
256 scaler_a * asc[i] * rcos[BTM_PLC_OLAL - 1 - i]);
257 }
258 }
259
cross_correlationbluetooth::audio::sco::wbs::tBTM_MSBC_PLC260 float cross_correlation(int16_t* x, int16_t* y) {
261 float sum = 0, x2 = 0, y2 = 0;
262
263 for (int i = 0; i < BTM_PLC_TL; i++) {
264 sum += ((float)x[i]) * y[i];
265 x2 += ((float)x[i]) * x[i];
266 y2 += ((float)y[i]) * y[i];
267 }
268 return sum / sqrtf(x2 * y2);
269 }
270
pattern_matchbluetooth::audio::sco::wbs::tBTM_MSBC_PLC271 int pattern_match(int16_t* hist) {
272 int best = 0;
273 float cn, max_cn = FLT_MIN;
274
275 for (int i = 0; i < BTM_PLC_WL; i++) {
276 cn = cross_correlation(&hist[BTM_PLC_HL - BTM_PLC_TL], &hist[i]);
277 if (cn > max_cn) {
278 best = i;
279 max_cn = cn;
280 }
281 }
282 return best;
283 }
284
amplitude_matchbluetooth::audio::sco::wbs::tBTM_MSBC_PLC285 float amplitude_match(int16_t* x, int16_t* y) {
286 uint32_t sum_x = 0, sum_y = 0;
287 float scaler;
288 for (int i = 0; i < BTM_MSBC_FS; i++) {
289 sum_x += abs(x[i]);
290 sum_y += abs(y[i]);
291 }
292
293 if (sum_y == 0) {
294 return 1.2f;
295 }
296
297 scaler = (float)sum_x / sum_y;
298 return scaler > 1.2f ? 1.2f : scaler < 0.75f ? 0.75f : scaler;
299 }
300
301 public:
initbluetooth::audio::sco::wbs::tBTM_MSBC_PLC302 void init() {
303 if (pl_window) {
304 osi_free(pl_window);
305 }
306 pl_window = (tBTM_MSBC_BTM_PLC_WINDOW*)osi_calloc(sizeof(*pl_window));
307 }
308
deinitbluetooth::audio::sco::wbs::tBTM_MSBC_PLC309 void deinit() {
310 if (pl_window) {
311 osi_free_and_reset((void**)&pl_window);
312 }
313 }
314
get_num_decoded_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC315 int get_num_decoded_frames() { return num_decoded_frames; }
316
get_num_lost_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC317 int get_num_lost_frames() { return num_lost_frames; }
318
handle_bad_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC319 void handle_bad_frames(const uint8_t** output) {
320 float scaler;
321 int16_t* best_match_hist;
322 int16_t* frame_head = &hist[BTM_PLC_HL];
323
324 num_decoded_frames++;
325 num_lost_frames++;
326
327 /* mSBC codec is stateful, the history of signal would contribute to the
328 * decode result decoded_buffer. This should never fail. */
329 GetInterfaceToProfiles()->msbcCodec->decodePacket(btm_msbc_zero_packet, decoded_buffer,
330 sizeof(decoded_buffer));
331
332 /* The PLC algorithm is more likely to generate bad results that sound
333 * robotic after severe packet losses happened. Only applying it when
334 * we are confident. */
335 if (!pl_window->is_packet_loss_too_high()) {
336 if (handled_bad_frames == 0) {
337 /* Finds the best matching samples and amplitude */
338 best_lag = pattern_match(hist) + BTM_PLC_TL;
339 best_match_hist = &hist[best_lag];
340 scaler = amplitude_match(&hist[BTM_PLC_HL - BTM_MSBC_FS], best_match_hist);
341
342 /* Constructs the substitution samples */
343 overlap_add(frame_head, 1.0, decoded_buffer, scaler, best_match_hist);
344 for (int i = BTM_PLC_OLAL; i < BTM_MSBC_FS; i++) {
345 hist[BTM_PLC_HL + i] = f_to_s16(scaler * best_match_hist[i]);
346 }
347 overlap_add(&frame_head[BTM_MSBC_FS], scaler, &best_match_hist[BTM_MSBC_FS], 1.0,
348 &best_match_hist[BTM_MSBC_FS]);
349
350 memmove(&frame_head[BTM_MSBC_FS + BTM_PLC_OLAL],
351 &best_match_hist[BTM_MSBC_FS + BTM_PLC_OLAL], BTM_PLC_SBCRL * BTM_MSBC_SAMPLE_SIZE);
352 } else {
353 /* Using the existing best lag and copy the following frames */
354 memmove(frame_head, &hist[best_lag],
355 (BTM_MSBC_FS + BTM_PLC_SBCRL + BTM_PLC_OLAL) * BTM_MSBC_SAMPLE_SIZE);
356 }
357 /* Copy the constructed frames to decoded buffer for caller to use */
358 std::copy(frame_head, &frame_head[BTM_MSBC_FS], decoded_buffer);
359
360 handled_bad_frames++;
361 } else {
362 /* This is a case similar to receiving a good frame with all zeros, we set
363 * handled_bad_frames to zero to prevent the following good frame from
364 * being concealed to reconverge with the zero frames we fill in. The
365 * concealment result sounds more artificial and weird than simply writing
366 * zeros and following samples.
367 */
368 std::copy(std::begin(decoded_buffer), std::end(decoded_buffer), frame_head);
369 std::fill(&frame_head[BTM_MSBC_FS], &frame_head[BTM_MSBC_FS + BTM_PLC_SBCRL + BTM_PLC_OLAL],
370 0);
371 /* No need to copy the frames as we'll use the decoded zero frames in the
372 * decoded buffer as our concealment frames */
373
374 handled_bad_frames = 0;
375 }
376
377 *output = (const uint8_t*)decoded_buffer;
378
379 /* Shift the frames to update the history window */
380 memmove(hist, &hist[BTM_MSBC_FS],
381 (BTM_PLC_HL + BTM_PLC_SBCRL + BTM_PLC_OLAL) * BTM_MSBC_SAMPLE_SIZE);
382 pl_window->update_plc_state(1);
383 }
384
handle_good_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC385 void handle_good_frames(int16_t* input) {
386 int16_t* frame_head;
387 num_decoded_frames++;
388 if (handled_bad_frames != 0) {
389 /* If there was a packet concealment before this good frame, we need to
390 * reconverge the input frames */
391 frame_head = &hist[BTM_PLC_HL];
392
393 /* For the first good frame after packet loss, we need to conceal the
394 * received samples to have it reconverge with the true output */
395 std::copy(frame_head, &frame_head[BTM_PLC_SBCRL], input);
396 /* Overlap the input frame with the previous output frame */
397 overlap_add(&input[BTM_PLC_SBCRL], 1.0, &frame_head[BTM_PLC_SBCRL], 1.0,
398 &input[BTM_PLC_SBCRL]);
399 handled_bad_frames = 0;
400 }
401
402 /* Shift the history and update the good frame to the end of it */
403 memmove(hist, &hist[BTM_MSBC_FS], (BTM_PLC_HL - BTM_MSBC_FS) * BTM_MSBC_SAMPLE_SIZE);
404 std::copy(input, &input[BTM_MSBC_FS], &hist[BTM_PLC_HL - BTM_MSBC_FS]);
405 pl_window->update_plc_state(0);
406 }
407 };
408
409 /* Define the structure that contains mSBC data */
410 struct tBTM_MSBC_INFO {
411 size_t packet_size; /* SCO mSBC packet size supported by lower layer */
412 size_t buf_size; /* The size of the buffer, determined by the packet_size. */
413
414 uint8_t* packet_buf; /* Temporary buffer to store the data */
415 uint8_t* msbc_decode_buf; /* Buffer to store mSBC packets to decode */
416 size_t decode_buf_wo; /* Write offset of the decode buffer */
417 size_t decode_buf_ro; /* Read offset of the decode buffer */
418
419 /* Within the circular buffer, which can be visualized as having
420 two halves, mirror indicators track the pointer's location,
421 signaling whether it resides in the first or second segment:
422
423 [buf_size-1] ┼ - - -─┼ [0]
424 │ │
425 │ │
426 wo = x, wo_mirror = 0 ^ v ro = x, ro_mirror = 1
427 │ │
428 │ │
429 [0] ┼ - - - ┼ [buf_size-1]
430 (First Half) (Second Half)
431 */
432 bool decode_buf_wo_mirror; /* The mirror indicator specifies whether
433 the write pointer is currently located
434 in the first or second half of the
435 circular buffer */
436 bool decode_buf_ro_mirror; /* The mirror indicator specifies whether
437 the read pointer is currently located
438 in the first or second half of the
439 circular buffer */
440 bool read_corrupted; /* If the current mSBC packet read is corrupted */
441
442 uint8_t* msbc_encode_buf; /* Buffer to store the encoded SCO packets */
443 size_t encode_buf_wo; /* Write offset of the encode buffer */
444 size_t encode_buf_ro; /* Read offset of the encode buffer */
445
446 int16_t decoded_pcm_buf[BTM_MSBC_FS]; /* Buffer to store decoded PCM */
447
448 uint8_t num_encoded_msbc_pkts; /* Number of the encoded mSBC packets */
449
450 tBTM_MSBC_PLC* plc; /* PLC component to handle the packet loss of input */
451 tBTM_SCO_PKT_STATUS* pkt_status; /* Record of mSBC packet status */
get_supported_packet_sizebluetooth::audio::sco::wbs::tBTM_MSBC_INFO452 static size_t get_supported_packet_size(size_t pkt_size, size_t* buffer_size) {
453 int i;
454 for (i = 0; btm_wbs_supported_pkt_size[i] != 0 && btm_wbs_supported_pkt_size[i] != pkt_size;
455 i++)
456 ;
457 /* In case of unsupported value, error log and fallback to
458 * BTM_MSBC_PKT_LEN(60). */
459 if (btm_wbs_supported_pkt_size[i] == 0) {
460 log::warn("Unsupported packet size {}", pkt_size);
461 i = 0;
462 }
463
464 if (buffer_size) {
465 *buffer_size = btm_wbs_msbc_buffer_size[i];
466 }
467 return btm_wbs_supported_pkt_size[i];
468 }
469
verify_h2_header_seq_numbluetooth::audio::sco::wbs::tBTM_MSBC_INFO470 bool verify_h2_header_seq_num(const uint8_t num) {
471 for (int i = 0; i < 4; i++) {
472 if (num == btm_h2_header_frames_count[i]) {
473 return true;
474 }
475 }
476 return false;
477 }
478
479 public:
initbluetooth::audio::sco::wbs::tBTM_MSBC_INFO480 size_t init(size_t pkt_size) {
481 decode_buf_wo = 0;
482 decode_buf_ro = 0;
483 decode_buf_wo_mirror = false;
484 decode_buf_ro_mirror = false;
485
486 encode_buf_wo = 0;
487 encode_buf_ro = 0;
488
489 pkt_size = get_supported_packet_size(pkt_size, &buf_size);
490 if (pkt_size == packet_size) {
491 return packet_size;
492 }
493 packet_size = pkt_size;
494
495 if (!packet_buf) {
496 packet_buf = (uint8_t*)osi_calloc(BTM_MSBC_PKT_LEN);
497 }
498
499 if (msbc_decode_buf) {
500 osi_free(msbc_decode_buf);
501 }
502 msbc_decode_buf = (uint8_t*)osi_calloc(buf_size);
503
504 if (msbc_encode_buf) {
505 osi_free(msbc_encode_buf);
506 }
507 msbc_encode_buf = (uint8_t*)osi_calloc(buf_size);
508
509 if (plc) {
510 plc->deinit();
511 osi_free(plc);
512 }
513 plc = (tBTM_MSBC_PLC*)osi_calloc(sizeof(*plc));
514 plc->init();
515
516 if (pkt_status) {
517 osi_free(pkt_status);
518 }
519 pkt_status = (tBTM_SCO_PKT_STATUS*)osi_calloc(sizeof(*pkt_status));
520 pkt_status->init();
521
522 return packet_size;
523 }
524
deinitbluetooth::audio::sco::wbs::tBTM_MSBC_INFO525 void deinit() {
526 if (msbc_decode_buf) {
527 osi_free(msbc_decode_buf);
528 }
529 if (packet_buf) {
530 osi_free(packet_buf);
531 }
532 if (msbc_encode_buf) {
533 osi_free(msbc_encode_buf);
534 }
535 if (plc) {
536 plc->deinit();
537 osi_free_and_reset((void**)&plc);
538 }
539 if (pkt_status) {
540 osi_free_and_reset((void**)&pkt_status);
541 }
542 }
543
incr_buf_offsetbluetooth::audio::sco::wbs::tBTM_MSBC_INFO544 void incr_buf_offset(size_t& offset, bool& mirror, size_t bsize, size_t amount) {
545 if (bsize - offset > amount) {
546 offset += amount;
547 return;
548 }
549
550 mirror = !mirror;
551 offset = amount - (bsize - offset);
552 }
553
decode_buf_statusbluetooth::audio::sco::wbs::tBTM_MSBC_INFO554 decode_buf_state decode_buf_status() {
555 if (decode_buf_ro == decode_buf_wo) {
556 if (decode_buf_ro_mirror == decode_buf_wo_mirror) {
557 return DECODE_BUF_EMPTY;
558 }
559 return DECODE_BUF_FULL;
560 }
561 return DECODE_BUF_HALFFULL;
562 }
563
decode_buf_data_lenbluetooth::audio::sco::wbs::tBTM_MSBC_INFO564 size_t decode_buf_data_len() {
565 switch (decode_buf_status()) {
566 case DECODE_BUF_EMPTY:
567 return 0;
568 case DECODE_BUF_FULL:
569 return buf_size;
570 case DECODE_BUF_HALFFULL:
571 default:
572 if (decode_buf_wo > decode_buf_ro) {
573 return decode_buf_wo - decode_buf_ro;
574 }
575 return buf_size - (decode_buf_ro - decode_buf_wo);
576 };
577 }
578
decode_buf_avail_lenbluetooth::audio::sco::wbs::tBTM_MSBC_INFO579 size_t decode_buf_avail_len() { return buf_size - decode_buf_data_len(); }
580
mark_pkt_decodedbluetooth::audio::sco::wbs::tBTM_MSBC_INFO581 void mark_pkt_decoded() {
582 if (decode_buf_data_len() < BTM_MSBC_PKT_LEN) {
583 log::error("Trying to mark read offset beyond write offset.");
584 return;
585 }
586
587 incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size, BTM_MSBC_PKT_LEN);
588 }
589
writebluetooth::audio::sco::wbs::tBTM_MSBC_INFO590 size_t write(const std::vector<uint8_t>& input) {
591 if (input.size() > decode_buf_avail_len()) {
592 log::warn(
593 "Cannot write input with size {} into decode_buf with {} empty "
594 "space.",
595 input.size(), decode_buf_avail_len());
596 return 0;
597 }
598
599 if (buf_size - decode_buf_wo > input.size()) {
600 std::copy(input.begin(), input.end(), msbc_decode_buf + decode_buf_wo);
601 } else {
602 std::copy(input.begin(), input.begin() + buf_size - decode_buf_wo,
603 msbc_decode_buf + decode_buf_wo);
604 std::copy(input.begin() + buf_size - decode_buf_wo, input.end(), msbc_decode_buf);
605 }
606
607 incr_buf_offset(decode_buf_wo, decode_buf_wo_mirror, buf_size, input.size());
608 return input.size();
609 }
610
find_msbc_pkt_headbluetooth::audio::sco::wbs::tBTM_MSBC_INFO611 const uint8_t* find_msbc_pkt_head() {
612 if (read_corrupted) {
613 read_corrupted = false;
614 return nullptr;
615 }
616
617 size_t rp = 0;
618 size_t data_len = decode_buf_data_len();
619 while (rp < BTM_MSBC_PKT_LEN && data_len - rp >= BTM_MSBC_PKT_LEN) {
620 if ((msbc_decode_buf[(decode_buf_ro + rp) % buf_size] != BTM_MSBC_H2_HEADER_0) ||
621 (!verify_h2_header_seq_num(msbc_decode_buf[(decode_buf_ro + rp + 1) % buf_size])) ||
622 (msbc_decode_buf[(decode_buf_ro + rp + 2) % buf_size] != BTM_MSBC_SYNC_WORD)) {
623 rp++;
624 continue;
625 }
626
627 if (rp != 0) {
628 log::warn("Skipped {} bytes of mSBC data ahead of a valid mSBC frame", rp);
629 incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size, rp);
630 }
631
632 // Get the frame head.
633 if (buf_size - decode_buf_ro >= BTM_MSBC_PKT_LEN) {
634 return &msbc_decode_buf[decode_buf_ro];
635 }
636
637 std::copy(msbc_decode_buf + decode_buf_ro, msbc_decode_buf + buf_size, packet_buf);
638 std::copy(msbc_decode_buf, msbc_decode_buf + BTM_MSBC_PKT_LEN - (buf_size - decode_buf_ro),
639 packet_buf + (buf_size - decode_buf_ro));
640 return packet_buf;
641 }
642
643 return nullptr;
644 }
645
646 /* Fill in the mSBC header and update the buffer's write offset to guard the
647 * buffer space to be written. Return a pointer to the start of mSBC packet's
648 * body for the caller to fill the encoded mSBC data if there is enough space
649 * in the buffer to fill in a new packet, otherwise return a nullptr. */
fill_msbc_pkt_templatebluetooth::audio::sco::wbs::tBTM_MSBC_INFO650 uint8_t* fill_msbc_pkt_template() {
651 uint8_t* wp = &msbc_encode_buf[encode_buf_wo];
652 if (buf_size - encode_buf_wo < BTM_MSBC_PKT_LEN) {
653 log::debug("Packet queue can't accommodate more packets.");
654 return nullptr;
655 }
656
657 wp[0] = BTM_MSBC_H2_HEADER_0;
658 wp[1] = btm_h2_header_frames_count[num_encoded_msbc_pkts % 4];
659 encode_buf_wo += BTM_MSBC_PKT_LEN;
660
661 num_encoded_msbc_pkts++;
662 return wp + BTM_MSBC_H2_HEADER_LEN;
663 }
664
mark_pkt_dequeuedbluetooth::audio::sco::wbs::tBTM_MSBC_INFO665 size_t mark_pkt_dequeued() {
666 if (encode_buf_wo - encode_buf_ro < packet_size) {
667 return 0;
668 }
669
670 encode_buf_ro += packet_size;
671 if (encode_buf_ro == encode_buf_wo) {
672 encode_buf_ro = 0;
673 encode_buf_wo = 0;
674 }
675
676 return packet_size;
677 }
678
sco_pkt_read_ptrbluetooth::audio::sco::wbs::tBTM_MSBC_INFO679 const uint8_t* sco_pkt_read_ptr() {
680 if (encode_buf_wo - encode_buf_ro < packet_size) {
681 return nullptr;
682 }
683
684 return &msbc_encode_buf[encode_buf_ro];
685 }
686 };
687
688 static tBTM_MSBC_INFO* msbc_info = nullptr;
689
init(size_t pkt_size)690 size_t init(size_t pkt_size) {
691 GetInterfaceToProfiles()->msbcCodec->initialize();
692
693 if (msbc_info) {
694 log::warn("Re-initiating mSBC buffer that is active or not cleaned");
695 msbc_info->deinit();
696 osi_free(msbc_info);
697 }
698
699 msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info));
700 return msbc_info->init(pkt_size);
701 }
702
cleanup()703 void cleanup() {
704 GetInterfaceToProfiles()->msbcCodec->cleanup();
705
706 if (msbc_info == nullptr) {
707 return;
708 }
709
710 msbc_info->deinit();
711 osi_free_and_reset((void**)&msbc_info);
712 }
713
fill_plc_stats(int * num_decoded_frames,double * packet_loss_ratio)714 bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) {
715 if (msbc_info == NULL || num_decoded_frames == NULL || packet_loss_ratio == NULL) {
716 return false;
717 }
718
719 int decoded_frames = msbc_info->plc->get_num_decoded_frames();
720 int lost_frames = msbc_info->plc->get_num_lost_frames();
721 if (decoded_frames <= 0 || lost_frames < 0 || lost_frames > decoded_frames) {
722 return false;
723 }
724
725 *num_decoded_frames = decoded_frames;
726 *packet_loss_ratio = (double)lost_frames / decoded_frames;
727 return true;
728 }
729
enqueue_packet(const std::vector<uint8_t> & data,bool corrupted)730 bool enqueue_packet(const std::vector<uint8_t>& data, bool corrupted) {
731 if (msbc_info == nullptr) {
732 log::warn("mSBC buffer uninitialized or cleaned");
733 return false;
734 }
735
736 if (data.size() != msbc_info->packet_size) {
737 log::warn(
738 "Ignoring the coming packet with size {} that is inconsistent with the "
739 "HAL reported packet size {}",
740 data.size(), msbc_info->packet_size);
741 return false;
742 }
743
744 msbc_info->read_corrupted |= corrupted;
745 if (msbc_info->write(data) != data.size()) {
746 return false;
747 }
748
749 return true;
750 }
751
decode(const uint8_t ** out_data)752 size_t decode(const uint8_t** out_data) {
753 const uint8_t* frame_head = nullptr;
754
755 if (msbc_info == nullptr) {
756 log::warn("mSBC buffer uninitialized or cleaned");
757 return 0;
758 }
759
760 if (out_data == nullptr) {
761 log::warn("Invalid output pointer");
762 return 0;
763 }
764
765 if (msbc_info->decode_buf_data_len() < BTM_MSBC_PKT_LEN) {
766 return 0;
767 }
768
769 frame_head = msbc_info->find_msbc_pkt_head();
770 if (frame_head == nullptr) {
771 /* Done with parsing the raw bytes just read. If we couldn't find a valid
772 * mSBC frame head, we shall treat the existing BTM_MSBC_PKT_LEN length
773 * of mSBC data as a corrupted packet and conduct the PLC. */
774 goto packet_loss;
775 }
776
777 if (!GetInterfaceToProfiles()->msbcCodec->decodePacket(frame_head, msbc_info->decoded_pcm_buf,
778 sizeof(msbc_info->decoded_pcm_buf))) {
779 goto packet_loss;
780 }
781
782 msbc_info->plc->handle_good_frames(msbc_info->decoded_pcm_buf);
783 msbc_info->pkt_status->update(false);
784 *out_data = (const uint8_t*)msbc_info->decoded_pcm_buf;
785 msbc_info->mark_pkt_decoded();
786 return BTM_MSBC_CODE_SIZE;
787
788 packet_loss:
789 msbc_info->plc->handle_bad_frames(out_data);
790 msbc_info->pkt_status->update(true);
791 msbc_info->mark_pkt_decoded();
792 return BTM_MSBC_CODE_SIZE;
793 }
794
encode(int16_t * data,size_t len)795 size_t encode(int16_t* data, size_t len) {
796 uint8_t* pkt_body = nullptr;
797 uint32_t encoded_size = 0;
798 if (msbc_info == nullptr) {
799 log::warn("mSBC buffer uninitialized or cleaned");
800 return 0;
801 }
802
803 if (data == nullptr) {
804 log::warn("Invalid data to encode");
805 return 0;
806 }
807
808 if (len < BTM_MSBC_CODE_SIZE) {
809 return 0;
810 }
811
812 pkt_body = msbc_info->fill_msbc_pkt_template();
813 if (pkt_body == nullptr) {
814 return 0;
815 }
816
817 encoded_size = GetInterfaceToProfiles()->msbcCodec->encodePacket(data, pkt_body);
818 if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) {
819 log::warn("Encoding invalid packet size: {}", encoded_size);
820 std::copy(&btm_msbc_zero_packet[BTM_MSBC_H2_HEADER_LEN], std::end(btm_msbc_zero_packet),
821 pkt_body);
822 }
823
824 return BTM_MSBC_CODE_SIZE;
825 }
826
dequeue_packet(const uint8_t ** output)827 size_t dequeue_packet(const uint8_t** output) {
828 if (msbc_info == nullptr) {
829 log::warn("mSBC buffer uninitialized or cleaned");
830 return 0;
831 }
832
833 if (output == nullptr) {
834 log::warn("Invalid output pointer");
835 return 0;
836 }
837
838 *output = msbc_info->sco_pkt_read_ptr();
839 if (*output == nullptr) {
840 return 0;
841 }
842
843 return msbc_info->mark_pkt_dequeued();
844 }
845
get_pkt_status()846 tBTM_SCO_PKT_STATUS* get_pkt_status() {
847 if (msbc_info == nullptr) {
848 return nullptr;
849 }
850 return msbc_info->pkt_status;
851 }
852
853 } // namespace wbs
854
855 // TODO(b/269970706): fill `pkt_status` and allow `debug_dump`
856 namespace swb {
857
858 /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits
859 * sequence number 0000, 0011, 1100, 1111. */
860 constexpr uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
861
862 /* Supported SCO packet sizes for LC3. The SWB-LC3 frame parsing
863 * code ties to limited packet size values. Specifically list them out
864 * to check against when setting packet size. The first entry is the default
865 * value as a fallback. */
866 constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 24, 0};
867
868 /* Buffer size should be set to least common multiple of SCO packet size and
869 * BTM_LC3_PKT_LEN for optimizing buffer copy. */
870 constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 120, 0};
871
872 /* Define the structure that contains LC3 data */
873 struct tBTM_LC3_INFO {
874 size_t packet_size; /* SCO LC3 packet size supported by lower layer */
875 size_t buf_size; /* The size of the buffer, determined by the packet_size. */
876
877 uint8_t* packet_buf; /* Temporary buffer to store the data */
878 uint8_t* lc3_decode_buf; /* Buffer to store LC3 packets to decode */
879 size_t decode_buf_wo; /* Write offset of the decode buffer */
880 size_t decode_buf_ro; /* Read offset of the decode buffer */
881
882 /* Within the circular buffer, which can be visualized as having
883 two halves, mirror indicators track the pointer's location,
884 signaling whether it resides in the first or second segment:
885
886 [buf_size-1] ┼ - - -─┼ [0]
887 │ │
888 │ │
889 wo = x, wo_mirror = 0 ^ v ro = x, ro_mirror = 1
890 │ │
891 │ │
892 [0] ┼ - - - ┼ [buf_size-1]
893 (First Half) (Second Half)
894 */
895 bool decode_buf_wo_mirror; /* The mirror indicator specifies whether
896 the write pointer is currently located
897 in the first or second half of the
898 circular buffer */
899 bool decode_buf_ro_mirror; /* The mirror indicator specifies whether
900 the read pointer is currently located
901 in the first or second half of the
902 circular buffer */
903 bool read_corrupted; /* If the current LC3 packet read is corrupted */
904
905 uint8_t* lc3_encode_buf; /* Buffer to store the encoded SCO packets */
906 size_t encode_buf_wo; /* Write offset of the encode buffer */
907 size_t encode_buf_ro; /* Read offset of the encode buffer */
908
909 int16_t decoded_pcm_buf[BTM_LC3_FS]; /* Buffer to store decoded PCM */
910
911 uint8_t num_encoded_lc3_pkts; /* Number of the encoded LC3 packets */
912
913 tBTM_SCO_PKT_STATUS* pkt_status; /* Record of LC3 packet status */
914
get_supported_packet_sizebluetooth::audio::sco::swb::tBTM_LC3_INFO915 static size_t get_supported_packet_size(size_t pkt_size, size_t* buffer_size) {
916 int i;
917 for (i = 0; btm_swb_supported_pkt_size[i] != 0 && btm_swb_supported_pkt_size[i] != pkt_size;
918 i++)
919 ;
920 /* In case of unsupported value, error log and fallback to
921 * BTM_LC3_PKT_LEN(60). */
922 if (btm_swb_supported_pkt_size[i] == 0) {
923 log::warn("Unsupported packet size {}", pkt_size);
924 i = 0;
925 }
926
927 if (buffer_size) {
928 *buffer_size = btm_swb_lc3_buffer_size[i];
929 }
930 return btm_swb_supported_pkt_size[i];
931 }
932
verify_h2_header_seq_numbluetooth::audio::sco::swb::tBTM_LC3_INFO933 bool verify_h2_header_seq_num(const uint8_t num) {
934 for (int i = 0; i < 4; i++) {
935 if (num == btm_h2_header_frames_count[i]) {
936 return true;
937 }
938 }
939 return false;
940 }
941
942 public:
initbluetooth::audio::sco::swb::tBTM_LC3_INFO943 size_t init(size_t pkt_size) {
944 decode_buf_wo = 0;
945 decode_buf_ro = 0;
946 decode_buf_wo_mirror = false;
947 decode_buf_ro_mirror = false;
948
949 encode_buf_wo = 0;
950 encode_buf_ro = 0;
951
952 pkt_size = get_supported_packet_size(pkt_size, &buf_size);
953 if (pkt_size == packet_size) {
954 return packet_size;
955 }
956 packet_size = pkt_size;
957
958 if (!packet_buf) {
959 packet_buf = (uint8_t*)osi_calloc(BTM_LC3_PKT_LEN);
960 }
961
962 if (lc3_decode_buf) {
963 osi_free(lc3_decode_buf);
964 }
965 lc3_decode_buf = (uint8_t*)osi_calloc(buf_size);
966
967 if (lc3_encode_buf) {
968 osi_free(lc3_encode_buf);
969 }
970 lc3_encode_buf = (uint8_t*)osi_calloc(buf_size);
971
972 if (pkt_status) {
973 osi_free(pkt_status);
974 }
975 pkt_status = (tBTM_SCO_PKT_STATUS*)osi_calloc(sizeof(*pkt_status));
976 pkt_status->init();
977
978 return packet_size;
979 }
980
deinitbluetooth::audio::sco::swb::tBTM_LC3_INFO981 void deinit() {
982 if (lc3_decode_buf) {
983 osi_free(lc3_decode_buf);
984 }
985 if (packet_buf) {
986 osi_free(packet_buf);
987 }
988 if (lc3_encode_buf) {
989 osi_free(lc3_encode_buf);
990 }
991 if (pkt_status) {
992 osi_free_and_reset((void**)&pkt_status);
993 }
994 }
995
incr_buf_offsetbluetooth::audio::sco::swb::tBTM_LC3_INFO996 void incr_buf_offset(size_t& offset, bool& mirror, size_t bsize, size_t amount) {
997 if (bsize - offset > amount) {
998 offset += amount;
999 return;
1000 }
1001
1002 mirror = !mirror;
1003 offset = amount - (bsize - offset);
1004 }
1005
decode_buf_statusbluetooth::audio::sco::swb::tBTM_LC3_INFO1006 decode_buf_state decode_buf_status() {
1007 if (decode_buf_ro == decode_buf_wo) {
1008 if (decode_buf_ro_mirror == decode_buf_wo_mirror) {
1009 return DECODE_BUF_EMPTY;
1010 }
1011 return DECODE_BUF_FULL;
1012 }
1013 return DECODE_BUF_HALFFULL;
1014 }
1015
decode_buf_data_lenbluetooth::audio::sco::swb::tBTM_LC3_INFO1016 size_t decode_buf_data_len() {
1017 switch (decode_buf_status()) {
1018 case DECODE_BUF_EMPTY:
1019 return 0;
1020 case DECODE_BUF_FULL:
1021 return buf_size;
1022 case DECODE_BUF_HALFFULL:
1023 default:
1024 if (decode_buf_wo > decode_buf_ro) {
1025 return decode_buf_wo - decode_buf_ro;
1026 }
1027 return buf_size - (decode_buf_ro - decode_buf_wo);
1028 };
1029 }
1030
decode_buf_avail_lenbluetooth::audio::sco::swb::tBTM_LC3_INFO1031 size_t decode_buf_avail_len() { return buf_size - decode_buf_data_len(); }
1032
fill_lc3_pkt_templatebluetooth::audio::sco::swb::tBTM_LC3_INFO1033 uint8_t* fill_lc3_pkt_template() {
1034 uint8_t* wp = &lc3_encode_buf[encode_buf_wo];
1035 if (buf_size - encode_buf_wo < BTM_LC3_PKT_LEN) {
1036 log::debug("Packet queue can't accommodate more packets.");
1037 return nullptr;
1038 }
1039
1040 wp[0] = BTM_LC3_H2_HEADER_0;
1041 wp[1] = btm_h2_header_frames_count[num_encoded_lc3_pkts % 4];
1042 encode_buf_wo += BTM_LC3_PKT_LEN;
1043
1044 num_encoded_lc3_pkts++;
1045 return wp + BTM_LC3_H2_HEADER_LEN;
1046 }
1047
mark_pkt_decodedbluetooth::audio::sco::swb::tBTM_LC3_INFO1048 void mark_pkt_decoded() {
1049 if (decode_buf_data_len() < BTM_LC3_PKT_LEN) {
1050 log::error("Trying to mark read offset beyond write offset.");
1051 return;
1052 }
1053
1054 incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size, BTM_LC3_PKT_LEN);
1055 }
1056
writebluetooth::audio::sco::swb::tBTM_LC3_INFO1057 size_t write(const std::vector<uint8_t>& input) {
1058 if (input.size() > decode_buf_avail_len()) {
1059 log::warn(
1060 "Cannot write input with size {} into decode_buf with {} empty "
1061 "space.",
1062 input.size(), decode_buf_avail_len());
1063 return 0;
1064 }
1065
1066 if (buf_size - decode_buf_wo > input.size()) {
1067 std::copy(input.begin(), input.end(), lc3_decode_buf + decode_buf_wo);
1068 } else {
1069 std::copy(input.begin(), input.begin() + buf_size - decode_buf_wo,
1070 lc3_decode_buf + decode_buf_wo);
1071 std::copy(input.begin() + buf_size - decode_buf_wo, input.end(), lc3_decode_buf);
1072 }
1073
1074 incr_buf_offset(decode_buf_wo, decode_buf_wo_mirror, buf_size, input.size());
1075 return input.size();
1076 }
1077
find_lc3_pkt_headbluetooth::audio::sco::swb::tBTM_LC3_INFO1078 const uint8_t* find_lc3_pkt_head() {
1079 if (read_corrupted) {
1080 read_corrupted = false;
1081 return nullptr;
1082 }
1083
1084 size_t rp = 0;
1085 size_t data_len = decode_buf_data_len();
1086 while (rp < BTM_LC3_PKT_LEN && data_len - rp >= BTM_LC3_PKT_LEN) {
1087 if ((lc3_decode_buf[(decode_buf_ro + rp) % buf_size] != BTM_LC3_H2_HEADER_0) ||
1088 !verify_h2_header_seq_num(lc3_decode_buf[(decode_buf_ro + rp + 1) % buf_size])) {
1089 rp++;
1090 continue;
1091 }
1092
1093 if (rp != 0) {
1094 log::warn("Skipped {} bytes of LC3 data ahead of a valid LC3 frame", rp);
1095 incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size, rp);
1096 }
1097
1098 // Get the frame head.
1099 if (buf_size - decode_buf_ro >= BTM_LC3_PKT_LEN) {
1100 return &lc3_decode_buf[decode_buf_ro];
1101 }
1102
1103 std::copy(lc3_decode_buf + decode_buf_ro, lc3_decode_buf + buf_size, packet_buf);
1104 std::copy(lc3_decode_buf, lc3_decode_buf + BTM_LC3_PKT_LEN - (buf_size - decode_buf_ro),
1105 packet_buf + (buf_size - decode_buf_ro));
1106 return packet_buf;
1107 }
1108
1109 return nullptr;
1110 }
1111
mark_pkt_dequeuedbluetooth::audio::sco::swb::tBTM_LC3_INFO1112 size_t mark_pkt_dequeued() {
1113 if (encode_buf_wo - encode_buf_ro < packet_size) {
1114 return 0;
1115 }
1116
1117 encode_buf_ro += packet_size;
1118 if (encode_buf_ro == encode_buf_wo) {
1119 encode_buf_ro = 0;
1120 encode_buf_wo = 0;
1121 }
1122
1123 return packet_size;
1124 }
1125
sco_pkt_read_ptrbluetooth::audio::sco::swb::tBTM_LC3_INFO1126 const uint8_t* sco_pkt_read_ptr() {
1127 if (encode_buf_wo - encode_buf_ro < packet_size) {
1128 return nullptr;
1129 }
1130
1131 return &lc3_encode_buf[encode_buf_ro];
1132 }
1133 };
1134
1135 static tBTM_LC3_INFO* lc3_info;
1136 static int decoded_frames;
1137 static int lost_frames;
1138
init(size_t pkt_size)1139 size_t init(size_t pkt_size) {
1140 GetInterfaceToProfiles()->lc3Codec->initialize();
1141
1142 decoded_frames = 0;
1143 lost_frames = 0;
1144
1145 if (lc3_info) {
1146 log::warn("Re-initiating LC3 buffer that is active or not cleaned");
1147 lc3_info->deinit();
1148 osi_free(lc3_info);
1149 }
1150
1151 lc3_info = (tBTM_LC3_INFO*)osi_calloc(sizeof(*lc3_info));
1152 return lc3_info->init(pkt_size);
1153 }
1154
cleanup()1155 void cleanup() {
1156 GetInterfaceToProfiles()->lc3Codec->cleanup();
1157
1158 decoded_frames = 0;
1159 lost_frames = 0;
1160
1161 if (lc3_info == nullptr) {
1162 return;
1163 }
1164
1165 lc3_info->deinit();
1166 osi_free_and_reset((void**)&lc3_info);
1167 }
1168
fill_plc_stats(int * num_decoded_frames,double * packet_loss_ratio)1169 bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) {
1170 if (lc3_info == NULL || num_decoded_frames == NULL || packet_loss_ratio == NULL) {
1171 return false;
1172 }
1173
1174 if (decoded_frames <= 0 || lost_frames < 0 || lost_frames > decoded_frames) {
1175 return false;
1176 }
1177
1178 *num_decoded_frames = decoded_frames;
1179 *packet_loss_ratio = (double)lost_frames / decoded_frames;
1180 return true;
1181 }
1182
enqueue_packet(const std::vector<uint8_t> & data,bool corrupted)1183 bool enqueue_packet(const std::vector<uint8_t>& data, bool corrupted) {
1184 if (lc3_info == nullptr) {
1185 log::warn("LC3 buffer uninitialized or cleaned");
1186 return false;
1187 }
1188
1189 if (data.size() != lc3_info->packet_size) {
1190 log::warn(
1191 "Ignoring the coming packet with size {} that is inconsistent with the "
1192 "HAL reported packet size {}",
1193 data.size(), lc3_info->packet_size);
1194 return false;
1195 }
1196
1197 lc3_info->read_corrupted |= corrupted;
1198 if (lc3_info->write(data) != data.size()) {
1199 return false;
1200 }
1201
1202 return true;
1203 }
1204
decode(const uint8_t ** out_data)1205 size_t decode(const uint8_t** out_data) {
1206 const uint8_t* frame_head = nullptr;
1207
1208 if (lc3_info == nullptr) {
1209 log::warn("LC3 buffer uninitialized or cleaned");
1210 return 0;
1211 }
1212
1213 if (out_data == nullptr) {
1214 log::warn("Invalid output pointer");
1215 return 0;
1216 }
1217
1218 if (lc3_info->decode_buf_data_len() < BTM_LC3_PKT_LEN) {
1219 return 0;
1220 }
1221
1222 frame_head = lc3_info->find_lc3_pkt_head();
1223
1224 bool plc_conducted = !GetInterfaceToProfiles()->lc3Codec->decodePacket(
1225 frame_head, lc3_info->decoded_pcm_buf, sizeof(lc3_info->decoded_pcm_buf));
1226
1227 lc3_info->pkt_status->update(plc_conducted);
1228
1229 ++decoded_frames;
1230 lost_frames += plc_conducted;
1231
1232 *out_data = (const uint8_t*)lc3_info->decoded_pcm_buf;
1233 lc3_info->mark_pkt_decoded();
1234
1235 return BTM_LC3_CODE_SIZE;
1236 }
1237
encode(int16_t * data,size_t len)1238 size_t encode(int16_t* data, size_t len) {
1239 uint8_t* pkt_body = nullptr;
1240 if (lc3_info == nullptr) {
1241 log::warn("LC3 buffer uninitialized or cleaned");
1242 return 0;
1243 }
1244
1245 if (data == nullptr) {
1246 log::warn("Invalid data to encode");
1247 return 0;
1248 }
1249
1250 if (len < BTM_LC3_CODE_SIZE) {
1251 return 0;
1252 }
1253
1254 pkt_body = lc3_info->fill_lc3_pkt_template();
1255 if (pkt_body == nullptr) {
1256 return 0;
1257 }
1258
1259 return GetInterfaceToProfiles()->lc3Codec->encodePacket(data, pkt_body);
1260 }
1261
dequeue_packet(const uint8_t ** output)1262 size_t dequeue_packet(const uint8_t** output) {
1263 if (lc3_info == nullptr) {
1264 log::warn("LC3 buffer uninitialized or cleaned");
1265 return 0;
1266 }
1267
1268 if (output == nullptr) {
1269 log::warn("Invalid output pointer");
1270 return 0;
1271 }
1272
1273 *output = lc3_info->sco_pkt_read_ptr();
1274 if (*output == nullptr) {
1275 return 0;
1276 }
1277
1278 return lc3_info->mark_pkt_dequeued();
1279 }
1280
get_pkt_status()1281 tBTM_SCO_PKT_STATUS* get_pkt_status() {
1282 if (lc3_info == nullptr) {
1283 return nullptr;
1284 }
1285 return lc3_info->pkt_status;
1286 }
1287 } // namespace swb
1288
1289 } // namespace sco
1290 } // namespace audio
1291 } // namespace bluetooth
1292