/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "device/include/esco_parameters.h" #include "internal_include/bt_target.h" #include "macros.h" #include "raw_address.h" #include "stack/btm/sco_pkt_status.h" #include "stack/include/btm_api_types.h" #define BTM_MSBC_CODE_SIZE 240 #define BTM_LC3_CODE_SIZE 480 constexpr uint16_t kMaxScoLinks = static_cast(BTM_MAX_SCO_LINKS); /* SCO-over-HCI audio related definitions */ namespace bluetooth::audio::sco { /* Initialize SCO-over-HCI socket (UIPC); the client is audio server */ void init(); /* Open the socket when there is SCO connection open */ void open(); /* Clean up the socket when the SCO connection is done */ void cleanup(); /* Read PCM data from the socket (audio server) for SCO Tx */ size_t read(uint8_t* p_buf, uint32_t len); /* Write PCM data to the socket from SCO Rx */ 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. Currently, the stack only supports 60 and 72. * Returns: * The selected packet size. Will fallback to the typical mSBC packet * length(60) if the pkt_size argument is not supported. */ size_t init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); /* Fill in packet loss stats * Args: * num_decoded_frames - Output argument for the number of decode frames * packet_loss_ratio - Output argument for the ratio of lost frames * Returns: * False for invalid arguments or unreasonable stats. True otherwise. */ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio); /* Try to enqueue a packet to a buffer. * Args: * data - Vector of received packet data bytes. * corrupted - If the current mSBC packet read is corrupted. * Returns: * true if enqueued, false if it failed. */ bool enqueue_packet(const std::vector& data, bool corrupted); /* 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); /* Get mSBC packets' status record. * Returns: * Pointer to the record struct, nullptr if not valid. */ tBTM_SCO_PKT_STATUS* get_pkt_status(); } // namespace bluetooth::audio::sco::wbs /* SCO-over-HCI audio HFP SWB related definitions */ namespace bluetooth::audio::sco::swb { /* Initialize struct used for storing SWB 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. Currently, the stack only supports 60 and 72. * Returns: * The selected packet size. Will fallback to the typical LC3 packet * length(60) if the pkt_size argument is not supported. */ size_t init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); /* Fill in packet loss stats * Args: * num_decoded_frames - Output argument for the number of decode frames * packet_loss_ratio - Output argument for the ratio of lost frames * Returns: * False for invalid arguments or unreasonable stats. True otherwise. */ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio); /* Try to enqueue a packet to a buffer. * Args: * data - Vector of received packet data bytes. * corrupted - If the current LC3 packet read is corrupted. * Returns: * true if enqueued, false if it failed. */ bool enqueue_packet(const std::vector& data, bool corrupted); /* Try to decode LC3 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 LC3 data if possible. The length of the * packet is determined by the pkt_size set by the init(). * Args: * output - Pointer to output LC3 packets encoded by the encoder. * Returns: * The length of dequeued packet. 0 if failed. */ size_t dequeue_packet(const uint8_t** output); /* Get LC3 packets' status record. * Returns: * Pointer to the record struct, nullptr if not valid. */ tBTM_SCO_PKT_STATUS* get_pkt_status(); } // namespace bluetooth::audio::sco::swb /* Define the structures needed by sco */ typedef enum : uint16_t { SCO_ST_UNUSED = 0, SCO_ST_LISTENING = 1, SCO_ST_W4_CONN_RSP = 2, SCO_ST_CONNECTING = 3, SCO_ST_CONNECTED = 4, SCO_ST_DISCONNECTING = 5, SCO_ST_PEND_UNPARK = 6, SCO_ST_PEND_ROLECHANGE = 7, SCO_ST_PEND_MODECHANGE = 8, } tSCO_STATE; inline std::string sco_state_text(const tSCO_STATE& state) { switch (state) { CASE_RETURN_TEXT(SCO_ST_UNUSED); CASE_RETURN_TEXT(SCO_ST_LISTENING); CASE_RETURN_TEXT(SCO_ST_W4_CONN_RSP); CASE_RETURN_TEXT(SCO_ST_CONNECTING); CASE_RETURN_TEXT(SCO_ST_CONNECTED); CASE_RETURN_TEXT(SCO_ST_DISCONNECTING); CASE_RETURN_TEXT(SCO_ST_PEND_UNPARK); CASE_RETURN_TEXT(SCO_ST_PEND_ROLECHANGE); CASE_RETURN_TEXT(SCO_ST_PEND_MODECHANGE); default: return std::string("unknown_sco_state: ") + std::to_string(static_cast(state)); } } /* Define the structure that contains (e)SCO data */ typedef struct { tBTM_ESCO_CBACK* p_esco_cback; /* Callback for eSCO events */ enh_esco_params_t setup; tBTM_ESCO_DATA data; /* Connection complete information */ uint8_t hci_status; } tBTM_ESCO_INFO; /* Define the structure used for SCO Management */ typedef struct { tBTM_ESCO_INFO esco; /* Current settings */ tBTM_SCO_CB* p_conn_cb; /* Callback for when connected */ tBTM_SCO_CB* p_disc_cb; /* Callback for when disconnect */ tSCO_STATE state; /* The state of the SCO link */ uint16_t hci_handle; /* HCI Handle */ public: bool is_active() const { return state != SCO_ST_UNUSED; } bool is_inband() const { return esco.setup.input_data_path == ESCO_DATA_PATH_HCI; } tBTM_SCO_CODEC_TYPE get_codec_type() const { switch (esco.setup.coding_format) { case ESCO_CODING_FORMAT_CVSD: return BTM_SCO_CODEC_CVSD; case ESCO_CODING_FORMAT_MSBC: return BTM_SCO_CODEC_MSBC; case ESCO_CODING_FORMAT_LC3: return BTM_SCO_CODEC_LC3; default: return BTM_SCO_CODEC_NONE; } } uint16_t Handle() const { return hci_handle; } bool is_orig; /* true if the originator */ bool rem_bd_known; /* true if remote BD addr known */ } tSCO_CONN; /* SCO Management control block */ struct tSCO_CB { tSCO_CONN sco_db[BTM_MAX_SCO_LINKS]; enh_esco_params_t def_esco_parms; bool esco_supported; /* true if 1.2 cntlr AND supports eSCO links */ tSCO_CONN* get_sco_connection_from_index(uint16_t index) { return (index < kMaxScoLinks) ? (&sco_db[index]) : nullptr; } tSCO_CONN* get_sco_connection_from_handle(uint16_t handle) { tSCO_CONN* p_sco = sco_db; for (uint16_t xx = 0; xx < kMaxScoLinks; xx++, p_sco++) { if (p_sco->hci_handle == handle) { return p_sco; } } return nullptr; } void Init(); void Free(); uint16_t get_index(const tSCO_CONN* p_sco) const { bluetooth::log::assert_that(p_sco != nullptr, "assert failed: p_sco != nullptr"); const tSCO_CONN* p = sco_db; for (uint16_t xx = 0; xx < kMaxScoLinks; xx++, p++) { if (p_sco == p) { return xx; } } return 0xffff; } }; void btm_sco_chk_pend_rolechange(uint16_t hci_handle); void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle); /* Send a SCO packet */ void btm_send_sco_packet(std::vector data); bool btm_peer_supports_esco_2m_phy(RawAddress remote_bda); bool btm_peer_supports_esco_3m_phy(RawAddress remote_bda); bool btm_peer_supports_esco_ev3(RawAddress remote_bda);