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