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