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 (auto entry = instance_->device_map_.begin();
89 entry != instance_->device_map_.end();) {
90 auto curr = entry;
91 entry++;
92 curr->second->DeviceDisconnected();
93 instance_->avrc_->Close(curr->first);
94 }
95 instance_->device_map_.clear();
96 instance_->feature_map_.clear();
97
98 instance_->weak_ptr_factory_.InvalidateWeakPtrs();
99
100 delete instance_;
101 instance_ = nullptr;
102
103 return true;
104 }
105
InitForTesting(ConnectionHandler * handler)106 void ConnectionHandler::InitForTesting(ConnectionHandler* handler) {
107 CHECK(instance_ == nullptr);
108 instance_ = handler;
109 }
110
ConnectDevice(const RawAddress & bdaddr)111 bool ConnectionHandler::ConnectDevice(const RawAddress& bdaddr) {
112 LOG(INFO) << "Attempting to connect to device " << bdaddr;
113
114 for (const auto& pair : device_map_) {
115 if (bdaddr == pair.second->GetAddress()) {
116 LOG(WARNING) << "Already connected to device with address " << bdaddr;
117 return false;
118 }
119 }
120
121 auto connection_lambda = [](ConnectionHandler* instance_,
122 const RawAddress& bdaddr, uint16_t status,
123 uint16_t version, uint16_t features) {
124 LOG(INFO) << __PRETTY_FUNCTION__
125 << " SDP Completed features=" << loghex(features);
126 if (status != AVRC_SUCCESS || !(features & BTA_AV_FEAT_RCCT)) {
127 LOG(ERROR) << "Failed to do SDP: status=" << loghex(status)
128 << " features=" << loghex(features)
129 << " supports controller: " << (features & BTA_AV_FEAT_RCCT);
130 instance_->connection_cb_.Run(std::shared_ptr<Device>());
131 }
132
133 instance_->feature_map_.emplace(bdaddr, features);
134 instance_->AvrcpConnect(true, bdaddr);
135 return;
136 };
137
138 return SdpLookup(bdaddr, base::Bind(connection_lambda, this, bdaddr), false);
139 }
140
DisconnectDevice(const RawAddress & bdaddr)141 bool ConnectionHandler::DisconnectDevice(const RawAddress& bdaddr) {
142 for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
143 if (bdaddr == it->second->GetAddress()) {
144 uint8_t handle = it->first;
145 return avrc_->Close(handle) == AVRC_SUCCESS;
146 }
147 }
148
149 return false;
150 }
151
SetBipClientStatus(const RawAddress & bdaddr,bool connected)152 void ConnectionHandler::SetBipClientStatus(const RawAddress& bdaddr,
153 bool connected) {
154 for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
155 if (bdaddr == it->second->GetAddress()) {
156 it->second->SetBipClientStatus(connected);
157 return;
158 }
159 }
160 }
161
GetListOfDevices() const162 std::vector<std::shared_ptr<Device>> ConnectionHandler::GetListOfDevices()
163 const {
164 std::vector<std::shared_ptr<Device>> list;
165 for (const auto& device : device_map_) {
166 list.push_back(device.second);
167 }
168 return list;
169 }
170
SdpLookup(const RawAddress & bdaddr,SdpCallback cb,bool retry)171 bool ConnectionHandler::SdpLookup(const RawAddress& bdaddr, SdpCallback cb,
172 bool retry) {
173 LOG(INFO) << __PRETTY_FUNCTION__;
174
175 tAVRC_SDP_DB_PARAMS db_params;
176 // TODO (apanicke): This needs to be replaced with smarter memory management.
177 tSDP_DISCOVERY_DB* disc_db =
178 (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
179 uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
180 ATTR_ID_BT_PROFILE_DESC_LIST,
181 ATTR_ID_SUPPORTED_FEATURES};
182
183 db_params.db_len =
184 BT_DEFAULT_BUFFER_SIZE; // Some magic number found in the AVRCP code
185 db_params.num_attr = sizeof(attr_list) / sizeof(attr_list[0]);
186 db_params.p_db = disc_db;
187 db_params.p_attrs = attr_list;
188
189 return avrc_->FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, bdaddr,
190 &db_params,
191 base::Bind(&ConnectionHandler::SdpCb,
192 weak_ptr_factory_.GetWeakPtr(), bdaddr,
193 cb, disc_db, retry)) == AVRC_SUCCESS;
194 }
195
AvrcpConnect(bool initiator,const RawAddress & bdaddr)196 bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) {
197 LOG(INFO) << "Connect to device " << bdaddr.ToString();
198
199 tAVRC_CONN_CB open_cb;
200 if (initiator) {
201 open_cb.ctrl_cback = base::Bind(&ConnectionHandler::InitiatorControlCb,
202 weak_ptr_factory_.GetWeakPtr());
203 } else {
204 open_cb.ctrl_cback = base::Bind(&ConnectionHandler::AcceptorControlCb,
205 weak_ptr_factory_.GetWeakPtr());
206 }
207 open_cb.msg_cback =
208 base::Bind(&ConnectionHandler::MessageCb, weak_ptr_factory_.GetWeakPtr());
209 open_cb.company_id = AVRC_CO_GOOGLE;
210 open_cb.conn = initiator ? AVRC_CONN_INT
211 : AVRC_CONN_ACP; // 0 if initiator, 1 if acceptor
212 // TODO (apanicke): We shouldn't need RCCT to do absolute volume. The current
213 // AVRC_API requires it though.
214 open_cb.control = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA
215 | AVRC_CT_PASSIVE;
216
217 uint8_t handle = 0;
218 uint16_t status = avrc_->Open(&handle, &open_cb, bdaddr);
219 LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
220 << " status= " << loghex(status);
221 return status == AVRC_SUCCESS;
222 }
223
InitiatorControlCb(uint8_t handle,uint8_t event,uint16_t result,const RawAddress * peer_addr)224 void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event,
225 uint16_t result,
226 const RawAddress* peer_addr) {
227 DCHECK(!connection_cb_.is_null());
228
229 LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
230 << " result=" << loghex(result)
231 << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
232
233 switch (event) {
234 case AVRC_OPEN_IND_EVT: {
235 LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
236
237 const auto& feature_iter = feature_map_.find(*peer_addr);
238 if (feature_iter == feature_map_.end()) {
239 LOG(ERROR) << "Features do not exist even though SDP should have been "
240 "done first";
241 return;
242 }
243
244 bool supports_browsing = feature_iter->second & BTA_AV_FEAT_BROWSE;
245
246 if (supports_browsing) {
247 avrc_->OpenBrowse(handle, AVCT_INT);
248 }
249
250 // TODO (apanicke): Implement a system to cache SDP entries. For most
251 // devices SDP is completed after the device connects AVRCP so that
252 // information isn't very useful when trying to control our
253 // capabilities. For now always use AVRCP 1.6.
254 auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
255 base::Unretained(this), handle);
256 auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
257 auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
258 std::shared_ptr<Device> newDevice = std::make_shared<Device>(
259 *peer_addr, !supports_browsing, callback, ctrl_mtu, browse_mtu);
260
261 device_map_[handle] = newDevice;
262 // TODO (apanicke): Create the device with all of the interfaces it
263 // needs. Return the new device where the service will register the
264 // interfaces it needs.
265 connection_cb_.Run(newDevice);
266
267 if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) {
268 newDevice->RegisterVolumeChanged();
269 } else if (instance_->vol_ != nullptr) {
270 instance_->vol_->DeviceConnected(newDevice->GetAddress());
271 }
272
273 } break;
274
275 case AVRC_CLOSE_IND_EVT: {
276 LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
277
278 if (device_map_.find(handle) == device_map_.end()) {
279 LOG(WARNING)
280 << "Connection Close received from device that doesn't exist";
281 return;
282 }
283 avrc_->Close(handle);
284 feature_map_.erase(device_map_[handle]->GetAddress());
285 device_map_[handle]->DeviceDisconnected();
286 device_map_.erase(handle);
287 } break;
288
289 case AVRC_BROWSE_OPEN_IND_EVT: {
290 LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
291 // NOTE (apanicke): We don't need to explicitly handle this message
292 // since the AVCTP Layer will still send us browsing messages
293 // regardless. It would be useful to note this though for future
294 // compatibility issues.
295 if (device_map_.find(handle) == device_map_.end()) {
296 LOG(WARNING) << "Browse Opened received from device that doesn't exist";
297 return;
298 }
299
300 auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
301 device_map_[handle]->SetBrowseMtu(browse_mtu);
302 } break;
303 case AVRC_BROWSE_CLOSE_IND_EVT:
304 LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
305 break;
306 default:
307 LOG(ERROR) << "Unknown AVRCP Control event";
308 break;
309 }
310 }
311
AcceptorControlCb(uint8_t handle,uint8_t event,uint16_t result,const RawAddress * peer_addr)312 void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event,
313 uint16_t result,
314 const RawAddress* peer_addr) {
315 DCHECK(!connection_cb_.is_null());
316
317 LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
318 << " result=" << loghex(result)
319 << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
320
321 switch (event) {
322 case AVRC_OPEN_IND_EVT: {
323 LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
324
325 auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
326 weak_ptr_factory_.GetWeakPtr(), handle);
327 auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
328 auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
329 std::shared_ptr<Device> newDevice = std::make_shared<Device>(
330 *peer_addr, false, callback, ctrl_mtu, browse_mtu);
331
332 device_map_[handle] = newDevice;
333 connection_cb_.Run(newDevice);
334
335 LOG(INFO) << __PRETTY_FUNCTION__
336 << ": Performing SDP on connected device. address="
337 << peer_addr->ToString();
338 auto sdp_lambda = [](ConnectionHandler* instance_, uint8_t handle,
339 uint16_t status, uint16_t version,
340 uint16_t features) {
341 if (instance_->device_map_.find(handle) ==
342 instance_->device_map_.end()) {
343 LOG(WARNING) << __PRETTY_FUNCTION__
344 << ": No device found for handle: " << loghex(handle);
345 return;
346 }
347
348 auto device = instance_->device_map_[handle];
349 instance_->feature_map_.emplace(device->GetAddress(), features);
350
351 // TODO (apanicke): Report to the VolumeInterface that a new Device is
352 // connected that doesn't support absolute volume.
353 if (features & BTA_AV_FEAT_ADV_CTRL) {
354 device->RegisterVolumeChanged();
355 } else if (instance_->vol_ != nullptr) {
356 instance_->vol_->DeviceConnected(device->GetAddress());
357 }
358 };
359
360 SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle), false);
361
362 avrc_->OpenBrowse(handle, AVCT_ACP);
363 AvrcpConnect(false, RawAddress::kAny);
364 } break;
365
366 case AVRC_CLOSE_IND_EVT: {
367 LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
368
369 if (device_map_.find(handle) == device_map_.end()) {
370 LOG(WARNING)
371 << "Connection Close received from device that doesn't exist";
372 return;
373 }
374 avrc_->Close(handle);
375 feature_map_.erase(device_map_[handle]->GetAddress());
376 device_map_[handle]->DeviceDisconnected();
377 device_map_.erase(handle);
378 } break;
379
380 case AVRC_BROWSE_OPEN_IND_EVT: {
381 LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
382 // NOTE (apanicke): We don't need to explicitly handle this message
383 // since the AVCTP Layer will still send us browsing messages
384 // regardless. It would be useful to note this though for future
385 // compatibility issues.
386 if (device_map_.find(handle) == device_map_.end()) {
387 LOG(WARNING) << "Browse Opened received from device that doesn't exist";
388 return;
389 }
390
391 auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
392 device_map_[handle]->SetBrowseMtu(browse_mtu);
393 } break;
394 case AVRC_BROWSE_CLOSE_IND_EVT:
395 LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
396 break;
397 default:
398 LOG(ERROR) << "Unknown AVRCP Control event";
399 break;
400 }
401 }
402
MessageCb(uint8_t handle,uint8_t label,uint8_t opcode,tAVRC_MSG * p_msg)403 void ConnectionHandler::MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
404 tAVRC_MSG* p_msg) {
405 if (device_map_.find(handle) == device_map_.end()) {
406 LOG(ERROR) << "Message received for unconnected device: handle="
407 << loghex(handle);
408 return;
409 }
410
411 auto pkt = AvrcpMessageConverter::Parse(p_msg);
412
413 if (opcode == AVRC_OP_BROWSE) {
414 VLOG(4) << "Browse Message received on handle " << (unsigned int)handle;
415 device_map_[handle]->BrowseMessageReceived(label, BrowsePacket::Parse(pkt));
416 return;
417 }
418
419 VLOG(4) << "Message received on handle " << (unsigned int)handle;
420 device_map_[handle]->MessageReceived(label, Packet::Parse(pkt));
421 }
422
SdpCb(RawAddress bdaddr,SdpCallback cb,tSDP_DISCOVERY_DB * disc_db,bool retry,uint16_t status)423 void ConnectionHandler::SdpCb(RawAddress bdaddr, SdpCallback cb,
424 tSDP_DISCOVERY_DB* disc_db, bool retry,
425 uint16_t status) {
426 VLOG(1) << __PRETTY_FUNCTION__ << ": SDP lookup callback received";
427
428 if (status == SDP_CONN_FAILED and !retry) {
429 LOG(WARNING) << __PRETTY_FUNCTION__ << ": SDP Failure retry again";
430 SdpLookup(bdaddr, cb, true);
431 return;
432 } else if (status != AVRC_SUCCESS) {
433 LOG(ERROR) << __PRETTY_FUNCTION__
434 << ": SDP Failure: status = " << (unsigned int)status;
435 cb.Run(status, 0, 0);
436 osi_free(disc_db);
437 return;
438 }
439
440 // Check the peer features
441 tSDP_DISC_REC* sdp_record = nullptr;
442 uint16_t peer_features = 0;
443 uint16_t peer_avrcp_version = 0;
444
445 // TODO (apanicke): Replace this in favor of our own supported features.
446 sdp_record =
447 sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, nullptr);
448 if (sdp_record != nullptr) {
449 LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
450 << " supports remote control";
451 peer_features |= BTA_AV_FEAT_RCCT;
452
453 if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
454 NULL) {
455 /* get profile version (if failure, version parameter is not updated) */
456 sdp_->FindProfileVersionInRec(
457 sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_avrcp_version);
458 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
459 << " peer avrcp version=" << loghex(peer_avrcp_version);
460
461 if (peer_avrcp_version >= AVRC_REV_1_3) {
462 // These are the standard features, another way to check this is to
463 // search for CAT1 on the remote device
464 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
465 << " supports metadata";
466 peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
467 }
468 if (peer_avrcp_version >= AVRC_REV_1_4) {
469 /* get supported categories */
470 VLOG(1) << __PRETTY_FUNCTION__ << " Get Supported categories";
471 tSDP_DISC_ATTR* sdp_attribute =
472 sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
473 if (sdp_attribute != NULL) {
474 VLOG(1) << __PRETTY_FUNCTION__
475 << "Get Supported categories SDP ATTRIBUTES != null";
476 uint16_t categories = sdp_attribute->attr_value.v.u16;
477 if (categories & AVRC_SUPF_CT_CAT2) {
478 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
479 << " supports advanced control";
480 if (IsAbsoluteVolumeEnabled(&bdaddr)) {
481 peer_features |= (BTA_AV_FEAT_ADV_CTRL);
482 }
483 }
484 if (categories & AVRC_SUPF_CT_BROWSE) {
485 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
486 << " supports browsing";
487 peer_features |= (BTA_AV_FEAT_BROWSE);
488 }
489 }
490 }
491 }
492 }
493
494 sdp_record = sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET,
495 nullptr);
496 if (sdp_record != nullptr) {
497 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
498 << " supports remote control target";
499
500 uint16_t peer_avrcp_target_version = 0;
501 sdp_->FindProfileVersionInRec(sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL,
502 &peer_avrcp_target_version);
503 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
504 << " peer avrcp target version="
505 << loghex(peer_avrcp_target_version);
506
507 if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
508 NULL) {
509 if (peer_avrcp_target_version >= AVRC_REV_1_4) {
510 /* get supported categories */
511 VLOG(1) << __PRETTY_FUNCTION__ << " Get Supported categories";
512 tSDP_DISC_ATTR* sdp_attribute =
513 sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
514 if (sdp_attribute != NULL) {
515 VLOG(1) << __PRETTY_FUNCTION__
516 << "Get Supported categories SDP ATTRIBUTES != null";
517 uint16_t categories = sdp_attribute->attr_value.v.u16;
518 if (categories & AVRC_SUPF_CT_CAT2) {
519 VLOG(1) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
520 << " supports advanced control";
521 if (IsAbsoluteVolumeEnabled(&bdaddr)) {
522 peer_features |= (BTA_AV_FEAT_ADV_CTRL);
523 }
524 }
525 }
526 }
527 }
528 }
529
530 osi_free(disc_db);
531
532 cb.Run(status, peer_avrcp_version, peer_features);
533 }
534
SendMessage(uint8_t handle,uint8_t label,bool browse,std::unique_ptr<::bluetooth::PacketBuilder> message)535 void ConnectionHandler::SendMessage(
536 uint8_t handle, uint8_t label, bool browse,
537 std::unique_ptr<::bluetooth::PacketBuilder> message) {
538 std::shared_ptr<::bluetooth::Packet> packet = VectorPacket::Make();
539 message->Serialize(packet);
540
541 uint8_t ctype = AVRC_RSP_ACCEPT;
542 if (!browse) {
543 ctype =
544 (uint8_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetCType());
545 }
546
547 DLOG(INFO) << "SendMessage to handle=" << loghex(handle);
548
549 BT_HDR* pkt = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
550
551 pkt->offset = AVCT_MSG_OFFSET;
552 // TODO (apanicke): Update this constant. Currently this is a unique event
553 // used to tell the AVRCP API layer that the data is properly formatted and
554 // doesn't need to be processed. In the future, this is the only place sending
555 // the packet so none of these layer specific fields will be used.
556 pkt->event = 0xFFFF;
557 /* Handle for AVRCP fragment */
558 uint16_t op_code = (uint16_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetOpcode());
559 if (!browse && (op_code == (uint16_t)(Opcode::VENDOR))) {
560 pkt->event = op_code;
561 }
562
563 // TODO (apanicke): This layer specific stuff can go away once we move over
564 // to the new service.
565 pkt->layer_specific = AVCT_DATA_CTRL;
566 if (browse) {
567 pkt->layer_specific = AVCT_DATA_BROWSE;
568 }
569
570 pkt->len = packet->size();
571 uint8_t* p_data = (uint8_t*)(pkt + 1) + pkt->offset;
572 for (auto it = packet->begin(); it != packet->end(); it++) {
573 *p_data++ = *it;
574 }
575
576 avrc_->MsgReq(handle, label, ctype, pkt);
577 }
578
579 } // namespace avrcp
580 } // namespace bluetooth
581