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 #define LOG_TAG "avrcp"
18
19 #include "device.h"
20
21 #include <bluetooth/log.h>
22 #include <com_android_bluetooth_flags.h>
23
24 #include "abstract_message_loop.h"
25 #include "avrcp_common.h"
26 #include "btif/include/btif_av.h"
27 #include "internal_include/stack_config.h"
28 #include "packet/avrcp/avrcp_reject_packet.h"
29 #include "packet/avrcp/general_reject_packet.h"
30 #include "packet/avrcp/get_current_player_application_setting_value.h"
31 #include "packet/avrcp/get_play_status_packet.h"
32 #include "packet/avrcp/list_player_application_setting_attributes.h"
33 #include "packet/avrcp/list_player_application_setting_values.h"
34 #include "packet/avrcp/pass_through_packet.h"
35 #include "packet/avrcp/set_absolute_volume.h"
36 #include "packet/avrcp/set_addressed_player.h"
37 #include "packet/avrcp/set_player_application_setting_value.h"
38 #include "types/raw_address.h"
39
40 template <>
41 struct std::formatter<bluetooth::avrcp::PlayState> : enum_formatter<bluetooth::avrcp::PlayState> {};
42
43 namespace bluetooth {
44 namespace avrcp {
45
46 #define VOL_NOT_SUPPORTED -1
47 #define VOL_REGISTRATION_FAILED -2
48
Device(const RawAddress & bdaddr,bool avrcp13_compatibility,base::RepeatingCallback<void (uint8_t label,bool browse,std::unique_ptr<::bluetooth::PacketBuilder> message)> send_msg_cb,uint16_t ctrl_mtu,uint16_t browse_mtu)49 Device::Device(const RawAddress& bdaddr, bool avrcp13_compatibility,
50 base::RepeatingCallback<void(uint8_t label, bool browse,
51 std::unique_ptr<::bluetooth::PacketBuilder> message)>
52 send_msg_cb,
53 uint16_t ctrl_mtu, uint16_t browse_mtu)
54 : weak_ptr_factory_(this),
55 address_(bdaddr),
56 avrcp13_compatibility_(avrcp13_compatibility),
57 send_message_cb_(send_msg_cb),
58 ctrl_mtu_(ctrl_mtu),
59 browse_mtu_(browse_mtu),
60 has_bip_client_(false) {}
61
RegisterInterfaces(MediaInterface * media_interface,A2dpInterface * a2dp_interface,VolumeInterface * volume_interface,PlayerSettingsInterface * player_settings_interface)62 void Device::RegisterInterfaces(MediaInterface* media_interface, A2dpInterface* a2dp_interface,
63 VolumeInterface* volume_interface,
64 PlayerSettingsInterface* player_settings_interface) {
65 log::assert_that(media_interface != nullptr, "assert failed: media_interface != nullptr");
66 log::assert_that(a2dp_interface != nullptr, "assert failed: a2dp_interface != nullptr");
67 a2dp_interface_ = a2dp_interface;
68 media_interface_ = media_interface;
69 volume_interface_ = volume_interface;
70 player_settings_interface_ = player_settings_interface;
71 }
72
Get()73 base::WeakPtr<Device> Device::Get() { return weak_ptr_factory_.GetWeakPtr(); }
74
SetBrowseMtu(uint16_t browse_mtu)75 void Device::SetBrowseMtu(uint16_t browse_mtu) {
76 log::info("{}: browse_mtu = {}", address_, browse_mtu);
77 browse_mtu_ = browse_mtu;
78 }
79
SetBipClientStatus(bool connected)80 void Device::SetBipClientStatus(bool connected) {
81 log::info("{}: connected = {}", address_, connected);
82 has_bip_client_ = connected;
83 }
84
HasBipClient() const85 bool Device::HasBipClient() const { return has_bip_client_; }
86
filter_cover_art(SongInfo & s)87 static void filter_cover_art(SongInfo& s) {
88 for (auto it = s.attributes.begin(); it != s.attributes.end(); it++) {
89 if (it->attribute() == Attribute::DEFAULT_COVER_ART) {
90 s.attributes.erase(it);
91 break;
92 }
93 }
94 }
95
IsActive() const96 bool Device::IsActive() const { return address_ == a2dp_interface_->active_peer(); }
97
IsInSilenceMode() const98 bool Device::IsInSilenceMode() const { return a2dp_interface_->is_peer_in_silence_mode(address_); }
99
VendorPacketHandler(uint8_t label,std::shared_ptr<VendorPacket> pkt)100 void Device::VendorPacketHandler(uint8_t label, std::shared_ptr<VendorPacket> pkt) {
101 log::assert_that(media_interface_ != nullptr, "assert failed: media_interface_ != nullptr");
102 log::verbose("pdu={}", pkt->GetCommandPdu());
103
104 if (!pkt->IsValid()) {
105 log::warn("{}: Request packet is not valid", address_);
106 auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
107 send_message(label, false, std::move(response));
108 return;
109 }
110
111 // All CTypes at and above NOT_IMPLEMENTED are all response types.
112 if (pkt->GetCType() == CType::NOT_IMPLEMENTED) {
113 return;
114 }
115
116 if (pkt->GetCType() >= CType::ACCEPTED) {
117 switch (pkt->GetCommandPdu()) {
118 // VOLUME_CHANGED is the only notification we register for while target.
119 case CommandPdu::REGISTER_NOTIFICATION: {
120 auto register_notification = Packet::Specialize<RegisterNotificationResponse>(pkt);
121
122 if ((!btif_av_src_sink_coexist_enabled() ||
123 (btif_av_src_sink_coexist_enabled() &&
124 register_notification->GetEvent() == Event::VOLUME_CHANGED)) &&
125 !register_notification->IsValid()) {
126 log::warn("{}: Request packet is not valid", address_);
127 auto response =
128 RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
129 send_message(label, false, std::move(response));
130 active_labels_.erase(label);
131 volume_interface_ = nullptr;
132 volume_ = VOL_REGISTRATION_FAILED;
133 return;
134 }
135
136 // The rejected packet doesn't have an event field, so we just have to assume it is indeed
137 // for the volume changed event since that's the only one we possibly register.
138 if (pkt->GetCType() == CType::REJECTED ||
139 register_notification->GetEvent() == Event::VOLUME_CHANGED) {
140 HandleVolumeChanged(label, register_notification);
141 } else {
142 log::warn("{}: Unhandled register notification received: {}", address_,
143 register_notification->GetEvent());
144 }
145 break;
146 }
147 case CommandPdu::SET_ABSOLUTE_VOLUME:
148 // TODO (apanicke): Add a retry mechanism if the response has a
149 // different volume than the one we set. For now, we don't care
150 // about the response to this message.
151 active_labels_.erase(label);
152 break;
153 default:
154 log::warn("{}: Unhandled Response: pdu={}", address_, pkt->GetCommandPdu());
155 break;
156 }
157 return;
158 }
159
160 switch (pkt->GetCommandPdu()) {
161 case CommandPdu::GET_CAPABILITIES: {
162 HandleGetCapabilities(label, Packet::Specialize<GetCapabilitiesRequest>(pkt));
163 } break;
164
165 case CommandPdu::REGISTER_NOTIFICATION: {
166 HandleNotification(label, Packet::Specialize<RegisterNotificationRequest>(pkt));
167 } break;
168
169 case CommandPdu::GET_ELEMENT_ATTRIBUTES: {
170 auto get_element_attributes_request_pkt =
171 Packet::Specialize<GetElementAttributesRequest>(pkt);
172
173 if (!get_element_attributes_request_pkt->IsValid()) {
174 log::warn("{}: Request packet is not valid", address_);
175 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
176 send_message(label, false, std::move(response));
177 return;
178 }
179 media_interface_->GetSongInfo(base::Bind(&Device::GetElementAttributesResponse,
180 weak_ptr_factory_.GetWeakPtr(), label,
181 get_element_attributes_request_pkt));
182 } break;
183
184 case CommandPdu::GET_PLAY_STATUS: {
185 media_interface_->GetPlayStatus(
186 base::Bind(&Device::GetPlayStatusResponse, weak_ptr_factory_.GetWeakPtr(), label));
187 } break;
188
189 case CommandPdu::PLAY_ITEM: {
190 HandlePlayItem(label, Packet::Specialize<PlayItemRequest>(pkt));
191 } break;
192
193 case CommandPdu::SET_ADDRESSED_PLAYER: {
194 auto set_addressed_player_request = Packet::Specialize<SetAddressedPlayerRequest>(pkt);
195
196 if (!set_addressed_player_request->IsValid()) {
197 log::warn("{}: Request packet is not valid", address_);
198 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
199 send_message(label, false, std::move(response));
200 return;
201 }
202
203 media_interface_->SetAddressedPlayer(
204 set_addressed_player_request->GetPlayerId(),
205 base::Bind(&Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(), label,
206 set_addressed_player_request));
207 } break;
208
209 case CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES: {
210 if (player_settings_interface_ == nullptr) {
211 log::error("Player Settings Interface not initialized.");
212 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_COMMAND);
213 send_message(label, false, std::move(response));
214 return;
215 }
216
217 player_settings_interface_->ListPlayerSettings(
218 base::Bind(&Device::ListPlayerApplicationSettingAttributesResponse,
219 weak_ptr_factory_.GetWeakPtr(), label));
220 } break;
221
222 case CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES: {
223 if (player_settings_interface_ == nullptr) {
224 log::error("Player Settings Interface not initialized.");
225 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_COMMAND);
226 send_message(label, false, std::move(response));
227 return;
228 }
229 auto list_player_setting_values_request =
230 Packet::Specialize<ListPlayerApplicationSettingValuesRequest>(pkt);
231
232 if (!list_player_setting_values_request->IsValid()) {
233 log::warn("{}: Request packet is not valid", address_);
234 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
235 send_message(label, false, std::move(response));
236 return;
237 }
238
239 PlayerAttribute attribute = list_player_setting_values_request->GetRequestedAttribute();
240 if (attribute < PlayerAttribute::EQUALIZER || attribute > PlayerAttribute::SCAN) {
241 log::warn("{}: Player Setting Attribute is not valid", address_);
242 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
243 send_message(label, false, std::move(response));
244 return;
245 }
246
247 player_settings_interface_->ListPlayerSettingValues(
248 attribute, base::Bind(&Device::ListPlayerApplicationSettingValuesResponse,
249 weak_ptr_factory_.GetWeakPtr(), label));
250 } break;
251
252 case CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE: {
253 if (player_settings_interface_ == nullptr) {
254 log::error("Player Settings Interface not initialized.");
255 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_COMMAND);
256 send_message(label, false, std::move(response));
257 return;
258 }
259 auto get_current_player_setting_value_request =
260 Packet::Specialize<GetCurrentPlayerApplicationSettingValueRequest>(pkt);
261
262 if (!get_current_player_setting_value_request->IsValid()) {
263 log::warn("{}: Request packet is not valid", address_);
264 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
265 send_message(label, false, std::move(response));
266 return;
267 }
268
269 std::vector<PlayerAttribute> attributes =
270 get_current_player_setting_value_request->GetRequestedAttributes();
271 for (auto attribute : attributes) {
272 if (attribute < PlayerAttribute::EQUALIZER || attribute > PlayerAttribute::SCAN) {
273 log::warn("{}: Player Setting Attribute is not valid", address_);
274 auto response =
275 RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
276 send_message(label, false, std::move(response));
277 return;
278 }
279 }
280
281 player_settings_interface_->GetCurrentPlayerSettingValue(
282 attributes, base::Bind(&Device::GetPlayerApplicationSettingValueResponse,
283 weak_ptr_factory_.GetWeakPtr(), label));
284 } break;
285
286 case CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE: {
287 if (player_settings_interface_ == nullptr) {
288 log::error("Player Settings Interface not initialized.");
289 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_COMMAND);
290 send_message(label, false, std::move(response));
291 return;
292 }
293 auto set_player_setting_value_request =
294 Packet::Specialize<SetPlayerApplicationSettingValueRequest>(pkt);
295
296 if (!set_player_setting_value_request->IsValid()) {
297 log::warn("{} : Request packet is not valid", address_);
298 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
299 send_message(label, false, std::move(response));
300 return;
301 }
302
303 std::vector<PlayerAttribute> attributes =
304 set_player_setting_value_request->GetRequestedAttributes();
305 std::vector<uint8_t> values = set_player_setting_value_request->GetRequestedValues();
306
307 bool invalid_request = false;
308 for (size_t i = 0; i < attributes.size(); i++) {
309 if (attributes[i] < PlayerAttribute::EQUALIZER || attributes[i] > PlayerAttribute::SCAN) {
310 log::warn("{}: Player Setting Attribute is not valid", address_);
311 invalid_request = true;
312 break;
313 }
314
315 if (attributes[i] == PlayerAttribute::REPEAT) {
316 PlayerRepeatValue value = static_cast<PlayerRepeatValue>(values[i]);
317 if (value < PlayerRepeatValue::OFF || value > PlayerRepeatValue::GROUP) {
318 log::warn("{}: Player Repeat Value is not valid", address_);
319 invalid_request = true;
320 break;
321 }
322 } else if (attributes[i] == PlayerAttribute::SHUFFLE) {
323 PlayerShuffleValue value = static_cast<PlayerShuffleValue>(values[i]);
324 if (value < PlayerShuffleValue::OFF || value > PlayerShuffleValue::GROUP) {
325 log::warn("{}: Player Shuffle Value is not valid", address_);
326 invalid_request = true;
327 break;
328 }
329 }
330 }
331
332 if (invalid_request) {
333 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
334 send_message(label, false, std::move(response));
335 return;
336 }
337
338 player_settings_interface_->SetPlayerSettings(
339 attributes, values,
340 base::Bind(&Device::SetPlayerApplicationSettingValueResponse,
341 weak_ptr_factory_.GetWeakPtr(), label, pkt->GetCommandPdu()));
342 } break;
343
344 default: {
345 log::error("{}: Unhandled Vendor Packet: {}", address_, pkt->ToString());
346 auto response =
347 RejectBuilder::MakeBuilder((CommandPdu)pkt->GetCommandPdu(), Status::INVALID_COMMAND);
348 send_message(label, false, std::move(response));
349 } break;
350 }
351 }
352
HandleGetCapabilities(uint8_t label,const std::shared_ptr<GetCapabilitiesRequest> & pkt)353 void Device::HandleGetCapabilities(uint8_t label,
354 const std::shared_ptr<GetCapabilitiesRequest>& pkt) {
355 if (!pkt->IsValid()) {
356 log::warn("{}: Request packet is not valid", address_);
357 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
358 send_message(label, false, std::move(response));
359 return;
360 }
361
362 log::verbose("capability={}", pkt->GetCapabilityRequested());
363
364 switch (pkt->GetCapabilityRequested()) {
365 case Capability::COMPANY_ID: {
366 auto response = GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958);
367 response->AddCompanyId(0x002345);
368 send_message_cb_.Run(label, false, std::move(response));
369 } break;
370
371 case Capability::EVENTS_SUPPORTED: {
372 auto response = GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
373 Event::PLAYBACK_STATUS_CHANGED);
374 response->AddEvent(Event::TRACK_CHANGED);
375 response->AddEvent(Event::PLAYBACK_POS_CHANGED);
376 if (player_settings_interface_ != nullptr) {
377 response->AddEvent(Event::PLAYER_APPLICATION_SETTING_CHANGED);
378 }
379
380 if (!avrcp13_compatibility_) {
381 response->AddEvent(Event::AVAILABLE_PLAYERS_CHANGED);
382 response->AddEvent(Event::ADDRESSED_PLAYER_CHANGED);
383 response->AddEvent(Event::UIDS_CHANGED);
384 response->AddEvent(Event::NOW_PLAYING_CONTENT_CHANGED);
385 }
386
387 send_message(label, false, std::move(response));
388 } break;
389
390 default: {
391 log::warn("{}: Unhandled Capability: {}", address_, pkt->GetCapabilityRequested());
392 auto response =
393 RejectBuilder::MakeBuilder(CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);
394 send_message(label, false, std::move(response));
395 } break;
396 }
397 }
398
HandleNotification(uint8_t label,const std::shared_ptr<RegisterNotificationRequest> & pkt)399 void Device::HandleNotification(uint8_t label,
400 const std::shared_ptr<RegisterNotificationRequest>& pkt) {
401 if (!pkt->IsValid()) {
402 log::warn("{}: Request packet is not valid", address_);
403 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
404 send_message(label, false, std::move(response));
405 return;
406 }
407
408 log::verbose("event={}", pkt->GetEventRegistered());
409
410 switch (pkt->GetEventRegistered()) {
411 case Event::TRACK_CHANGED: {
412 media_interface_->GetNowPlayingList(base::Bind(&Device::TrackChangedNotificationResponse,
413 weak_ptr_factory_.GetWeakPtr(), label, true));
414 } break;
415
416 case Event::PLAYBACK_STATUS_CHANGED: {
417 media_interface_->GetPlayStatus(base::Bind(&Device::PlaybackStatusNotificationResponse,
418 weak_ptr_factory_.GetWeakPtr(), label, true));
419 } break;
420
421 case Event::PLAYBACK_POS_CHANGED: {
422 play_pos_interval_ = pkt->GetInterval();
423 media_interface_->GetPlayStatus(base::Bind(&Device::PlaybackPosNotificationResponse,
424 weak_ptr_factory_.GetWeakPtr(), label, true));
425 } break;
426
427 case Event::PLAYER_APPLICATION_SETTING_CHANGED: {
428 if (player_settings_interface_ == nullptr) {
429 log::error("Player Settings Interface not initialized.");
430 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_COMMAND);
431 send_message(label, false, std::move(response));
432 return;
433 }
434 std::vector<PlayerAttribute> attributes = {PlayerAttribute::EQUALIZER,
435 PlayerAttribute::REPEAT, PlayerAttribute::SHUFFLE,
436 PlayerAttribute::SCAN};
437 player_settings_interface_->GetCurrentPlayerSettingValue(
438 attributes, base::Bind(&Device::PlayerSettingChangedNotificationResponse,
439 weak_ptr_factory_.GetWeakPtr(), label, true));
440 } break;
441
442 case Event::NOW_PLAYING_CONTENT_CHANGED: {
443 media_interface_->GetNowPlayingList(base::Bind(&Device::HandleNowPlayingNotificationResponse,
444 weak_ptr_factory_.GetWeakPtr(), label, true));
445 } break;
446
447 case Event::AVAILABLE_PLAYERS_CHANGED: {
448 // TODO (apanicke): If we make a separate handler function for this, make
449 // sure to register the notification in the interim response.
450
451 // Respond immediately since this notification doesn't require any info
452 avail_players_changed_ = Notification(true, label);
453 auto response = RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(true);
454 send_message(label, false, std::move(response));
455 } break;
456
457 case Event::ADDRESSED_PLAYER_CHANGED: {
458 media_interface_->GetAddressedPlayer(base::Bind(&Device::AddressedPlayerNotificationResponse,
459 weak_ptr_factory_.GetWeakPtr(), label, true));
460 } break;
461
462 case Event::UIDS_CHANGED: {
463 // TODO (apanicke): If we make a separate handler function for this, make
464 // sure to register the notification in the interim response.
465
466 // Respond immediately since this notification doesn't require any info
467 uids_changed_ = Notification(true, label);
468 auto response = RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(true, 0);
469 send_message(label, false, std::move(response));
470 } break;
471
472 default: {
473 log::error("{}: Unknown event registered. Event ID={}", address_, pkt->GetEventRegistered());
474 auto response = RejectBuilder::MakeBuilder((CommandPdu)pkt->GetCommandPdu(),
475 Status::INVALID_PARAMETER);
476 send_message(label, false, std::move(response));
477 } break;
478 }
479 }
480
RegisterVolumeChanged()481 void Device::RegisterVolumeChanged() {
482 log::verbose("");
483 if (volume_interface_ == nullptr) {
484 return;
485 }
486
487 auto request = RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
488
489 // Find an open transaction label to prevent conflicts with other commands
490 // that are in flight. We can not use the reserved label while the
491 // notification hasn't been completed.
492 uint8_t label = MAX_TRANSACTION_LABEL;
493 for (uint8_t i = 0; i < MAX_TRANSACTION_LABEL; i++) {
494 if (active_labels_.find(i) == active_labels_.end()) {
495 active_labels_.insert(i);
496 label = i;
497 break;
498 }
499 }
500
501 if (label == MAX_TRANSACTION_LABEL) {
502 log::fatal("{}: Abandon all hope, something went catastrophically wrong", address_);
503 }
504
505 send_message_cb_.Run(label, false, std::move(request));
506 }
507
HandleVolumeChanged(uint8_t label,const std::shared_ptr<RegisterNotificationResponse> & pkt)508 void Device::HandleVolumeChanged(uint8_t label,
509 const std::shared_ptr<RegisterNotificationResponse>& pkt) {
510 log::verbose("interim={}", pkt->IsInterim());
511
512 if (volume_interface_ == nullptr) {
513 return;
514 }
515
516 if (pkt->GetCType() == CType::REJECTED) {
517 // Disable Absolute Volume
518 active_labels_.erase(label);
519 volume_ = VOL_REGISTRATION_FAILED;
520 volume_interface_->DeviceConnected(GetAddress());
521 return;
522 }
523
524 // We only update on interim and just re-register on changes.
525 if (!pkt->IsInterim()) {
526 active_labels_.erase(label);
527 RegisterVolumeChanged();
528 return;
529 }
530
531 // Handle the first volume update.
532 if (volume_ == VOL_NOT_SUPPORTED) {
533 volume_ = pkt->GetVolume();
534 volume_ &= ~0x80; // remove RFA bit
535 volume_interface_->DeviceConnected(
536 GetAddress(), base::Bind(&Device::SetVolume, weak_ptr_factory_.GetWeakPtr()));
537
538 // Ignore the returned volume in favor of the volume returned
539 // by the volume interface.
540 return;
541 }
542
543 if (!IsActive()) {
544 log::verbose("Ignoring volume changes from non active device");
545 return;
546 }
547
548 volume_ = pkt->GetVolume();
549 volume_ &= ~0x80; // remove RFA bit
550 log::verbose("Volume has changed to {}", (uint32_t)volume_);
551 volume_interface_->SetVolume(volume_);
552 }
553
SetVolume(int8_t volume)554 void Device::SetVolume(int8_t volume) {
555 // TODO (apanicke): Implement logic for Multi-AVRCP
556 log::verbose("volume={}", (int)volume);
557 if (volume == volume_) {
558 log::warn("{}: Ignoring volume change same as current volume level", address_);
559 return;
560 }
561 auto request = SetAbsoluteVolumeRequestBuilder::MakeBuilder(volume);
562
563 uint8_t label = MAX_TRANSACTION_LABEL;
564 for (uint8_t i = 0; i < MAX_TRANSACTION_LABEL; i++) {
565 if (active_labels_.find(i) == active_labels_.end()) {
566 active_labels_.insert(i);
567 label = i;
568 break;
569 }
570 }
571
572 volume_ = volume;
573 send_message_cb_.Run(label, false, std::move(request));
574 }
575
TrackChangedNotificationResponse(uint8_t label,bool interim,std::string curr_song_id,std::vector<SongInfo> song_list)576 void Device::TrackChangedNotificationResponse(uint8_t label, bool interim, std::string curr_song_id,
577 std::vector<SongInfo> song_list) {
578 log::verbose("");
579
580 if (interim) {
581 track_changed_ = Notification(true, label);
582 } else if (!track_changed_.first) {
583 log::verbose("Device not registered for update");
584 return;
585 }
586
587 if (!interim) {
588 if (curr_song_id.empty()) {
589 // CHANGED response is only defined when there is media selected
590 // for playing.
591 return;
592 }
593 active_labels_.erase(label);
594 track_changed_ = Notification(false, 0);
595 }
596
597 // Case for browsing not supported;
598 // PTS BV-04-C and BV-5-C assume browsing not supported
599 if (stack_config_get_interface()->get_pts_avrcp_test()) {
600 log::warn("{}: pts test mode", address_);
601 uint64_t uid =
602 (curr_song_id.empty() || curr_song_id == "Not Provided") ? 0xffffffffffffffff : 0;
603 auto response = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(interim, uid);
604 send_message_cb_.Run(label, false, std::move(response));
605 return;
606 }
607
608 // Anytime we use the now playing list, update our map so that its always
609 // current
610 now_playing_ids_.clear();
611 uint64_t uid = 0;
612 for (const SongInfo& song : song_list) {
613 now_playing_ids_.insert(song.media_id);
614 if (curr_song_id == song.media_id) {
615 log::verbose("Found media ID match for {}", song.media_id);
616 uid = now_playing_ids_.get_uid(curr_song_id);
617 }
618 }
619
620 if (uid == 0) {
621 // uid 0 is not valid here when browsing is supported
622 log::error("{}: No match for media ID found", address_);
623 }
624
625 auto response = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(interim, uid);
626 send_message_cb_.Run(label, false, std::move(response));
627 }
628
PlaybackStatusNotificationResponse(uint8_t label,bool interim,PlayStatus status)629 void Device::PlaybackStatusNotificationResponse(uint8_t label, bool interim, PlayStatus status) {
630 log::verbose("");
631 if (status.state == PlayState::PAUSED) {
632 play_pos_update_cb_.Cancel();
633 }
634
635 if (interim) {
636 play_status_changed_ = Notification(true, label);
637 } else if (!play_status_changed_.first) {
638 log::verbose("Device not registered for update");
639 return;
640 }
641
642 auto state_to_send = status.state;
643 if (!IsActive()) {
644 state_to_send = PlayState::PAUSED;
645 }
646 if (!interim && state_to_send == last_play_status_.state) {
647 log::verbose("Not sending notification due to no state update {}", address_);
648 return;
649 }
650
651 last_play_status_.state = state_to_send;
652
653 auto response = RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
654 interim, IsActive() ? status.state : PlayState::PAUSED);
655 send_message_cb_.Run(label, false, std::move(response));
656
657 if (!interim) {
658 active_labels_.erase(label);
659 play_status_changed_ = Notification(false, 0);
660 }
661 }
662
PlaybackPosNotificationResponse(uint8_t label,bool interim,PlayStatus status)663 void Device::PlaybackPosNotificationResponse(uint8_t label, bool interim, PlayStatus status) {
664 log::verbose("");
665
666 if (interim) {
667 play_pos_changed_ = Notification(true, label);
668 } else if (!play_pos_changed_.first) {
669 log::verbose("Device not registered for update");
670 return;
671 }
672
673 if (!interim && last_play_status_.position == status.position) {
674 log::warn("{}: No update to play position", address_);
675 return;
676 }
677
678 auto response = RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(interim,
679 status.position);
680 send_message_cb_.Run(label, false, std::move(response));
681
682 last_play_status_.position = status.position;
683
684 if (!interim) {
685 active_labels_.erase(label);
686 play_pos_changed_ = Notification(false, 0);
687 }
688
689 // We still try to send updates while music is playing to the non active
690 // device even though the device thinks the music is paused. This makes
691 // the status bar on the remote device move.
692 if (status.state == PlayState::PLAYING && !IsInSilenceMode()) {
693 log::verbose("Queue next play position update");
694 play_pos_update_cb_.Reset(
695 base::Bind(&Device::HandlePlayPosUpdate, weak_ptr_factory_.GetWeakPtr()));
696 btbase::AbstractMessageLoop::current_task_runner()->PostDelayedTask(
697 FROM_HERE, play_pos_update_cb_.callback(),
698 #if BASE_VER < 931007
699 base::TimeDelta::FromSeconds(play_pos_interval_));
700 #else
701 base::Seconds(play_pos_interval_));
702 #endif
703 }
704 }
705
AddressedPlayerNotificationResponse(uint8_t label,bool interim,uint16_t curr_player)706 void Device::AddressedPlayerNotificationResponse(uint8_t label, bool interim,
707 uint16_t curr_player) {
708 log::verbose("curr_player_id={}", (unsigned int)curr_player);
709
710 if (interim) {
711 addr_player_changed_ = Notification(true, label);
712 } else if (!addr_player_changed_.first) {
713 log::verbose("Device not registered for update");
714 return;
715 }
716
717 // If there is no set browsed player, use the current addressed player as the
718 // default NOTE: Using any browsing commands before the browsed player is set
719 // is a violation of the AVRCP Spec but there are some carkits that try too
720 // anyways
721 if (curr_browsed_player_id_ == -1) {
722 curr_browsed_player_id_ = curr_player;
723 }
724 curr_addressed_player_id_ = curr_player;
725
726 auto response = RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
727 interim, curr_player, 0x0000);
728 send_message_cb_.Run(label, false, std::move(response));
729
730 if (!interim) {
731 active_labels_.erase(label);
732 addr_player_changed_ = Notification(false, 0);
733 RejectNotification();
734 }
735 }
736
RejectNotification()737 void Device::RejectNotification() {
738 log::verbose("");
739 Notification* rejectNotification[] = {&play_status_changed_, &track_changed_, &play_pos_changed_,
740 &now_playing_changed_};
741 for (int i = 0; i < 4; i++) {
742 uint8_t label = rejectNotification[i]->second;
743 auto response = RejectBuilder::MakeBuilder(CommandPdu::REGISTER_NOTIFICATION,
744 Status::ADDRESSED_PLAYER_CHANGED);
745 send_message_cb_.Run(label, false, std::move(response));
746 active_labels_.erase(label);
747 rejectNotification[i] = new Notification(false, 0);
748 }
749 }
750
GetPlayStatusResponse(uint8_t label,PlayStatus status)751 void Device::GetPlayStatusResponse(uint8_t label, PlayStatus status) {
752 log::verbose("position={} duration={} state={}", status.position, status.duration, status.state);
753 auto response = GetPlayStatusResponseBuilder::MakeBuilder(
754 status.duration, status.position, IsActive() ? status.state : PlayState::PAUSED);
755 send_message(label, false, std::move(response));
756 }
757
GetElementAttributesResponse(uint8_t label,std::shared_ptr<GetElementAttributesRequest> pkt,SongInfo info)758 void Device::GetElementAttributesResponse(uint8_t label,
759 std::shared_ptr<GetElementAttributesRequest> pkt,
760 SongInfo info) {
761 auto get_element_attributes_pkt = pkt;
762 auto attributes_requested = get_element_attributes_pkt->GetAttributesRequested();
763 bool all_attributes_flag = com::android::bluetooth::flags::get_all_element_attributes_empty();
764
765 auto response = GetElementAttributesResponseBuilder::MakeBuilder(ctrl_mtu_);
766
767 // Filter out DEFAULT_COVER_ART handle if this device has no client
768 if (!HasBipClient()) {
769 filter_cover_art(info);
770 }
771
772 last_song_info_ = info;
773
774 if (attributes_requested.size() != 0) {
775 for (const auto& attribute : attributes_requested) {
776 if (info.attributes.find(attribute) != info.attributes.end()) {
777 response->AddAttributeEntry(*info.attributes.find(attribute));
778 } else if (all_attributes_flag) {
779 response->AddAttributeEntry(attribute, std::string());
780 }
781 }
782 } else { // zero attributes requested which means all attributes requested
783 if (!all_attributes_flag) {
784 for (const auto& attribute : info.attributes) {
785 response->AddAttributeEntry(attribute);
786 }
787 } else {
788 std::vector<Attribute> all_attributes = {Attribute::TITLE,
789 Attribute::ARTIST_NAME,
790 Attribute::ALBUM_NAME,
791 Attribute::TRACK_NUMBER,
792 Attribute::TOTAL_NUMBER_OF_TRACKS,
793 Attribute::GENRE,
794 Attribute::PLAYING_TIME,
795 Attribute::DEFAULT_COVER_ART};
796 for (const auto& attribute : all_attributes) {
797 if (info.attributes.find(attribute) != info.attributes.end()) {
798 response->AddAttributeEntry(*info.attributes.find(attribute));
799 } else {
800 // If all attributes were requested, we send a response even for attributes that we don't
801 // have a value for.
802 response->AddAttributeEntry(attribute, std::string());
803 }
804 }
805 }
806 }
807
808 send_message(label, false, std::move(response));
809 }
810
MessageReceived(uint8_t label,std::shared_ptr<Packet> pkt)811 void Device::MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt) {
812 if (!pkt->IsValid()) {
813 log::warn("{}: Request packet is not valid", address_);
814 auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
815 send_message(label, false, std::move(response));
816 return;
817 }
818
819 log::verbose("opcode={}", pkt->GetOpcode());
820 active_labels_.insert(label);
821 switch (pkt->GetOpcode()) {
822 // TODO (apanicke): Remove handling of UNIT_INFO and SUBUNIT_INFO from
823 // the AVRC_API and instead handle it here to reduce fragmentation.
824 case Opcode::UNIT_INFO: {
825 } break;
826 case Opcode::SUBUNIT_INFO: {
827 } break;
828 case Opcode::PASS_THROUGH: {
829 /** Newavrcp not passthrough response pkt. @{ */
830 if (pkt->GetCType() == CType::ACCEPTED || pkt->GetCType() == CType::REJECTED ||
831 pkt->GetCType() == CType::NOT_IMPLEMENTED) {
832 break;
833 }
834 /** @} */
835 auto pass_through_packet = Packet::Specialize<PassThroughPacket>(pkt);
836
837 if (!pass_through_packet->IsValid()) {
838 log::warn("{}: Request packet is not valid", address_);
839 auto response =
840 RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
841 send_message(label, false, std::move(response));
842 return;
843 }
844
845 auto response = PassThroughPacketBuilder::MakeBuilder(
846 true, pass_through_packet->GetKeyState() == KeyState::PUSHED,
847 pass_through_packet->GetOperationId());
848 send_message(label, false, std::move(response));
849
850 // TODO (apanicke): Use an enum for media key ID's
851 if (pass_through_packet->GetOperationId() == 0x44 &&
852 pass_through_packet->GetKeyState() == KeyState::PUSHED) {
853 // We need to get the play status since we need to know
854 // what the actual playstate is without being modified
855 // by whether the device is active.
856 media_interface_->GetPlayStatus(base::Bind(
857 [](base::WeakPtr<Device> d, PlayStatus s) {
858 if (!d) {
859 return;
860 }
861
862 if (!d->IsActive()) {
863 log::info("Setting {} to be the active device", d->address_);
864 d->media_interface_->SetActiveDevice(d->address_);
865
866 if (s.state == PlayState::PLAYING) {
867 log::info("Skipping sendKeyEvent since music is already playing");
868 return;
869 }
870 }
871
872 d->media_interface_->SendKeyEvent(0x44, KeyState::PUSHED);
873 },
874 weak_ptr_factory_.GetWeakPtr()));
875 return;
876 }
877
878 if (IsActive()) {
879 media_interface_->SendKeyEvent(pass_through_packet->GetOperationId(),
880 pass_through_packet->GetKeyState());
881 }
882 } break;
883 case Opcode::VENDOR: {
884 auto vendor_pkt = Packet::Specialize<VendorPacket>(pkt);
885 VendorPacketHandler(label, vendor_pkt);
886 } break;
887 }
888 }
889
HandlePlayItem(uint8_t label,std::shared_ptr<PlayItemRequest> pkt)890 void Device::HandlePlayItem(uint8_t label, std::shared_ptr<PlayItemRequest> pkt) {
891 if (!pkt->IsValid()) {
892 log::warn("{}: Request packet is not valid", address_);
893 auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
894 send_message(label, false, std::move(response));
895 return;
896 }
897
898 log::verbose("scope={} uid={}", pkt->GetScope(), pkt->GetUid());
899
900 std::string media_id = "";
901 switch (pkt->GetScope()) {
902 case Scope::NOW_PLAYING:
903 media_id = now_playing_ids_.get_media_id(pkt->GetUid());
904 break;
905 case Scope::VFS:
906 media_id = vfs_ids_.get_media_id(pkt->GetUid());
907 break;
908 default:
909 log::warn("{}: Unknown scope for play item", address_);
910 }
911
912 if (media_id == "") {
913 log::verbose("Could not find item");
914 auto response = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM, Status::DOES_NOT_EXIST);
915 send_message(label, false, std::move(response));
916 return;
917 }
918
919 media_interface_->PlayItem(curr_browsed_player_id_, pkt->GetScope() == Scope::NOW_PLAYING,
920 media_id);
921
922 auto response = PlayItemResponseBuilder::MakeBuilder(Status::NO_ERROR);
923 send_message(label, false, std::move(response));
924 }
925
HandleSetAddressedPlayer(uint8_t label,std::shared_ptr<SetAddressedPlayerRequest> pkt,uint16_t curr_player)926 void Device::HandleSetAddressedPlayer(uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> pkt,
927 uint16_t curr_player) {
928 log::verbose("PlayerId={}", pkt->GetPlayerId());
929 log::verbose("curr_player={}", curr_player);
930
931 if (curr_player != pkt->GetPlayerId()) {
932 log::verbose("Reject invalid addressed player ID");
933 auto response =
934 RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID);
935 send_message(label, false, std::move(response));
936 return;
937 }
938
939 curr_addressed_player_id_ = curr_player;
940
941 auto response = SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
942 send_message(label, false, std::move(response));
943 }
944
ListPlayerApplicationSettingAttributesResponse(uint8_t label,std::vector<PlayerAttribute> attributes)945 void Device::ListPlayerApplicationSettingAttributesResponse(
946 uint8_t label, std::vector<PlayerAttribute> attributes) {
947 uint8_t num_of_attributes = attributes.size();
948 log::verbose("num_of_attributes={}", num_of_attributes);
949 if (num_of_attributes > 0) {
950 for (auto attribute : attributes) {
951 log::verbose("attribute={}", attribute);
952 }
953 }
954 auto response =
955 ListPlayerApplicationSettingAttributesResponseBuilder::MakeBuilder(std::move(attributes));
956 send_message(label, false, std::move(response));
957 }
958
ListPlayerApplicationSettingValuesResponse(uint8_t label,PlayerAttribute attribute,std::vector<uint8_t> values)959 void Device::ListPlayerApplicationSettingValuesResponse(uint8_t label, PlayerAttribute attribute,
960 std::vector<uint8_t> values) {
961 uint8_t number_of_values = values.size();
962 log::verbose("attribute={}, number_of_values={}", attribute, number_of_values);
963
964 if (number_of_values > 0) {
965 if (attribute == PlayerAttribute::REPEAT) {
966 for (auto value : values) {
967 log::verbose("value={}", static_cast<PlayerRepeatValue>(value));
968 }
969 } else if (attribute == PlayerAttribute::SHUFFLE) {
970 for (auto value : values) {
971 log::verbose("value={}", static_cast<PlayerShuffleValue>(value));
972 }
973 } else {
974 log::verbose("value=0x{:x}", values.at(0));
975 }
976 }
977
978 auto response = ListPlayerApplicationSettingValuesResponseBuilder::MakeBuilder(std::move(values));
979 send_message(label, false, std::move(response));
980 }
981
GetPlayerApplicationSettingValueResponse(uint8_t label,std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)982 void Device::GetPlayerApplicationSettingValueResponse(uint8_t label,
983 std::vector<PlayerAttribute> attributes,
984 std::vector<uint8_t> values) {
985 for (size_t i = 0; i < attributes.size(); i++) {
986 log::verbose("attribute={}", static_cast<PlayerAttribute>(attributes[i]));
987 if (attributes[i] == PlayerAttribute::REPEAT) {
988 log::verbose("value={}", static_cast<PlayerRepeatValue>(values[i]));
989 } else if (attributes[i] == PlayerAttribute::SHUFFLE) {
990 log::verbose("value={}", static_cast<PlayerShuffleValue>(values[i]));
991 } else {
992 log::verbose("value=0x{:x}", values.at(0));
993 }
994 }
995
996 auto response = GetCurrentPlayerApplicationSettingValueResponseBuilder::MakeBuilder(
997 std::move(attributes), std::move(values));
998 send_message(label, false, std::move(response));
999 }
1000
SetPlayerApplicationSettingValueResponse(uint8_t label,CommandPdu pdu,bool success)1001 void Device::SetPlayerApplicationSettingValueResponse(uint8_t label, CommandPdu pdu, bool success) {
1002 if (!success) {
1003 log::error("{}: Set Player Application Setting Value failed", address_);
1004 auto response = RejectBuilder::MakeBuilder(pdu, Status::INVALID_PARAMETER);
1005 send_message(label, false, std::move(response));
1006 return;
1007 }
1008
1009 auto response = SetPlayerApplicationSettingValueResponseBuilder::MakeBuilder();
1010 send_message(label, false, std::move(response));
1011 }
1012
BrowseMessageReceived(uint8_t label,std::shared_ptr<BrowsePacket> pkt)1013 void Device::BrowseMessageReceived(uint8_t label, std::shared_ptr<BrowsePacket> pkt) {
1014 if (!pkt->IsValid()) {
1015 log::warn("{}: Request packet is not valid", address_);
1016 auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
1017 send_message(label, false, std::move(response));
1018 return;
1019 }
1020
1021 log::verbose("pdu={}", pkt->GetPdu());
1022
1023 switch (pkt->GetPdu()) {
1024 case BrowsePdu::SET_BROWSED_PLAYER:
1025 HandleSetBrowsedPlayer(label, Packet::Specialize<SetBrowsedPlayerRequest>(pkt));
1026 break;
1027 case BrowsePdu::GET_FOLDER_ITEMS:
1028 HandleGetFolderItems(label, Packet::Specialize<GetFolderItemsRequest>(pkt));
1029 break;
1030 case BrowsePdu::CHANGE_PATH:
1031 HandleChangePath(label, Packet::Specialize<ChangePathRequest>(pkt));
1032 break;
1033 case BrowsePdu::GET_ITEM_ATTRIBUTES:
1034 HandleGetItemAttributes(label, Packet::Specialize<GetItemAttributesRequest>(pkt));
1035 break;
1036 case BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS:
1037 HandleGetTotalNumberOfItems(label, Packet::Specialize<GetTotalNumberOfItemsRequest>(pkt));
1038 break;
1039 default:
1040 log::warn("{}: pdu={}", address_, pkt->GetPdu());
1041 auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
1042 send_message(label, true, std::move(response));
1043
1044 break;
1045 }
1046 }
1047
HandleGetFolderItems(uint8_t label,std::shared_ptr<GetFolderItemsRequest> pkt)1048 void Device::HandleGetFolderItems(uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt) {
1049 if (!pkt->IsValid()) {
1050 // The specific get folder items builder is unimportant on failure.
1051 log::warn("{}: Get folder items request packet is not valid", address_);
1052 auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER,
1053 0x0000, browse_mtu_);
1054 send_message(label, true, std::move(response));
1055 return;
1056 }
1057
1058 log::verbose("scope={}", pkt->GetScope());
1059
1060 switch (pkt->GetScope()) {
1061 case Scope::MEDIA_PLAYER_LIST:
1062 media_interface_->GetMediaPlayerList(base::Bind(&Device::GetMediaPlayerListResponse,
1063 weak_ptr_factory_.GetWeakPtr(), label, pkt));
1064 break;
1065 case Scope::VFS:
1066 media_interface_->GetFolderItems(
1067 curr_browsed_player_id_, CurrentFolder(),
1068 base::Bind(&Device::GetVFSListResponse, weak_ptr_factory_.GetWeakPtr(), label, pkt));
1069 break;
1070 case Scope::NOW_PLAYING:
1071 media_interface_->GetNowPlayingList(base::Bind(&Device::GetNowPlayingListResponse,
1072 weak_ptr_factory_.GetWeakPtr(), label, pkt));
1073 break;
1074 default:
1075 log::error("{}: scope={}", address_, pkt->GetScope());
1076 auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
1077 Status::INVALID_PARAMETER, 0, browse_mtu_);
1078 send_message(label, true, std::move(response));
1079 break;
1080 }
1081 }
1082
HandleGetTotalNumberOfItems(uint8_t label,std::shared_ptr<GetTotalNumberOfItemsRequest> pkt)1083 void Device::HandleGetTotalNumberOfItems(uint8_t label,
1084 std::shared_ptr<GetTotalNumberOfItemsRequest> pkt) {
1085 if (!pkt->IsValid()) {
1086 log::warn("{}: Request packet is not valid", address_);
1087 auto response =
1088 GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0);
1089 send_message(label, true, std::move(response));
1090 return;
1091 }
1092
1093 log::verbose("scope={}", pkt->GetScope());
1094
1095 switch (pkt->GetScope()) {
1096 case Scope::MEDIA_PLAYER_LIST: {
1097 media_interface_->GetMediaPlayerList(
1098 base::Bind(&Device::GetTotalNumberOfItemsMediaPlayersResponse,
1099 weak_ptr_factory_.GetWeakPtr(), label));
1100 break;
1101 }
1102 case Scope::VFS:
1103 media_interface_->GetFolderItems(curr_browsed_player_id_, CurrentFolder(),
1104 base::Bind(&Device::GetTotalNumberOfItemsVFSResponse,
1105 weak_ptr_factory_.GetWeakPtr(), label));
1106 break;
1107 case Scope::NOW_PLAYING:
1108 media_interface_->GetNowPlayingList(
1109 base::Bind(&Device::GetTotalNumberOfItemsNowPlayingResponse,
1110 weak_ptr_factory_.GetWeakPtr(), label));
1111 break;
1112 default:
1113 log::error("{}: scope={}", address_, pkt->GetScope());
1114 break;
1115 }
1116 }
1117
GetTotalNumberOfItemsMediaPlayersResponse(uint8_t label,uint16_t,std::vector<MediaPlayerInfo> list)1118 void Device::GetTotalNumberOfItemsMediaPlayersResponse(uint8_t label, uint16_t /*curr_player*/,
1119 std::vector<MediaPlayerInfo> list) {
1120 log::verbose("num_items={}", list.size());
1121
1122 auto builder =
1123 GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, list.size());
1124 send_message(label, true, std::move(builder));
1125 }
1126
GetTotalNumberOfItemsVFSResponse(uint8_t label,std::vector<ListItem> list)1127 void Device::GetTotalNumberOfItemsVFSResponse(uint8_t label, std::vector<ListItem> list) {
1128 log::verbose("num_items={}", list.size());
1129
1130 if (curr_browsed_player_id_ == -1) {
1131 auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::NO_AVAILABLE_PLAYERS,
1132 0x0000, 0);
1133 send_message(label, true, std::move(response));
1134 return;
1135 }
1136
1137 auto builder =
1138 GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, list.size());
1139 send_message(label, true, std::move(builder));
1140 }
1141
GetTotalNumberOfItemsNowPlayingResponse(uint8_t label,std::string,std::vector<SongInfo> list)1142 void Device::GetTotalNumberOfItemsNowPlayingResponse(uint8_t label, std::string /*curr_song_id*/,
1143 std::vector<SongInfo> list) {
1144 log::verbose("num_items={}", list.size());
1145
1146 if (curr_addressed_player_id_ == -1) {
1147 auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::NO_AVAILABLE_PLAYERS,
1148 0x0000, 0);
1149 send_message(label, true, std::move(response));
1150 return;
1151 }
1152
1153 auto builder =
1154 GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, list.size());
1155 send_message(label, true, std::move(builder));
1156 }
1157
HandleChangePath(uint8_t label,std::shared_ptr<ChangePathRequest> pkt)1158 void Device::HandleChangePath(uint8_t label, std::shared_ptr<ChangePathRequest> pkt) {
1159 if (!pkt->IsValid()) {
1160 log::warn("{}: Request packet is not valid", address_);
1161 auto response = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
1162 send_message(label, true, std::move(response));
1163 return;
1164 }
1165
1166 log::verbose("direction={} uid=0x{:x}", pkt->GetDirection(), pkt->GetUid());
1167
1168 if (pkt->GetDirection() == Direction::DOWN && vfs_ids_.get_media_id(pkt->GetUid()) == "") {
1169 log::error("{}: No item found for UID={}", address_, pkt->GetUid());
1170 auto builder = ChangePathResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST, 0);
1171 send_message(label, true, std::move(builder));
1172 return;
1173 }
1174
1175 if (pkt->GetDirection() == Direction::DOWN) {
1176 current_path_.push(vfs_ids_.get_media_id(pkt->GetUid()));
1177 log::verbose("Pushing Path to stack: \"{}\"", CurrentFolder());
1178 } else {
1179 // Don't pop the root id off the stack
1180 if (current_path_.size() > 1) {
1181 current_path_.pop();
1182 } else {
1183 log::error("{}: Trying to change directory up past root.", address_);
1184 auto builder = ChangePathResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST, 0);
1185 send_message(label, true, std::move(builder));
1186 return;
1187 }
1188
1189 log::verbose("Popping Path from stack: new path=\"{}\"", CurrentFolder());
1190 }
1191
1192 media_interface_->GetFolderItems(
1193 curr_browsed_player_id_, CurrentFolder(),
1194 base::Bind(&Device::ChangePathResponse, weak_ptr_factory_.GetWeakPtr(), label, pkt));
1195 }
1196
ChangePathResponse(uint8_t label,std::shared_ptr<ChangePathRequest>,std::vector<ListItem> list)1197 void Device::ChangePathResponse(uint8_t label, std::shared_ptr<ChangePathRequest> /*pkt*/,
1198 std::vector<ListItem> list) {
1199 // TODO (apanicke): Reconstruct the VFS ID's here. Right now it gets
1200 // reconstructed in GetFolderItemsVFS
1201 auto builder = ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list.size());
1202 send_message(label, true, std::move(builder));
1203 }
1204
HandleGetItemAttributes(uint8_t label,std::shared_ptr<GetItemAttributesRequest> pkt)1205 void Device::HandleGetItemAttributes(uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt) {
1206 if (!pkt->IsValid()) {
1207 log::warn("{}: Request packet is not valid", address_);
1208 auto builder =
1209 GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, browse_mtu_);
1210 send_message(label, true, std::move(builder));
1211 return;
1212 }
1213
1214 log::verbose("scope={} uid=0x{:x} uid counter=0x{:x}", pkt->GetScope(), pkt->GetUid(),
1215 pkt->GetUidCounter());
1216 if (pkt->GetUidCounter() != 0x0000) { // For database unaware player, use 0
1217 log::warn("{}: UidCounter is invalid", address_);
1218 auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::UIDS_CHANGED, browse_mtu_);
1219 send_message(label, true, std::move(builder));
1220 return;
1221 }
1222
1223 switch (pkt->GetScope()) {
1224 case Scope::NOW_PLAYING: {
1225 media_interface_->GetNowPlayingList(base::Bind(&Device::GetItemAttributesNowPlayingResponse,
1226 weak_ptr_factory_.GetWeakPtr(), label, pkt));
1227 } break;
1228 case Scope::VFS:
1229 // TODO (apanicke): Check the vfs_ids_ here. If the item doesn't exist
1230 // then we can auto send the error without calling up. We do this check
1231 // later right now though in order to prevent race conditions with updates
1232 // on the media layer.
1233 media_interface_->GetFolderItems(curr_browsed_player_id_, CurrentFolder(),
1234 base::Bind(&Device::GetItemAttributesVFSResponse,
1235 weak_ptr_factory_.GetWeakPtr(), label, pkt));
1236 break;
1237 default:
1238 log::error("{}: UNKNOWN SCOPE FOR HANDLE GET ITEM ATTRIBUTES", address_);
1239 break;
1240 }
1241 }
1242
GetItemAttributesNowPlayingResponse(uint8_t label,std::shared_ptr<GetItemAttributesRequest> pkt,std::string curr_media_id,std::vector<SongInfo> song_list)1243 void Device::GetItemAttributesNowPlayingResponse(uint8_t label,
1244 std::shared_ptr<GetItemAttributesRequest> pkt,
1245 std::string curr_media_id,
1246 std::vector<SongInfo> song_list) {
1247 log::verbose("uid=0x{:x}", pkt->GetUid());
1248 auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, browse_mtu_);
1249
1250 auto media_id = now_playing_ids_.get_media_id(pkt->GetUid());
1251 if (media_id == "") {
1252 media_id = curr_media_id;
1253 }
1254
1255 log::verbose("media_id=\"{}\"", media_id);
1256
1257 SongInfo info;
1258 if (song_list.size() == 1) {
1259 log::verbose("Send out the only song in the queue as now playing song.");
1260 info = song_list.front();
1261 } else {
1262 for (const auto& temp : song_list) {
1263 if (temp.media_id == media_id) {
1264 info = temp;
1265 }
1266 }
1267 }
1268
1269 // Filter out DEFAULT_COVER_ART handle if this device has no client
1270 if (!HasBipClient()) {
1271 filter_cover_art(info);
1272 }
1273
1274 auto attributes_requested = pkt->GetAttributesRequested();
1275 if (attributes_requested.size() != 0) {
1276 for (const auto& attribute : attributes_requested) {
1277 if (info.attributes.find(attribute) != info.attributes.end()) {
1278 builder->AddAttributeEntry(*info.attributes.find(attribute));
1279 }
1280 }
1281 } else {
1282 // If zero attributes were requested, that means all attributes were
1283 // requested
1284 for (const auto& attribute : info.attributes) {
1285 builder->AddAttributeEntry(attribute);
1286 }
1287 }
1288
1289 send_message(label, true, std::move(builder));
1290 }
1291
GetItemAttributesVFSResponse(uint8_t label,std::shared_ptr<GetItemAttributesRequest> pkt,std::vector<ListItem> item_list)1292 void Device::GetItemAttributesVFSResponse(uint8_t label,
1293 std::shared_ptr<GetItemAttributesRequest> pkt,
1294 std::vector<ListItem> item_list) {
1295 log::verbose("uid=0x{:x}", pkt->GetUid());
1296
1297 auto media_id = vfs_ids_.get_media_id(pkt->GetUid());
1298 if (media_id == "") {
1299 log::warn("Item not found");
1300 auto builder =
1301 GetItemAttributesResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST, browse_mtu_);
1302 send_message(label, true, std::move(builder));
1303 return;
1304 }
1305
1306 auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, browse_mtu_);
1307
1308 ListItem item_requested;
1309 item_requested.type = ListItem::SONG;
1310
1311 for (const auto& temp : item_list) {
1312 if ((temp.type == ListItem::FOLDER && temp.folder.media_id == media_id) ||
1313 (temp.type == ListItem::SONG && temp.song.media_id == media_id)) {
1314 item_requested = temp;
1315 }
1316 }
1317
1318 // Filter out DEFAULT_COVER_ART handle if this device has no client
1319 if (item_requested.type == ListItem::SONG && !HasBipClient()) {
1320 filter_cover_art(item_requested.song);
1321 }
1322
1323 // TODO (apanicke): Add a helper function or allow adding a map
1324 // of attributes to GetItemAttributesResponseBuilder
1325 auto attributes_requested = pkt->GetAttributesRequested();
1326 if (item_requested.type == ListItem::FOLDER) {
1327 if (attributes_requested.size() == 0) {
1328 builder->AddAttributeEntry(Attribute::TITLE, item_requested.folder.name);
1329 } else {
1330 for (auto& attr : attributes_requested) {
1331 if (attr == Attribute::TITLE) {
1332 builder->AddAttributeEntry(Attribute::TITLE, item_requested.folder.name);
1333 }
1334 }
1335 }
1336 } else {
1337 if (attributes_requested.size() != 0) {
1338 for (const auto& attribute : attributes_requested) {
1339 if (item_requested.song.attributes.find(attribute) !=
1340 item_requested.song.attributes.end()) {
1341 builder->AddAttributeEntry(*item_requested.song.attributes.find(attribute));
1342 }
1343 }
1344 } else {
1345 // If zero attributes were requested, that means all attributes were
1346 // requested
1347 for (const auto& attribute : item_requested.song.attributes) {
1348 builder->AddAttributeEntry(attribute);
1349 }
1350 }
1351 }
1352
1353 send_message(label, true, std::move(builder));
1354 }
1355
GetMediaPlayerListResponse(uint8_t label,std::shared_ptr<GetFolderItemsRequest> pkt,uint16_t curr_player,std::vector<MediaPlayerInfo> players)1356 void Device::GetMediaPlayerListResponse(uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
1357 uint16_t curr_player,
1358 std::vector<MediaPlayerInfo> players) {
1359 log::verbose("");
1360
1361 if (players.size() == 0) {
1362 auto no_items_rsp = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
1363 Status::RANGE_OUT_OF_BOUNDS, 0x0000, browse_mtu_);
1364 send_message(label, true, std::move(no_items_rsp));
1365 return;
1366 }
1367
1368 auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::NO_ERROR, 0x0000,
1369 browse_mtu_);
1370
1371 // Move the current player to the first slot due to some carkits always
1372 // connecting to the first listed player rather than using the ID
1373 // returned by Addressed Player Changed
1374 for (auto it = players.begin(); it != players.end(); it++) {
1375 if (it->id == curr_player) {
1376 log::verbose("Adding player to first spot: {}", it->name);
1377 auto temp_player = *it;
1378 players.erase(it);
1379 players.insert(players.begin(), temp_player);
1380 break;
1381 }
1382 }
1383
1384 for (size_t i = pkt->GetStartItem(); i <= pkt->GetEndItem() && i < players.size(); i++) {
1385 MediaPlayerItem item(players[i].id, players[i].name, players[i].browsing_supported);
1386 builder->AddMediaPlayer(item);
1387 }
1388
1389 send_message(label, true, std::move(builder));
1390 }
1391
filter_attributes_requested(const SongInfo & song,const std::vector<Attribute> & attrs)1392 static std::set<AttributeEntry> filter_attributes_requested(const SongInfo& song,
1393 const std::vector<Attribute>& attrs) {
1394 std::set<AttributeEntry> result;
1395 for (const auto& attr : attrs) {
1396 if (song.attributes.find(attr) != song.attributes.end()) {
1397 result.insert(*song.attributes.find(attr));
1398 }
1399 }
1400
1401 return result;
1402 }
1403
GetVFSListResponse(uint8_t label,std::shared_ptr<GetFolderItemsRequest> pkt,std::vector<ListItem> items)1404 void Device::GetVFSListResponse(uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
1405 std::vector<ListItem> items) {
1406 log::verbose("start_item={} end_item={}", pkt->GetStartItem(), pkt->GetEndItem());
1407
1408 // The builder will automatically correct the status if there are zero items
1409 auto builder =
1410 GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000, browse_mtu_);
1411
1412 // TODO (apanicke): Add test that checks if vfs_ids_ is the correct size after
1413 // an operation.
1414 for (const auto& item : items) {
1415 if (item.type == ListItem::FOLDER) {
1416 vfs_ids_.insert(item.folder.media_id);
1417 } else if (item.type == ListItem::SONG) {
1418 vfs_ids_.insert(item.song.media_id);
1419 }
1420 }
1421
1422 // Add the elements retrieved in the last get folder items request and map
1423 // them to UIDs The maps will be cleared every time a directory change
1424 // happens. These items do not need to correspond with the now playing list as
1425 // the UID's only need to be unique in the context of the current scope and
1426 // the current folder
1427 for (auto i = pkt->GetStartItem(); i <= pkt->GetEndItem() && i < items.size(); i++) {
1428 if (items[i].type == ListItem::FOLDER) {
1429 auto folder = items[i].folder;
1430 // right now we always use folders of mixed type
1431 FolderItem folder_item(vfs_ids_.get_uid(folder.media_id), 0x00, folder.is_playable,
1432 folder.name);
1433 if (!builder->AddFolder(folder_item)) {
1434 break;
1435 }
1436 } else if (items[i].type == ListItem::SONG) {
1437 auto song = items[i].song;
1438
1439 // Filter out DEFAULT_COVER_ART handle if this device has no client
1440 if (!HasBipClient()) {
1441 filter_cover_art(song);
1442 }
1443
1444 auto title = song.attributes.find(Attribute::TITLE) != song.attributes.end()
1445 ? song.attributes.find(Attribute::TITLE)->value()
1446 : std::string();
1447 MediaElementItem song_item(vfs_ids_.get_uid(song.media_id), title,
1448 std::set<AttributeEntry>());
1449
1450 if (pkt->GetNumAttributes() == 0x00) { // All attributes requested
1451 song_item.attributes_ = std::move(song.attributes);
1452 } else {
1453 song_item.attributes_ = filter_attributes_requested(song, pkt->GetAttributesRequested());
1454 }
1455
1456 // If we fail to add a song, don't accidentally add one later that might
1457 // fit.
1458 if (!builder->AddSong(song_item)) {
1459 break;
1460 }
1461 }
1462 }
1463
1464 send_message(label, true, std::move(builder));
1465 }
1466
GetNowPlayingListResponse(uint8_t label,std::shared_ptr<GetFolderItemsRequest> pkt,std::string,std::vector<SongInfo> song_list)1467 void Device::GetNowPlayingListResponse(uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
1468 std::string /* unused curr_song_id */,
1469 std::vector<SongInfo> song_list) {
1470 log::verbose("");
1471 auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status::NO_ERROR, 0x0000,
1472 browse_mtu_);
1473
1474 now_playing_ids_.clear();
1475 for (const SongInfo& song : song_list) {
1476 now_playing_ids_.insert(song.media_id);
1477 }
1478
1479 for (size_t i = pkt->GetStartItem(); i <= pkt->GetEndItem() && i < song_list.size(); i++) {
1480 auto song = song_list[i];
1481
1482 // Filter out DEFAULT_COVER_ART handle if this device has no client
1483 if (!HasBipClient()) {
1484 filter_cover_art(song);
1485 }
1486
1487 auto title = song.attributes.find(Attribute::TITLE) != song.attributes.end()
1488 ? song.attributes.find(Attribute::TITLE)->value()
1489 : std::string();
1490
1491 MediaElementItem item(i + 1, title, std::set<AttributeEntry>());
1492 if (pkt->GetNumAttributes() == 0x00) {
1493 item.attributes_ = std::move(song.attributes);
1494 } else {
1495 item.attributes_ = filter_attributes_requested(song, pkt->GetAttributesRequested());
1496 }
1497
1498 // If we fail to add a song, don't accidentally add one later that might
1499 // fit.
1500 if (!builder->AddSong(item)) {
1501 break;
1502 }
1503 }
1504
1505 send_message(label, true, std::move(builder));
1506 }
1507
HandleSetBrowsedPlayer(uint8_t label,std::shared_ptr<SetBrowsedPlayerRequest> pkt)1508 void Device::HandleSetBrowsedPlayer(uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt) {
1509 if (!pkt->IsValid()) {
1510 log::warn("{}: Request packet is not valid", address_);
1511 auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000,
1512 0, 0, "");
1513 send_message(label, true, std::move(response));
1514 return;
1515 }
1516
1517 log::verbose("player_id={}", pkt->GetPlayerId());
1518 media_interface_->SetBrowsedPlayer(pkt->GetPlayerId(), CurrentFolder(),
1519 base::Bind(&Device::SetBrowsedPlayerResponse,
1520 weak_ptr_factory_.GetWeakPtr(), label, pkt));
1521 }
1522
SetBrowsedPlayerResponse(uint8_t label,std::shared_ptr<SetBrowsedPlayerRequest> pkt,bool success,std::string current_path,uint32_t num_items)1523 void Device::SetBrowsedPlayerResponse(uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt,
1524 bool success, std::string current_path, uint32_t num_items) {
1525 log::verbose("success={} current_path=\"{}\" num_items={}", success, current_path, num_items);
1526
1527 if (!success) {
1528 auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::INVALID_PLAYER_ID, 0x0000,
1529 num_items, 0, "");
1530 send_message(label, true, std::move(response));
1531 return;
1532 }
1533
1534 if (pkt->GetPlayerId() == 0 && num_items == 0) {
1535 // Response fail if no browsable player in Bluetooth Player
1536 auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::PLAYER_NOT_BROWSABLE,
1537 0x0000, num_items, 0, "");
1538 send_message(label, true, std::move(response));
1539 return;
1540 }
1541
1542 curr_browsed_player_id_ = pkt->GetPlayerId();
1543
1544 // Clear the path and push the new root or current path.
1545 current_path_ = std::stack<std::string>();
1546 current_path_.push(current_path);
1547
1548 auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, num_items,
1549 0, current_path);
1550 send_message(label, true, std::move(response));
1551 }
1552
SendMediaUpdate(bool metadata,bool play_status,bool queue)1553 void Device::SendMediaUpdate(bool metadata, bool play_status, bool queue) {
1554 bool is_silence = IsInSilenceMode();
1555
1556 log::assert_that(media_interface_ != nullptr, "assert failed: media_interface_ != nullptr");
1557 log::verbose("Metadata={} : play_status= {} : queue={} : is_silence={}", metadata, play_status,
1558 queue, is_silence);
1559
1560 if (queue) {
1561 HandleNowPlayingUpdate();
1562 }
1563
1564 if (play_status) {
1565 HandlePlayStatusUpdate();
1566 if (!is_silence) {
1567 HandlePlayPosUpdate();
1568 }
1569 }
1570
1571 if (metadata) {
1572 HandleTrackUpdate();
1573 }
1574 }
1575
SendFolderUpdate(bool available_players,bool addressed_player,bool)1576 void Device::SendFolderUpdate(bool available_players, bool addressed_player, bool /*uids*/) {
1577 log::assert_that(media_interface_ != nullptr, "assert failed: media_interface_ != nullptr");
1578 log::verbose("");
1579
1580 if (available_players) {
1581 HandleAvailablePlayerUpdate();
1582 }
1583
1584 if (addressed_player) {
1585 HandleAddressedPlayerUpdate();
1586 }
1587 }
1588
HandleTrackUpdate()1589 void Device::HandleTrackUpdate() {
1590 log::verbose("");
1591 if (!track_changed_.first) {
1592 log::warn("Device is not registered for track changed updates");
1593 return;
1594 }
1595
1596 media_interface_->GetNowPlayingList(base::Bind(&Device::TrackChangedNotificationResponse,
1597 weak_ptr_factory_.GetWeakPtr(),
1598 track_changed_.second, false));
1599 }
1600
HandlePlayStatusUpdate()1601 void Device::HandlePlayStatusUpdate() {
1602 log::verbose("");
1603 if (!play_status_changed_.first) {
1604 log::warn("Device is not registered for play status updates");
1605 return;
1606 }
1607
1608 media_interface_->GetPlayStatus(base::Bind(&Device::PlaybackStatusNotificationResponse,
1609 weak_ptr_factory_.GetWeakPtr(),
1610 play_status_changed_.second, false));
1611 }
1612
HandleNowPlayingUpdate()1613 void Device::HandleNowPlayingUpdate() {
1614 log::verbose("");
1615
1616 if (!now_playing_changed_.first) {
1617 log::warn("Device is not registered for now playing updates");
1618 return;
1619 }
1620
1621 media_interface_->GetNowPlayingList(base::Bind(&Device::HandleNowPlayingNotificationResponse,
1622 weak_ptr_factory_.GetWeakPtr(),
1623 now_playing_changed_.second, false));
1624 }
1625
HandlePlayerSettingChanged(std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)1626 void Device::HandlePlayerSettingChanged(std::vector<PlayerAttribute> attributes,
1627 std::vector<uint8_t> values) {
1628 log::verbose("");
1629 if (!player_setting_changed_.first) {
1630 log::warn("Device is not registered for player settings updates");
1631 return;
1632 }
1633
1634 for (size_t i = 0; i < attributes.size(); i++) {
1635 log::verbose("attribute: {}", attributes[i]);
1636 if (attributes[i] == PlayerAttribute::SHUFFLE) {
1637 log::verbose("value: {}", (PlayerShuffleValue)values[i]);
1638 } else if (attributes[i] == PlayerAttribute::REPEAT) {
1639 log::verbose("value: {}", (PlayerRepeatValue)values[i]);
1640 } else {
1641 log::verbose("value: {}", values[i]);
1642 }
1643 }
1644
1645 auto response = RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
1646 false, attributes, values);
1647 send_message(player_setting_changed_.second, false, std::move(response));
1648 }
1649
PlayerSettingChangedNotificationResponse(uint8_t label,bool interim,std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)1650 void Device::PlayerSettingChangedNotificationResponse(uint8_t label, bool interim,
1651 std::vector<PlayerAttribute> attributes,
1652 std::vector<uint8_t> values) {
1653 log::verbose("interim: {}", interim);
1654 for (size_t i = 0; i < attributes.size(); i++) {
1655 log::verbose("attribute: {}", attributes[i]);
1656 if (attributes[i] == PlayerAttribute::SHUFFLE) {
1657 log::verbose("value: {}", (PlayerShuffleValue)values[i]);
1658 } else if (attributes[i] == PlayerAttribute::REPEAT) {
1659 log::verbose("value: {}", (PlayerRepeatValue)values[i]);
1660 } else {
1661 log::verbose("value: {}", values[i]);
1662 }
1663 }
1664
1665 if (interim) {
1666 player_setting_changed_ = Notification(true, label);
1667 } else if (!player_setting_changed_.first) {
1668 log::warn("Device is not registered for now playing updates");
1669 return;
1670 }
1671
1672 auto response = RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
1673 interim, attributes, values);
1674 send_message(player_setting_changed_.second, false, std::move(response));
1675
1676 if (!interim) {
1677 active_labels_.erase(label);
1678 player_setting_changed_ = Notification(false, 0);
1679 }
1680 }
1681
HandleNowPlayingNotificationResponse(uint8_t label,bool interim,std::string,std::vector<SongInfo> song_list)1682 void Device::HandleNowPlayingNotificationResponse(uint8_t label, bool interim,
1683 std::string /*curr_song_id*/,
1684 std::vector<SongInfo> song_list) {
1685 if (interim) {
1686 now_playing_changed_ = Notification(true, label);
1687 } else if (!now_playing_changed_.first) {
1688 log::warn("Device is not registered for now playing updates");
1689 return;
1690 }
1691
1692 now_playing_ids_.clear();
1693 for (const SongInfo& song : song_list) {
1694 now_playing_ids_.insert(song.media_id);
1695 }
1696
1697 auto response = RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(interim);
1698 send_message(now_playing_changed_.second, false, std::move(response));
1699
1700 if (!interim) {
1701 active_labels_.erase(label);
1702 now_playing_changed_ = Notification(false, 0);
1703 }
1704 }
1705
HandlePlayPosUpdate()1706 void Device::HandlePlayPosUpdate() {
1707 log::verbose("");
1708 if (!play_pos_changed_.first) {
1709 log::warn("Device is not registered for play position updates");
1710 return;
1711 }
1712
1713 media_interface_->GetPlayStatus(base::Bind(&Device::PlaybackPosNotificationResponse,
1714 weak_ptr_factory_.GetWeakPtr(),
1715 play_pos_changed_.second, false));
1716 }
1717
HandleAvailablePlayerUpdate()1718 void Device::HandleAvailablePlayerUpdate() {
1719 log::verbose("");
1720
1721 if (!avail_players_changed_.first) {
1722 log::warn("Device is not registered for available player updates");
1723 return;
1724 }
1725
1726 auto response = RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(false);
1727 send_message_cb_.Run(avail_players_changed_.second, false, std::move(response));
1728
1729 if (!avail_players_changed_.first) {
1730 active_labels_.erase(avail_players_changed_.second);
1731 avail_players_changed_ = Notification(false, 0);
1732 }
1733 }
1734
HandleAddressedPlayerUpdate()1735 void Device::HandleAddressedPlayerUpdate() {
1736 log::verbose("");
1737 if (!addr_player_changed_.first) {
1738 log::warn("{}: Device is not registered for addressed player updates", address_);
1739 return;
1740 }
1741 media_interface_->GetAddressedPlayer(base::Bind(&Device::AddressedPlayerNotificationResponse,
1742 weak_ptr_factory_.GetWeakPtr(),
1743 addr_player_changed_.second, false));
1744 }
1745
DeviceDisconnected()1746 void Device::DeviceDisconnected() {
1747 log::info("{} : Device was disconnected", address_);
1748 play_pos_update_cb_.Cancel();
1749
1750 // TODO (apanicke): Once the interfaces are set in the Device construction,
1751 // remove these conditionals.
1752 if (volume_interface_ != nullptr) {
1753 volume_interface_->DeviceDisconnected(GetAddress());
1754 }
1755 // The volume at connection is set by the remote device when indicating
1756 // that it supports absolute volume, in case it's not, we need
1757 // to reset the local volume var to be sure we send the correct value
1758 // to the remote device on the next connection.
1759 volume_ = VOL_NOT_SUPPORTED;
1760 }
1761
volumeToStr(int8_t volume)1762 static std::string volumeToStr(int8_t volume) {
1763 if (volume == VOL_NOT_SUPPORTED) {
1764 return "Absolute Volume not supported";
1765 }
1766 if (volume == VOL_REGISTRATION_FAILED) {
1767 return "Volume changed notification was rejected";
1768 }
1769 return std::to_string(volume);
1770 }
1771
operator <<(std::ostream & out,const Device & d)1772 std::ostream& operator<<(std::ostream& out, const Device& d) {
1773 // TODO: whether this should be turned into LOGGABLE STRING?
1774 out << " " << d.address_.ToRedactedStringForLogging();
1775 if (d.IsActive()) {
1776 out << " <Active>";
1777 }
1778 out << std::endl;
1779 out << " Current Volume: " << volumeToStr(d.volume_) << std::endl;
1780 out << " Current Browsed Player ID: " << d.curr_browsed_player_id_ << std::endl;
1781 out << " Registered Notifications:\n";
1782 if (d.track_changed_.first) {
1783 out << " Track Changed\n";
1784 }
1785 if (d.play_status_changed_.first) {
1786 out << " Play Status\n";
1787 }
1788 if (d.play_pos_changed_.first) {
1789 out << " Play Position\n";
1790 }
1791 if (d.player_setting_changed_.first) {
1792 out << " Player Setting Changed\n";
1793 }
1794 if (d.now_playing_changed_.first) {
1795 out << " Now Playing\n";
1796 }
1797 if (d.addr_player_changed_.first) {
1798 out << " Addressed Player\n";
1799 }
1800 if (d.avail_players_changed_.first) {
1801 out << " Available Players\n";
1802 }
1803 if (d.uids_changed_.first) {
1804 out << " UIDs Changed\n";
1805 }
1806 out << " Last Play State: " << d.last_play_status_.state << std::endl;
1807 out << " Last Song Sent ID: \"" << d.last_song_info_.media_id << "\"\n";
1808 out << " Current Folder: \"" << d.CurrentFolder() << "\"\n";
1809 out << " MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_ << std::endl;
1810 // TODO (apanicke): Add supported features as well as media keys
1811 return out;
1812 }
1813
1814 } // namespace avrcp
1815 } // namespace bluetooth
1816