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