• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <errno.h>
18 #include <grp.h>
19 #include <math.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 
23 #include <cfloat>
24 #include <memory>
25 
26 // Define before including log.h
27 #define LOG_TAG "sco_hci"
28 
29 #include "btif/include/core_callbacks.h"
30 #include "btif/include/stack_manager.h"
31 #include "osi/include/allocator.h"
32 #include "osi/include/log.h"
33 #include "stack/btm/btm_sco.h"
34 #include "udrv/include/uipc.h"
35 
36 #define SCO_DATA_READ_POLL_MS 10
37 #define SCO_HOST_DATA_PATH "/var/run/bluetooth/audio/.sco_data"
38 // TODO(b/198260375): Make SCO data owner group configurable.
39 #define SCO_HOST_DATA_GROUP "bluetooth-audio"
40 
41 /* Per Bluetooth Core v5.0 and HFP 1.7 specification. */
42 #define BTM_MSBC_H2_HEADER_0 0x01
43 #define BTM_MSBC_H2_HEADER_LEN 2
44 #define BTM_MSBC_PKT_LEN 60
45 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */
46 #define BTM_MSBC_SYNC_WORD 0xAD
47 
48 /* Used by PLC */
49 #define BTM_MSBC_SAMPLE_SIZE 2 /* 2 bytes*/
50 #define BTM_MSBC_FS 120        /* Frame Size */
51 
52 #define BTM_PLC_WL 256 /* 16ms - Window Length for pattern matching */
53 #define BTM_PLC_TL 64  /* 4ms - Template Length for matching */
54 #define BTM_PLC_HL \
55   (BTM_PLC_WL + BTM_MSBC_FS - 1) /* Length of History buffer required */
56 #define BTM_PLC_SBCRL 36         /* SBC Reconvergence sample Length */
57 #define BTM_PLC_OLAL 16          /* OverLap-Add Length */
58 
59 /* Disable the PLC when there are more than threshold of lost packets in the
60  * window */
61 #define BTM_PLC_WINDOW_SIZE 5
62 #define BTM_PLC_PL_THRESHOLD 1
63 
64 namespace {
65 
66 std::unique_ptr<tUIPC_STATE> sco_uipc = nullptr;
67 
sco_data_cb(tUIPC_CH_ID,tUIPC_EVENT event)68 void sco_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
69   switch (event) {
70     case UIPC_OPEN_EVT:
71       /*
72        * Read directly from media task from here on (keep callback for
73        * connection events.
74        */
75       UIPC_Ioctl(*sco_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET,
76                  NULL);
77       UIPC_Ioctl(*sco_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
78                  reinterpret_cast<void*>(SCO_DATA_READ_POLL_MS));
79       break;
80     default:
81       break;
82   }
83 }
84 
85 }  // namespace
86 
87 namespace bluetooth {
88 namespace audio {
89 namespace sco {
90 
open()91 void open() {
92   if (sco_uipc != nullptr) {
93     LOG_WARN("Re-opening UIPC that is already running");
94   }
95 
96   sco_uipc = UIPC_Init();
97   if (sco_uipc == nullptr) {
98     LOG_ERROR("%s failed to init UIPC", __func__);
99     return;
100   }
101 
102   UIPC_Open(*sco_uipc, UIPC_CH_ID_AV_AUDIO, sco_data_cb, SCO_HOST_DATA_PATH);
103   struct group* grp = getgrnam(SCO_HOST_DATA_GROUP);
104   chmod(SCO_HOST_DATA_PATH, 0770);
105   if (grp) {
106     int res = chown(SCO_HOST_DATA_PATH, -1, grp->gr_gid);
107     if (res == -1) {
108       LOG_ERROR("%s failed: %s", __func__, strerror(errno));
109     }
110   }
111 }
112 
cleanup()113 void cleanup() {
114   if (sco_uipc == nullptr) {
115     return;
116   }
117   UIPC_Close(*sco_uipc, UIPC_CH_ID_ALL);
118   sco_uipc = nullptr;
119 }
120 
read(uint8_t * p_buf,uint32_t len)121 size_t read(uint8_t* p_buf, uint32_t len) {
122   if (sco_uipc == nullptr) {
123     LOG_WARN("Read from uninitialized or closed UIPC");
124     return 0;
125   }
126   return UIPC_Read(*sco_uipc, UIPC_CH_ID_AV_AUDIO, p_buf, len);
127 }
128 
write(const uint8_t * p_buf,uint32_t len)129 size_t write(const uint8_t* p_buf, uint32_t len) {
130   if (sco_uipc == nullptr) {
131     LOG_WARN("Write to uninitialized or closed UIPC");
132     return 0;
133   }
134   return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0;
135 }
136 
137 namespace wbs {
138 
139 /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits
140  * sequence number 0000, 0011, 1100, 1111. */
141 static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
142 
143 /* Supported SCO packet sizes for mSBC. The wideband speech mSBC frame parsing
144  * code ties to limited packet size values. Specifically list them out
145  * to check against when setting packet size. The first entry is the default
146  * value as a fallback. */
147 constexpr size_t btm_wbs_supported_pkt_size[] = {BTM_MSBC_PKT_LEN, 72, 0};
148 /* Buffer size should be set to least common multiple of SCO packet size and
149  * BTM_MSBC_PKT_LEN for optimizing buffer copy. */
150 constexpr size_t btm_wbs_msbc_buffer_size[] = {BTM_MSBC_PKT_LEN, 360, 0};
151 
152 /* The pre-computed SCO packet per HFP 1.7 spec. This mSBC packet will be
153  * decoded into all-zero input PCM. */
154 static const uint8_t btm_msbc_zero_packet[] = {
155     0x01, 0x08, /* Mock H2 header */
156     0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd,
157     0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6,
158     0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
159     0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
160     0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c,
161     /* End of Audio Samples */
162     0x00 /* A padding byte defined by mSBC */};
163 
164 /* Raised Cosine table for OLA */
165 static const float rcos[BTM_PLC_OLAL] = {
166     0.99148655f, 0.96623611f, 0.92510857f, 0.86950446f,
167     0.80131732f, 0.72286918f, 0.63683150f, 0.54613418f,
168     0.45386582f, 0.36316850f, 0.27713082f, 0.19868268f,
169     0.13049554f, 0.07489143f, 0.03376389f, 0.00851345f};
170 
f_to_s16(float input)171 static int16_t f_to_s16(float input) {
172   return input > INT16_MAX   ? INT16_MAX
173          : input < INT16_MIN ? INT16_MIN
174                              : (int16_t)input;
175 }
176 /* This structure tracks the packet loss for last PLC_WINDOW_SIZE of packets */
177 struct tBTM_MSBC_BTM_PLC_WINDOW {
178   bool loss_hist[BTM_PLC_WINDOW_SIZE]; /* The packet loss history of receiving
179                                       packets.*/
180   unsigned int idx;   /* The index of the to be updated packet loss status. */
181   unsigned int count; /* The count of lost packets in the window. */
182 
183  public:
update_plc_statebluetooth::audio::sco::wbs::tBTM_MSBC_BTM_PLC_WINDOW184   void update_plc_state(bool is_packet_loss) {
185     bool* curr = &loss_hist[idx];
186     if (is_packet_loss != *curr) {
187       count += (is_packet_loss - *curr);
188       *curr = is_packet_loss;
189     }
190     idx = (idx + 1) % BTM_PLC_WINDOW_SIZE;
191   }
192 
is_packet_loss_too_highbluetooth::audio::sco::wbs::tBTM_MSBC_BTM_PLC_WINDOW193   bool is_packet_loss_too_high() {
194     /* The packet loss count comes from a time window and we use it as an
195      * indicator of our confidence of the PLC algorithm. It is known to
196      * generate poorer and robotic feeling sounds, when the majority of
197      * samples in the PLC history buffer are from the concealment results.
198      */
199     return count > BTM_PLC_PL_THRESHOLD;
200   }
201 };
202 
203 /* The PLC is specifically designed for mSBC. The algorithm searches the
204  * history of receiving samples to find the best match samples and constructs
205  * substitutions for the lost samples. The selection is based on pattern
206  * matching a template, composed of a length of samples preceding to the lost
207  * samples. It then uses the following samples after the best match as the
208  * replacement samples and applies Overlap-Add to reduce the audible
209  * distortion.
210  *
211  * This structure holds related info needed to conduct the PLC algorithm.
212  */
213 struct tBTM_MSBC_PLC {
214   int16_t hist[BTM_PLC_HL + BTM_MSBC_FS + BTM_PLC_SBCRL +
215                BTM_PLC_OLAL]; /* The history buffer for receiving samples, we
216                                  also use it to buffer the processed
217                                  replacement samples */
218   unsigned best_lag;      /* The index of the best substitution samples in the
219                              sample history */
220   int handled_bad_frames; /* Number of bad frames handled since the last good
221                              frame */
222   int16_t decoded_buffer[BTM_MSBC_FS]; /* Used for storing the samples from
223                                       decoding the mSBC zero frame packet and
224                                       also constructed frames */
225   tBTM_MSBC_BTM_PLC_WINDOW*
226       pl_window; /* Used to monitor how many packets are bad within the recent
227                     BTM_PLC_WINDOW_SIZE of packets. We use this to determine if
228                     we want to disable the PLC temporarily */
229 
230   int num_decoded_frames; /* Number of total read mSBC frames. */
231   int num_lost_frames;    /* Number of total lost mSBC frames. */
232 
overlap_addbluetooth::audio::sco::wbs::tBTM_MSBC_PLC233   void overlap_add(int16_t* output, float scaler_d, const int16_t* desc,
234                    float scaler_a, const int16_t* asc) {
235     for (int i = 0; i < BTM_PLC_OLAL; i++) {
236       output[i] = f_to_s16(scaler_d * desc[i] * rcos[i] +
237                            scaler_a * asc[i] * rcos[BTM_PLC_OLAL - 1 - i]);
238     }
239   }
240 
cross_correlationbluetooth::audio::sco::wbs::tBTM_MSBC_PLC241   float cross_correlation(int16_t* x, int16_t* y) {
242     float sum = 0, x2 = 0, y2 = 0;
243 
244     for (int i = 0; i < BTM_PLC_TL; i++) {
245       sum += ((float)x[i]) * y[i];
246       x2 += ((float)x[i]) * x[i];
247       y2 += ((float)y[i]) * y[i];
248     }
249     return sum / sqrtf(x2 * y2);
250   }
251 
pattern_matchbluetooth::audio::sco::wbs::tBTM_MSBC_PLC252   int pattern_match(int16_t* hist) {
253     int best = 0;
254     float cn, max_cn = FLT_MIN;
255 
256     for (int i = 0; i < BTM_PLC_WL; i++) {
257       cn = cross_correlation(&hist[BTM_PLC_HL - BTM_PLC_TL], &hist[i]);
258       if (cn > max_cn) {
259         best = i;
260         max_cn = cn;
261       }
262     }
263     return best;
264   }
265 
amplitude_matchbluetooth::audio::sco::wbs::tBTM_MSBC_PLC266   float amplitude_match(int16_t* x, int16_t* y) {
267     uint32_t sum_x = 0, sum_y = 0;
268     float scaler;
269     for (int i = 0; i < BTM_MSBC_FS; i++) {
270       sum_x += abs(x[i]);
271       sum_y += abs(y[i]);
272     }
273 
274     if (sum_y == 0) return 1.2f;
275 
276     scaler = (float)sum_x / sum_y;
277     return scaler > 1.2f ? 1.2f : scaler < 0.75f ? 0.75f : scaler;
278   }
279 
280  public:
initbluetooth::audio::sco::wbs::tBTM_MSBC_PLC281   void init() {
282     if (pl_window) osi_free(pl_window);
283     pl_window = (tBTM_MSBC_BTM_PLC_WINDOW*)osi_calloc(sizeof(*pl_window));
284   }
285 
deinitbluetooth::audio::sco::wbs::tBTM_MSBC_PLC286   void deinit() {
287     if (pl_window) osi_free_and_reset((void**)&pl_window);
288   }
289 
get_num_decoded_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC290   int get_num_decoded_frames() { return num_decoded_frames; }
291 
get_num_lost_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC292   int get_num_lost_frames() { return num_lost_frames; }
293 
handle_bad_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC294   void handle_bad_frames(const uint8_t** output) {
295     float scaler;
296     int16_t* best_match_hist;
297     int16_t* frame_head = &hist[BTM_PLC_HL];
298 
299     num_decoded_frames++;
300     num_lost_frames++;
301 
302     /* mSBC codec is stateful, the history of signal would contribute to the
303      * decode result decoded_buffer. This should never fail. */
304     GetInterfaceToProfiles()->msbcCodec->decodePacket(
305         btm_msbc_zero_packet, decoded_buffer, sizeof(decoded_buffer));
306 
307     /* The PLC algorithm is more likely to generate bad results that sound
308      * robotic after severe packet losses happened. Only applying it when
309      * we are confident. */
310     if (!pl_window->is_packet_loss_too_high()) {
311       if (handled_bad_frames == 0) {
312         /* Finds the best matching samples and amplitude */
313         best_lag = pattern_match(hist) + BTM_PLC_TL;
314         best_match_hist = &hist[best_lag];
315         scaler =
316             amplitude_match(&hist[BTM_PLC_HL - BTM_MSBC_FS], best_match_hist);
317 
318         /* Constructs the substitution samples */
319         overlap_add(frame_head, 1.0, decoded_buffer, scaler, best_match_hist);
320         for (int i = BTM_PLC_OLAL; i < BTM_MSBC_FS; i++)
321           hist[BTM_PLC_HL + i] = f_to_s16(scaler * best_match_hist[i]);
322         overlap_add(&frame_head[BTM_MSBC_FS], scaler,
323                     &best_match_hist[BTM_MSBC_FS], 1.0,
324                     &best_match_hist[BTM_MSBC_FS]);
325 
326         memmove(&frame_head[BTM_MSBC_FS + BTM_PLC_OLAL],
327                 &best_match_hist[BTM_MSBC_FS + BTM_PLC_OLAL],
328                 BTM_PLC_SBCRL * BTM_MSBC_SAMPLE_SIZE);
329       } else {
330         /* Using the existing best lag and copy the following frames */
331         memmove(frame_head, &hist[best_lag],
332                 (BTM_MSBC_FS + BTM_PLC_SBCRL + BTM_PLC_OLAL) *
333                     BTM_MSBC_SAMPLE_SIZE);
334       }
335       /* Copy the constructed frames to decoded buffer for caller to use */
336       std::copy(frame_head, &frame_head[BTM_MSBC_FS], decoded_buffer);
337 
338       handled_bad_frames++;
339     } else {
340       /* This is a case similar to receiving a good frame with all zeros, we set
341        * handled_bad_frames to zero to prevent the following good frame from
342        * being concealed to reconverge with the zero frames we fill in. The
343        * concealment result sounds more artificial and weird than simply writing
344        * zeros and following samples.
345        */
346       std::copy(std::begin(decoded_buffer), std::end(decoded_buffer),
347                 frame_head);
348       std::fill(&frame_head[BTM_MSBC_FS],
349                 &frame_head[BTM_MSBC_FS + BTM_PLC_SBCRL + BTM_PLC_OLAL], 0);
350       /* No need to copy the frames as we'll use the decoded zero frames in the
351        * decoded buffer as our concealment frames */
352 
353       handled_bad_frames = 0;
354     }
355 
356     *output = (const uint8_t*)decoded_buffer;
357 
358     /* Shift the frames to update the history window */
359     memmove(hist, &hist[BTM_MSBC_FS],
360             (BTM_PLC_HL + BTM_PLC_SBCRL + BTM_PLC_OLAL) * BTM_MSBC_SAMPLE_SIZE);
361     pl_window->update_plc_state(1);
362   }
363 
handle_good_framesbluetooth::audio::sco::wbs::tBTM_MSBC_PLC364   void handle_good_frames(int16_t* input) {
365     int16_t* frame_head;
366     num_decoded_frames++;
367     if (handled_bad_frames != 0) {
368       /* If there was a packet concealment before this good frame, we need to
369        * reconverge the input frames */
370       frame_head = &hist[BTM_PLC_HL];
371 
372       /* For the first good frame after packet loss, we need to conceal the
373        * received samples to have it reconverge with the true output */
374       std::copy(frame_head, &frame_head[BTM_PLC_SBCRL], input);
375       /* Overlap the input frame with the previous output frame */
376       overlap_add(&input[BTM_PLC_SBCRL], 1.0, &frame_head[BTM_PLC_SBCRL], 1.0,
377                   &input[BTM_PLC_SBCRL]);
378       handled_bad_frames = 0;
379     }
380 
381     /* Shift the history and update the good frame to the end of it */
382     memmove(hist, &hist[BTM_MSBC_FS],
383             (BTM_PLC_HL - BTM_MSBC_FS) * BTM_MSBC_SAMPLE_SIZE);
384     std::copy(input, &input[BTM_MSBC_FS], &hist[BTM_PLC_HL - BTM_MSBC_FS]);
385     pl_window->update_plc_state(0);
386   }
387 };
388 
389 /* Define the structure that contains mSBC data */
390 struct tBTM_MSBC_INFO {
391   size_t packet_size; /* SCO mSBC packet size supported by lower layer */
392   size_t buf_size; /* The size of the buffer, determined by the packet_size. */
393 
394   uint8_t* msbc_decode_buf; /* Buffer to store mSBC packets to decode */
395   size_t decode_buf_wo;     /* Write offset of the decode buffer */
396   size_t decode_buf_ro;     /* Read offset of the decode buffer */
397   bool read_corrupted;      /* If the current mSBC packet read is corrupted */
398 
399   uint8_t* msbc_encode_buf; /* Buffer to store the encoded SCO packets */
400   size_t encode_buf_wo;     /* Write offset of the encode buffer */
401   size_t encode_buf_ro;     /* Read offset of the encode buffer */
402 
403   int16_t decoded_pcm_buf[BTM_MSBC_FS]; /* Buffer to store decoded PCM */
404 
405   uint8_t num_encoded_msbc_pkts; /* Number of the encoded mSBC packets */
406 
407   tBTM_MSBC_PLC* plc; /* PLC component to handle the packet loss of input */
get_supported_packet_sizebluetooth::audio::sco::wbs::tBTM_MSBC_INFO408   static size_t get_supported_packet_size(size_t pkt_size,
409                                           size_t* buffer_size) {
410     int i;
411     for (i = 0; btm_wbs_supported_pkt_size[i] != 0 &&
412                 btm_wbs_supported_pkt_size[i] != pkt_size;
413          i++)
414       ;
415     /* In case of unsupported value, error log and fallback to
416      * BTM_MSBC_PKT_LEN(60). */
417     if (btm_wbs_supported_pkt_size[i] == 0) {
418       LOG_WARN("Unsupported packet size %lu", (unsigned long)pkt_size);
419       i = 0;
420     }
421 
422     if (buffer_size) {
423       *buffer_size = btm_wbs_msbc_buffer_size[i];
424     }
425     return btm_wbs_supported_pkt_size[i];
426   }
427 
verify_h2_header_seq_numbluetooth::audio::sco::wbs::tBTM_MSBC_INFO428   bool verify_h2_header_seq_num(const uint8_t num) {
429     for (int i = 0; i < 4; i++) {
430       if (num == btm_h2_header_frames_count[i]) {
431         return true;
432       }
433     }
434     return false;
435   }
436 
437  public:
initbluetooth::audio::sco::wbs::tBTM_MSBC_INFO438   size_t init(size_t pkt_size) {
439     decode_buf_wo = 0;
440     decode_buf_ro = 0;
441     encode_buf_wo = 0;
442     encode_buf_ro = 0;
443 
444     pkt_size = get_supported_packet_size(pkt_size, &buf_size);
445     if (pkt_size == packet_size) return packet_size;
446     packet_size = pkt_size;
447 
448     if (msbc_decode_buf) osi_free(msbc_decode_buf);
449     msbc_decode_buf = (uint8_t*)osi_calloc(buf_size);
450 
451     if (msbc_encode_buf) osi_free(msbc_encode_buf);
452     msbc_encode_buf = (uint8_t*)osi_calloc(buf_size);
453 
454     if (plc) {
455       plc->deinit();
456       osi_free(plc);
457     }
458     plc = (tBTM_MSBC_PLC*)osi_calloc(sizeof(*plc));
459     plc->init();
460     return packet_size;
461   }
462 
deinitbluetooth::audio::sco::wbs::tBTM_MSBC_INFO463   void deinit() {
464     if (msbc_decode_buf) osi_free(msbc_decode_buf);
465     if (msbc_encode_buf) osi_free(msbc_encode_buf);
466     if (plc) {
467       plc->deinit();
468       osi_free_and_reset((void**)&plc);
469     }
470   }
471 
decodablebluetooth::audio::sco::wbs::tBTM_MSBC_INFO472   size_t decodable() { return decode_buf_wo - decode_buf_ro; }
473 
mark_pkt_decodedbluetooth::audio::sco::wbs::tBTM_MSBC_INFO474   void mark_pkt_decoded() {
475     if (decode_buf_ro + BTM_MSBC_PKT_LEN > decode_buf_wo) {
476       LOG_ERROR("Trying to mark read offset beyond write offset.");
477       return;
478     }
479 
480     decode_buf_ro += BTM_MSBC_PKT_LEN;
481     if (decode_buf_ro == decode_buf_wo) {
482       decode_buf_ro = 0;
483       decode_buf_wo = 0;
484     }
485   }
486 
writebluetooth::audio::sco::wbs::tBTM_MSBC_INFO487   size_t write(const uint8_t* input, size_t len) {
488     if (len > buf_size - decode_buf_wo) {
489       return 0;
490     }
491 
492     std::copy(input, input + len, msbc_decode_buf + decode_buf_wo);
493     decode_buf_wo += len;
494     return len;
495   }
496 
find_msbc_pkt_headbluetooth::audio::sco::wbs::tBTM_MSBC_INFO497   const uint8_t* find_msbc_pkt_head() {
498     if (read_corrupted) {
499       LOG_DEBUG("Skip corrupted mSBC packets");
500       read_corrupted = false;
501       return nullptr;
502     }
503 
504     size_t rp = 0;
505     while (rp < BTM_MSBC_PKT_LEN &&
506            decode_buf_wo - (decode_buf_ro + rp) >= BTM_MSBC_PKT_LEN) {
507       if ((msbc_decode_buf[decode_buf_ro + rp] != BTM_MSBC_H2_HEADER_0) ||
508           (!verify_h2_header_seq_num(
509               msbc_decode_buf[decode_buf_ro + rp + 1])) ||
510           (msbc_decode_buf[decode_buf_ro + rp + 2] != BTM_MSBC_SYNC_WORD)) {
511         rp++;
512         continue;
513       }
514 
515       if (rp != 0) {
516         LOG_WARN("Skipped %lu bytes of mSBC data ahead of a valid mSBC frame",
517                  (unsigned long)rp);
518         decode_buf_ro += rp;
519       }
520       return &msbc_decode_buf[decode_buf_ro];
521     }
522 
523     return nullptr;
524   }
525 
526   /* Fill in the mSBC header and update the buffer's write offset to guard the
527    * buffer space to be written. Return a pointer to the start of mSBC packet's
528    * body for the caller to fill the encoded mSBC data if there is enough space
529    * in the buffer to fill in a new packet, otherwise return a nullptr. */
fill_msbc_pkt_templatebluetooth::audio::sco::wbs::tBTM_MSBC_INFO530   uint8_t* fill_msbc_pkt_template() {
531     uint8_t* wp = &msbc_encode_buf[encode_buf_wo];
532     if (buf_size - encode_buf_wo < BTM_MSBC_PKT_LEN) {
533       LOG_DEBUG("Packet queue can't accommodate more packets.");
534       return nullptr;
535     }
536 
537     wp[0] = BTM_MSBC_H2_HEADER_0;
538     wp[1] = btm_h2_header_frames_count[num_encoded_msbc_pkts % 4];
539     encode_buf_wo += BTM_MSBC_PKT_LEN;
540 
541     num_encoded_msbc_pkts++;
542     return wp + BTM_MSBC_H2_HEADER_LEN;
543   }
544 
mark_pkt_dequeuedbluetooth::audio::sco::wbs::tBTM_MSBC_INFO545   size_t mark_pkt_dequeued() {
546     LOG_DEBUG(
547         "Try to mark an encoded packet dequeued: ro:%lu wo:%lu pkt_size:%lu",
548         (unsigned long)encode_buf_ro, (unsigned long)encode_buf_wo,
549         (unsigned long)packet_size);
550 
551     if (encode_buf_wo - encode_buf_ro < packet_size) return 0;
552 
553     encode_buf_ro += packet_size;
554     if (encode_buf_ro == encode_buf_wo) {
555       encode_buf_ro = 0;
556       encode_buf_wo = 0;
557     }
558 
559     return packet_size;
560   }
561 
sco_pkt_read_ptrbluetooth::audio::sco::wbs::tBTM_MSBC_INFO562   const uint8_t* sco_pkt_read_ptr() {
563     if (encode_buf_wo - encode_buf_ro < packet_size) {
564       LOG_DEBUG("Insufficient data as a SCO packet to read.");
565       return nullptr;
566     }
567 
568     return &msbc_encode_buf[encode_buf_ro];
569   }
570 };
571 
572 static tBTM_MSBC_INFO* msbc_info = nullptr;
573 
init(size_t pkt_size)574 size_t init(size_t pkt_size) {
575   GetInterfaceToProfiles()->msbcCodec->initialize();
576 
577   if (msbc_info) {
578     LOG_WARN("Re-initiating mSBC buffer that is active or not cleaned");
579     msbc_info->deinit();
580     osi_free(msbc_info);
581   }
582 
583   msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info));
584   return msbc_info->init(pkt_size);
585 }
586 
cleanup()587 void cleanup() {
588   GetInterfaceToProfiles()->msbcCodec->cleanup();
589 
590   if (msbc_info == nullptr) return;
591 
592   msbc_info->deinit();
593   osi_free_and_reset((void**)&msbc_info);
594 }
595 
fill_plc_stats(int * num_decoded_frames,double * packet_loss_ratio)596 bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) {
597   if (msbc_info == NULL || num_decoded_frames == NULL ||
598       packet_loss_ratio == NULL)
599     return false;
600 
601   int decoded_frames = msbc_info->plc->get_num_decoded_frames();
602   int lost_frames = msbc_info->plc->get_num_lost_frames();
603   if (decoded_frames <= 0 || lost_frames < 0 || lost_frames > decoded_frames)
604     return false;
605 
606   *num_decoded_frames = decoded_frames;
607   *packet_loss_ratio = (double)lost_frames / decoded_frames;
608   return true;
609 }
610 
enqueue_packet(const uint8_t * data,size_t pkt_size,bool corrupted)611 size_t enqueue_packet(const uint8_t* data, size_t pkt_size, bool corrupted) {
612   if (msbc_info == nullptr) {
613     LOG_WARN("mSBC buffer uninitialized or cleaned");
614     return 0;
615   }
616 
617   if (pkt_size != msbc_info->packet_size) {
618     LOG_WARN(
619         "Ignoring the coming packet with size %lu that is inconsistent with "
620         "the HAL reported packet size %lu",
621         (unsigned long)pkt_size, (unsigned long)msbc_info->packet_size);
622     return 0;
623   }
624 
625   if (data == nullptr) {
626     LOG_WARN("Invalid data to enqueue");
627     return 0;
628   }
629 
630   msbc_info->read_corrupted |= corrupted;
631   if (msbc_info->write(data, pkt_size) != pkt_size) {
632     LOG_DEBUG("Fail to write packet with size %lu to buffer",
633               (unsigned long)pkt_size);
634     return 0;
635   }
636 
637   return pkt_size;
638 }
639 
decode(const uint8_t ** out_data)640 size_t decode(const uint8_t** out_data) {
641   const uint8_t* frame_head = nullptr;
642 
643   if (msbc_info == nullptr) {
644     LOG_WARN("mSBC buffer uninitialized or cleaned");
645     return 0;
646   }
647 
648   if (out_data == nullptr) {
649     LOG_WARN("%s Invalid output pointer", __func__);
650     return 0;
651   }
652 
653   if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) {
654     LOG_DEBUG("No complete mSBC packet to decode");
655     return 0;
656   }
657 
658   frame_head = msbc_info->find_msbc_pkt_head();
659   if (frame_head == nullptr) {
660     LOG_DEBUG("No valid mSBC packet to decode %lu, %lu",
661               (unsigned long)msbc_info->decode_buf_ro,
662               (unsigned long)msbc_info->decode_buf_wo);
663     /* Done with parsing the raw bytes just read. If we couldn't find a valid
664      * mSBC frame head, we shall treat the existing BTM_MSBC_PKT_LEN length
665      * of mSBC data as a corrupted packet and conduct the PLC. */
666     goto packet_loss;
667   }
668 
669   if (!GetInterfaceToProfiles()->msbcCodec->decodePacket(
670           frame_head, msbc_info->decoded_pcm_buf,
671           sizeof(msbc_info->decoded_pcm_buf))) {
672     LOG_DEBUG("Decoding mSBC packet failed");
673     goto packet_loss;
674   }
675 
676   msbc_info->plc->handle_good_frames(msbc_info->decoded_pcm_buf);
677   *out_data = (const uint8_t*)msbc_info->decoded_pcm_buf;
678   msbc_info->mark_pkt_decoded();
679   return BTM_MSBC_CODE_SIZE;
680 
681 packet_loss:
682   msbc_info->plc->handle_bad_frames(out_data);
683   msbc_info->mark_pkt_decoded();
684   return BTM_MSBC_CODE_SIZE;
685 }
686 
encode(int16_t * data,size_t len)687 size_t encode(int16_t* data, size_t len) {
688   uint8_t* pkt_body = nullptr;
689   uint32_t encoded_size = 0;
690   if (msbc_info == nullptr) {
691     LOG_WARN("mSBC buffer uninitialized or cleaned");
692     return 0;
693   }
694 
695   if (data == nullptr) {
696     LOG_WARN("Invalid data to encode");
697     return 0;
698   }
699 
700   if (len < BTM_MSBC_CODE_SIZE) {
701     LOG_DEBUG(
702         "PCM frames with size %lu is insufficient to be encoded into a mSBC "
703         "packet",
704         (unsigned long)len);
705     return 0;
706   }
707 
708   pkt_body = msbc_info->fill_msbc_pkt_template();
709   if (pkt_body == nullptr) {
710     LOG_DEBUG("Failed to fill the template to fill the mSBC packet");
711     return 0;
712   }
713 
714   encoded_size =
715       GetInterfaceToProfiles()->msbcCodec->encodePacket(data, pkt_body);
716   if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) {
717     LOG_WARN("Encoding invalid packet size: %lu", (unsigned long)encoded_size);
718     std::copy(&btm_msbc_zero_packet[BTM_MSBC_H2_HEADER_LEN],
719               std::end(btm_msbc_zero_packet), pkt_body);
720   }
721 
722   return BTM_MSBC_CODE_SIZE;
723 }
724 
dequeue_packet(const uint8_t ** output)725 size_t dequeue_packet(const uint8_t** output) {
726   if (msbc_info == nullptr) {
727     LOG_WARN("mSBC buffer uninitialized or cleaned");
728     return 0;
729   }
730 
731   if (output == nullptr) {
732     LOG_WARN("%s Invalid output pointer", __func__);
733     return 0;
734   }
735 
736   *output = msbc_info->sco_pkt_read_ptr();
737   if (*output == nullptr) {
738     LOG_DEBUG("Insufficient data to dequeue.");
739     return 0;
740   }
741 
742   return msbc_info->mark_pkt_dequeued();
743 }
744 
745 }  // namespace wbs
746 
747 }  // namespace sco
748 }  // namespace audio
749 }  // namespace bluetooth
750