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 (alarm_is_scheduled(operation_timeout_)) 93 alarm_cancel(operation_timeout_); 94 95 alarm_free(operation_timeout_); 96 operation_timeout_ = nullptr; 97 } 98 IsGroupOperationVolumeOperation99 bool IsGroupOperation(void) { 100 return (group_id_ != bluetooth::groups::kGroupUnknown); 101 } 102 IsStartedVolumeOperation103 bool IsStarted(void) { return started_; }; StartVolumeOperation104 void Start(void) { started_ = true; } 105 }; 106 107 struct VolumeOffset { 108 uint8_t id; 109 uint8_t change_counter; 110 int16_t offset; 111 uint32_t location; 112 uint16_t service_handle; 113 uint16_t state_handle; 114 uint16_t state_ccc_handle; 115 uint16_t audio_location_handle; 116 uint16_t audio_location_ccc_handle; 117 uint16_t audio_descr_handle; 118 uint16_t audio_descr_ccc_handle; 119 uint16_t control_point_handle; 120 bool audio_location_writable; 121 bool audio_descr_writable; 122 VolumeOffsetVolumeOffset123 VolumeOffset(uint16_t service_handle) 124 : id(0), 125 change_counter(0), 126 offset(0), 127 location(0), 128 service_handle(service_handle), 129 state_handle(0), 130 state_ccc_handle(0), 131 audio_location_handle(0), 132 audio_location_ccc_handle(0), 133 audio_descr_handle(0), 134 audio_descr_ccc_handle(0), 135 control_point_handle(0), 136 audio_location_writable(false), 137 audio_descr_writable(false) {} 138 }; 139 140 class VolumeOffsets { 141 public: Add(VolumeOffset & offset)142 void Add(VolumeOffset& offset) { 143 offset.id = (uint8_t)Size() + 1; 144 volume_offsets.push_back(offset); 145 } 146 FindByLocation(uint8_t location)147 VolumeOffset* FindByLocation(uint8_t location) { 148 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 149 [&location](const VolumeOffset& item) { 150 return item.location == location; 151 }); 152 153 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 154 } 155 FindByServiceHandle(uint16_t service_handle)156 VolumeOffset* FindByServiceHandle(uint16_t service_handle) { 157 auto iter = std::find_if(volume_offsets.begin(), volume_offsets.end(), 158 [&service_handle](const VolumeOffset& item) { 159 return item.service_handle == service_handle; 160 }); 161 162 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 163 } 164 FindById(uint16_t id)165 VolumeOffset* FindById(uint16_t id) { 166 auto iter = 167 std::find_if(volume_offsets.begin(), volume_offsets.end(), 168 [&id](const VolumeOffset& item) { return item.id == id; }); 169 170 return (iter == volume_offsets.end()) ? nullptr : &(*iter); 171 } 172 Clear()173 void Clear() { volume_offsets.clear(); } 174 Size()175 size_t Size() { return volume_offsets.size(); } 176 Dump(int fd)177 void Dump(int fd) { 178 std::stringstream stream; 179 int n = Size(); 180 stream << " == number of offsets: " << n << " == \n"; 181 182 for (int i = 0; i < n; i++) { 183 auto v = volume_offsets[i]; 184 stream << " id: " << +v.id << "\n" 185 << " offset: " << +v.offset << "\n" 186 << " changeCnt: " << +v.change_counter << "\n" 187 << " location: " << +v.location << "\n" 188 << " service_handle: " << +v.service_handle << "\n" 189 << " audio_location_writable " << v.audio_location_writable 190 << "\n" 191 << " audio_descr_writable: " << v.audio_descr_writable << "\n"; 192 } 193 dprintf(fd, "%s", stream.str().c_str()); 194 } 195 196 std::vector<VolumeOffset> volume_offsets; 197 }; 198 199 } // namespace internal 200 } // namespace vc 201 } // namespace bluetooth 202