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 <queue> 21 #include <vector> 22 23 #include "bta/include/bta_groups.h" 24 #include "osi/include/alarm.h" 25 #include "raw_address.h" 26 #include "types/bluetooth/uuid.h" 27 28 namespace bluetooth { 29 namespace vc { 30 namespace internal { 31 32 /* clang-format off */ 33 /* Volume control point opcodes */ 34 static constexpr uint8_t kControlPointOpcodeVolumeDown = 0x00; 35 static constexpr uint8_t kControlPointOpcodeVolumeUp = 0x01; 36 static constexpr uint8_t kControlPointOpcodeUnmuteVolumeDown = 0x02; 37 static constexpr uint8_t kControlPointOpcodeUnmuteVolumeUp = 0x03; 38 static constexpr uint8_t kControlPointOpcodeSetAbsoluteVolume = 0x04; 39 static constexpr uint8_t kControlPointOpcodeUnmute = 0x05; 40 static constexpr uint8_t kControlPointOpcodeMute = 0x06; 41 42 /* Volume offset control point opcodes */ 43 static constexpr uint8_t kVolumeOffsetControlPointOpcodeSet = 0x01; 44 45 /* Volume input control point opcodes */ 46 static constexpr uint8_t kVolumeInputControlPointOpcodeSetGain = 0x01; 47 static constexpr uint8_t kVolumeInputControlPointOpcodeUnmute = 0x02; 48 static constexpr uint8_t kVolumeInputControlPointOpcodeMute = 0x03; 49 static constexpr uint8_t kVolumeInputControlPointOpcodeSetManualGainMode = 0x04; 50 static constexpr uint8_t kVolumeInputControlPointOpcodeSetAutoGainMode = 0x05; 51 52 static const Uuid kVolumeControlUuid = Uuid::From16Bit(0x1844); 53 static const Uuid kVolumeControlStateUuid = Uuid::From16Bit(0x2B7D); 54 static const Uuid kVolumeControlPointUuid = Uuid::From16Bit(0x2B7E); 55 static const Uuid kVolumeFlagsUuid = Uuid::From16Bit(0x2B7F); 56 57 static const Uuid kVolumeOffsetUuid = Uuid::From16Bit(0x1845); 58 static const Uuid kVolumeOffsetStateUuid = Uuid::From16Bit(0x2B80); 59 static const Uuid kVolumeOffsetLocationUuid = Uuid::From16Bit(0x2B81); 60 static const Uuid kVolumeOffsetControlPointUuid = Uuid::From16Bit(0x2B82); 61 static const Uuid kVolumeOffsetOutputDescriptionUuid = Uuid::From16Bit(0x2B83); 62 /* clang-format on */ 63 64 struct VolumeOperation { 65 int operation_id_; 66 int group_id_; 67 68 bool started_; 69 bool is_autonomous_; 70 71 uint8_t opcode_; 72 std::vector<uint8_t> arguments_; 73 74 std::vector<RawAddress> devices_; 75 alarm_t* operation_timeout_; 76 VolumeOperationVolumeOperation77 VolumeOperation(int operation_id, int group_id, bool is_autonomous, uint8_t opcode, 78 std::vector<uint8_t> arguments, 79 std::vector<RawAddress> devices) 80 : operation_id_(operation_id), 81 group_id_(group_id), 82 is_autonomous_(is_autonomous), 83 opcode_(opcode), 84 arguments_(arguments), 85 devices_(devices) { 86 auto name = "operation_timeout_" + std::to_string(operation_id); 87 operation_timeout_ = alarm_new(name.c_str()); 88 started_ = false; 89 }; 90 ~VolumeOperationVolumeOperation91 ~VolumeOperation() { 92 if (operation_timeout_ == nullptr) { 93 log::warn("operation_timeout_ should not be null, id {}, device cnt {}", 94 operation_id_, devices_.size()); 95 return; 96 } 97 98 if (alarm_is_scheduled(operation_timeout_)) 99 alarm_cancel(operation_timeout_); 100 101 alarm_free(operation_timeout_); 102 operation_timeout_ = nullptr; 103 } 104 IsGroupOperationVolumeOperation105 bool IsGroupOperation(void) { 106 return (group_id_ != bluetooth::groups::kGroupUnknown); 107 } 108 IsStartedVolumeOperation109 bool IsStarted(void) { return started_; }; StartVolumeOperation110 void Start(void) { started_ = true; } 111 }; 112 113 struct VolumeOffset { 114 uint8_t id; 115 uint8_t change_counter; 116 int16_t offset; 117 uint32_t location; 118 uint16_t service_handle; 119 uint16_t state_handle; 120 uint16_t state_ccc_handle; 121 uint16_t audio_location_handle; 122 uint16_t audio_location_ccc_handle; 123 uint16_t audio_descr_handle; 124 uint16_t audio_descr_ccc_handle; 125 uint16_t control_point_handle; 126 bool audio_location_writable; 127 bool audio_descr_writable; 128 VolumeOffsetVolumeOffset129 VolumeOffset(uint16_t service_handle) 130 : id(0), 131 change_counter(0), 132 offset(0), 133 location(0), 134 service_handle(service_handle), 135 state_handle(0), 136 state_ccc_handle(0), 137 audio_location_handle(0), 138 audio_location_ccc_handle(0), 139 audio_descr_handle(0), 140 audio_descr_ccc_handle(0), 141 control_point_handle(0), 142 audio_location_writable(false), 143 audio_descr_writable(false) {} 144 }; 145 146 class VolumeOffsets { 147 public: Add(VolumeOffset & offset)148 void Add(VolumeOffset& offset) { 149 offset.id = (uint8_t)Size() + 1; 150 volume_offsets.push_back(offset); 151 } 152 FindByLocation(uint8_t location)153 VolumeOffset* FindByLocation(uint8_t location) { 154 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 155 [&location](const VolumeOffset& item) { 156 return item.location == location; 157 }); 158 159 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 160 } 161 FindByServiceHandle(uint16_t service_handle)162 VolumeOffset* FindByServiceHandle(uint16_t service_handle) { 163 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 164 [&service_handle](const VolumeOffset& item) { 165 return item.service_handle == service_handle; 166 }); 167 168 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 169 } 170 FindById(uint16_t id)171 VolumeOffset* FindById(uint16_t id) { 172 auto iter = 173 std::find_if(volume_offsets.begin(), volume_offsets.end(), 174 [&id](const VolumeOffset& item) { return item.id == id; }); 175 176 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 177 } 178 Clear()179 void Clear() { volume_offsets.clear(); } 180 Size()181 size_t Size() { return volume_offsets.size(); } 182 Dump(int fd)183 void Dump(int fd) { 184 std::stringstream stream; 185 int n = Size(); 186 stream << " == number of offsets: " << n << " == \n"; 187 188 for (int i = 0; i < n; i++) { 189 auto v = volume_offsets[i]; 190 stream << " id: " << +v.id << "\n" 191 << " offset: " << +v.offset << "\n" 192 << " changeCnt: " << +v.change_counter << "\n" 193 << " location: " << +v.location << "\n" 194 << " service_handle: " << +v.service_handle << "\n" 195 << " audio_location_writable " << v.audio_location_writable 196 << "\n" 197 << " audio_descr_writable: " << v.audio_descr_writable << "\n"; 198 } 199 dprintf(fd, "%s", stream.str().c_str()); 200 } 201 202 std::vector<VolumeOffset> volume_offsets; 203 }; 204 205 } // namespace internal 206 } // namespace vc 207 } // namespace bluetooth 208