1 /* 2 * Copyright 2021 HIMSA II K/S - www.himsa.com. 3 * Represented by EHIMA - www.ehima.com 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #pragma once 19 20 #include <cstdint> 21 #include <unordered_set> 22 #include <vector> 23 24 #include "bta/include/bta_gatt_api.h" 25 #include "bta/vc/types.h" 26 #include "include/hardware/bt_vc.h" 27 #include "types/raw_address.h" 28 29 namespace bluetooth { 30 namespace vc { 31 namespace internal { 32 33 class VolumeControlDevice { 34 public: 35 RawAddress address; 36 /* This is true only during first connection to profile, until we store the 37 * device 38 */ 39 bool first_connection; 40 41 /* we are making active attempt to connect to this device, 'direct connect'. 42 * This is true only during initial phase of first connection. */ 43 bool connecting_actively; 44 45 bool service_changed_rcvd; 46 47 uint8_t volume; 48 uint8_t change_counter; 49 bool mute; 50 uint8_t flags; 51 52 uint16_t connection_id; 53 54 /* Volume Control Service */ 55 uint16_t volume_state_handle; 56 uint16_t volume_state_ccc_handle; 57 uint16_t volume_control_point_handle; 58 uint16_t volume_flags_handle; 59 uint16_t volume_flags_ccc_handle; 60 61 bool device_ready; /* Set when device read server status and registgered for 62 notifications */ 63 VolumeControlDevice(const RawAddress & address,bool first_connection)64 VolumeControlDevice(const RawAddress& address, bool first_connection) 65 : address(address), 66 first_connection(first_connection), 67 connecting_actively(first_connection), 68 service_changed_rcvd(false), 69 volume(0), 70 change_counter(0), 71 mute(false), 72 flags(0), 73 connection_id(GATT_INVALID_CONN_ID), 74 volume_state_handle(0), 75 volume_state_ccc_handle(0), 76 volume_control_point_handle(0), 77 volume_flags_handle(0), 78 volume_flags_ccc_handle(0), 79 device_ready(false) {} 80 81 ~VolumeControlDevice() = default; 82 ToString()83 inline std::string ToString() { return address.ToString(); } 84 DebugDump(int fd)85 void DebugDump(int fd) { dprintf(fd, "%s\n", this->ToString().c_str()); } 86 IsConnected()87 bool IsConnected() { return connection_id != GATT_INVALID_CONN_ID; } 88 89 void Disconnect(tGATT_IF gatt_if); 90 91 bool UpdateHandles(void); 92 93 void ResetHandles(void); 94 HasHandles(void)95 bool HasHandles(void) { return GATT_HANDLE_IS_VALID(volume_state_handle); } 96 97 void ControlPointOperation(uint8_t opcode, const std::vector<uint8_t>* arg, 98 GATT_WRITE_OP_CB cb, void* cb_data); 99 bool IsEncryptionEnabled(); 100 101 bool EnableEncryption(tBTM_SEC_CALLBACK* callback); 102 103 bool EnqueueInitialRequests(tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb, 104 GATT_WRITE_OP_CB cccd_write_cb); 105 void EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb, 106 GATT_WRITE_OP_CB cccd_write_cb); 107 bool VerifyReady(uint16_t handle); 108 109 private: 110 /* 111 * This is used to track the pending GATT operation handles. Once the list is 112 * empty the device is assumed ready and connected. We are doing it because we 113 * want to make sure all the required characteristics and descritors are 114 * available on server side. 115 */ 116 std::unordered_set<uint16_t> handles_pending; 117 118 uint16_t find_ccc_handle(uint16_t chrc_handle); 119 bool set_volume_control_service_handles(const gatt::Service& service); 120 bool subscribe_for_notifications(tGATT_IF gatt_if, uint16_t handle, 121 uint16_t ccc_handle, GATT_WRITE_OP_CB cb); 122 }; 123 124 class VolumeControlDevices { 125 public: Add(const RawAddress & address,bool first_connection)126 void Add(const RawAddress& address, bool first_connection) { 127 if (FindByAddress(address) != nullptr) return; 128 129 devices_.emplace_back(address, first_connection); 130 } 131 Remove(const RawAddress & address)132 void Remove(const RawAddress& address) { 133 for (auto it = devices_.begin(); it != devices_.end(); it++) { 134 if (it->address == address) { 135 it = devices_.erase(it); 136 break; 137 } 138 } 139 } 140 FindByAddress(const RawAddress & address)141 VolumeControlDevice* FindByAddress(const RawAddress& address) { 142 auto iter = std::find_if(devices_.begin(), devices_.end(), 143 [&address](const VolumeControlDevice& device) { 144 return device.address == address; 145 }); 146 147 return (iter == devices_.end()) ? nullptr : &(*iter); 148 } 149 FindByConnId(uint16_t connection_id)150 VolumeControlDevice* FindByConnId(uint16_t connection_id) { 151 auto iter = 152 std::find_if(devices_.begin(), devices_.end(), 153 [&connection_id](const VolumeControlDevice& device) { 154 return device.connection_id == connection_id; 155 }); 156 157 return (iter == devices_.end()) ? nullptr : &(*iter); 158 } 159 Size()160 size_t Size() { return (devices_.size()); } 161 Clear()162 void Clear() { devices_.clear(); } 163 DebugDump(int fd)164 void DebugDump(int fd) { 165 for (auto& device : devices_) { 166 device.DebugDump(fd); 167 } 168 } 169 Disconnect(tGATT_IF gatt_if)170 void Disconnect(tGATT_IF gatt_if) { 171 for (auto& device : devices_) { 172 device.Disconnect(gatt_if); 173 } 174 } 175 ControlPointOperation(std::vector<RawAddress> & devices,uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)176 void ControlPointOperation(std::vector<RawAddress>& devices, uint8_t opcode, 177 const std::vector<uint8_t>* arg, 178 GATT_WRITE_OP_CB cb, void* cb_data) { 179 for (auto& addr : devices) { 180 VolumeControlDevice* device = FindByAddress(addr); 181 if (device && device->IsConnected()) 182 device->ControlPointOperation(opcode, arg, cb, cb_data); 183 } 184 } 185 186 private: 187 std::vector<VolumeControlDevice> devices_; 188 }; 189 190 } // namespace internal 191 } // namespace vc 192 } // namespace bluetooth 193