• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #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