1 /*
2 * Copyright 2021 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 <base/bind.h>
19 #include <base/bind_helpers.h>
20 #include <base/logging.h>
21 #include <base/strings/string_number_conversions.h>
22 #include <hardware/bt_vc.h>
23
24 #include <string>
25 #include <vector>
26
27 #include "bta_gatt_api.h"
28 #include "bta_gatt_queue.h"
29 #include "bta_vc_api.h"
30 #include "btif_storage.h"
31 #include "devices.h"
32
33 using base::Closure;
34 using bluetooth::Uuid;
35 using bluetooth::vc::ConnectionState;
36 using namespace bluetooth::vc::internal;
37
38 namespace {
39 class VolumeControlImpl;
40 VolumeControlImpl* instance;
41
42 /**
43 * Overview:
44 *
45 * This is Volume Control Implementation class which realize Volume Control
46 * Profile (VCP)
47 *
48 * Each connected peer device supporting Volume Control Service (VCS) is on the
49 * list of devices (volume_control_devices_).
50 *
51 * Once all the mandatory characteristis for all the services are discovered,
52 * Fluoride calls ON_CONNECTED callback.
53 *
54 * It is assumed that whenever application changes general audio options in this
55 * profile e.g. Volume up/down, mute/unmute etc, profile configures all the
56 * devices which are active Le Audio devices.
57 *
58 *
59 */
60 class VolumeControlImpl : public VolumeControl {
61 public:
62 ~VolumeControlImpl() override = default;
63
VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks * callbacks)64 VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks* callbacks)
65 : gatt_if_(0), callbacks_(callbacks) {
66 BTA_GATTC_AppRegister(
67 gattc_callback_static,
68 base::Bind([](uint8_t client_id, uint8_t status) {
69 if (status != GATT_SUCCESS) {
70 LOG(ERROR) << "Can't start Volume Control profile - no gatt "
71 "clients left!";
72 return;
73 }
74 instance->gatt_if_ = client_id;
75 }),
76 true);
77 }
78
Connect(const RawAddress & address)79 void Connect(const RawAddress& address) override {
80 LOG(INFO) << __func__ << " " << address;
81
82 auto device = volume_control_devices_.FindByAddress(address);
83 if (!device) {
84 volume_control_devices_.Add(address, true);
85 } else {
86 device->connecting_actively = true;
87 }
88
89 BTA_GATTC_Open(gatt_if_, address, true, false);
90 }
91
AddFromStorage(const RawAddress & address,bool auto_connect)92 void AddFromStorage(const RawAddress& address, bool auto_connect) {
93 LOG(INFO) << __func__ << " " << address
94 << ", auto_connect=" << auto_connect;
95
96 if (auto_connect) {
97 volume_control_devices_.Add(address, false);
98
99 /* Add device into BG connection to accept remote initiated connection */
100 BTA_GATTC_Open(gatt_if_, address, false, false);
101 }
102 }
103
OnGattConnected(tGATT_STATUS status,uint16_t connection_id,tGATT_IF,RawAddress address,tBT_TRANSPORT,uint16_t)104 void OnGattConnected(tGATT_STATUS status, uint16_t connection_id,
105 tGATT_IF /*client_if*/, RawAddress address,
106 tBT_TRANSPORT /*transport*/, uint16_t /*mtu*/) {
107 LOG(INFO) << __func__ << ": address=" << address
108 << ", connection_id=" << connection_id;
109
110 VolumeControlDevice* device =
111 volume_control_devices_.FindByAddress(address);
112 if (!device) {
113 LOG(ERROR) << __func__ << "Skipping unknown device, address=" << address;
114 return;
115 }
116
117 if (status != GATT_SUCCESS) {
118 LOG(INFO) << "Failed to connect to Volume Control device";
119 device_cleanup_helper(device, device->connecting_actively);
120 return;
121 }
122
123 device->connection_id = connection_id;
124
125 if (device->IsEncryptionEnabled()) {
126 OnEncryptionComplete(address, BTM_SUCCESS);
127 return;
128 }
129
130 if (!device->EnableEncryption(enc_callback_static)) {
131 device_cleanup_helper(device, device->connecting_actively);
132 }
133 }
134
OnEncryptionComplete(const RawAddress & address,uint8_t success)135 void OnEncryptionComplete(const RawAddress& address, uint8_t success) {
136 VolumeControlDevice* device =
137 volume_control_devices_.FindByAddress(address);
138 if (!device) {
139 LOG(ERROR) << __func__ << "Skipping unknown device" << address;
140 return;
141 }
142
143 if (success != BTM_SUCCESS) {
144 LOG(ERROR) << "encryption failed "
145 << "status: " << int{success};
146 // If the encryption failed, do not remove the device.
147 // Disconnect only, since the Android will try to re-enable encryption
148 // after disconnection
149 device->Disconnect(gatt_if_);
150 if (device->connecting_actively)
151 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
152 device->address);
153 return;
154 }
155
156 LOG(INFO) << __func__ << " " << address << "status: " << success;
157
158 if (device->HasHandles()) {
159 device->EnqueueInitialRequests(gatt_if_, chrc_read_callback_static,
160 OnGattWriteCccStatic);
161
162 } else {
163 device->first_connection = true;
164 BTA_GATTC_ServiceSearchRequest(device->connection_id,
165 &kVolumeControlUuid);
166 }
167 }
168
OnServiceChangeEvent(const RawAddress & address)169 void OnServiceChangeEvent(const RawAddress& address) {
170 VolumeControlDevice* device =
171 volume_control_devices_.FindByAddress(address);
172 if (!device) {
173 LOG(ERROR) << __func__ << "Skipping unknown device" << address;
174 return;
175 }
176 LOG(INFO) << __func__ << ": address=" << address;
177 device->first_connection = true;
178 device->service_changed_rcvd = true;
179 BtaGattQueue::Clean(device->connection_id);
180 }
181
OnServiceDiscDoneEvent(const RawAddress & address)182 void OnServiceDiscDoneEvent(const RawAddress& address) {
183 VolumeControlDevice* device =
184 volume_control_devices_.FindByAddress(address);
185 if (!device) {
186 LOG(ERROR) << __func__ << "Skipping unknown device" << address;
187 return;
188 }
189
190 if (device->service_changed_rcvd)
191 BTA_GATTC_ServiceSearchRequest(device->connection_id,
192 &kVolumeControlUuid);
193 }
194
OnServiceSearchComplete(uint16_t connection_id,tGATT_STATUS status)195 void OnServiceSearchComplete(uint16_t connection_id, tGATT_STATUS status) {
196 VolumeControlDevice* device =
197 volume_control_devices_.FindByConnId(connection_id);
198 if (!device) {
199 LOG(ERROR) << __func__ << "Skipping unknown device, connection_id="
200 << loghex(connection_id);
201 return;
202 }
203
204 /* Known device, nothing to do */
205 if (!device->first_connection) return;
206
207 if (status != GATT_SUCCESS) {
208 /* close connection and report service discovery complete with error */
209 LOG(ERROR) << "Service discovery failed";
210 device_cleanup_helper(device, device->first_connection);
211 return;
212 }
213
214 bool success = device->UpdateHandles();
215 if (!success) {
216 LOG(ERROR) << "Incomplete service database";
217 device_cleanup_helper(device, true);
218 return;
219 }
220
221 device->EnqueueInitialRequests(gatt_if_, chrc_read_callback_static,
222 OnGattWriteCccStatic);
223 }
224
OnCharacteristicValueChanged(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void *)225 void OnCharacteristicValueChanged(uint16_t conn_id, tGATT_STATUS status,
226 uint16_t handle, uint16_t len,
227 uint8_t* value, void* /* data */) {
228 VolumeControlDevice* device = volume_control_devices_.FindByConnId(conn_id);
229 if (!device) {
230 LOG(INFO) << __func__ << ": unknown conn_id=" << loghex(conn_id);
231 return;
232 }
233
234 if (status != GATT_SUCCESS) {
235 LOG(INFO) << __func__ << ": status=" << static_cast<int>(status);
236 return;
237 }
238
239 if (handle == device->volume_state_handle) {
240 OnVolumeControlStateChanged(device, len, value);
241 verify_device_ready(device, handle);
242 return;
243 }
244 if (handle == device->volume_flags_handle) {
245 OnVolumeControlFlagsChanged(device, len, value);
246 verify_device_ready(device, handle);
247 return;
248 }
249
250 LOG(ERROR) << __func__ << ": unknown handle=" << loghex(handle);
251 }
252
OnNotificationEvent(uint16_t conn_id,uint16_t handle,uint16_t len,uint8_t * value)253 void OnNotificationEvent(uint16_t conn_id, uint16_t handle, uint16_t len,
254 uint8_t* value) {
255 LOG(INFO) << __func__ << ": handle=" << loghex(handle);
256 OnCharacteristicValueChanged(conn_id, GATT_SUCCESS, handle, len, value,
257 nullptr);
258 }
259
VolumeControlReadCommon(uint16_t conn_id,uint16_t handle)260 void VolumeControlReadCommon(uint16_t conn_id, uint16_t handle) {
261 BtaGattQueue::ReadCharacteristic(conn_id, handle, chrc_read_callback_static,
262 nullptr);
263 }
264
OnVolumeControlStateChanged(VolumeControlDevice * device,uint16_t len,uint8_t * value)265 void OnVolumeControlStateChanged(VolumeControlDevice* device, uint16_t len,
266 uint8_t* value) {
267 if (len != 3) {
268 LOG(INFO) << __func__ << ": malformed len=" << loghex(len);
269 return;
270 }
271
272 uint8_t* pp = value;
273 STREAM_TO_UINT8(device->volume, pp);
274 STREAM_TO_UINT8(device->mute, pp);
275 STREAM_TO_UINT8(device->change_counter, pp);
276
277 LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
278 LOG(INFO) << __func__ << "volume " << loghex(device->volume) << "mute"
279 << loghex(device->mute) << "change_counter"
280 << loghex(device->change_counter);
281
282 if (!device->device_ready) return;
283
284 callbacks_->OnVolumeStateChanged(device->address, device->volume,
285 device->mute);
286 }
287
OnVolumeControlFlagsChanged(VolumeControlDevice * device,uint16_t len,uint8_t * value)288 void OnVolumeControlFlagsChanged(VolumeControlDevice* device, uint16_t len,
289 uint8_t* value) {
290 device->flags = *value;
291
292 LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
293 LOG(INFO) << __func__ << "flags " << loghex(device->flags);
294 }
295
OnGattWriteCcc(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,void *)296 void OnGattWriteCcc(uint16_t connection_id, tGATT_STATUS status,
297 uint16_t handle, void* /*data*/) {
298 VolumeControlDevice* device =
299 volume_control_devices_.FindByConnId(connection_id);
300 if (!device) {
301 LOG(INFO) << __func__
302 << "unknown connection_id=" << loghex(connection_id);
303 BtaGattQueue::Clean(connection_id);
304 return;
305 }
306
307 if (status != GATT_SUCCESS) {
308 LOG(ERROR) << __func__
309 << "Failed to register for notification: " << loghex(handle)
310 << " status: " << status;
311 device_cleanup_helper(device, true);
312 return;
313 }
314
315 LOG(INFO) << __func__
316 << "Successfully register for indications: " << loghex(handle);
317
318 verify_device_ready(device, handle);
319 }
320
OnGattWriteCccStatic(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,void * data)321 static void OnGattWriteCccStatic(uint16_t connection_id, tGATT_STATUS status,
322 uint16_t handle, void* data) {
323 if (!instance) {
324 LOG(ERROR) << __func__ << "No instance=" << handle;
325 return;
326 }
327
328 instance->OnGattWriteCcc(connection_id, status, handle, data);
329 }
330
Dump(int fd)331 void Dump(int fd) { volume_control_devices_.DebugDump(fd); }
332
Disconnect(const RawAddress & address)333 void Disconnect(const RawAddress& address) override {
334 VolumeControlDevice* device =
335 volume_control_devices_.FindByAddress(address);
336 if (!device) {
337 LOG(INFO) << "Device not connected to profile" << address;
338 return;
339 }
340
341 LOG(INFO) << __func__ << ": " << address;
342 LOG(INFO) << "GAP_EVT_CONN_CLOSED: " << device->address;
343 device_cleanup_helper(device, true);
344 }
345
OnGattDisconnected(uint16_t connection_id,tGATT_IF,RawAddress remote_bda,tGATT_DISCONN_REASON)346 void OnGattDisconnected(uint16_t connection_id, tGATT_IF /*client_if*/,
347 RawAddress remote_bda,
348 tGATT_DISCONN_REASON /*reason*/) {
349 VolumeControlDevice* device =
350 volume_control_devices_.FindByConnId(connection_id);
351 if (!device) {
352 LOG(ERROR) << __func__
353 << " Skipping unknown device disconnect, connection_id="
354 << loghex(connection_id);
355 return;
356 }
357
358 // If we get here, it means, device has not been exlicitly disconnected.
359 bool device_ready = device->device_ready;
360
361 device_cleanup_helper(device, device->connecting_actively);
362
363 if (device_ready) {
364 volume_control_devices_.Add(remote_bda, true);
365
366 /* Add device into BG connection to accept remote initiated connection */
367 BTA_GATTC_Open(gatt_if_, remote_bda, false, false);
368 }
369 }
370
OnWriteControlResponse(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,void *)371 void OnWriteControlResponse(uint16_t connection_id, tGATT_STATUS status,
372 uint16_t handle, void* /*data*/) {
373 VolumeControlDevice* device =
374 volume_control_devices_.FindByConnId(connection_id);
375 if (!device) {
376 LOG(ERROR) << __func__
377 << "Skipping unknown device disconnect, connection_id="
378 << loghex(connection_id);
379 return;
380 }
381
382 LOG(INFO) << "Write response handle: " << loghex(handle)
383 << " status: " << loghex((int)(status));
384 }
385
SetVolume(std::variant<RawAddress,int> addr_or_group_id,uint8_t volume)386 void SetVolume(std::variant<RawAddress, int> addr_or_group_id,
387 uint8_t volume) override {
388 LOG(INFO) << __func__ << "vol: " << +volume;
389
390 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
391 std::vector<RawAddress> devices = {
392 std::get<RawAddress>(addr_or_group_id)};
393 std::vector<uint8_t> arg({volume});
394 devices_control_point_helper(devices,
395 kControlPointOpcodeSetAbsoluteVolume, &arg);
396 return;
397 }
398
399 /* TODO implement handling group request */
400 }
401
CleanUp()402 void CleanUp() {
403 LOG(INFO) << __func__;
404 volume_control_devices_.Disconnect(gatt_if_);
405 volume_control_devices_.Clear();
406 BTA_GATTC_AppDeregister(gatt_if_);
407 }
408
409 private:
410 tGATT_IF gatt_if_;
411 bluetooth::vc::VolumeControlCallbacks* callbacks_;
412 VolumeControlDevices volume_control_devices_;
413
verify_device_ready(VolumeControlDevice * device,uint16_t handle)414 void verify_device_ready(VolumeControlDevice* device, uint16_t handle) {
415 if (device->device_ready) return;
416
417 // VerifyReady sets the device_ready flag if all remaining GATT operations
418 // are completed
419 if (device->VerifyReady(handle)) {
420 LOG(INFO) << __func__ << "Outstanding reads completed ";
421
422 callbacks_->OnConnectionState(ConnectionState::CONNECTED,
423 device->address);
424
425 device->connecting_actively = true;
426
427 device->first_connection = false;
428
429 // once profile connected we can notify current states
430 callbacks_->OnVolumeStateChanged(device->address, device->volume,
431 device->mute);
432
433 device->EnqueueRemainingRequests(gatt_if_, chrc_read_callback_static,
434 OnGattWriteCccStatic);
435 }
436 }
437
device_cleanup_helper(VolumeControlDevice * device,bool notify)438 void device_cleanup_helper(VolumeControlDevice* device, bool notify) {
439 device->Disconnect(gatt_if_);
440 if (notify)
441 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
442 device->address);
443 volume_control_devices_.Remove(device->address);
444 }
445
devices_control_point_helper(std::vector<RawAddress> & devices,uint8_t opcode,const std::vector<uint8_t> * arg)446 void devices_control_point_helper(std::vector<RawAddress>& devices,
447 uint8_t opcode,
448 const std::vector<uint8_t>* arg) {
449 volume_control_devices_.ControlPointOperation(
450 devices, opcode, arg,
451 [](uint16_t connection_id, tGATT_STATUS status, uint16_t handle,
452 void* data) {
453 if (instance)
454 instance->OnWriteControlResponse(connection_id, status, handle,
455 data);
456 },
457 nullptr);
458 }
459
gattc_callback(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)460 void gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
461 LOG(INFO) << __func__ << " event = " << static_cast<int>(event);
462
463 if (p_data == nullptr) return;
464
465 switch (event) {
466 case BTA_GATTC_OPEN_EVT: {
467 tBTA_GATTC_OPEN& o = p_data->open;
468 OnGattConnected(o.status, o.conn_id, o.client_if, o.remote_bda,
469 o.transport, o.mtu);
470
471 } break;
472
473 case BTA_GATTC_CLOSE_EVT: {
474 tBTA_GATTC_CLOSE& c = p_data->close;
475 OnGattDisconnected(c.conn_id, c.client_if, c.remote_bda, c.reason);
476 } break;
477
478 case BTA_GATTC_SEARCH_CMPL_EVT:
479 OnServiceSearchComplete(p_data->search_cmpl.conn_id,
480 p_data->search_cmpl.status);
481 break;
482
483 case BTA_GATTC_NOTIF_EVT: {
484 tBTA_GATTC_NOTIFY& n = p_data->notify;
485 if (!n.is_notify || n.len > GATT_MAX_ATTR_LEN) {
486 LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
487 << n.is_notify << ", len=" << static_cast<int>(n.len);
488 break;
489 }
490 OnNotificationEvent(n.conn_id, n.handle, n.len, n.value);
491 } break;
492
493 case BTA_GATTC_ENC_CMPL_CB_EVT:
494 OnEncryptionComplete(p_data->enc_cmpl.remote_bda, true);
495 break;
496
497 case BTA_GATTC_SRVC_CHG_EVT:
498 OnServiceChangeEvent(p_data->remote_bda);
499 break;
500
501 case BTA_GATTC_SRVC_DISC_DONE_EVT:
502 OnServiceDiscDoneEvent(p_data->remote_bda);
503 break;
504
505 default:
506 break;
507 }
508 }
509
gattc_callback_static(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)510 static void gattc_callback_static(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
511 if (instance) instance->gattc_callback(event, p_data);
512 }
513
enc_callback_static(const RawAddress * address,tBT_TRANSPORT,void *,tBTM_STATUS status)514 static void enc_callback_static(const RawAddress* address, tBT_TRANSPORT,
515 void*, tBTM_STATUS status) {
516 if (instance) instance->OnEncryptionComplete(*address, status);
517 }
518
chrc_read_callback_static(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)519 static void chrc_read_callback_static(uint16_t conn_id, tGATT_STATUS status,
520 uint16_t handle, uint16_t len,
521 uint8_t* value, void* data) {
522 if (instance)
523 instance->OnCharacteristicValueChanged(conn_id, status, handle, len,
524 value, data);
525 }
526 };
527 } // namespace
528
Initialize(bluetooth::vc::VolumeControlCallbacks * callbacks)529 void VolumeControl::Initialize(
530 bluetooth::vc::VolumeControlCallbacks* callbacks) {
531 if (instance) {
532 LOG(ERROR) << "Already initialized!";
533 return;
534 }
535
536 instance = new VolumeControlImpl(callbacks);
537 }
538
IsVolumeControlRunning()539 bool VolumeControl::IsVolumeControlRunning() { return instance; }
540
Get(void)541 VolumeControl* VolumeControl::Get(void) {
542 CHECK(instance);
543 return instance;
544 };
545
AddFromStorage(const RawAddress & address,bool auto_connect)546 void VolumeControl::AddFromStorage(const RawAddress& address,
547 bool auto_connect) {
548 if (!instance) {
549 LOG(ERROR) << "Not initialized yet";
550 return;
551 }
552
553 instance->AddFromStorage(address, auto_connect);
554 };
555
CleanUp()556 void VolumeControl::CleanUp() {
557 if (!instance) {
558 LOG(ERROR) << "not initialized!";
559 return;
560 }
561
562 VolumeControlImpl* ptr = instance;
563 instance = nullptr;
564
565 ptr->CleanUp();
566
567 delete ptr;
568 };
569
DebugDump(int fd)570 void VolumeControl::DebugDump(int fd) {
571 dprintf(fd, "Volume Control Manager:\n");
572 if (instance) instance->Dump(fd);
573 dprintf(fd, "\n");
574 }
575