Loading system/stack/btm/btm_sco.cc +39 −95 Original line number Diff line number Diff line Loading @@ -33,8 +33,6 @@ #include "device/include/controller.h" #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" #include "hfp_msbc_decoder.h" #include "hfp_msbc_encoder.h" #include "osi/include/allocator.h" #include "osi/include/log.h" #include "osi/include/osi.h" Loading Loading @@ -94,30 +92,6 @@ static int16_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; * They are only used for WBS and the unit is byte. */ static size_t btm_pcm_buf_read_offset = 0; static size_t btm_pcm_buf_write_offset = 0; /* Per Bluetooth Core v5.0 and HFP 1.7 specification. */ #define BTM_MSBC_H2_HEADER_0 0x01 #define BTM_MSBC_H2_HEADER_LEN 2 #define BTM_MSBC_PKT_LEN 60 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */ #define BTM_MSBC_CODE_SIZE 240 /* The pre-computed zero input bit stream of mSBC codec, per HFP 1.7 spec. * This mSBC frame will be decoded into all-zero input PCM. */ static const uint8_t btm_msbc_zero_packet[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c}; static const uint8_t btm_msbc_zero_frames[BTM_MSBC_CODE_SIZE] = {0}; /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits * sequence number 0000, 0011, 1100, 1111. */ static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; static uint8_t btm_msbc_num_out_frames; /******************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /******************************************************************************/ Loading Loading @@ -210,15 +184,6 @@ static tSCO_CONN* btm_get_active_sco() { return nullptr; } static bool verify_h2_header_seq_num(const uint8_t num) { for (int i = 0; i < 4; i++) { if (num == btm_h2_header_frames_count[i]) { return true; } } return false; } /******************************************************************************* * * Function btm_route_sco_data Loading Loading @@ -261,40 +226,20 @@ void btm_route_sco_data(BT_HDR* p_msg) { } const uint8_t* decoded = nullptr; size_t written = 0; size_t written = 0, rc = 0; if (active_sco->is_wbs()) { /* TODO(b/235901463): Support packet size != BTM_MSBC_PKT_LEN */ if (data_len != BTM_MSBC_PKT_LEN) { LOG_ERROR("Received invalid mSBC packet with invalid length:%hhu", data_len); osi_free(p_msg); return; } rc = bluetooth::audio::sco::wbs::enqueue_packet(payload, data_len); if (rc != data_len) LOG_DEBUG("Failed to enqueue packet"); uint8_t h2_header; STREAM_TO_UINT8(h2_header, payload); if (h2_header != BTM_MSBC_H2_HEADER_0) { LOG_ERROR("Received invalid mSBC packet with invalid h2 header:%x", h2_header); osi_free(p_msg); return; } uint8_t seq_num; STREAM_TO_UINT8(seq_num, payload); if (!verify_h2_header_seq_num(seq_num)) { LOG_ERROR("Received invalid mSBC packet with invalid sequence number :%x", seq_num); osi_free(p_msg); return; while (rc) { rc = bluetooth::audio::sco::wbs::decode(&decoded); if (rc == 0) { LOG_DEBUG("Failed to decode frames"); break; } if (!hfp_msbc_decoder_decode_packet(p_msg, &decoded)) { LOG_ERROR("Decode mSBC packet failed"); decoded = btm_msbc_zero_frames; written += bluetooth::audio::sco::write(decoded, rc); } written = bluetooth::audio::sco::write(decoded, BTM_MSBC_CODE_SIZE); } else { written = bluetooth::audio::sco::write(payload, data_len); } Loading @@ -303,6 +248,7 @@ void btm_route_sco_data(BT_HDR* p_msg) { /* For Chrome OS, we send the outgoing data after receiving an incoming one. * server, so that we can keep the data read/write rate balanced */ size_t read = 0, avail = 0; const uint8_t* encoded = nullptr; if (active_sco->is_wbs()) { while (written) { avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; Loading Loading @@ -343,35 +289,34 @@ void btm_route_sco_data(BT_HDR* p_msg) { } btm_pcm_buf_write_offset += read; if (btm_pcm_buf_write_offset - btm_pcm_buf_read_offset < BTM_MSBC_CODE_SIZE) { continue; } rc = bluetooth::audio::sco::wbs::encode( &btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); uint8_t encoded[BTM_MSBC_PKT_LEN] = { BTM_MSBC_H2_HEADER_0, btm_h2_header_frames_count[btm_msbc_num_out_frames % 4]}; uint32_t encoded_size; encoded_size = hfp_msbc_encode_frames(btm_pcm_buf, encoded + 2); if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) { LOG_WARN("Encode invalid packet size: %lu", (unsigned long)encoded_size); std::copy(std::begin(btm_msbc_zero_packet), std::end(btm_msbc_zero_packet), &encoded[BTM_MSBC_H2_HEADER_LEN]); } auto data = std::vector<uint8_t>(encoded, encoded + BTM_MSBC_PKT_LEN); btm_send_sco_packet(std::move(data)); btm_msbc_num_out_frames++; if (!rc) LOG_DEBUG( "Failed to encode data starting at ReadOffset:%lu to " "WriteOffset:%lu", (unsigned long)btm_pcm_buf_read_offset, (unsigned long)btm_pcm_buf_write_offset); /* The offsets should reset some time as the buffer length should always * divisible by BTM_MSBC_CODE_SIZE(240) */ btm_pcm_buf_read_offset += BTM_MSBC_CODE_SIZE; * divisible by BTM_MSBC_CODE_SIZE(240) and wbs::encode only returns * BTM_MSBC_CODE_SIZE or 0 */ btm_pcm_buf_read_offset += rc; if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) { btm_pcm_buf_write_offset = 0; btm_pcm_buf_read_offset = 0; } /* Send all of the available SCO packets buffered in the queue */ while (1) { rc = bluetooth::audio::sco::wbs::dequeue_packet(&encoded); if (!rc) break; auto data = std::vector<uint8_t>(encoded, encoded + rc); btm_send_sco_packet(std::move(data)); } } } else { while (written) { Loading Loading @@ -910,6 +855,7 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, uint16_t xx; bool spt = false; tBTM_CHG_ESCO_PARAMS parms = {}; int codec; for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) { if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) || Loading Loading @@ -944,19 +890,18 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, (*p->p_conn_cb)(xx); codec = hfp_hal_interface::esco_coding_to_codec( p->esco.setup.transmit_coding_format.coding_format); hfp_hal_interface::notify_sco_connection_change( bda, /*is_connected=*/true, hfp_hal_interface::esco_coding_to_codec( p->esco.setup.transmit_coding_format.coding_format)); bda, /*is_connected=*/true, codec); /* In-band (non-offload) data path */ if (p->is_inband()) { if (p->is_wbs()) { btm_pcm_buf_read_offset = 0; btm_pcm_buf_write_offset = 0; btm_msbc_num_out_frames = 0; hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); bluetooth::audio::sco::wbs::init( hfp_hal_interface::get_packet_size(codec)); } std::fill(std::begin(btm_pcm_buf), std::end(btm_pcm_buf), 0); Loading Loading @@ -1187,8 +1132,7 @@ void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) { if (p_sco->is_inband()) { if (p_sco->is_wbs()) { hfp_msbc_decoder_cleanup(); hfp_msbc_encoder_cleanup(); bluetooth::audio::sco::wbs::cleanup(); } bluetooth::audio::sco::cleanup(); Loading system/stack/btm/btm_sco.h +55 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "device/include/esco_parameters.h" #include "stack/include/btm_api_types.h" #define BTM_MSBC_CODE_SIZE 240 constexpr uint16_t kMaxScoLinks = static_cast<uint16_t>(BTM_MAX_SCO_LINKS); /* SCO-over-HCI audio related definitions */ Loading @@ -44,6 +46,59 @@ size_t read(uint8_t* p_buf, uint32_t len); size_t write(const uint8_t* buf, uint32_t len); } // namespace bluetooth::audio::sco /* SCO-over-HCI audio HFP WBS related definitions */ namespace bluetooth::audio::sco::wbs { /* Initialize struct used for storing WBS related information. * Args: * pkt_size - Length of the SCO packet. It is determined based on the BT-USB * adapter's capability and alt mode setting. The value should be queried * from HAL interface. It will be used to determine the size of the SCO * packet buffer. */ void init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); /* Try to enqueue a packet to a buffer. * Args: * data - Pointer to received packet data bytes. * pkt_size - Length of input packet. Passing packet with inconsistent size * from the pkt_size set in init() will trigger a reset of the buffer. * Returns: * The length of enqueued bytes. 0 if failed. */ size_t enqueue_packet(const uint8_t* data, size_t pkt_size); /* Try to decode mSBC frames from the packets in the buffer. * Args: * output - Pointer to the decoded PCM bytes caller can read from. * Returns: * The length of decoded bytes. 0 if failed. */ size_t decode(const uint8_t** output); /* Try to encode PCM data into one SCO packet and put the packets in the buffer. * Args: * data - Pointer to the input PCM bytes for the encoder to encode. * len - Length of the input data. * Returns: * The length of input data that is encoded. 0 if failed. */ size_t encode(int16_t* data, size_t len); /* Dequeue a SCO packet with encoded mSBC data if possible. The length of the * packet is determined by the pkt_size set by the init(). * Args: * output - Pointer to output mSBC packets encoded by the encoder. * Returns: * The length of dequeued packet. 0 if failed. */ size_t dequeue_packet(const uint8_t** output); } // namespace bluetooth::audio::sco::wbs /* Define the structures needed by sco */ typedef enum : uint16_t { SCO_ST_UNUSED = 0, Loading system/stack/btm/btm_sco_hci.cc +336 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #include <memory> #include "hfp_msbc_decoder.h" #include "hfp_msbc_encoder.h" #include "osi/include/allocator.h" #include "osi/include/log.h" #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" Loading @@ -30,6 +33,13 @@ // TODO(b/198260375): Make SCO data owner group configurable. #define SCO_HOST_DATA_GROUP "bluetooth-audio" /* Per Bluetooth Core v5.0 and HFP 1.7 specification. */ #define BTM_MSBC_H2_HEADER_0 0x01 #define BTM_MSBC_H2_HEADER_LEN 2 #define BTM_MSBC_PKT_LEN 60 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */ #define BTM_MSBC_SYNC_WORD 0xAD namespace { std::unique_ptr<tUIPC_STATE> sco_uipc = nullptr; Loading Loading @@ -97,6 +107,332 @@ size_t write(const uint8_t* p_buf, uint32_t len) { return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0; } namespace wbs { /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits * sequence number 0000, 0011, 1100, 1111. */ static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; /* Supported SCO packet sizes for mSBC. The wideband speech mSBC frame parsing * code ties to limited packet size values. Specifically list them out * to check against when setting packet size. The first entry is the default * value as a fallback. */ constexpr size_t btm_wbs_supported_pkt_size[] = {BTM_MSBC_PKT_LEN, 72, 0}; /* Buffer size should be set to least common multiple of SCO packet size and * BTM_MSBC_PKT_LEN for optimizing buffer copy. */ constexpr size_t btm_wbs_msbc_buffer_size[] = {BTM_MSBC_PKT_LEN, 360, 0}; /* The pre-computed zero input bit stream of mSBC codec, per HFP 1.7 spec. * This mSBC frame will be decoded into all-zero input PCM. */ static const uint8_t btm_msbc_zero_packet[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c}; static const uint8_t btm_msbc_zero_frames[BTM_MSBC_CODE_SIZE] = {0}; /* Define the structure that contains mSBC data */ typedef struct { size_t packet_size; /* SCO mSBC packet size supported by lower layer */ bool check_alignment; /* True to wait for mSBC packet to align */ size_t buf_size; /* The size of the buffer, determined by the packet_size. */ uint8_t* msbc_decode_buf; /* Buffer to store mSBC packets to decode */ size_t decode_buf_wo; /* Write offset of the decode buffer */ size_t decode_buf_ro; /* Read offset of the decode buffer */ uint8_t* msbc_encode_buf; /* Buffer to store the encoded SCO packets */ size_t encode_buf_wo; /* Write offset of the encode buffer */ size_t encode_buf_ro; /* Read offset of the encode buffer */ uint8_t num_encoded_msbc_pkts; /* Number of the encoded mSBC packets */ static size_t get_supported_packet_size(size_t pkt_size, size_t* buffer_size) { int i; for (i = 0; btm_wbs_supported_pkt_size[i] != 0 && btm_wbs_supported_pkt_size[i] != pkt_size; i++) ; /* In case of unsupported value, error log and fallback to * BTM_MSBC_PKT_LEN(60). */ if (btm_wbs_supported_pkt_size[i] == 0) { LOG_WARN("Unsupported packet size %lu", (unsigned long)pkt_size); i = 0; } if (buffer_size) { *buffer_size = btm_wbs_msbc_buffer_size[i]; } return btm_wbs_supported_pkt_size[i]; } bool verify_h2_header_seq_num(const uint8_t num) { for (int i = 0; i < 4; i++) { if (num == btm_h2_header_frames_count[i]) { return true; } } return false; } public: void init(size_t pkt_size) { decode_buf_wo = 0; decode_buf_ro = 0; encode_buf_wo = 0; encode_buf_ro = 0; pkt_size = get_supported_packet_size(pkt_size, &buf_size); if (pkt_size != BTM_MSBC_PKT_LEN) check_alignment = true; if (pkt_size == packet_size) return; packet_size = pkt_size; if (msbc_decode_buf) osi_free(msbc_decode_buf); msbc_decode_buf = (uint8_t*)osi_calloc(buf_size); if (msbc_encode_buf) osi_free(msbc_encode_buf); msbc_encode_buf = (uint8_t*)osi_calloc(buf_size); } void deinit() { if (msbc_decode_buf) osi_free(msbc_decode_buf); if (msbc_encode_buf) osi_free(msbc_encode_buf); } size_t decodable() { return decode_buf_wo - decode_buf_ro; } void mark_pkt_decoded() { if (decode_buf_ro + BTM_MSBC_PKT_LEN > decode_buf_wo) { LOG_ERROR("Trying to mark read offset beyond write offset."); return; } decode_buf_ro += BTM_MSBC_PKT_LEN; if (decode_buf_ro == decode_buf_wo) { decode_buf_ro = 0; decode_buf_wo = 0; } } size_t write(const uint8_t* input, size_t len) { if (len > buf_size - decode_buf_wo) { return 0; } std::copy(input, input + len, msbc_decode_buf + decode_buf_wo); decode_buf_wo += len; return len; } const uint8_t* find_msbc_pkt_head() { size_t rp = 0; while (decode_buf_wo - decode_buf_ro - rp >= BTM_MSBC_PKT_LEN) { if ((msbc_decode_buf[decode_buf_ro + rp] != BTM_MSBC_H2_HEADER_0) || (!verify_h2_header_seq_num( msbc_decode_buf[decode_buf_ro + rp + 1])) || (msbc_decode_buf[decode_buf_ro + rp + 2] != BTM_MSBC_SYNC_WORD)) { rp++; continue; } return &msbc_decode_buf[decode_buf_ro + rp]; } return nullptr; } /* Fill in the mSBC header and update the buffer's write offset to guard the * buffer space to be written. Return a pointer to the start of mSBC packet's * body for the caller to fill the encoded mSBC data if there is enough space * in the buffer to fill in a new packet, otherwise return a nullptr. */ uint8_t* fill_msbc_pkt_template() { uint8_t* wp = &msbc_encode_buf[encode_buf_wo]; if (buf_size - encode_buf_wo < BTM_MSBC_PKT_LEN) { LOG_DEBUG("Packet queue can't accommodate more packets."); return nullptr; } wp[0] = BTM_MSBC_H2_HEADER_0; wp[1] = btm_h2_header_frames_count[num_encoded_msbc_pkts % 4]; encode_buf_wo += BTM_MSBC_PKT_LEN; num_encoded_msbc_pkts++; return wp + BTM_MSBC_H2_HEADER_LEN; } size_t mark_pkt_dequeued() { LOG_DEBUG( "Try to mark an encoded packet dequeued: ro:%lu wo:%lu pkt_size:%lu", (unsigned long)encode_buf_ro, (unsigned long)encode_buf_wo, (unsigned long)packet_size); if (encode_buf_wo - encode_buf_ro < packet_size) return 0; encode_buf_ro += packet_size; if (encode_buf_ro == encode_buf_wo) { encode_buf_ro = 0; encode_buf_wo = 0; } return packet_size; } const uint8_t* sco_pkt_read_ptr() { if (encode_buf_wo - encode_buf_ro < packet_size) { LOG_DEBUG("Insufficient data as a SCO packet to read."); return nullptr; } return &msbc_encode_buf[encode_buf_ro]; } } tBTM_MSBC_INFO; static tBTM_MSBC_INFO* msbc_info = nullptr; void init(size_t pkt_size) { hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); if (msbc_info) { LOG_WARN("Re-initiating mSBC buffer that is active or not cleaned"); msbc_info->deinit(); osi_free(msbc_info); } msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info)); msbc_info->init(pkt_size); } void cleanup() { hfp_msbc_decoder_cleanup(); hfp_msbc_encoder_cleanup(); if (msbc_info == nullptr) return; msbc_info->deinit(); osi_free(msbc_info); msbc_info = nullptr; } size_t enqueue_packet(const uint8_t* data, size_t pkt_size) { if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (pkt_size != msbc_info->packet_size) { LOG_WARN( "Ignoring the coming packet with size %lu that is inconsistent with " "the HAL reported packet size %lu", (unsigned long)pkt_size, (unsigned long)msbc_info->packet_size); return 0; } if (msbc_info->check_alignment) { if (data[0] != BTM_MSBC_H2_HEADER_0 || data[2] != BTM_MSBC_SYNC_WORD) { LOG_DEBUG("Waiting for valid mSBC frame head"); return 0; } msbc_info->check_alignment = false; } if (msbc_info->write(data, pkt_size) != pkt_size) { LOG_DEBUG("Fail to write packet with size %lu to buffer", (unsigned long)pkt_size); return 0; } return pkt_size; } size_t decode(const uint8_t** out_data) { const uint8_t* frame_head = nullptr; if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) { LOG_DEBUG("No complete mSBC packet to decode"); return 0; } frame_head = msbc_info->find_msbc_pkt_head(); if (frame_head == nullptr) { LOG_DEBUG("No valid mSBC packet to decode %lu, %lu", (unsigned long)msbc_info->decode_buf_ro, (unsigned long)msbc_info->decode_buf_wo); /* Done with parsing the raw bytes just read. If mSBC frame head not found, * we shall handle it as packet loss. */ goto packet_loss; } if (!hfp_msbc_decoder_decode_packet(frame_head, out_data)) { LOG_DEBUG("Decoding mSBC packet failed"); goto packet_loss; } msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; packet_loss: *out_data = btm_msbc_zero_frames; msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; } size_t encode(int16_t* data, size_t len) { uint8_t* pkt_body = nullptr; uint32_t encoded_size = 0; if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (len < BTM_MSBC_CODE_SIZE) { LOG_DEBUG( "PCM frames with size %lu is insufficient to be encoded into a mSBC " "packet", (unsigned long)len); return 0; } pkt_body = msbc_info->fill_msbc_pkt_template(); if (pkt_body == nullptr) { LOG_DEBUG("Failed to fill the template to fill the mSBC packet"); return 0; } encoded_size = hfp_msbc_encode_frames(data, pkt_body); if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) { LOG_WARN("Encoding invalid packet size: %lu", (unsigned long)encoded_size); std::copy(std::begin(btm_msbc_zero_packet), std::end(btm_msbc_zero_packet), pkt_body); } return BTM_MSBC_CODE_SIZE; } size_t dequeue_packet(const uint8_t** output) { if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } *output = msbc_info->sco_pkt_read_ptr(); if (*output == nullptr) { LOG_DEBUG("Insufficient data to dequeue."); return 0; } return msbc_info->mark_pkt_dequeued(); } } // namespace wbs } // namespace sco } // namespace audio } // namespace bluetooth system/stack/btm/hfp_msbc_decoder.cc +9 −12 Original line number Diff line number Diff line Loading @@ -25,7 +25,8 @@ #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" #include "osi/include/log.h" #include "stack/include/bt_hdr.h" #define HFP_MSBC_PKT_LEN 60 typedef struct { OI_CODEC_SBC_DECODER_CONTEXT decoder_context; Loading Loading @@ -59,19 +60,15 @@ void hfp_msbc_decoder_cleanup(void) { memset(&hfp_msbc_decoder, 0, sizeof(hfp_msbc_decoder)); } bool hfp_msbc_decoder_decode_packet(BT_HDR* p_buf, const uint8_t** out_buf) { // Get the HFP MSBC encoded maximum frame size bool hfp_msbc_decoder_decode_packet(const uint8_t* i_buf, const uint8_t** o_buf) { const OI_BYTE* oi_data; uint32_t oi_size, out_avail; int16_t* out_ptr; // TODO(b/232463744): Query the HFP HAL for the packet size. if (p_buf->len != 63) { LOG_ERROR("%s: Invalid packet", __func__); return false; } oi_data = p_buf->data + p_buf->offset; oi_size = p_buf->len; oi_data = i_buf; oi_size = HFP_MSBC_PKT_LEN; out_avail = sizeof(hfp_msbc_decoder.decode_buf); out_ptr = hfp_msbc_decoder.decode_buf; Loading @@ -79,11 +76,11 @@ bool hfp_msbc_decoder_decode_packet(BT_HDR* p_buf, const uint8_t** out_buf) { OI_CODEC_SBC_DecodeFrame(&hfp_msbc_decoder.decoder_context, &oi_data, &oi_size, out_ptr, &out_avail); if (!OI_SUCCESS(status) || out_avail != 240 || oi_size != 0) { LOG_ERROR("%s: Decoding failure: %d, %lu, %lu", __func__, status, LOG_ERROR("Decoding failure: %d, %lu, %lu", status, (unsigned long)out_avail, (unsigned long)oi_size); return false; } *out_buf = (const uint8_t*)&hfp_msbc_decoder.decode_buf; *o_buf = (const uint8_t*)&hfp_msbc_decoder.decode_buf; return true; } system/stack/btm/hfp_msbc_encoder.cc +0 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ void hfp_msbc_encoder_init(void) { void hfp_msbc_encoder_cleanup(void) { hfp_msbc_encoder = {}; } // Get the HFP MSBC encoded maximum frame size uint32_t hfp_msbc_encode_frames(int16_t* input, uint8_t* output) { return SBC_Encode(&hfp_msbc_encoder.sbc_encoder_params, input, output); } Loading
system/stack/btm/btm_sco.cc +39 −95 Original line number Diff line number Diff line Loading @@ -33,8 +33,6 @@ #include "device/include/controller.h" #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" #include "hfp_msbc_decoder.h" #include "hfp_msbc_encoder.h" #include "osi/include/allocator.h" #include "osi/include/log.h" #include "osi/include/osi.h" Loading Loading @@ -94,30 +92,6 @@ static int16_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; * They are only used for WBS and the unit is byte. */ static size_t btm_pcm_buf_read_offset = 0; static size_t btm_pcm_buf_write_offset = 0; /* Per Bluetooth Core v5.0 and HFP 1.7 specification. */ #define BTM_MSBC_H2_HEADER_0 0x01 #define BTM_MSBC_H2_HEADER_LEN 2 #define BTM_MSBC_PKT_LEN 60 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */ #define BTM_MSBC_CODE_SIZE 240 /* The pre-computed zero input bit stream of mSBC codec, per HFP 1.7 spec. * This mSBC frame will be decoded into all-zero input PCM. */ static const uint8_t btm_msbc_zero_packet[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c}; static const uint8_t btm_msbc_zero_frames[BTM_MSBC_CODE_SIZE] = {0}; /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits * sequence number 0000, 0011, 1100, 1111. */ static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; static uint8_t btm_msbc_num_out_frames; /******************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /******************************************************************************/ Loading Loading @@ -210,15 +184,6 @@ static tSCO_CONN* btm_get_active_sco() { return nullptr; } static bool verify_h2_header_seq_num(const uint8_t num) { for (int i = 0; i < 4; i++) { if (num == btm_h2_header_frames_count[i]) { return true; } } return false; } /******************************************************************************* * * Function btm_route_sco_data Loading Loading @@ -261,40 +226,20 @@ void btm_route_sco_data(BT_HDR* p_msg) { } const uint8_t* decoded = nullptr; size_t written = 0; size_t written = 0, rc = 0; if (active_sco->is_wbs()) { /* TODO(b/235901463): Support packet size != BTM_MSBC_PKT_LEN */ if (data_len != BTM_MSBC_PKT_LEN) { LOG_ERROR("Received invalid mSBC packet with invalid length:%hhu", data_len); osi_free(p_msg); return; } rc = bluetooth::audio::sco::wbs::enqueue_packet(payload, data_len); if (rc != data_len) LOG_DEBUG("Failed to enqueue packet"); uint8_t h2_header; STREAM_TO_UINT8(h2_header, payload); if (h2_header != BTM_MSBC_H2_HEADER_0) { LOG_ERROR("Received invalid mSBC packet with invalid h2 header:%x", h2_header); osi_free(p_msg); return; } uint8_t seq_num; STREAM_TO_UINT8(seq_num, payload); if (!verify_h2_header_seq_num(seq_num)) { LOG_ERROR("Received invalid mSBC packet with invalid sequence number :%x", seq_num); osi_free(p_msg); return; while (rc) { rc = bluetooth::audio::sco::wbs::decode(&decoded); if (rc == 0) { LOG_DEBUG("Failed to decode frames"); break; } if (!hfp_msbc_decoder_decode_packet(p_msg, &decoded)) { LOG_ERROR("Decode mSBC packet failed"); decoded = btm_msbc_zero_frames; written += bluetooth::audio::sco::write(decoded, rc); } written = bluetooth::audio::sco::write(decoded, BTM_MSBC_CODE_SIZE); } else { written = bluetooth::audio::sco::write(payload, data_len); } Loading @@ -303,6 +248,7 @@ void btm_route_sco_data(BT_HDR* p_msg) { /* For Chrome OS, we send the outgoing data after receiving an incoming one. * server, so that we can keep the data read/write rate balanced */ size_t read = 0, avail = 0; const uint8_t* encoded = nullptr; if (active_sco->is_wbs()) { while (written) { avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; Loading Loading @@ -343,35 +289,34 @@ void btm_route_sco_data(BT_HDR* p_msg) { } btm_pcm_buf_write_offset += read; if (btm_pcm_buf_write_offset - btm_pcm_buf_read_offset < BTM_MSBC_CODE_SIZE) { continue; } rc = bluetooth::audio::sco::wbs::encode( &btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); uint8_t encoded[BTM_MSBC_PKT_LEN] = { BTM_MSBC_H2_HEADER_0, btm_h2_header_frames_count[btm_msbc_num_out_frames % 4]}; uint32_t encoded_size; encoded_size = hfp_msbc_encode_frames(btm_pcm_buf, encoded + 2); if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) { LOG_WARN("Encode invalid packet size: %lu", (unsigned long)encoded_size); std::copy(std::begin(btm_msbc_zero_packet), std::end(btm_msbc_zero_packet), &encoded[BTM_MSBC_H2_HEADER_LEN]); } auto data = std::vector<uint8_t>(encoded, encoded + BTM_MSBC_PKT_LEN); btm_send_sco_packet(std::move(data)); btm_msbc_num_out_frames++; if (!rc) LOG_DEBUG( "Failed to encode data starting at ReadOffset:%lu to " "WriteOffset:%lu", (unsigned long)btm_pcm_buf_read_offset, (unsigned long)btm_pcm_buf_write_offset); /* The offsets should reset some time as the buffer length should always * divisible by BTM_MSBC_CODE_SIZE(240) */ btm_pcm_buf_read_offset += BTM_MSBC_CODE_SIZE; * divisible by BTM_MSBC_CODE_SIZE(240) and wbs::encode only returns * BTM_MSBC_CODE_SIZE or 0 */ btm_pcm_buf_read_offset += rc; if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) { btm_pcm_buf_write_offset = 0; btm_pcm_buf_read_offset = 0; } /* Send all of the available SCO packets buffered in the queue */ while (1) { rc = bluetooth::audio::sco::wbs::dequeue_packet(&encoded); if (!rc) break; auto data = std::vector<uint8_t>(encoded, encoded + rc); btm_send_sco_packet(std::move(data)); } } } else { while (written) { Loading Loading @@ -910,6 +855,7 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, uint16_t xx; bool spt = false; tBTM_CHG_ESCO_PARAMS parms = {}; int codec; for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) { if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) || Loading Loading @@ -944,19 +890,18 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, (*p->p_conn_cb)(xx); codec = hfp_hal_interface::esco_coding_to_codec( p->esco.setup.transmit_coding_format.coding_format); hfp_hal_interface::notify_sco_connection_change( bda, /*is_connected=*/true, hfp_hal_interface::esco_coding_to_codec( p->esco.setup.transmit_coding_format.coding_format)); bda, /*is_connected=*/true, codec); /* In-band (non-offload) data path */ if (p->is_inband()) { if (p->is_wbs()) { btm_pcm_buf_read_offset = 0; btm_pcm_buf_write_offset = 0; btm_msbc_num_out_frames = 0; hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); bluetooth::audio::sco::wbs::init( hfp_hal_interface::get_packet_size(codec)); } std::fill(std::begin(btm_pcm_buf), std::end(btm_pcm_buf), 0); Loading Loading @@ -1187,8 +1132,7 @@ void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) { if (p_sco->is_inband()) { if (p_sco->is_wbs()) { hfp_msbc_decoder_cleanup(); hfp_msbc_encoder_cleanup(); bluetooth::audio::sco::wbs::cleanup(); } bluetooth::audio::sco::cleanup(); Loading
system/stack/btm/btm_sco.h +55 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "device/include/esco_parameters.h" #include "stack/include/btm_api_types.h" #define BTM_MSBC_CODE_SIZE 240 constexpr uint16_t kMaxScoLinks = static_cast<uint16_t>(BTM_MAX_SCO_LINKS); /* SCO-over-HCI audio related definitions */ Loading @@ -44,6 +46,59 @@ size_t read(uint8_t* p_buf, uint32_t len); size_t write(const uint8_t* buf, uint32_t len); } // namespace bluetooth::audio::sco /* SCO-over-HCI audio HFP WBS related definitions */ namespace bluetooth::audio::sco::wbs { /* Initialize struct used for storing WBS related information. * Args: * pkt_size - Length of the SCO packet. It is determined based on the BT-USB * adapter's capability and alt mode setting. The value should be queried * from HAL interface. It will be used to determine the size of the SCO * packet buffer. */ void init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); /* Try to enqueue a packet to a buffer. * Args: * data - Pointer to received packet data bytes. * pkt_size - Length of input packet. Passing packet with inconsistent size * from the pkt_size set in init() will trigger a reset of the buffer. * Returns: * The length of enqueued bytes. 0 if failed. */ size_t enqueue_packet(const uint8_t* data, size_t pkt_size); /* Try to decode mSBC frames from the packets in the buffer. * Args: * output - Pointer to the decoded PCM bytes caller can read from. * Returns: * The length of decoded bytes. 0 if failed. */ size_t decode(const uint8_t** output); /* Try to encode PCM data into one SCO packet and put the packets in the buffer. * Args: * data - Pointer to the input PCM bytes for the encoder to encode. * len - Length of the input data. * Returns: * The length of input data that is encoded. 0 if failed. */ size_t encode(int16_t* data, size_t len); /* Dequeue a SCO packet with encoded mSBC data if possible. The length of the * packet is determined by the pkt_size set by the init(). * Args: * output - Pointer to output mSBC packets encoded by the encoder. * Returns: * The length of dequeued packet. 0 if failed. */ size_t dequeue_packet(const uint8_t** output); } // namespace bluetooth::audio::sco::wbs /* Define the structures needed by sco */ typedef enum : uint16_t { SCO_ST_UNUSED = 0, Loading
system/stack/btm/btm_sco_hci.cc +336 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #include <memory> #include "hfp_msbc_decoder.h" #include "hfp_msbc_encoder.h" #include "osi/include/allocator.h" #include "osi/include/log.h" #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" Loading @@ -30,6 +33,13 @@ // TODO(b/198260375): Make SCO data owner group configurable. #define SCO_HOST_DATA_GROUP "bluetooth-audio" /* Per Bluetooth Core v5.0 and HFP 1.7 specification. */ #define BTM_MSBC_H2_HEADER_0 0x01 #define BTM_MSBC_H2_HEADER_LEN 2 #define BTM_MSBC_PKT_LEN 60 #define BTM_MSBC_PKT_FRAME_LEN 57 /* Packet length without the header */ #define BTM_MSBC_SYNC_WORD 0xAD namespace { std::unique_ptr<tUIPC_STATE> sco_uipc = nullptr; Loading Loading @@ -97,6 +107,332 @@ size_t write(const uint8_t* p_buf, uint32_t len) { return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0; } namespace wbs { /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits * sequence number 0000, 0011, 1100, 1111. */ static const uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; /* Supported SCO packet sizes for mSBC. The wideband speech mSBC frame parsing * code ties to limited packet size values. Specifically list them out * to check against when setting packet size. The first entry is the default * value as a fallback. */ constexpr size_t btm_wbs_supported_pkt_size[] = {BTM_MSBC_PKT_LEN, 72, 0}; /* Buffer size should be set to least common multiple of SCO packet size and * BTM_MSBC_PKT_LEN for optimizing buffer copy. */ constexpr size_t btm_wbs_msbc_buffer_size[] = {BTM_MSBC_PKT_LEN, 360, 0}; /* The pre-computed zero input bit stream of mSBC codec, per HFP 1.7 spec. * This mSBC frame will be decoded into all-zero input PCM. */ static const uint8_t btm_msbc_zero_packet[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c}; static const uint8_t btm_msbc_zero_frames[BTM_MSBC_CODE_SIZE] = {0}; /* Define the structure that contains mSBC data */ typedef struct { size_t packet_size; /* SCO mSBC packet size supported by lower layer */ bool check_alignment; /* True to wait for mSBC packet to align */ size_t buf_size; /* The size of the buffer, determined by the packet_size. */ uint8_t* msbc_decode_buf; /* Buffer to store mSBC packets to decode */ size_t decode_buf_wo; /* Write offset of the decode buffer */ size_t decode_buf_ro; /* Read offset of the decode buffer */ uint8_t* msbc_encode_buf; /* Buffer to store the encoded SCO packets */ size_t encode_buf_wo; /* Write offset of the encode buffer */ size_t encode_buf_ro; /* Read offset of the encode buffer */ uint8_t num_encoded_msbc_pkts; /* Number of the encoded mSBC packets */ static size_t get_supported_packet_size(size_t pkt_size, size_t* buffer_size) { int i; for (i = 0; btm_wbs_supported_pkt_size[i] != 0 && btm_wbs_supported_pkt_size[i] != pkt_size; i++) ; /* In case of unsupported value, error log and fallback to * BTM_MSBC_PKT_LEN(60). */ if (btm_wbs_supported_pkt_size[i] == 0) { LOG_WARN("Unsupported packet size %lu", (unsigned long)pkt_size); i = 0; } if (buffer_size) { *buffer_size = btm_wbs_msbc_buffer_size[i]; } return btm_wbs_supported_pkt_size[i]; } bool verify_h2_header_seq_num(const uint8_t num) { for (int i = 0; i < 4; i++) { if (num == btm_h2_header_frames_count[i]) { return true; } } return false; } public: void init(size_t pkt_size) { decode_buf_wo = 0; decode_buf_ro = 0; encode_buf_wo = 0; encode_buf_ro = 0; pkt_size = get_supported_packet_size(pkt_size, &buf_size); if (pkt_size != BTM_MSBC_PKT_LEN) check_alignment = true; if (pkt_size == packet_size) return; packet_size = pkt_size; if (msbc_decode_buf) osi_free(msbc_decode_buf); msbc_decode_buf = (uint8_t*)osi_calloc(buf_size); if (msbc_encode_buf) osi_free(msbc_encode_buf); msbc_encode_buf = (uint8_t*)osi_calloc(buf_size); } void deinit() { if (msbc_decode_buf) osi_free(msbc_decode_buf); if (msbc_encode_buf) osi_free(msbc_encode_buf); } size_t decodable() { return decode_buf_wo - decode_buf_ro; } void mark_pkt_decoded() { if (decode_buf_ro + BTM_MSBC_PKT_LEN > decode_buf_wo) { LOG_ERROR("Trying to mark read offset beyond write offset."); return; } decode_buf_ro += BTM_MSBC_PKT_LEN; if (decode_buf_ro == decode_buf_wo) { decode_buf_ro = 0; decode_buf_wo = 0; } } size_t write(const uint8_t* input, size_t len) { if (len > buf_size - decode_buf_wo) { return 0; } std::copy(input, input + len, msbc_decode_buf + decode_buf_wo); decode_buf_wo += len; return len; } const uint8_t* find_msbc_pkt_head() { size_t rp = 0; while (decode_buf_wo - decode_buf_ro - rp >= BTM_MSBC_PKT_LEN) { if ((msbc_decode_buf[decode_buf_ro + rp] != BTM_MSBC_H2_HEADER_0) || (!verify_h2_header_seq_num( msbc_decode_buf[decode_buf_ro + rp + 1])) || (msbc_decode_buf[decode_buf_ro + rp + 2] != BTM_MSBC_SYNC_WORD)) { rp++; continue; } return &msbc_decode_buf[decode_buf_ro + rp]; } return nullptr; } /* Fill in the mSBC header and update the buffer's write offset to guard the * buffer space to be written. Return a pointer to the start of mSBC packet's * body for the caller to fill the encoded mSBC data if there is enough space * in the buffer to fill in a new packet, otherwise return a nullptr. */ uint8_t* fill_msbc_pkt_template() { uint8_t* wp = &msbc_encode_buf[encode_buf_wo]; if (buf_size - encode_buf_wo < BTM_MSBC_PKT_LEN) { LOG_DEBUG("Packet queue can't accommodate more packets."); return nullptr; } wp[0] = BTM_MSBC_H2_HEADER_0; wp[1] = btm_h2_header_frames_count[num_encoded_msbc_pkts % 4]; encode_buf_wo += BTM_MSBC_PKT_LEN; num_encoded_msbc_pkts++; return wp + BTM_MSBC_H2_HEADER_LEN; } size_t mark_pkt_dequeued() { LOG_DEBUG( "Try to mark an encoded packet dequeued: ro:%lu wo:%lu pkt_size:%lu", (unsigned long)encode_buf_ro, (unsigned long)encode_buf_wo, (unsigned long)packet_size); if (encode_buf_wo - encode_buf_ro < packet_size) return 0; encode_buf_ro += packet_size; if (encode_buf_ro == encode_buf_wo) { encode_buf_ro = 0; encode_buf_wo = 0; } return packet_size; } const uint8_t* sco_pkt_read_ptr() { if (encode_buf_wo - encode_buf_ro < packet_size) { LOG_DEBUG("Insufficient data as a SCO packet to read."); return nullptr; } return &msbc_encode_buf[encode_buf_ro]; } } tBTM_MSBC_INFO; static tBTM_MSBC_INFO* msbc_info = nullptr; void init(size_t pkt_size) { hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); if (msbc_info) { LOG_WARN("Re-initiating mSBC buffer that is active or not cleaned"); msbc_info->deinit(); osi_free(msbc_info); } msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info)); msbc_info->init(pkt_size); } void cleanup() { hfp_msbc_decoder_cleanup(); hfp_msbc_encoder_cleanup(); if (msbc_info == nullptr) return; msbc_info->deinit(); osi_free(msbc_info); msbc_info = nullptr; } size_t enqueue_packet(const uint8_t* data, size_t pkt_size) { if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (pkt_size != msbc_info->packet_size) { LOG_WARN( "Ignoring the coming packet with size %lu that is inconsistent with " "the HAL reported packet size %lu", (unsigned long)pkt_size, (unsigned long)msbc_info->packet_size); return 0; } if (msbc_info->check_alignment) { if (data[0] != BTM_MSBC_H2_HEADER_0 || data[2] != BTM_MSBC_SYNC_WORD) { LOG_DEBUG("Waiting for valid mSBC frame head"); return 0; } msbc_info->check_alignment = false; } if (msbc_info->write(data, pkt_size) != pkt_size) { LOG_DEBUG("Fail to write packet with size %lu to buffer", (unsigned long)pkt_size); return 0; } return pkt_size; } size_t decode(const uint8_t** out_data) { const uint8_t* frame_head = nullptr; if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) { LOG_DEBUG("No complete mSBC packet to decode"); return 0; } frame_head = msbc_info->find_msbc_pkt_head(); if (frame_head == nullptr) { LOG_DEBUG("No valid mSBC packet to decode %lu, %lu", (unsigned long)msbc_info->decode_buf_ro, (unsigned long)msbc_info->decode_buf_wo); /* Done with parsing the raw bytes just read. If mSBC frame head not found, * we shall handle it as packet loss. */ goto packet_loss; } if (!hfp_msbc_decoder_decode_packet(frame_head, out_data)) { LOG_DEBUG("Decoding mSBC packet failed"); goto packet_loss; } msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; packet_loss: *out_data = btm_msbc_zero_frames; msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; } size_t encode(int16_t* data, size_t len) { uint8_t* pkt_body = nullptr; uint32_t encoded_size = 0; if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } if (len < BTM_MSBC_CODE_SIZE) { LOG_DEBUG( "PCM frames with size %lu is insufficient to be encoded into a mSBC " "packet", (unsigned long)len); return 0; } pkt_body = msbc_info->fill_msbc_pkt_template(); if (pkt_body == nullptr) { LOG_DEBUG("Failed to fill the template to fill the mSBC packet"); return 0; } encoded_size = hfp_msbc_encode_frames(data, pkt_body); if (encoded_size != BTM_MSBC_PKT_FRAME_LEN) { LOG_WARN("Encoding invalid packet size: %lu", (unsigned long)encoded_size); std::copy(std::begin(btm_msbc_zero_packet), std::end(btm_msbc_zero_packet), pkt_body); } return BTM_MSBC_CODE_SIZE; } size_t dequeue_packet(const uint8_t** output) { if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); return 0; } *output = msbc_info->sco_pkt_read_ptr(); if (*output == nullptr) { LOG_DEBUG("Insufficient data to dequeue."); return 0; } return msbc_info->mark_pkt_dequeued(); } } // namespace wbs } // namespace sco } // namespace audio } // namespace bluetooth
system/stack/btm/hfp_msbc_decoder.cc +9 −12 Original line number Diff line number Diff line Loading @@ -25,7 +25,8 @@ #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" #include "osi/include/log.h" #include "stack/include/bt_hdr.h" #define HFP_MSBC_PKT_LEN 60 typedef struct { OI_CODEC_SBC_DECODER_CONTEXT decoder_context; Loading Loading @@ -59,19 +60,15 @@ void hfp_msbc_decoder_cleanup(void) { memset(&hfp_msbc_decoder, 0, sizeof(hfp_msbc_decoder)); } bool hfp_msbc_decoder_decode_packet(BT_HDR* p_buf, const uint8_t** out_buf) { // Get the HFP MSBC encoded maximum frame size bool hfp_msbc_decoder_decode_packet(const uint8_t* i_buf, const uint8_t** o_buf) { const OI_BYTE* oi_data; uint32_t oi_size, out_avail; int16_t* out_ptr; // TODO(b/232463744): Query the HFP HAL for the packet size. if (p_buf->len != 63) { LOG_ERROR("%s: Invalid packet", __func__); return false; } oi_data = p_buf->data + p_buf->offset; oi_size = p_buf->len; oi_data = i_buf; oi_size = HFP_MSBC_PKT_LEN; out_avail = sizeof(hfp_msbc_decoder.decode_buf); out_ptr = hfp_msbc_decoder.decode_buf; Loading @@ -79,11 +76,11 @@ bool hfp_msbc_decoder_decode_packet(BT_HDR* p_buf, const uint8_t** out_buf) { OI_CODEC_SBC_DecodeFrame(&hfp_msbc_decoder.decoder_context, &oi_data, &oi_size, out_ptr, &out_avail); if (!OI_SUCCESS(status) || out_avail != 240 || oi_size != 0) { LOG_ERROR("%s: Decoding failure: %d, %lu, %lu", __func__, status, LOG_ERROR("Decoding failure: %d, %lu, %lu", status, (unsigned long)out_avail, (unsigned long)oi_size); return false; } *out_buf = (const uint8_t*)&hfp_msbc_decoder.decode_buf; *o_buf = (const uint8_t*)&hfp_msbc_decoder.decode_buf; return true; }
system/stack/btm/hfp_msbc_encoder.cc +0 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ void hfp_msbc_encoder_init(void) { void hfp_msbc_encoder_cleanup(void) { hfp_msbc_encoder = {}; } // Get the HFP MSBC encoded maximum frame size uint32_t hfp_msbc_encode_frames(int16_t* input, uint8_t* output) { return SBC_Encode(&hfp_msbc_encoder.sbc_encoder_params, input, output); }