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