• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <map>
19 #include <vector>
20 
21 #include "bta_gatt_api.h"
22 #include "bta_gatt_queue.h"
23 #include "devices.h"
24 #include "gatt_api.h"
25 #include "stack/btm/btm_sec.h"
26 #include "types/bluetooth/uuid.h"
27 
28 #include <base/logging.h>
29 
30 using namespace bluetooth::vc::internal;
31 
DeregisterNotifications(tGATT_IF gatt_if)32 void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) {
33   if (volume_state_handle != 0)
34     BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_state_handle);
35 
36   if (volume_flags_handle != 0)
37     BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_flags_handle);
38 
39   for (const VolumeOffset& of : audio_offsets.volume_offsets) {
40     BTA_GATTC_DeregisterForNotifications(gatt_if, address,
41                                          of.audio_descr_handle);
42     BTA_GATTC_DeregisterForNotifications(gatt_if, address,
43                                          of.audio_location_handle);
44     BTA_GATTC_DeregisterForNotifications(gatt_if, address, of.state_handle);
45   }
46 }
47 
Disconnect(tGATT_IF gatt_if)48 void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) {
49   LOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(address);
50 
51   if (IsConnected()) {
52     DeregisterNotifications(gatt_if);
53     BtaGattQueue::Clean(connection_id);
54     BTA_GATTC_Close(connection_id);
55     connection_id = GATT_INVALID_CONN_ID;
56   } else {
57     BTA_GATTC_CancelOpen(gatt_if, address, false);
58   }
59 
60   device_ready = false;
61   handles_pending.clear();
62 }
63 
64 /*
65  * Find the handle for the client characteristics configuration of a given
66  * characteristics
67  */
find_ccc_handle(uint16_t chrc_handle)68 uint16_t VolumeControlDevice::find_ccc_handle(uint16_t chrc_handle) {
69   const gatt::Characteristic* p_char =
70       BTA_GATTC_GetCharacteristic(connection_id, chrc_handle);
71   if (!p_char) {
72     LOG(WARNING) << __func__ << ": no such handle=" << loghex(chrc_handle);
73     return 0;
74   }
75 
76   for (const gatt::Descriptor& desc : p_char->descriptors) {
77     if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
78       return desc.handle;
79   }
80 
81   return 0;
82 }
83 
set_volume_control_service_handles(const gatt::Service & service)84 bool VolumeControlDevice::set_volume_control_service_handles(
85     const gatt::Service& service) {
86   uint16_t state_handle = 0, state_ccc_handle = 0, control_point_handle = 0,
87            flags_handle = 0, flags_ccc_handle = 0;
88 
89   for (const gatt::Characteristic& chrc : service.characteristics) {
90     if (chrc.uuid == kVolumeControlStateUuid) {
91       state_handle = chrc.value_handle;
92       state_ccc_handle = find_ccc_handle(chrc.value_handle);
93     } else if (chrc.uuid == kVolumeControlPointUuid) {
94       control_point_handle = chrc.value_handle;
95     } else if (chrc.uuid == kVolumeFlagsUuid) {
96       flags_handle = chrc.value_handle;
97       flags_ccc_handle = find_ccc_handle(chrc.value_handle);
98     } else {
99       LOG(WARNING) << __func__ << ": unknown characteristic=" << chrc.uuid;
100     }
101   }
102 
103   // Validate service handles
104   if (GATT_HANDLE_IS_VALID(state_handle) &&
105       GATT_HANDLE_IS_VALID(state_ccc_handle) &&
106       GATT_HANDLE_IS_VALID(control_point_handle) &&
107       GATT_HANDLE_IS_VALID(flags_handle)
108       /* volume_flags_ccc_handle is optional */) {
109     volume_state_handle = state_handle;
110     volume_state_ccc_handle = state_ccc_handle;
111     volume_control_point_handle = control_point_handle;
112     volume_flags_handle = flags_handle;
113     volume_flags_ccc_handle = flags_ccc_handle;
114     return true;
115   }
116 
117   return false;
118 }
119 
set_volume_offset_control_service_handles(const gatt::Service & service)120 void VolumeControlDevice::set_volume_offset_control_service_handles(
121     const gatt::Service& service) {
122   VolumeOffset offset = VolumeOffset(service.handle);
123 
124   for (const gatt::Characteristic& chrc : service.characteristics) {
125     if (chrc.uuid == kVolumeOffsetStateUuid) {
126       offset.state_handle = chrc.value_handle;
127       offset.state_ccc_handle = find_ccc_handle(chrc.value_handle);
128 
129     } else if (chrc.uuid == kVolumeOffsetLocationUuid) {
130       offset.audio_location_handle = chrc.value_handle;
131       offset.audio_location_ccc_handle = find_ccc_handle(chrc.value_handle);
132       offset.audio_location_writable =
133           chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
134 
135     } else if (chrc.uuid == kVolumeOffsetControlPointUuid) {
136       offset.control_point_handle = chrc.value_handle;
137 
138     } else if (chrc.uuid == kVolumeOffsetOutputDescriptionUuid) {
139       offset.audio_descr_handle = chrc.value_handle;
140       offset.audio_descr_ccc_handle = find_ccc_handle(chrc.value_handle);
141       offset.audio_descr_writable =
142           chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
143 
144     } else {
145       LOG(WARNING) << __func__ << ": unknown characteristic=" << chrc.uuid;
146     }
147   }
148 
149   // Check if all mandatory attributes are present
150   if (GATT_HANDLE_IS_VALID(offset.state_handle) &&
151       GATT_HANDLE_IS_VALID(offset.state_ccc_handle) &&
152       GATT_HANDLE_IS_VALID(offset.audio_location_handle) &&
153       /* audio_location_ccc_handle is optional */
154       GATT_HANDLE_IS_VALID(offset.control_point_handle) &&
155       GATT_HANDLE_IS_VALID(offset.audio_descr_handle)
156       /* audio_descr_ccc_handle is optional */) {
157     audio_offsets.Add(offset);
158     LOG(INFO) << "Offset added id=" << loghex(offset.id);
159   } else {
160     LOG(WARNING) << "Ignoring offset handle=" << loghex(service.handle);
161   }
162 }
163 
UpdateHandles(void)164 bool VolumeControlDevice::UpdateHandles(void) {
165   ResetHandles();
166 
167   bool vcs_found = false;
168   const std::list<gatt::Service>* services =
169       BTA_GATTC_GetServices(connection_id);
170   if (services == nullptr) {
171     LOG(ERROR) << "No services found";
172     return false;
173   }
174 
175   for (auto const& service : *services) {
176     if (service.uuid == kVolumeControlUuid) {
177       LOG(INFO) << "Found VCS, handle=" << loghex(service.handle);
178       vcs_found = set_volume_control_service_handles(service);
179       if (!vcs_found) break;
180 
181       known_service_handles_ = true;
182       for (auto const& included : service.included_services) {
183         const gatt::Service* service =
184             BTA_GATTC_GetOwningService(connection_id, included.start_handle);
185         if (service == nullptr) continue;
186 
187         if (included.uuid == kVolumeOffsetUuid) {
188           LOG(INFO) << "Found VOCS, handle=" << loghex(service->handle);
189           set_volume_offset_control_service_handles(*service);
190 
191         } else {
192           LOG(WARNING) << __func__ << ": unknown service=" << service->uuid;
193         }
194       }
195     }
196   }
197 
198   return vcs_found;
199 }
200 
ResetHandles(void)201 void VolumeControlDevice::ResetHandles(void) {
202   known_service_handles_ = false;
203   device_ready = false;
204 
205   // the handles are not valid, so discard pending GATT operations
206   BtaGattQueue::Clean(connection_id);
207 
208   volume_state_handle = 0;
209   volume_state_ccc_handle = 0;
210   volume_control_point_handle = 0;
211   volume_flags_handle = 0;
212   volume_flags_ccc_handle = 0;
213 
214   if (audio_offsets.Size() != 0) audio_offsets.Clear();
215 }
216 
ControlPointOperation(uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)217 void VolumeControlDevice::ControlPointOperation(uint8_t opcode,
218                                                 const std::vector<uint8_t>* arg,
219                                                 GATT_WRITE_OP_CB cb,
220                                                 void* cb_data) {
221   std::vector<uint8_t> set_value({opcode, change_counter});
222   if (arg != nullptr)
223     set_value.insert(set_value.end(), (*arg).begin(), (*arg).end());
224 
225   BtaGattQueue::WriteCharacteristic(connection_id, volume_control_point_handle,
226                                     set_value, GATT_WRITE, cb, cb_data);
227 }
228 
subscribe_for_notifications(tGATT_IF gatt_if,uint16_t handle,uint16_t ccc_handle,GATT_WRITE_OP_CB cb)229 bool VolumeControlDevice::subscribe_for_notifications(tGATT_IF gatt_if,
230                                                       uint16_t handle,
231                                                       uint16_t ccc_handle,
232                                                       GATT_WRITE_OP_CB cb) {
233   tGATT_STATUS status =
234       BTA_GATTC_RegisterForNotifications(gatt_if, address, handle);
235   if (status != GATT_SUCCESS) {
236     LOG(ERROR) << __func__ << ": failed, status=" << loghex(+status);
237     return false;
238   }
239 
240   std::vector<uint8_t> value(2);
241   uint8_t* ptr = value.data();
242   UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION);
243   BtaGattQueue::WriteDescriptor(connection_id, ccc_handle, std::move(value),
244                                 GATT_WRITE, cb, nullptr);
245 
246   return true;
247 }
248 
249 /**
250  * Enqueue GATT requests that are required by the Volume Control to be
251  * functional. This includes State characteristics read and subscription.
252  * Those characteristics contain the change counter needed to send any request
253  * via Control Point. Once completed successfully, the device can be stored
254  * and reported as connected. In each case we subscribe first to be sure we do
255  * not miss any value change.
256  */
EnqueueInitialRequests(tGATT_IF gatt_if,GATT_READ_OP_CB chrc_read_cb,GATT_WRITE_OP_CB cccd_write_cb)257 bool VolumeControlDevice::EnqueueInitialRequests(
258     tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
259     GATT_WRITE_OP_CB cccd_write_cb) {
260   handles_pending.clear();
261   handles_pending.insert(volume_state_handle);
262   handles_pending.insert(volume_state_ccc_handle);
263   if (!subscribe_for_notifications(gatt_if, volume_state_handle,
264                                    volume_state_ccc_handle, cccd_write_cb)) {
265     return false;
266   }
267 
268   for (auto const& offset : audio_offsets.volume_offsets) {
269     handles_pending.insert(offset.state_handle);
270     handles_pending.insert(offset.state_ccc_handle);
271     if (!subscribe_for_notifications(gatt_if, offset.state_handle,
272                                      offset.state_ccc_handle, cccd_write_cb)) {
273       return false;
274     }
275 
276     BtaGattQueue::ReadCharacteristic(connection_id, offset.state_handle,
277                                      chrc_read_cb, nullptr);
278   }
279 
280   BtaGattQueue::ReadCharacteristic(connection_id, volume_state_handle,
281                                    chrc_read_cb, nullptr);
282 
283   return true;
284 }
285 
286 /**
287  * Enqueue the remaining requests. Those are not so crucial and can be done
288  * once Volume Control instance indicates it's readiness to profile.
289  * This includes characteristics read and subscription.
290  * In each case we subscribe first to be sure we do not miss any value change.
291  */
EnqueueRemainingRequests(tGATT_IF gatt_if,GATT_READ_OP_CB chrc_read_cb,GATT_WRITE_OP_CB cccd_write_cb)292 void VolumeControlDevice::EnqueueRemainingRequests(
293     tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
294     GATT_WRITE_OP_CB cccd_write_cb) {
295   std::map<uint16_t, uint16_t> handle_pairs{
296       {volume_flags_handle, volume_flags_ccc_handle},
297   };
298 
299   for (auto const& offset : audio_offsets.volume_offsets) {
300     handle_pairs[offset.audio_location_handle] =
301         offset.audio_location_ccc_handle;
302     handle_pairs[offset.audio_descr_handle] = offset.audio_descr_ccc_handle;
303   }
304 
305   for (auto const& handles : handle_pairs) {
306     if (GATT_HANDLE_IS_VALID(handles.second)) {
307       subscribe_for_notifications(gatt_if, handles.first, handles.second,
308                                   cccd_write_cb);
309     }
310 
311     BtaGattQueue::ReadCharacteristic(connection_id, handles.first, chrc_read_cb,
312                                      nullptr);
313   }
314 }
315 
VerifyReady(uint16_t handle)316 bool VolumeControlDevice::VerifyReady(uint16_t handle) {
317   handles_pending.erase(handle);
318   device_ready = handles_pending.size() == 0;
319   return device_ready;
320 }
321 
GetExtAudioOutVolumeOffset(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)322 void VolumeControlDevice::GetExtAudioOutVolumeOffset(uint8_t ext_output_id,
323                                                      GATT_READ_OP_CB cb,
324                                                      void* cb_data) {
325   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
326   if (!offset) {
327     LOG(ERROR) << __func__ << ": no such offset!";
328     return;
329   }
330 
331   BtaGattQueue::ReadCharacteristic(connection_id, offset->state_handle, cb,
332                                    cb_data);
333 }
334 
GetExtAudioOutLocation(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)335 void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id,
336                                                  GATT_READ_OP_CB cb,
337                                                  void* cb_data) {
338   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
339   if (!offset) {
340     LOG(ERROR) << __func__ << ": no such offset!";
341     return;
342   }
343 
344   BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_location_handle,
345                                    cb, cb_data);
346 }
347 
SetExtAudioOutLocation(uint8_t ext_output_id,uint32_t location)348 void VolumeControlDevice::SetExtAudioOutLocation(uint8_t ext_output_id,
349                                                  uint32_t location) {
350   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
351   if (!offset) {
352     LOG(ERROR) << __func__ << ": no such offset!";
353     return;
354   }
355 
356   if (!offset->audio_location_writable) {
357     LOG(WARNING) << __func__ << ": not writable";
358     return;
359   }
360 
361   std::vector<uint8_t> value(4);
362   uint8_t* ptr = value.data();
363   UINT32_TO_STREAM(ptr, location);
364   BtaGattQueue::WriteCharacteristic(connection_id,
365                                     offset->audio_location_handle, value,
366                                     GATT_WRITE_NO_RSP, nullptr, nullptr);
367 }
368 
GetExtAudioOutDescription(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)369 void VolumeControlDevice::GetExtAudioOutDescription(uint8_t ext_output_id,
370                                                     GATT_READ_OP_CB cb,
371                                                     void* cb_data) {
372   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
373   if (!offset) {
374     LOG(ERROR) << __func__ << ": no such offset!";
375     return;
376   }
377 
378   BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_descr_handle,
379                                    cb, cb_data);
380 }
381 
SetExtAudioOutDescription(uint8_t ext_output_id,std::string & descr)382 void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id,
383                                                     std::string& descr) {
384   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
385   if (!offset) {
386     LOG(ERROR) << __func__ << ": no such offset!";
387     return;
388   }
389 
390   if (!offset->audio_descr_writable) {
391     LOG(WARNING) << __func__ << ": not writable";
392     return;
393   }
394 
395   std::vector<uint8_t> value(descr.begin(), descr.end());
396   BtaGattQueue::WriteCharacteristic(connection_id, offset->audio_descr_handle,
397                                     value, GATT_WRITE_NO_RSP, nullptr, nullptr);
398 }
399 
ExtAudioOutControlPointOperation(uint8_t ext_output_id,uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)400 void VolumeControlDevice::ExtAudioOutControlPointOperation(
401     uint8_t ext_output_id, uint8_t opcode, const std::vector<uint8_t>* arg,
402     GATT_WRITE_OP_CB cb, void* cb_data) {
403   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
404   if (!offset) {
405     LOG(ERROR) << __func__ << ": no such offset!";
406     return;
407   }
408 
409   std::vector<uint8_t> set_value({opcode, offset->change_counter});
410   if (arg != nullptr)
411     set_value.insert(set_value.end(), (*arg).begin(), (*arg).end());
412 
413   BtaGattQueue::WriteCharacteristic(connection_id, offset->control_point_handle,
414                                     set_value, GATT_WRITE, cb, cb_data);
415 }
416 
IsEncryptionEnabled()417 bool VolumeControlDevice::IsEncryptionEnabled() {
418   return BTM_IsEncrypted(address, BT_TRANSPORT_LE);
419 }
420 
EnableEncryption()421 void VolumeControlDevice::EnableEncryption() {
422   int result = BTM_SetEncryption(address, BT_TRANSPORT_LE, nullptr, nullptr,
423                                  BTM_BLE_SEC_ENCRYPT);
424   LOG(INFO) << __func__ << ": result=" << +result;
425 }
426