• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "connection_handler.h"
18 
19 #include <base/bind.h>
20 #include <base/logging.h>
21 #include <map>
22 
23 #include "avrc_defs.h"
24 #include "avrcp_message_converter.h"
25 #include "bt_types.h"
26 #include "btu.h"
27 #include "packet/avrcp/avrcp_packet.h"
28 // TODO (apanicke): Remove dependency on this header once we cleanup feature
29 // handling.
30 #include "bta/include/bta_av_api.h"
31 #include "device/include/interop.h"
32 #include "osi/include/allocator.h"
33 #include "osi/include/properties.h"
34 
35 namespace bluetooth {
36 namespace avrcp {
37 
38 ConnectionHandler* ConnectionHandler::instance_ = nullptr;
39 
Get()40 ConnectionHandler* ConnectionHandler::Get() {
41   CHECK(instance_);
42 
43   return instance_;
44 }
45 
IsAbsoluteVolumeEnabled(const RawAddress * bdaddr)46 bool IsAbsoluteVolumeEnabled(const RawAddress* bdaddr) {
47   char volume_disabled[PROPERTY_VALUE_MAX] = {0};
48   osi_property_get("persist.bluetooth.disableabsvol", volume_disabled, "false");
49   if (strncmp(volume_disabled, "true", 4) == 0) {
50     LOG(INFO) << "Absolute volume disabled by property";
51     return false;
52   }
53   if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, bdaddr)) {
54     LOG(INFO) << "Absolute volume disabled by IOP table";
55     return false;
56   }
57   return true;
58 }
59 
Initialize(const ConnectionCallback & callback,AvrcpInterface * avrcp,SdpInterface * sdp,VolumeInterface * vol)60 bool ConnectionHandler::Initialize(const ConnectionCallback& callback,
61                                    AvrcpInterface* avrcp, SdpInterface* sdp,
62                                    VolumeInterface* vol) {
63   CHECK(instance_ == nullptr);
64   CHECK(avrcp != nullptr);
65   CHECK(sdp != nullptr);
66 
67   // TODO (apanicke): When transitioning to using this service, implement
68   // SDP Initialization for AVRCP Here.
69   instance_ = new ConnectionHandler();
70   instance_->connection_cb_ = callback;
71   instance_->avrc_ = avrcp;
72   instance_->sdp_ = sdp;
73   instance_->vol_ = vol;
74 
75   // Set up the AVRCP acceptor connection
76   if (!instance_->AvrcpConnect(false, RawAddress::kAny)) {
77     instance_->CleanUp();
78     return false;
79   }
80 
81   return true;
82 }
83 
CleanUp()84 bool ConnectionHandler::CleanUp() {
85   CHECK(instance_ != nullptr);
86 
87   // TODO (apanicke): Cleanup the SDP Entries here
88   for (const auto& entry : instance_->device_map_) {
89     entry.second->DeviceDisconnected();
90     instance_->avrc_->Close(entry.first);
91   }
92   instance_->device_map_.clear();
93   instance_->feature_map_.clear();
94 
95   instance_->weak_ptr_factory_.InvalidateWeakPtrs();
96 
97   delete instance_;
98   instance_ = nullptr;
99 
100   return true;
101 }
102 
InitForTesting(ConnectionHandler * handler)103 void ConnectionHandler::InitForTesting(ConnectionHandler* handler) {
104   CHECK(instance_ == nullptr);
105   instance_ = handler;
106 }
107 
ConnectDevice(const RawAddress & bdaddr)108 bool ConnectionHandler::ConnectDevice(const RawAddress& bdaddr) {
109   LOG(INFO) << "Attempting to connect to device " << bdaddr;
110 
111   for (const auto& pair : device_map_) {
112     if (bdaddr == pair.second->GetAddress()) {
113       LOG(WARNING) << "Already connected to device with address " << bdaddr;
114       return false;
115     }
116   }
117 
118   auto connection_lambda = [](ConnectionHandler* instance_,
119                               const RawAddress& bdaddr, uint16_t status,
120                               uint16_t version, uint16_t features) {
121     LOG(INFO) << __PRETTY_FUNCTION__
122               << " SDP Completed features=" << loghex(features);
123     if (status != AVRC_SUCCESS || !(features & BTA_AV_FEAT_RCCT)) {
124       LOG(ERROR) << "Failed to do SDP: status=" << loghex(status)
125                  << " features=" << loghex(features)
126                  << " supports controller: " << (features & BTA_AV_FEAT_RCCT);
127       instance_->connection_cb_.Run(std::shared_ptr<Device>());
128     }
129 
130     instance_->feature_map_.emplace(bdaddr, features);
131     instance_->AvrcpConnect(true, bdaddr);
132     return;
133   };
134 
135   return SdpLookup(bdaddr, base::Bind(connection_lambda, this, bdaddr));
136 }
137 
DisconnectDevice(const RawAddress & bdaddr)138 bool ConnectionHandler::DisconnectDevice(const RawAddress& bdaddr) {
139   for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
140     if (bdaddr == it->second->GetAddress()) {
141       it->second->DeviceDisconnected();
142       uint8_t handle = it->first;
143       device_map_.erase(handle);
144       return avrc_->Close(handle) == AVRC_SUCCESS;
145     }
146   }
147 
148   return false;
149 }
150 
GetListOfDevices() const151 std::vector<std::shared_ptr<Device>> ConnectionHandler::GetListOfDevices()
152     const {
153   std::vector<std::shared_ptr<Device>> list;
154   for (const auto& device : device_map_) {
155     list.push_back(device.second);
156   }
157   return list;
158 }
159 
SdpLookup(const RawAddress & bdaddr,SdpCallback cb)160 bool ConnectionHandler::SdpLookup(const RawAddress& bdaddr, SdpCallback cb) {
161   LOG(INFO) << __PRETTY_FUNCTION__;
162 
163   tAVRC_SDP_DB_PARAMS db_params;
164   // TODO (apanicke): This needs to be replaced with smarter memory management.
165   tSDP_DISCOVERY_DB* disc_db =
166       (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
167   uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
168                           ATTR_ID_BT_PROFILE_DESC_LIST,
169                           ATTR_ID_SUPPORTED_FEATURES};
170 
171   db_params.db_len =
172       BT_DEFAULT_BUFFER_SIZE;  // Some magic number found in the AVRCP code
173   db_params.num_attr = sizeof(attr_list) / sizeof(attr_list[0]);
174   db_params.p_db = disc_db;
175   db_params.p_attrs = attr_list;
176 
177   return avrc_->FindService(
178              UUID_SERVCLASS_AV_REMOTE_CONTROL, bdaddr, &db_params,
179              base::Bind(&ConnectionHandler::SdpCb,
180                         weak_ptr_factory_.GetWeakPtr(), bdaddr, cb, disc_db)) ==
181          AVRC_SUCCESS;
182 }
183 
AvrcpConnect(bool initiator,const RawAddress & bdaddr)184 bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) {
185   LOG(INFO) << "Connect to device " << bdaddr.ToString();
186 
187   tAVRC_CONN_CB open_cb;
188   if (initiator) {
189     open_cb.ctrl_cback = base::Bind(&ConnectionHandler::InitiatorControlCb,
190                                     weak_ptr_factory_.GetWeakPtr());
191   } else {
192     open_cb.ctrl_cback = base::Bind(&ConnectionHandler::AcceptorControlCb,
193                                     weak_ptr_factory_.GetWeakPtr());
194   }
195   open_cb.msg_cback =
196       base::Bind(&ConnectionHandler::MessageCb, weak_ptr_factory_.GetWeakPtr());
197   open_cb.company_id = AVRC_CO_GOOGLE;
198   open_cb.conn = initiator ? AVRC_CONN_INT
199                            : AVRC_CONN_ACP;  // 0 if initiator, 1 if acceptor
200   // TODO (apanicke): We shouldn't need RCCT to do absolute volume. The current
201   // AVRC_API requires it though.
202   open_cb.control = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA;
203 
204   uint8_t handle = 0;
205   uint16_t status = avrc_->Open(&handle, &open_cb, bdaddr);
206   LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
207             << " status= " << loghex(status);
208   return status == AVRC_SUCCESS;
209 }
210 
InitiatorControlCb(uint8_t handle,uint8_t event,uint16_t result,const RawAddress * peer_addr)211 void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event,
212                                            uint16_t result,
213                                            const RawAddress* peer_addr) {
214   DCHECK(!connection_cb_.is_null());
215 
216   LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
217             << " result=" << loghex(result)
218             << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
219 
220   switch (event) {
221     case AVRC_OPEN_IND_EVT: {
222       LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
223 
224       const auto& feature_iter = feature_map_.find(*peer_addr);
225       if (feature_iter == feature_map_.end()) {
226         LOG(ERROR) << "Features do not exist even though SDP should have been "
227                       "done first";
228         return;
229       }
230 
231       bool supports_browsing = feature_iter->second & BTA_AV_FEAT_BROWSE;
232 
233       if (supports_browsing) {
234         avrc_->OpenBrowse(handle, AVCT_INT);
235       }
236 
237       // TODO (apanicke): Implement a system to cache SDP entries. For most
238       // devices SDP is completed after the device connects AVRCP so that
239       // information isn't very useful when trying to control our
240       // capabilities. For now always use AVRCP 1.6.
241       auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
242                                    base::Unretained(this), handle);
243       auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
244       auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
245       std::shared_ptr<Device> newDevice = std::make_shared<Device>(
246           *peer_addr, !supports_browsing, callback, ctrl_mtu, browse_mtu);
247 
248       device_map_[handle] = newDevice;
249       // TODO (apanicke): Create the device with all of the interfaces it
250       // needs. Return the new device where the service will register the
251       // interfaces it needs.
252       connection_cb_.Run(newDevice);
253 
254       if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) {
255         newDevice->RegisterVolumeChanged();
256       } else if (instance_->vol_ != nullptr) {
257         instance_->vol_->DeviceConnected(newDevice->GetAddress());
258       }
259 
260     } break;
261 
262     case AVRC_CLOSE_IND_EVT: {
263       LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
264 
265       if (device_map_.find(handle) == device_map_.end()) {
266         LOG(WARNING)
267             << "Connection Close received from device that doesn't exist";
268         return;
269       }
270       avrc_->Close(handle);
271       feature_map_.erase(device_map_[handle]->GetAddress());
272       device_map_[handle]->DeviceDisconnected();
273       device_map_.erase(handle);
274     } break;
275 
276     case AVRC_BROWSE_OPEN_IND_EVT: {
277       LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
278       // NOTE (apanicke): We don't need to explicitly handle this message
279       // since the AVCTP Layer will still send us browsing messages
280       // regardless. It would be useful to note this though for future
281       // compatibility issues.
282       if (device_map_.find(handle) == device_map_.end()) {
283         LOG(WARNING) << "Browse Opened received from device that doesn't exist";
284         return;
285       }
286 
287       auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
288       device_map_[handle]->SetBrowseMtu(browse_mtu);
289     } break;
290     case AVRC_BROWSE_CLOSE_IND_EVT:
291       LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
292       break;
293     default:
294       LOG(ERROR) << "Unknown AVRCP Control event";
295       break;
296   }
297 }
298 
AcceptorControlCb(uint8_t handle,uint8_t event,uint16_t result,const RawAddress * peer_addr)299 void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event,
300                                           uint16_t result,
301                                           const RawAddress* peer_addr) {
302   DCHECK(!connection_cb_.is_null());
303 
304   LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
305             << " result=" << loghex(result)
306             << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
307 
308   switch (event) {
309     case AVRC_OPEN_IND_EVT: {
310       LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
311 
312       auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
313                                    weak_ptr_factory_.GetWeakPtr(), handle);
314       auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
315       auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
316       std::shared_ptr<Device> newDevice = std::make_shared<Device>(
317           *peer_addr, false, callback, ctrl_mtu, browse_mtu);
318 
319       device_map_[handle] = newDevice;
320       connection_cb_.Run(newDevice);
321 
322       LOG(INFO) << __PRETTY_FUNCTION__
323                 << ": Performing SDP on connected device. address="
324                 << peer_addr->ToString();
325       auto sdp_lambda = [](ConnectionHandler* instance_, uint8_t handle,
326                            uint16_t status, uint16_t version,
327                            uint16_t features) {
328         if (instance_->device_map_.find(handle) ==
329             instance_->device_map_.end()) {
330           LOG(WARNING) << __PRETTY_FUNCTION__
331                        << ": No device found for handle: " << loghex(handle);
332           return;
333         }
334 
335         auto device = instance_->device_map_[handle];
336         instance_->feature_map_.emplace(device->GetAddress(), features);
337 
338         // TODO (apanicke): Report to the VolumeInterface that a new Device is
339         // connected that doesn't support absolute volume.
340         if (features & BTA_AV_FEAT_ADV_CTRL) {
341           device->RegisterVolumeChanged();
342         } else if (instance_->vol_ != nullptr) {
343           instance_->vol_->DeviceConnected(device->GetAddress());
344         }
345       };
346 
347       SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle));
348 
349       avrc_->OpenBrowse(handle, AVCT_ACP);
350       AvrcpConnect(false, RawAddress::kAny);
351     } break;
352 
353     case AVRC_CLOSE_IND_EVT: {
354       LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
355 
356       if (device_map_.find(handle) == device_map_.end()) {
357         LOG(WARNING)
358             << "Connection Close received from device that doesn't exist";
359         return;
360       }
361       avrc_->Close(handle);
362       feature_map_.erase(device_map_[handle]->GetAddress());
363       device_map_[handle]->DeviceDisconnected();
364       device_map_.erase(handle);
365     } break;
366 
367     case AVRC_BROWSE_OPEN_IND_EVT: {
368       LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
369       // NOTE (apanicke): We don't need to explicitly handle this message
370       // since the AVCTP Layer will still send us browsing messages
371       // regardless. It would be useful to note this though for future
372       // compatibility issues.
373       if (device_map_.find(handle) == device_map_.end()) {
374         LOG(WARNING) << "Browse Opened received from device that doesn't exist";
375         return;
376       }
377 
378       auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
379       device_map_[handle]->SetBrowseMtu(browse_mtu);
380     } break;
381     case AVRC_BROWSE_CLOSE_IND_EVT:
382       LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
383       break;
384     default:
385       LOG(ERROR) << "Unknown AVRCP Control event";
386       break;
387   }
388 }
389 
MessageCb(uint8_t handle,uint8_t label,uint8_t opcode,tAVRC_MSG * p_msg)390 void ConnectionHandler::MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
391                                   tAVRC_MSG* p_msg) {
392   if (device_map_.find(handle) == device_map_.end()) {
393     LOG(ERROR) << "Message received for unconnected device: handle="
394                << loghex(handle);
395     return;
396   }
397 
398   auto pkt = AvrcpMessageConverter::Parse(p_msg);
399 
400   if (opcode == AVRC_OP_BROWSE) {
401     VLOG(4) << "Browse Message received on handle " << (unsigned int)handle;
402     device_map_[handle]->BrowseMessageReceived(label, BrowsePacket::Parse(pkt));
403     return;
404   }
405 
406   VLOG(4) << "Message received on handle " << (unsigned int)handle;
407   device_map_[handle]->MessageReceived(label, Packet::Parse(pkt));
408 }
409 
SdpCb(const RawAddress & bdaddr,SdpCallback cb,tSDP_DISCOVERY_DB * disc_db,uint16_t status)410 void ConnectionHandler::SdpCb(const RawAddress& bdaddr, SdpCallback cb,
411                               tSDP_DISCOVERY_DB* disc_db, uint16_t status) {
412   LOG(INFO) << __PRETTY_FUNCTION__ << ": SDP lookup callback received";
413 
414   if (status != AVRC_SUCCESS) {
415     LOG(ERROR) << __PRETTY_FUNCTION__
416                << ": SDP Failure: status = " << (unsigned int)status;
417     cb.Run(status, 0, 0);
418     osi_free(disc_db);
419     return;
420   }
421 
422   // Check the peer features
423   tSDP_DISC_REC* sdp_record = nullptr;
424   uint16_t peer_features = 0;
425   uint16_t peer_avrcp_version = 0;
426 
427   // TODO (apanicke): Replace this in favor of our own supported features.
428   sdp_record =
429       sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, nullptr);
430   if (sdp_record != nullptr) {
431     LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
432               << " supports remote control";
433     peer_features |= BTA_AV_FEAT_RCCT;
434 
435     if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
436         NULL) {
437       /* get profile version (if failure, version parameter is not updated) */
438       sdp_->FindProfileVersionInRec(
439           sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_avrcp_version);
440       LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
441                 << " peer avrcp version=" << loghex(peer_avrcp_version);
442 
443       if (peer_avrcp_version >= AVRC_REV_1_3) {
444         // These are the standard features, another way to check this is to
445         // search for CAT1 on the remote device
446         LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
447                   << " supports metadata";
448         peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
449       }
450       if (peer_avrcp_version >= AVRC_REV_1_4) {
451         /* get supported categories */
452         LOG(INFO) << __PRETTY_FUNCTION__ << " Get Supported categories";
453         tSDP_DISC_ATTR* sdp_attribute =
454             sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
455         if (sdp_attribute != NULL) {
456           LOG(INFO) << __PRETTY_FUNCTION__
457                     << "Get Supported categories SDP ATTRIBUTES != null";
458           uint16_t categories = sdp_attribute->attr_value.v.u16;
459           if (categories & AVRC_SUPF_CT_CAT2) {
460             LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
461                       << " supports advanced control";
462             if (IsAbsoluteVolumeEnabled(&bdaddr)) {
463               peer_features |= (BTA_AV_FEAT_ADV_CTRL);
464             }
465           }
466           if (categories & AVRC_SUPF_CT_BROWSE) {
467             LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
468                       << " supports browsing";
469             peer_features |= (BTA_AV_FEAT_BROWSE);
470           }
471         }
472       }
473     }
474   }
475 
476   sdp_record = sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET,
477                                      nullptr);
478   if (sdp_record != nullptr) {
479     LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
480               << " supports remote control target";
481 
482     uint16_t peer_avrcp_target_version = 0;
483     sdp_->FindProfileVersionInRec(sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL,
484                                   &peer_avrcp_target_version);
485     LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
486               << " peer avrcp target version="
487               << loghex(peer_avrcp_target_version);
488 
489     if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
490         NULL) {
491       if (peer_avrcp_target_version >= AVRC_REV_1_4) {
492         /* get supported categories */
493         LOG(INFO) << __PRETTY_FUNCTION__ << " Get Supported categories";
494         tSDP_DISC_ATTR* sdp_attribute =
495             sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
496         if (sdp_attribute != NULL) {
497           LOG(INFO) << __PRETTY_FUNCTION__
498                     << "Get Supported categories SDP ATTRIBUTES != null";
499           uint16_t categories = sdp_attribute->attr_value.v.u16;
500           if (categories & AVRC_SUPF_CT_CAT2) {
501             LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
502                       << " supports advanced control";
503             if (IsAbsoluteVolumeEnabled(&bdaddr)) {
504               peer_features |= (BTA_AV_FEAT_ADV_CTRL);
505             }
506           }
507         }
508       }
509     }
510   }
511 
512   osi_free(disc_db);
513 
514   cb.Run(status, peer_avrcp_version, peer_features);
515 }
516 
SendMessage(uint8_t handle,uint8_t label,bool browse,std::unique_ptr<::bluetooth::PacketBuilder> message)517 void ConnectionHandler::SendMessage(
518     uint8_t handle, uint8_t label, bool browse,
519     std::unique_ptr<::bluetooth::PacketBuilder> message) {
520   std::shared_ptr<::bluetooth::Packet> packet = VectorPacket::Make();
521   message->Serialize(packet);
522 
523   uint8_t ctype = AVRC_RSP_ACCEPT;
524   if (!browse) {
525     ctype =
526         (uint8_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetCType());
527   }
528 
529   DLOG(INFO) << "SendMessage to handle=" << loghex(handle);
530 
531   BT_HDR* pkt = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
532 
533   pkt->offset = AVCT_MSG_OFFSET;
534   // TODO (apanicke): Update this constant. Currently this is a unique event
535   // used to tell the AVRCP API layer that the data is properly formatted and
536   // doesn't need to be processed. In the future, this is the only place sending
537   // the packet so none of these layer specific fields will be used.
538   pkt->event = 0xFFFF;
539 
540   // TODO (apanicke): This layer specific stuff can go away once we move over
541   // to the new service.
542   pkt->layer_specific = AVCT_DATA_CTRL;
543   if (browse) {
544     pkt->layer_specific = AVCT_DATA_BROWSE;
545   }
546 
547   pkt->len = packet->size();
548   uint8_t* p_data = (uint8_t*)(pkt + 1) + pkt->offset;
549   for (auto it = packet->begin(); it != packet->end(); it++) {
550     *p_data++ = *it;
551   }
552 
553   avrc_->MsgReq(handle, label, ctype, pkt);
554 }
555 
556 }  // namespace avrcp
557 }  // namespace bluetooth
558