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