| /* |
| * 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 <cstdint> |
| #include <string> |
| |
| #include "device/include/esco_parameters.h" |
| #include "stack/include/btm_api_types.h" |
| |
| constexpr uint16_t kMaxScoLinks = static_cast<uint16_t>(BTM_MAX_SCO_LINKS); |
| |
| #ifndef ESCO_DATA_PATH |
| #ifdef OS_ANDROID |
| #define ESCO_DATA_PATH ESCO_DATA_PATH_PCM |
| #else |
| #define ESCO_DATA_PATH ESCO_DATA_PATH_HCI |
| #endif |
| #endif |
| |
| // 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 from the socket (audio server) for SCO Tx |
| size_t read(uint8_t* p_buf, uint32_t len); |
| |
| // Write to the socket from SCO Rx |
| size_t write(const uint8_t* buf, uint32_t len); |
| } // namespace bluetooth::audio::sco |
| |
| /* 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 SCO_ST_UNUSED: |
| return std::string("unused"); |
| case SCO_ST_LISTENING: |
| return std::string("listening"); |
| case SCO_ST_W4_CONN_RSP: |
| return std::string("connect_response"); |
| case SCO_ST_CONNECTING: |
| return std::string("connecting"); |
| case SCO_ST_CONNECTED: |
| return std::string("connected"); |
| case SCO_ST_DISCONNECTING: |
| return std::string("disconnecting"); |
| case SCO_ST_PEND_UNPARK: |
| return std::string("pending_unpark"); |
| case SCO_ST_PEND_ROLECHANGE: |
| return std::string("pending_role_change"); |
| case SCO_ST_PEND_MODECHANGE: |
| return std::string("pending_mode_change"); |
| } |
| } |
| |
| /* 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; } |
| 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 */ |
| typedef struct { |
| 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() { |
| def_esco_parms = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3); |
| bluetooth::audio::sco::init(); |
| } |
| |
| uint16_t get_index(const tSCO_CONN* p_sco) const { |
| CHECK(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; |
| } |
| |
| } tSCO_CB; |
| |
| extern void btm_sco_chk_pend_rolechange(uint16_t hci_handle); |
| extern void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle); |
| |
| // Visible for test only |
| BT_HDR* btm_sco_make_packet(std::vector<uint8_t> data, uint16_t sco_handle); |
| |
| // Send a SCO packet |
| void btm_send_sco_packet(std::vector<uint8_t> data); |