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