1 /* 2 * Copyright 2020 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 <aics/api.h> 21 #include <hardware/bt_vc.h> 22 23 #include <algorithm> 24 #include <queue> 25 #include <string> 26 #include <vector> 27 28 #include "bta/include/bta_groups.h" 29 #include "osi/include/alarm.h" 30 #include "types/bluetooth/uuid.h" 31 #include "types/raw_address.h" 32 33 namespace bluetooth { 34 namespace vc { 35 namespace internal { 36 37 /* clang-format off */ 38 /* Volume control point opcodes */ 39 static constexpr uint8_t kControlPointOpcodeVolumeDown = 0x00; 40 static constexpr uint8_t kControlPointOpcodeVolumeUp = 0x01; 41 static constexpr uint8_t kControlPointOpcodeUnmuteVolumeDown = 0x02; 42 static constexpr uint8_t kControlPointOpcodeUnmuteVolumeUp = 0x03; 43 static constexpr uint8_t kControlPointOpcodeSetAbsoluteVolume = 0x04; 44 static constexpr uint8_t kControlPointOpcodeUnmute = 0x05; 45 static constexpr uint8_t kControlPointOpcodeMute = 0x06; 46 47 /* Volume offset control point opcodes */ 48 static constexpr uint8_t kVolumeOffsetControlPointOpcodeSet = 0x01; 49 50 /* Volume input control point opcodes */ 51 static constexpr uint8_t kVolumeInputControlPointOpcodeSetGain = 0x01; 52 static constexpr uint8_t kVolumeInputControlPointOpcodeUnmute = 0x02; 53 static constexpr uint8_t kVolumeInputControlPointOpcodeMute = 0x03; 54 static constexpr uint8_t kVolumeInputControlPointOpcodeSetManualGainMode = 0x04; 55 static constexpr uint8_t kVolumeInputControlPointOpcodeSetAutoGainMode = 0x05; 56 57 static const Uuid kVolumeControlUuid = Uuid::From16Bit(0x1844); 58 static const Uuid kVolumeControlStateUuid = Uuid::From16Bit(0x2B7D); 59 static const Uuid kVolumeControlPointUuid = Uuid::From16Bit(0x2B7E); 60 static const Uuid kVolumeFlagsUuid = Uuid::From16Bit(0x2B7F); 61 62 static const Uuid kVolumeOffsetUuid = Uuid::From16Bit(0x1845); 63 static const Uuid kVolumeOffsetStateUuid = Uuid::From16Bit(0x2B80); 64 static const Uuid kVolumeOffsetLocationUuid = Uuid::From16Bit(0x2B81); 65 static const Uuid kVolumeOffsetControlPointUuid = Uuid::From16Bit(0x2B82); 66 static const Uuid kVolumeOffsetOutputDescriptionUuid = Uuid::From16Bit(0x2B83); 67 68 static const Uuid kVolumeAudioInputUuid = Uuid::From16Bit(0x1843); 69 static const Uuid kVolumeAudioInputStateUuid = Uuid::From16Bit(0x2B77); 70 static const Uuid kVolumeAudioInputGainSettingPropertiesUuid = Uuid::From16Bit(0x2B78); 71 static const Uuid kVolumeAudioInputTypeUuid = Uuid::From16Bit(0x2B79); 72 static const Uuid kVolumeAudioInputStatusUuid = Uuid::From16Bit(0x2B7A); 73 static const Uuid kVolumeAudioInputControlPointUuid = Uuid::From16Bit(0x2B7B); 74 static const Uuid kVolumeAudioInputDescriptionUuid = Uuid::From16Bit(0x2B7C); 75 76 /* clang-format on */ 77 78 struct VolumeOperation { 79 int operation_id_; 80 int group_id_; 81 82 bool started_; 83 bool is_autonomous_; 84 85 uint8_t opcode_; 86 std::vector<uint8_t> arguments_; 87 88 std::vector<RawAddress> devices_; 89 alarm_t* operation_timeout_; 90 VolumeOperationVolumeOperation91 VolumeOperation(int operation_id, int group_id, bool is_autonomous, uint8_t opcode, 92 std::vector<uint8_t> arguments, std::vector<RawAddress> devices) 93 : operation_id_(operation_id), 94 group_id_(group_id), 95 is_autonomous_(is_autonomous), 96 opcode_(opcode), 97 arguments_(arguments), 98 devices_(devices) { 99 auto name = "operation_timeout_" + std::to_string(operation_id); 100 operation_timeout_ = alarm_new(name.c_str()); 101 started_ = false; 102 } 103 104 // Disallow copying due to owning operation_timeout_t which is freed in the 105 // destructor - prevents double free. 106 VolumeOperation(const VolumeOperation&) = delete; 107 VolumeOperation& operator=(const VolumeOperation&) = delete; 108 ~VolumeOperationVolumeOperation109 ~VolumeOperation() { 110 if (operation_timeout_ == nullptr) { 111 log::warn("operation_timeout_ should not be null, id {}, device cnt {}", operation_id_, 112 devices_.size()); 113 return; 114 } 115 116 if (alarm_is_scheduled(operation_timeout_)) { 117 alarm_cancel(operation_timeout_); 118 } 119 120 alarm_free(operation_timeout_); 121 operation_timeout_ = nullptr; 122 } 123 IsGroupOperationVolumeOperation124 bool IsGroupOperation(void) { return group_id_ != bluetooth::groups::kGroupUnknown; } 125 IsStartedVolumeOperation126 bool IsStarted(void) { return started_; } StartVolumeOperation127 void Start(void) { started_ = true; } 128 }; 129 130 struct GainSettings { 131 uint8_t unit = 0; 132 int8_t min = 0; 133 int8_t max = 0; 134 GainSettingsGainSettings135 GainSettings() {} 136 }; 137 138 struct VolumeAudioInput { 139 /* const */ uint8_t id; 140 int8_t gain_setting = 0; 141 bluetooth::aics::Mute mute = bluetooth::aics::Mute::DISABLED; 142 bluetooth::aics::GainMode gain_mode = bluetooth::aics::GainMode::MANUAL_ONLY; 143 VolumeInputStatus status = VolumeInputStatus::Inactive; 144 VolumeInputType type = VolumeInputType::Unspecified; 145 uint8_t change_counter = 0; 146 std::string description = ""; 147 /* const */ uint16_t service_handle; 148 /* const */ uint16_t state_handle; 149 /* const */ uint16_t state_ccc_handle; 150 /* const */ uint16_t gain_setting_handle; 151 /* const */ uint16_t type_handle; 152 /* const */ uint16_t status_handle; 153 /* const */ uint16_t status_ccc_handle; 154 /* const */ uint16_t control_point_handle; 155 /* const */ uint16_t description_handle; 156 /* const */ uint16_t description_ccc_handle; 157 /* const */ bool description_writable; 158 struct GainSettings gain_settings = GainSettings(); 159 VolumeAudioInputVolumeAudioInput160 explicit VolumeAudioInput(uint8_t id, uint16_t service_handle, uint16_t state_handle, 161 uint16_t state_ccc_handle, uint16_t gain_setting_handle, 162 uint16_t type_handle, uint16_t status_handle, 163 uint16_t status_ccc_handle, uint16_t control_point_handle, 164 uint16_t description_handle, uint16_t description_ccc_handle, 165 bool description_writable) 166 : id(id), 167 service_handle(service_handle), 168 state_handle(state_handle), 169 state_ccc_handle(state_ccc_handle), 170 gain_setting_handle(gain_setting_handle), 171 type_handle(type_handle), 172 status_handle(status_handle), 173 status_ccc_handle(status_ccc_handle), 174 control_point_handle(control_point_handle), 175 description_handle(description_handle), 176 description_ccc_handle(description_ccc_handle), 177 description_writable(description_writable) {} 178 }; 179 180 class VolumeAudioInputs { 181 public: Add(VolumeAudioInput input)182 void Add(VolumeAudioInput input) { volume_audio_inputs.push_back(input); } 183 FindByType(VolumeInputType type)184 VolumeAudioInput* FindByType(VolumeInputType type) { 185 auto iter = std::find_if(volume_audio_inputs.begin(), volume_audio_inputs.end(), 186 [&type](const VolumeAudioInput& item) { return item.type == type; }); 187 188 return (iter == volume_audio_inputs.end()) ? nullptr : &(*iter); 189 } 190 FindByServiceHandle(uint16_t service_handle)191 VolumeAudioInput* FindByServiceHandle(uint16_t service_handle) { 192 auto iter = std::find_if(volume_audio_inputs.begin(), volume_audio_inputs.end(), 193 [&service_handle](const VolumeAudioInput& item) { 194 return item.service_handle == service_handle; 195 }); 196 197 return (iter == volume_audio_inputs.end()) ? nullptr : &(*iter); 198 } 199 FindById(uint8_t id)200 VolumeAudioInput* FindById(uint8_t id) { 201 auto iter = std::find_if(volume_audio_inputs.begin(), volume_audio_inputs.end(), 202 [&id](const VolumeAudioInput& item) { return item.id == id; }); 203 204 return (iter == volume_audio_inputs.end()) ? nullptr : &(*iter); 205 } 206 Clear()207 void Clear() { volume_audio_inputs.clear(); } 208 Size()209 size_t Size() { return volume_audio_inputs.size(); } 210 Dump(int fd)211 void Dump(int fd) { 212 std::stringstream stream; 213 int n = Size(); 214 stream << " == number of inputs: " << n << " == \n"; 215 216 for (auto const v : volume_audio_inputs) { 217 stream << " id: " << +v.id << "\n" 218 << " description: " << v.description << "\n" 219 << " type: " << static_cast<int>(v.type) << "\n" 220 << " status: " << static_cast<int>(v.status) << "\n" 221 << " changeCnt: " << +v.change_counter << "\n" 222 << " service_handle: " << +v.service_handle << "\n" 223 << " description_writable" << v.description_writable << "\n"; 224 } 225 dprintf(fd, "%s", stream.str().c_str()); 226 } 227 228 std::vector<VolumeAudioInput> volume_audio_inputs; 229 }; 230 231 struct VolumeOffset { 232 uint8_t id; 233 uint8_t change_counter; 234 int16_t offset; 235 uint32_t location; 236 std::string description; 237 uint16_t service_handle; 238 uint16_t state_handle; 239 uint16_t state_ccc_handle; 240 uint16_t audio_location_handle; 241 uint16_t audio_location_ccc_handle; 242 uint16_t audio_descr_handle; 243 uint16_t audio_descr_ccc_handle; 244 uint16_t control_point_handle; 245 bool audio_location_writable; 246 bool audio_descr_writable; 247 VolumeOffsetVolumeOffset248 explicit VolumeOffset(uint16_t service_handle) 249 : id(0), 250 change_counter(0), 251 offset(0), 252 location(0), 253 description(""), 254 service_handle(service_handle), 255 state_handle(0), 256 state_ccc_handle(0), 257 audio_location_handle(0), 258 audio_location_ccc_handle(0), 259 audio_descr_handle(0), 260 audio_descr_ccc_handle(0), 261 control_point_handle(0), 262 audio_location_writable(false), 263 audio_descr_writable(false) {} 264 }; 265 266 class VolumeOffsets { 267 public: Add(VolumeOffset offset)268 void Add(VolumeOffset offset) { 269 offset.id = static_cast<uint8_t>(Size()) + 1; 270 volume_offsets.push_back(offset); 271 } 272 FindByLocation(uint8_t location)273 VolumeOffset* FindByLocation(uint8_t location) { 274 auto iter = std::find_if( 275 volume_offsets.begin(), volume_offsets.end(), 276 [&location](const VolumeOffset& item) { return item.location == location; }); 277 278 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 279 } 280 FindByServiceHandle(uint16_t service_handle)281 VolumeOffset* FindByServiceHandle(uint16_t service_handle) { 282 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 283 [&service_handle](const VolumeOffset& item) { 284 return item.service_handle == service_handle; 285 }); 286 287 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 288 } 289 FindById(uint16_t id)290 VolumeOffset* FindById(uint16_t id) { 291 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 292 [&id](const VolumeOffset& item) { return item.id == id; }); 293 294 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 295 } 296 Clear()297 void Clear() { volume_offsets.clear(); } 298 Size()299 size_t Size() { return volume_offsets.size(); } 300 Dump(int fd)301 void Dump(int fd) { 302 std::stringstream stream; 303 int n = Size(); 304 stream << " == number of offsets: " << n << " == \n"; 305 306 for (auto const v : volume_offsets) { 307 stream << " id: " << +v.id << "\n" 308 << " offset: " << +v.offset << "\n" 309 << " changeCnt: " << +v.change_counter << "\n" 310 << " location: " << +v.location << "\n" 311 << " description: " << v.description << "\n" 312 << " service_handle: " << +v.service_handle << "\n" 313 << " audio_location_writable " << v.audio_location_writable << "\n" 314 << " audio_descr_writable: " << v.audio_descr_writable << "\n"; 315 } 316 dprintf(fd, "%s", stream.str().c_str()); 317 } 318 319 std::vector<VolumeOffset> volume_offsets; 320 }; 321 322 } // namespace internal 323 } // namespace vc 324 } // namespace bluetooth 325