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/functional/bind.h>
19 #include <base/logging.h>
20 #include <base/strings/string_number_conversions.h>
21 #include <base/strings/string_util.h>
22 #include <hardware/bt_vc.h>
23
24 #include <mutex>
25 #include <string>
26 #include <vector>
27
28 #include "bind_helpers.h"
29 #include "bta/le_audio/le_audio_types.h"
30 #include "bta_csis_api.h"
31 #include "bta_gatt_api.h"
32 #include "bta_gatt_queue.h"
33 #include "bta_vc_api.h"
34 #include "btif_storage.h"
35 #include "devices.h"
36 #include "gd/common/strings.h"
37 #include "osi/include/log.h"
38 #include "osi/include/osi.h"
39 #include "stack/btm/btm_sec.h"
40 #include "types/bluetooth/uuid.h"
41 #include "types/raw_address.h"
42
43 using base::Closure;
44 using bluetooth::Uuid;
45 using bluetooth::csis::CsisClient;
46 using bluetooth::vc::ConnectionState;
47 using namespace bluetooth::vc::internal;
48
49 namespace {
50 class VolumeControlImpl;
51 VolumeControlImpl* instance;
52 std::mutex instance_mutex;
53
54 /**
55 * Overview:
56 *
57 * This is Volume Control Implementation class which realize Volume Control
58 * Profile (VCP)
59 *
60 * Each connected peer device supporting Volume Control Service (VCS) is on the
61 * list of devices (volume_control_devices_). When VCS is discovered on the peer
62 * device, Android does search for all the instances Volume Offset Service
63 * (VOCS). Note that AIS and VOCS are optional.
64 *
65 * Once all the mandatory characteristis for all the services are discovered,
66 * Fluoride calls ON_CONNECTED callback.
67 *
68 * It is assumed that whenever application changes general audio options in this
69 * profile e.g. Volume up/down, mute/unmute etc, profile configures all the
70 * devices which are active Le Audio devices.
71 *
72 * Peer devices has at maximum one instance of VCS and 0 or more instance of
73 * VOCS. Android gets access to External Audio Outputs using appropriate ID.
74 * Also each of the External Device has description
75 * characteristic and Type which gives the application hint what it is a device.
76 * Examples of such devices:
77 * External Output: 1 instance to controller ballance between set of devices
78 * External Output: each of 5.1 speaker set etc.
79 */
80 class VolumeControlImpl : public VolumeControl {
81 public:
82 ~VolumeControlImpl() override = default;
83
VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks * callbacks)84 VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks* callbacks)
85 : gatt_if_(0), callbacks_(callbacks), latest_operation_id_(0) {
86 BTA_GATTC_AppRegister(
87 gattc_callback_static,
88 base::Bind([](uint8_t client_id, uint8_t status) {
89 if (status != GATT_SUCCESS) {
90 LOG(ERROR) << "Can't start Volume Control profile - no gatt "
91 "clients left!";
92 return;
93 }
94 instance->gatt_if_ = client_id;
95 }),
96 true);
97 }
98
Connect(const RawAddress & address)99 void Connect(const RawAddress& address) override {
100 LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(address);
101
102 auto device = volume_control_devices_.FindByAddress(address);
103 if (!device) {
104 volume_control_devices_.Add(address, true);
105 } else {
106 device->connecting_actively = true;
107
108 if (device->IsConnected()) {
109 LOG(WARNING) << __func__ << ": address=" << address
110 << ", connection_id=" << device->connection_id
111 << " already connected.";
112
113 if (device->IsReady()) {
114 callbacks_->OnConnectionState(ConnectionState::CONNECTED,
115 device->address);
116 } else {
117 OnGattConnected(GATT_SUCCESS, device->connection_id, gatt_if_,
118 device->address, BT_TRANSPORT_LE, GATT_MAX_MTU_SIZE);
119 }
120 return;
121 }
122 }
123
124 BTA_GATTC_Open(gatt_if_, address, BTM_BLE_DIRECT_CONNECTION, false);
125 }
126
AddFromStorage(const RawAddress & address,bool auto_connect)127 void AddFromStorage(const RawAddress& address, bool auto_connect) {
128 LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(address)
129 << ", auto_connect=" << auto_connect;
130
131 if (auto_connect) {
132 volume_control_devices_.Add(address, false);
133
134 /* Add device into BG connection to accept remote initiated connection */
135 BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
136 }
137 }
138
OnGattConnected(tGATT_STATUS status,uint16_t connection_id,tGATT_IF,RawAddress address,tBT_TRANSPORT,uint16_t)139 void OnGattConnected(tGATT_STATUS status, uint16_t connection_id,
140 tGATT_IF /*client_if*/, RawAddress address,
141 tBT_TRANSPORT /*transport*/, uint16_t /*mtu*/) {
142 LOG(INFO) << __func__ << ": address=" << ADDRESS_TO_LOGGABLE_STR(address)
143 << ", connection_id=" << connection_id;
144
145 VolumeControlDevice* device =
146 volume_control_devices_.FindByAddress(address);
147 if (!device) {
148 LOG(ERROR) << __func__ << "Skipping unknown device, address="
149 << ADDRESS_TO_LOGGABLE_STR(address);
150 return;
151 }
152
153 if (status != GATT_SUCCESS) {
154 LOG(INFO) << "Failed to connect to Volume Control device";
155 device_cleanup_helper(device, device->connecting_actively);
156 return;
157 }
158
159 device->connection_id = connection_id;
160
161 if (device->IsEncryptionEnabled()) {
162 OnEncryptionComplete(address, BTM_SUCCESS);
163 return;
164 }
165
166 device->EnableEncryption();
167 }
168
OnEncryptionComplete(const RawAddress & address,uint8_t success)169 void OnEncryptionComplete(const RawAddress& address, uint8_t success) {
170 VolumeControlDevice* device =
171 volume_control_devices_.FindByAddress(address);
172 if (!device) {
173 LOG(ERROR) << __func__ << "Skipping unknown device "
174 << ADDRESS_TO_LOGGABLE_STR(address);
175 return;
176 }
177
178 if (success != BTM_SUCCESS) {
179 LOG(ERROR) << "encryption failed "
180 << "status: " << int{success};
181 // If the encryption failed, do not remove the device.
182 // Disconnect only, since the Android will try to re-enable encryption
183 // after disconnection
184 device_cleanup_helper(device, device->connecting_actively);
185 return;
186 }
187
188 LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(address)
189 << " status: " << +success;
190
191 if (device->HasHandles()) {
192 device->EnqueueInitialRequests(gatt_if_, chrc_read_callback_static,
193 OnGattWriteCccStatic);
194
195 } else {
196 BTA_GATTC_ServiceSearchRequest(device->connection_id,
197 &kVolumeControlUuid);
198 }
199 }
200
ClearDeviceInformationAndStartSearch(VolumeControlDevice * device)201 void ClearDeviceInformationAndStartSearch(VolumeControlDevice* device) {
202 if (!device) {
203 LOG_ERROR("Device is null");
204 return;
205 }
206
207 LOG_INFO(": address=%s", ADDRESS_TO_LOGGABLE_CSTR(device->address));
208 if (device->known_service_handles_ == false) {
209 LOG_INFO("Device already is waiting for new services");
210 return;
211 }
212
213 std::vector<RawAddress> devices = {device->address};
214 device->DeregisterNotifications(gatt_if_);
215
216 RemovePendingVolumeControlOperations(devices,
217 bluetooth::groups::kGroupUnknown);
218 device->ResetHandles();
219 BTA_GATTC_ServiceSearchRequest(device->connection_id, &kVolumeControlUuid);
220 }
221
OnServiceChangeEvent(const RawAddress & address)222 void OnServiceChangeEvent(const RawAddress& address) {
223 VolumeControlDevice* device =
224 volume_control_devices_.FindByAddress(address);
225 if (!device) {
226 LOG(ERROR) << __func__ << "Skipping unknown device "
227 << ADDRESS_TO_LOGGABLE_STR(address);
228 return;
229 }
230
231 ClearDeviceInformationAndStartSearch(device);
232 }
233
OnServiceDiscDoneEvent(const RawAddress & address)234 void OnServiceDiscDoneEvent(const RawAddress& address) {
235 VolumeControlDevice* device =
236 volume_control_devices_.FindByAddress(address);
237 if (!device) {
238 LOG(ERROR) << __func__ << "Skipping unknown device "
239 << ADDRESS_TO_LOGGABLE_STR(address);
240 return;
241 }
242
243 if (device->known_service_handles_ == false) {
244 BTA_GATTC_ServiceSearchRequest(device->connection_id,
245 &kVolumeControlUuid);
246 }
247 }
248
OnServiceSearchComplete(uint16_t connection_id,tGATT_STATUS status)249 void OnServiceSearchComplete(uint16_t connection_id, tGATT_STATUS status) {
250 VolumeControlDevice* device =
251 volume_control_devices_.FindByConnId(connection_id);
252 if (!device) {
253 LOG(ERROR) << __func__ << "Skipping unknown device, connection_id="
254 << loghex(connection_id);
255 return;
256 }
257
258 /* Known device, nothing to do */
259 if (device->IsReady()) return;
260
261 if (status != GATT_SUCCESS) {
262 /* close connection and report service discovery complete with error */
263 LOG(ERROR) << "Service discovery failed";
264 device_cleanup_helper(device, device->connecting_actively);
265 return;
266 }
267
268 bool success = device->UpdateHandles();
269 if (!success) {
270 LOG(ERROR) << "Incomplete service database";
271 device_cleanup_helper(device, device->connecting_actively);
272 return;
273 }
274
275 device->EnqueueInitialRequests(gatt_if_, chrc_read_callback_static,
276 OnGattWriteCccStatic);
277 }
278
OnCharacteristicValueChanged(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data,bool is_notification)279 void OnCharacteristicValueChanged(uint16_t conn_id, tGATT_STATUS status,
280 uint16_t handle, uint16_t len,
281 uint8_t* value, void* data,
282 bool is_notification) {
283 VolumeControlDevice* device = volume_control_devices_.FindByConnId(conn_id);
284 if (!device) {
285 LOG(INFO) << __func__ << ": unknown conn_id=" << loghex(conn_id);
286 return;
287 }
288
289 if (status != GATT_SUCCESS) {
290 LOG_INFO(": status=0x%02x", static_cast<int>(status));
291 if (status == GATT_DATABASE_OUT_OF_SYNC) {
292 LOG_INFO("Database out of sync for %s",
293 ADDRESS_TO_LOGGABLE_CSTR(device->address));
294 ClearDeviceInformationAndStartSearch(device);
295 }
296 return;
297 }
298
299 if (handle == device->volume_state_handle) {
300 OnVolumeControlStateReadOrNotified(device, len, value, is_notification);
301 verify_device_ready(device, handle);
302 return;
303 }
304 if (handle == device->volume_flags_handle) {
305 OnVolumeControlFlagsChanged(device, len, value);
306 verify_device_ready(device, handle);
307 return;
308 }
309
310 const gatt::Service* service = BTA_GATTC_GetOwningService(conn_id, handle);
311 if (service == nullptr) return;
312
313 VolumeOffset* offset =
314 device->audio_offsets.FindByServiceHandle(service->handle);
315 if (offset != nullptr) {
316 if (handle == offset->state_handle) {
317 OnExtAudioOutStateChanged(device, offset, len, value);
318 } else if (handle == offset->audio_location_handle) {
319 OnExtAudioOutLocationChanged(device, offset, len, value);
320 } else if (handle == offset->audio_descr_handle) {
321 OnOffsetOutputDescChanged(device, offset, len, value);
322 } else {
323 LOG(ERROR) << __func__ << ": unknown offset handle=" << loghex(handle);
324 return;
325 }
326
327 verify_device_ready(device, handle);
328 return;
329 }
330
331 LOG(ERROR) << __func__ << ": unknown handle=" << loghex(handle);
332 }
333
OnNotificationEvent(uint16_t conn_id,uint16_t handle,uint16_t len,uint8_t * value)334 void OnNotificationEvent(uint16_t conn_id, uint16_t handle, uint16_t len,
335 uint8_t* value) {
336 LOG(INFO) << __func__ << ": handle=" << loghex(handle);
337 OnCharacteristicValueChanged(conn_id, GATT_SUCCESS, handle, len, value,
338 nullptr, true);
339 }
340
VolumeControlReadCommon(uint16_t conn_id,uint16_t handle)341 void VolumeControlReadCommon(uint16_t conn_id, uint16_t handle) {
342 BtaGattQueue::ReadCharacteristic(conn_id, handle, chrc_read_callback_static,
343 nullptr);
344 }
345
HandleAutonomusVolumeChange(VolumeControlDevice * device,bool is_volume_change,bool is_mute_change)346 void HandleAutonomusVolumeChange(VolumeControlDevice* device,
347 bool is_volume_change, bool is_mute_change) {
348 DLOG(INFO) << __func__ << ADDRESS_TO_LOGGABLE_STR(device->address)
349 << " is volume change: " << is_volume_change
350 << " is mute change: " << is_mute_change;
351
352 if (!is_volume_change && !is_mute_change) {
353 LOG(ERROR) << __func__
354 << "Autonomous change but volume and mute did not changed.";
355 return;
356 }
357
358 auto csis_api = CsisClient::Get();
359 if (!csis_api) {
360 DLOG(INFO) << __func__ << " Csis is not available";
361 callbacks_->OnVolumeStateChanged(device->address, device->volume,
362 device->mute, true);
363 return;
364 }
365
366 auto group_id =
367 csis_api->GetGroupId(device->address, le_audio::uuid::kCapServiceUuid);
368 if (group_id == bluetooth::groups::kGroupUnknown) {
369 DLOG(INFO) << __func__ << " No group for device "
370 << ADDRESS_TO_LOGGABLE_STR(device->address);
371 callbacks_->OnVolumeStateChanged(device->address, device->volume,
372 device->mute, true);
373 return;
374 }
375
376 auto devices = csis_api->GetDeviceList(group_id);
377 for (auto it = devices.begin(); it != devices.end();) {
378 auto dev = volume_control_devices_.FindByAddress(*it);
379 if (!dev || !dev->IsConnected() || (dev->address == device->address)) {
380 it = devices.erase(it);
381 } else {
382 it++;
383 }
384 }
385
386 if (devices.empty() && (is_volume_change || is_mute_change)) {
387 LOG_INFO("No more devices in the group right now");
388 callbacks_->OnGroupVolumeStateChanged(group_id, device->volume,
389 device->mute, true);
390 return;
391 }
392
393 if (is_volume_change) {
394 std::vector<uint8_t> arg({device->volume});
395 PrepareVolumeControlOperation(devices, group_id, true,
396 kControlPointOpcodeSetAbsoluteVolume, arg);
397 }
398
399 if (is_mute_change) {
400 std::vector<uint8_t> arg;
401 uint8_t opcode =
402 device->mute ? kControlPointOpcodeMute : kControlPointOpcodeUnmute;
403 PrepareVolumeControlOperation(devices, group_id, true, opcode, arg);
404 }
405
406 StartQueueOperation();
407 }
408
OnVolumeControlStateReadOrNotified(VolumeControlDevice * device,uint16_t len,uint8_t * value,bool is_notification)409 void OnVolumeControlStateReadOrNotified(VolumeControlDevice* device,
410 uint16_t len, uint8_t* value,
411 bool is_notification) {
412 if (len != 3) {
413 LOG(INFO) << __func__ << ": malformed len=" << loghex(len);
414 return;
415 }
416
417 uint8_t vol;
418 uint8_t mute;
419 uint8_t* pp = value;
420 STREAM_TO_UINT8(vol, pp);
421 STREAM_TO_UINT8(mute, pp);
422 STREAM_TO_UINT8(device->change_counter, pp);
423
424 bool is_volume_change = (device->volume != vol);
425 device->volume = vol;
426
427 bool is_mute_change = (device->mute != mute);
428 device->mute = mute;
429
430 LOG(INFO) << __func__ << " volume " << loghex(device->volume) << " mute "
431 << loghex(device->mute) << " change_counter "
432 << loghex(device->change_counter);
433
434 if (!device->IsReady()) {
435 LOG_INFO("Device: %s is not ready yet.",
436 ADDRESS_TO_LOGGABLE_CSTR(device->address));
437 return;
438 }
439
440 /* This is just a read, send single notification */
441 if (!is_notification) {
442 callbacks_->OnVolumeStateChanged(device->address, device->volume,
443 device->mute, false);
444 return;
445 }
446
447 auto addr = device->address;
448 auto op = find_if(ongoing_operations_.begin(), ongoing_operations_.end(),
449 [addr](auto& operation) {
450 auto it = find(operation.devices_.begin(),
451 operation.devices_.end(), addr);
452 return it != operation.devices_.end();
453 });
454 if (op == ongoing_operations_.end()) {
455 DLOG(INFO) << __func__ << " Could not find operation id for device: "
456 << ADDRESS_TO_LOGGABLE_STR(device->address)
457 << ". Autonomus change";
458 HandleAutonomusVolumeChange(device, is_volume_change, is_mute_change);
459 return;
460 }
461
462 DLOG(INFO) << __func__ << " operation found: " << op->operation_id_
463 << " for group id: " << op->group_id_;
464
465 /* Received notification from the device we do expect */
466 auto it = find(op->devices_.begin(), op->devices_.end(), device->address);
467 op->devices_.erase(it);
468 if (!op->devices_.empty()) {
469 DLOG(INFO) << __func__ << " wait for more responses for operation_id: "
470 << op->operation_id_;
471 return;
472 }
473
474 if (op->IsGroupOperation()) {
475 callbacks_->OnGroupVolumeStateChanged(op->group_id_, device->volume,
476 device->mute, op->is_autonomous_);
477 } else {
478 /* op->is_autonomous_ will always be false,
479 since we only make it true for group operations */
480 callbacks_->OnVolumeStateChanged(device->address, device->volume,
481 device->mute, false);
482 }
483
484 ongoing_operations_.erase(op);
485 StartQueueOperation();
486 }
487
OnVolumeControlFlagsChanged(VolumeControlDevice * device,uint16_t len,uint8_t * value)488 void OnVolumeControlFlagsChanged(VolumeControlDevice* device, uint16_t len,
489 uint8_t* value) {
490 device->flags = *value;
491
492 LOG(INFO) << __func__ << " flags " << loghex(device->flags);
493 }
494
OnExtAudioOutStateChanged(VolumeControlDevice * device,VolumeOffset * offset,uint16_t len,uint8_t * value)495 void OnExtAudioOutStateChanged(VolumeControlDevice* device,
496 VolumeOffset* offset, uint16_t len,
497 uint8_t* value) {
498 if (len != 3) {
499 LOG(INFO) << __func__ << ": malformed len=" << loghex(len);
500 return;
501 }
502
503 uint8_t* pp = value;
504 STREAM_TO_UINT16(offset->offset, pp);
505 STREAM_TO_UINT8(offset->change_counter, pp);
506
507 LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
508 LOG(INFO) << __func__ << " id: " << loghex(offset->id)
509 << " offset: " << loghex(offset->offset)
510 << " counter: " << loghex(offset->change_counter);
511
512 if (!device->IsReady()) {
513 LOG_INFO("Device: %s is not ready yet.",
514 ADDRESS_TO_LOGGABLE_CSTR(device->address));
515 return;
516 }
517
518 callbacks_->OnExtAudioOutVolumeOffsetChanged(device->address, offset->id,
519 offset->offset);
520 }
521
OnExtAudioOutLocationChanged(VolumeControlDevice * device,VolumeOffset * offset,uint16_t len,uint8_t * value)522 void OnExtAudioOutLocationChanged(VolumeControlDevice* device,
523 VolumeOffset* offset, uint16_t len,
524 uint8_t* value) {
525 if (len != 4) {
526 LOG(INFO) << __func__ << ": malformed len=" << loghex(len);
527 return;
528 }
529
530 uint8_t* pp = value;
531 STREAM_TO_UINT32(offset->location, pp);
532
533 LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
534 LOG(INFO) << __func__ << "id " << loghex(offset->id) << "location "
535 << loghex(offset->location);
536
537 if (!device->IsReady()) {
538 LOG_INFO("Device: %s is not ready yet.",
539 ADDRESS_TO_LOGGABLE_CSTR(device->address));
540 return;
541 }
542
543 callbacks_->OnExtAudioOutLocationChanged(device->address, offset->id,
544 offset->location);
545 }
546
OnExtAudioOutCPWrite(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,void *)547 void OnExtAudioOutCPWrite(uint16_t connection_id, tGATT_STATUS status,
548 uint16_t handle, void* /*data*/) {
549 VolumeControlDevice* device =
550 volume_control_devices_.FindByConnId(connection_id);
551 if (!device) {
552 LOG(ERROR) << __func__
553 << "Skipping unknown device disconnect, connection_id="
554 << loghex(connection_id);
555 return;
556 }
557
558 LOG(INFO) << "Offset Control Point write response handle" << loghex(handle)
559 << " status: " << loghex((int)(status));
560
561 /* TODO Design callback API to notify about changes */
562 }
563
OnOffsetOutputDescChanged(VolumeControlDevice * device,VolumeOffset * offset,uint16_t len,uint8_t * value)564 void OnOffsetOutputDescChanged(VolumeControlDevice* device,
565 VolumeOffset* offset, uint16_t len,
566 uint8_t* value) {
567 std::string description = std::string(value, value + len);
568 if (!base::IsStringUTF8(description)) description = "<invalid utf8 string>";
569
570 LOG(INFO) << __func__ << " " << description;
571
572 if (!device->IsReady()) {
573 LOG_INFO("Device: %s is not ready yet.",
574 ADDRESS_TO_LOGGABLE_CSTR(device->address));
575 return;
576 }
577
578 callbacks_->OnExtAudioOutDescriptionChanged(device->address, offset->id,
579 std::move(description));
580 }
581
OnGattWriteCcc(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void *)582 void OnGattWriteCcc(uint16_t connection_id, tGATT_STATUS status,
583 uint16_t handle, uint16_t len, const uint8_t* value,
584 void* /*data*/) {
585 VolumeControlDevice* device =
586 volume_control_devices_.FindByConnId(connection_id);
587 if (!device) {
588 LOG(INFO) << __func__
589 << "unknown connection_id=" << loghex(connection_id);
590 BtaGattQueue::Clean(connection_id);
591 return;
592 }
593
594 if (status != GATT_SUCCESS) {
595 if (status == GATT_DATABASE_OUT_OF_SYNC) {
596 LOG_INFO("Database out of sync for %s, conn_id: 0x%04x",
597 ADDRESS_TO_LOGGABLE_CSTR(device->address), connection_id);
598 ClearDeviceInformationAndStartSearch(device);
599 } else {
600 LOG_ERROR("Failed to register for notification: 0x%04x, status 0x%02x",
601 handle, status);
602 device_cleanup_helper(device, true);
603 }
604 return;
605 }
606
607 LOG(INFO) << __func__
608 << "Successfully register for indications: " << loghex(handle);
609
610 verify_device_ready(device, handle);
611 }
612
OnGattWriteCccStatic(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * data)613 static void OnGattWriteCccStatic(uint16_t connection_id, tGATT_STATUS status,
614 uint16_t handle, uint16_t len,
615 const uint8_t* value, void* data) {
616 if (!instance) {
617 LOG(ERROR) << __func__ << "No instance=" << handle;
618 return;
619 }
620
621 instance->OnGattWriteCcc(connection_id, status, handle, len, value, data);
622 }
623
Dump(int fd)624 void Dump(int fd) {
625 dprintf(fd, "APP ID: %d\n", gatt_if_);
626 volume_control_devices_.DebugDump(fd);
627 }
628
Disconnect(const RawAddress & address)629 void Disconnect(const RawAddress& address) override {
630 VolumeControlDevice* device =
631 volume_control_devices_.FindByAddress(address);
632 if (!device) {
633 LOG_WARN("Device not connected to profile %s",
634 ADDRESS_TO_LOGGABLE_CSTR(address));
635 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, address);
636 return;
637 }
638
639 LOG(INFO) << __func__ << " GAP_EVT_CONN_CLOSED: "
640 << ADDRESS_TO_LOGGABLE_STR(device->address);
641 device->connecting_actively = false;
642 device_cleanup_helper(device, true);
643 }
644
OnGattDisconnected(uint16_t connection_id,tGATT_IF,RawAddress remote_bda,tGATT_DISCONN_REASON reason)645 void OnGattDisconnected(uint16_t connection_id, tGATT_IF /*client_if*/,
646 RawAddress remote_bda, tGATT_DISCONN_REASON reason) {
647 VolumeControlDevice* device =
648 volume_control_devices_.FindByConnId(connection_id);
649 if (!device) {
650 LOG(ERROR) << __func__
651 << " Skipping unknown device disconnect, connection_id="
652 << loghex(connection_id);
653 return;
654 }
655
656 if (!device->IsConnected()) {
657 LOG(ERROR) << __func__
658 << " Skipping disconnect of the already disconnected device, "
659 "connection_id="
660 << loghex(connection_id);
661 return;
662 }
663
664 device_cleanup_helper(device, device->connecting_actively);
665
666 if (reason != GATT_CONN_TERMINATE_LOCAL_HOST &&
667 device->connecting_actively) {
668 /* Add device into BG connection to accept remote initiated connection */
669 BTA_GATTC_Open(gatt_if_, remote_bda, BTM_BLE_BKG_CONNECT_ALLOW_LIST,
670 false);
671 }
672 }
673
RemoveDeviceFromOperationList(const RawAddress & addr,int operation_id)674 void RemoveDeviceFromOperationList(const RawAddress& addr, int operation_id) {
675 auto op = find_if(ongoing_operations_.begin(), ongoing_operations_.end(),
676 [operation_id](auto& operation) {
677 return operation.operation_id_ == operation_id;
678 });
679
680 if (op == ongoing_operations_.end()) {
681 LOG(ERROR) << __func__
682 << " Could not find operation id: " << operation_id;
683 return;
684 }
685
686 auto it = find(op->devices_.begin(), op->devices_.end(), addr);
687 if (it != op->devices_.end()) {
688 op->devices_.erase(it);
689 if (op->devices_.empty()) {
690 ongoing_operations_.erase(op);
691 StartQueueOperation();
692 }
693 return;
694 }
695 }
696
RemovePendingVolumeControlOperations(std::vector<RawAddress> & devices,int group_id)697 void RemovePendingVolumeControlOperations(std::vector<RawAddress>& devices,
698 int group_id) {
699 for (auto op = ongoing_operations_.begin();
700 op != ongoing_operations_.end();) {
701 // We only remove operations that don't affect the mute field.
702 if (op->IsStarted() ||
703 (op->opcode_ != kControlPointOpcodeSetAbsoluteVolume &&
704 op->opcode_ != kControlPointOpcodeVolumeUp &&
705 op->opcode_ != kControlPointOpcodeVolumeDown)) {
706 op++;
707 continue;
708 }
709 if (group_id != bluetooth::groups::kGroupUnknown &&
710 op->group_id_ == group_id) {
711 op = ongoing_operations_.erase(op);
712 continue;
713 }
714 for (auto const& addr : devices) {
715 auto it = find(op->devices_.begin(), op->devices_.end(), addr);
716 if (it != op->devices_.end()) {
717 op->devices_.erase(it);
718 }
719 }
720 if (op->devices_.empty()) {
721 op = ongoing_operations_.erase(op);
722 } else {
723 op++;
724 }
725 }
726 }
727
OnWriteControlResponse(uint16_t connection_id,tGATT_STATUS status,uint16_t handle,void * data)728 void OnWriteControlResponse(uint16_t connection_id, tGATT_STATUS status,
729 uint16_t handle, void* data) {
730 VolumeControlDevice* device =
731 volume_control_devices_.FindByConnId(connection_id);
732 if (!device) {
733 LOG(ERROR) << __func__
734 << "Skipping unknown device disconnect, connection_id="
735 << loghex(connection_id);
736 return;
737 }
738
739 LOG(INFO) << "Write response handle: " << loghex(handle)
740 << " status: " << loghex((int)(status));
741
742 if (status == GATT_SUCCESS) return;
743
744 /* In case of error, remove device from the tracking operation list */
745 RemoveDeviceFromOperationList(device->address, PTR_TO_INT(data));
746
747 if (status == GATT_DATABASE_OUT_OF_SYNC) {
748 LOG_INFO("Database out of sync for %s",
749 ADDRESS_TO_LOGGABLE_CSTR(device->address));
750 ClearDeviceInformationAndStartSearch(device);
751 }
752 }
753
operation_callback(void * data)754 static void operation_callback(void* data) {
755 instance->CancelVolumeOperation(PTR_TO_INT(data));
756 }
757
StartQueueOperation(void)758 void StartQueueOperation(void) {
759 LOG(INFO) << __func__;
760 if (ongoing_operations_.empty()) {
761 return;
762 };
763
764 auto op = &ongoing_operations_.front();
765
766 LOG(INFO) << __func__ << " operation_id: " << op->operation_id_;
767
768 if (op->IsStarted()) {
769 LOG(INFO) << __func__ << " wait until operation " << op->operation_id_
770 << " is complete";
771 return;
772 }
773
774 op->Start();
775
776 alarm_set_on_mloop(op->operation_timeout_, 3000, operation_callback,
777 INT_TO_PTR(op->operation_id_));
778 devices_control_point_helper(
779 op->devices_, op->opcode_,
780 op->arguments_.size() == 0 ? nullptr : &(op->arguments_));
781 }
782
CancelVolumeOperation(int operation_id)783 void CancelVolumeOperation(int operation_id) {
784 LOG(INFO) << __func__ << " canceling operation_id: " << operation_id;
785
786 auto op = find_if(
787 ongoing_operations_.begin(), ongoing_operations_.end(),
788 [operation_id](auto& it) { return it.operation_id_ == operation_id; });
789
790 if (op == ongoing_operations_.end()) {
791 LOG(ERROR) << __func__
792 << " Could not find operation_id: " << operation_id;
793 return;
794 }
795
796 /* Possibly close GATT operations */
797 ongoing_operations_.erase(op);
798 StartQueueOperation();
799 }
800
ProceedVolumeOperation(int operation_id)801 void ProceedVolumeOperation(int operation_id) {
802 auto op = find_if(ongoing_operations_.begin(), ongoing_operations_.end(),
803 [operation_id](auto& operation) {
804 return operation.operation_id_ == operation_id;
805 });
806
807 DLOG(INFO) << __func__ << " operation_id: " << operation_id;
808
809 if (op == ongoing_operations_.end()) {
810 LOG(ERROR) << __func__
811 << " Could not find operation_id: " << operation_id;
812 return;
813 }
814
815 DLOG(INFO) << __func__ << " procedure continued for operation_id: "
816 << op->operation_id_;
817
818 alarm_set_on_mloop(op->operation_timeout_, 3000, operation_callback,
819 INT_TO_PTR(op->operation_id_));
820 devices_control_point_helper(op->devices_, op->opcode_, &(op->arguments_));
821 }
822
PrepareVolumeControlOperation(std::vector<RawAddress> devices,int group_id,bool is_autonomous,uint8_t opcode,std::vector<uint8_t> & arguments)823 void PrepareVolumeControlOperation(std::vector<RawAddress> devices,
824 int group_id, bool is_autonomous,
825 uint8_t opcode,
826 std::vector<uint8_t>& arguments) {
827 LOG_DEBUG(
828 "num of devices: %zu, group_id: %d, is_autonomous: %s opcode: %d, arg "
829 "size: %zu",
830 devices.size(), group_id, is_autonomous ? "true" : "false", +opcode,
831 arguments.size());
832
833 if (std::find_if(ongoing_operations_.begin(), ongoing_operations_.end(),
834 [opcode, &devices, &arguments](const VolumeOperation& op) {
835 if (op.opcode_ != opcode) return false;
836 if (!std::equal(op.arguments_.begin(),
837 op.arguments_.end(), arguments.begin()))
838 return false;
839 // Filter out all devices which have the exact operation
840 // already scheduled
841 devices.erase(
842 std::remove_if(devices.begin(), devices.end(),
843 [&op](auto d) {
844 return find(op.devices_.begin(),
845 op.devices_.end(),
846 d) != op.devices_.end();
847 }),
848 devices.end());
849 return devices.empty();
850 }) == ongoing_operations_.end()) {
851 ongoing_operations_.emplace_back(latest_operation_id_++, group_id,
852 is_autonomous, opcode, arguments,
853 devices);
854 }
855 }
856
MuteUnmute(std::variant<RawAddress,int> addr_or_group_id,bool mute)857 void MuteUnmute(std::variant<RawAddress, int> addr_or_group_id, bool mute) {
858 std::vector<uint8_t> arg;
859
860 uint8_t opcode = mute ? kControlPointOpcodeMute : kControlPointOpcodeUnmute;
861
862 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
863 VolumeControlDevice* dev = volume_control_devices_.FindByAddress(
864 std::get<RawAddress>(addr_or_group_id));
865 if (dev != nullptr) {
866 LOG_DEBUG("Address: %s: isReady: %s",
867 ADDRESS_TO_LOGGABLE_CSTR(dev->address),
868 dev->IsReady() ? "true" : "false");
869 if (dev->IsReady() && (dev->mute != mute)) {
870 std::vector<RawAddress> devices = {dev->address};
871 PrepareVolumeControlOperation(
872 devices, bluetooth::groups::kGroupUnknown, false, opcode, arg);
873 }
874 }
875 } else {
876 /* Handle group change */
877 auto group_id = std::get<int>(addr_or_group_id);
878 LOG_DEBUG("group: %d", group_id);
879 auto csis_api = CsisClient::Get();
880 if (!csis_api) {
881 LOG(ERROR) << __func__ << " Csis is not there";
882 return;
883 }
884
885 auto devices = csis_api->GetDeviceList(group_id);
886 for (auto it = devices.begin(); it != devices.end();) {
887 auto dev = volume_control_devices_.FindByAddress(*it);
888 if (!dev || !dev->IsReady() || (dev->mute == mute)) {
889 it = devices.erase(it);
890 } else {
891 it++;
892 }
893 }
894
895 if (devices.empty()) {
896 LOG(ERROR) << __func__ << " group id : " << group_id
897 << " is not connected? ";
898 return;
899 }
900
901 PrepareVolumeControlOperation(devices, group_id, false, opcode, arg);
902 }
903
904 StartQueueOperation();
905 }
906
Mute(std::variant<RawAddress,int> addr_or_group_id)907 void Mute(std::variant<RawAddress, int> addr_or_group_id) override {
908 LOG_DEBUG();
909 MuteUnmute(addr_or_group_id, true /* mute */);
910 }
911
UnMute(std::variant<RawAddress,int> addr_or_group_id)912 void UnMute(std::variant<RawAddress, int> addr_or_group_id) override {
913 LOG_DEBUG();
914 MuteUnmute(addr_or_group_id, false /* mute */);
915 }
916
SetVolume(std::variant<RawAddress,int> addr_or_group_id,uint8_t volume)917 void SetVolume(std::variant<RawAddress, int> addr_or_group_id,
918 uint8_t volume) override {
919 DLOG(INFO) << __func__ << " vol: " << +volume;
920
921 std::vector<uint8_t> arg({volume});
922 uint8_t opcode = kControlPointOpcodeSetAbsoluteVolume;
923
924 if (std::holds_alternative<RawAddress>(addr_or_group_id)) {
925 LOG_DEBUG("Address: %s: ", ADDRESS_TO_LOGGABLE_CSTR(
926 std::get<RawAddress>(addr_or_group_id)));
927 VolumeControlDevice* dev = volume_control_devices_.FindByAddress(
928 std::get<RawAddress>(addr_or_group_id));
929 if (dev != nullptr) {
930 LOG_DEBUG("Address: %s: isReady: %s",
931 ADDRESS_TO_LOGGABLE_CSTR(dev->address),
932 dev->IsReady() ? "true" : "false");
933 if (dev->IsReady() && (dev->volume != volume)) {
934 std::vector<RawAddress> devices = {dev->address};
935 RemovePendingVolumeControlOperations(
936 devices, bluetooth::groups::kGroupUnknown);
937 PrepareVolumeControlOperation(
938 devices, bluetooth::groups::kGroupUnknown, false, opcode, arg);
939 }
940 }
941 } else {
942 /* Handle group change */
943 auto group_id = std::get<int>(addr_or_group_id);
944 DLOG(INFO) << __func__ << " group: " << group_id;
945 auto csis_api = CsisClient::Get();
946 if (!csis_api) {
947 LOG(ERROR) << __func__ << " Csis is not there";
948 return;
949 }
950
951 auto devices = csis_api->GetDeviceList(group_id);
952 for (auto it = devices.begin(); it != devices.end();) {
953 auto dev = volume_control_devices_.FindByAddress(*it);
954 if (!dev || !dev->IsReady() || (dev->volume == volume)) {
955 it = devices.erase(it);
956 } else {
957 it++;
958 }
959 }
960
961 if (devices.empty()) {
962 LOG(ERROR) << __func__ << " group id : " << group_id
963 << " is not connected? ";
964 return;
965 }
966
967 RemovePendingVolumeControlOperations(devices, group_id);
968 PrepareVolumeControlOperation(devices, group_id, false, opcode, arg);
969 }
970
971 StartQueueOperation();
972 }
973
974 /* Methods to operate on Volume Control Offset Service (VOCS) */
GetExtAudioOutVolumeOffset(const RawAddress & address,uint8_t ext_output_id)975 void GetExtAudioOutVolumeOffset(const RawAddress& address,
976 uint8_t ext_output_id) override {
977 VolumeControlDevice* device =
978 volume_control_devices_.FindByAddress(address);
979 if (!device) {
980 LOG(ERROR) << __func__ << ", no such device!";
981 return;
982 }
983
984 device->GetExtAudioOutVolumeOffset(ext_output_id, chrc_read_callback_static,
985 nullptr);
986 }
987
SetExtAudioOutVolumeOffset(const RawAddress & address,uint8_t ext_output_id,int16_t offset_val)988 void SetExtAudioOutVolumeOffset(const RawAddress& address,
989 uint8_t ext_output_id,
990 int16_t offset_val) override {
991 std::vector<uint8_t> arg(2);
992 uint8_t* ptr = arg.data();
993 UINT16_TO_STREAM(ptr, offset_val);
994 ext_audio_out_control_point_helper(
995 address, ext_output_id, kVolumeOffsetControlPointOpcodeSet, &arg);
996 }
997
GetExtAudioOutLocation(const RawAddress & address,uint8_t ext_output_id)998 void GetExtAudioOutLocation(const RawAddress& address,
999 uint8_t ext_output_id) override {
1000 VolumeControlDevice* device =
1001 volume_control_devices_.FindByAddress(address);
1002 if (!device) {
1003 LOG(ERROR) << __func__ << ", no such device!";
1004 return;
1005 }
1006
1007 device->GetExtAudioOutLocation(ext_output_id, chrc_read_callback_static,
1008 nullptr);
1009 }
1010
SetExtAudioOutLocation(const RawAddress & address,uint8_t ext_output_id,uint32_t location)1011 void SetExtAudioOutLocation(const RawAddress& address, uint8_t ext_output_id,
1012 uint32_t location) override {
1013 VolumeControlDevice* device =
1014 volume_control_devices_.FindByAddress(address);
1015 if (!device) {
1016 LOG(ERROR) << __func__ << ", no such device!";
1017 return;
1018 }
1019
1020 device->SetExtAudioOutLocation(ext_output_id, location);
1021 }
1022
GetExtAudioOutDescription(const RawAddress & address,uint8_t ext_output_id)1023 void GetExtAudioOutDescription(const RawAddress& address,
1024 uint8_t ext_output_id) override {
1025 VolumeControlDevice* device =
1026 volume_control_devices_.FindByAddress(address);
1027 if (!device) {
1028 LOG(ERROR) << __func__ << ", no such device!";
1029 return;
1030 }
1031
1032 device->GetExtAudioOutDescription(ext_output_id, chrc_read_callback_static,
1033 nullptr);
1034 }
1035
SetExtAudioOutDescription(const RawAddress & address,uint8_t ext_output_id,std::string descr)1036 void SetExtAudioOutDescription(const RawAddress& address,
1037 uint8_t ext_output_id,
1038 std::string descr) override {
1039 VolumeControlDevice* device =
1040 volume_control_devices_.FindByAddress(address);
1041 if (!device) {
1042 LOG(ERROR) << __func__ << ", no such device!";
1043 return;
1044 }
1045
1046 device->SetExtAudioOutDescription(ext_output_id, descr);
1047 }
1048
CleanUp()1049 void CleanUp() {
1050 LOG(INFO) << __func__;
1051 volume_control_devices_.Disconnect(gatt_if_);
1052 volume_control_devices_.Clear();
1053 ongoing_operations_.clear();
1054 BTA_GATTC_AppDeregister(gatt_if_);
1055 }
1056
1057 private:
1058 tGATT_IF gatt_if_;
1059 bluetooth::vc::VolumeControlCallbacks* callbacks_;
1060 VolumeControlDevices volume_control_devices_;
1061
1062 /* Used to track volume control operations */
1063 std::list<VolumeOperation> ongoing_operations_;
1064 int latest_operation_id_;
1065
verify_device_ready(VolumeControlDevice * device,uint16_t handle)1066 void verify_device_ready(VolumeControlDevice* device, uint16_t handle) {
1067 if (device->IsReady()) return;
1068
1069 // VerifyReady sets the device_ready flag if all remaining GATT operations
1070 // are completed
1071 if (device->VerifyReady(handle)) {
1072 LOG(INFO) << __func__ << " Outstanding reads completed.";
1073
1074 callbacks_->OnDeviceAvailable(device->address,
1075 device->audio_offsets.Size());
1076 callbacks_->OnConnectionState(ConnectionState::CONNECTED,
1077 device->address);
1078
1079 // once profile connected we can notify current states
1080 callbacks_->OnVolumeStateChanged(device->address, device->volume,
1081 device->mute, false);
1082
1083 for (auto const& offset : device->audio_offsets.volume_offsets) {
1084 callbacks_->OnExtAudioOutVolumeOffsetChanged(device->address, offset.id,
1085 offset.offset);
1086 }
1087
1088 device->EnqueueRemainingRequests(gatt_if_, chrc_read_callback_static,
1089 OnGattWriteCccStatic);
1090 }
1091 }
1092
device_cleanup_helper(VolumeControlDevice * device,bool notify)1093 void device_cleanup_helper(VolumeControlDevice* device, bool notify) {
1094 device->Disconnect(gatt_if_);
1095 if (notify)
1096 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
1097 device->address);
1098 }
1099
devices_control_point_helper(std::vector<RawAddress> & devices,uint8_t opcode,const std::vector<uint8_t> * arg,int operation_id=-1)1100 void devices_control_point_helper(std::vector<RawAddress>& devices,
1101 uint8_t opcode,
1102 const std::vector<uint8_t>* arg,
1103 int operation_id = -1) {
1104 volume_control_devices_.ControlPointOperation(
1105 devices, opcode, arg,
1106 [](uint16_t connection_id, tGATT_STATUS status, uint16_t handle,
1107 uint16_t len, const uint8_t* value, void* data) {
1108 if (instance)
1109 instance->OnWriteControlResponse(connection_id, status, handle,
1110 data);
1111 },
1112 INT_TO_PTR(operation_id));
1113 }
1114
ext_audio_out_control_point_helper(const RawAddress & address,uint8_t ext_output_id,uint8_t opcode,const std::vector<uint8_t> * arg)1115 void ext_audio_out_control_point_helper(const RawAddress& address,
1116 uint8_t ext_output_id, uint8_t opcode,
1117 const std::vector<uint8_t>* arg) {
1118 LOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(address)
1119 << " id=" << loghex(ext_output_id) << " op=" << loghex(opcode);
1120 VolumeControlDevice* device =
1121 volume_control_devices_.FindByAddress(address);
1122 if (!device) {
1123 LOG(ERROR) << __func__ << ", no such device!";
1124 return;
1125 }
1126 device->ExtAudioOutControlPointOperation(
1127 ext_output_id, opcode, arg,
1128 [](uint16_t connection_id, tGATT_STATUS status, uint16_t handle,
1129 uint16_t len, const uint8_t* value, void* data) {
1130 if (instance)
1131 instance->OnExtAudioOutCPWrite(connection_id, status, handle, data);
1132 },
1133 nullptr);
1134 }
1135
gattc_callback(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)1136 void gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
1137 LOG(INFO) << __func__ << " event = " << static_cast<int>(event);
1138
1139 if (p_data == nullptr) return;
1140
1141 switch (event) {
1142 case BTA_GATTC_OPEN_EVT: {
1143 tBTA_GATTC_OPEN& o = p_data->open;
1144 OnGattConnected(o.status, o.conn_id, o.client_if, o.remote_bda,
1145 o.transport, o.mtu);
1146
1147 } break;
1148
1149 case BTA_GATTC_CLOSE_EVT: {
1150 tBTA_GATTC_CLOSE& c = p_data->close;
1151 OnGattDisconnected(c.conn_id, c.client_if, c.remote_bda, c.reason);
1152 } break;
1153
1154 case BTA_GATTC_SEARCH_CMPL_EVT:
1155 OnServiceSearchComplete(p_data->search_cmpl.conn_id,
1156 p_data->search_cmpl.status);
1157 break;
1158
1159 case BTA_GATTC_NOTIF_EVT: {
1160 tBTA_GATTC_NOTIFY& n = p_data->notify;
1161 if (!n.is_notify || n.len > GATT_MAX_ATTR_LEN) {
1162 LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
1163 << n.is_notify << ", len=" << static_cast<int>(n.len);
1164 break;
1165 }
1166 OnNotificationEvent(n.conn_id, n.handle, n.len, n.value);
1167 } break;
1168
1169 case BTA_GATTC_ENC_CMPL_CB_EVT: {
1170 uint8_t encryption_status;
1171 if (BTM_IsEncrypted(p_data->enc_cmpl.remote_bda, BT_TRANSPORT_LE)) {
1172 encryption_status = BTM_SUCCESS;
1173 } else {
1174 encryption_status = BTM_FAILED_ON_SECURITY;
1175 }
1176 OnEncryptionComplete(p_data->enc_cmpl.remote_bda, encryption_status);
1177 } break;
1178
1179 case BTA_GATTC_SRVC_CHG_EVT:
1180 OnServiceChangeEvent(p_data->remote_bda);
1181 break;
1182
1183 case BTA_GATTC_SRVC_DISC_DONE_EVT:
1184 OnServiceDiscDoneEvent(p_data->remote_bda);
1185 break;
1186
1187 default:
1188 break;
1189 }
1190 }
1191
gattc_callback_static(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)1192 static void gattc_callback_static(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
1193 if (instance) instance->gattc_callback(event, p_data);
1194 }
1195
chrc_read_callback_static(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)1196 static void chrc_read_callback_static(uint16_t conn_id, tGATT_STATUS status,
1197 uint16_t handle, uint16_t len,
1198 uint8_t* value, void* data) {
1199 if (instance)
1200 instance->OnCharacteristicValueChanged(conn_id, status, handle, len,
1201 value, data, false);
1202 }
1203 };
1204 } // namespace
1205
Initialize(bluetooth::vc::VolumeControlCallbacks * callbacks)1206 void VolumeControl::Initialize(
1207 bluetooth::vc::VolumeControlCallbacks* callbacks) {
1208 std::scoped_lock<std::mutex> lock(instance_mutex);
1209 if (instance) {
1210 LOG(ERROR) << "Already initialized!";
1211 return;
1212 }
1213
1214 instance = new VolumeControlImpl(callbacks);
1215 }
1216
IsVolumeControlRunning()1217 bool VolumeControl::IsVolumeControlRunning() { return instance; }
1218
Get(void)1219 VolumeControl* VolumeControl::Get(void) {
1220 CHECK(instance);
1221 return instance;
1222 };
1223
AddFromStorage(const RawAddress & address,bool auto_connect)1224 void VolumeControl::AddFromStorage(const RawAddress& address,
1225 bool auto_connect) {
1226 if (!instance) {
1227 LOG(ERROR) << "Not initialized yet";
1228 return;
1229 }
1230
1231 instance->AddFromStorage(address, auto_connect);
1232 };
1233
CleanUp()1234 void VolumeControl::CleanUp() {
1235 std::scoped_lock<std::mutex> lock(instance_mutex);
1236 if (!instance) {
1237 LOG(ERROR) << "Not initialized!";
1238 return;
1239 }
1240
1241 VolumeControlImpl* ptr = instance;
1242 instance = nullptr;
1243
1244 ptr->CleanUp();
1245
1246 delete ptr;
1247 };
1248
DebugDump(int fd)1249 void VolumeControl::DebugDump(int fd) {
1250 std::scoped_lock<std::mutex> lock(instance_mutex);
1251 dprintf(fd, "Volume Control Manager:\n");
1252 if (instance) instance->Dump(fd);
1253 dprintf(fd, "\n");
1254 }
1255