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