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 #pragma once
18 
19 #include <iostream>
20 #include <memory>
21 #include <stack>
22 
23 #include <base/bind.h>
24 #include <base/cancelable_callback.h>
25 
26 #include "avrcp.h"
27 #include "avrcp_internal.h"
28 #include "avrcp_packet.h"
29 #include "media_id_map.h"
30 #include "raw_address.h"
31 
32 namespace bluetooth {
33 namespace avrcp {
34 
35 /**
36  * A class representing a connection with a remote AVRCP device. It holds all
37  * the state and message handling for the device that it represents.
38  */
39 // TODO (apanicke): Once we move over to having the individual message
40 // responders for Browse and Classic AVRCP Messages move the device around via a
41 // weak pointer.
42 class Device {
43  public:
44   /**
45    * Device is friends with Avrcp::ConnectionHandler so that ConnectionHandler
46    * can deliver messages to individual devices.
47    */
48   friend class ConnectionHandler;
49 
50   Device(
51       const RawAddress& bdaddr, bool avrcp13_compatibility,
52       base::Callback<void(uint8_t label, bool browse,
53                           std::unique_ptr<::bluetooth::PacketBuilder> message)>
54           send_msg_cb,
55       uint16_t ctrl_mtu, uint16_t browse_mtu);
56   virtual ~Device() = default;
57 
GetAddress()58   const RawAddress& GetAddress() const { return address_; };
59 
60   /**
61    * Disconnects the AVRCP connection that this device represents.
62    */
63   bool Disconnect();
64 
65   /**
66    * Returns true if the current device is active.
67    */
68   bool IsActive() const;
69 
70   /**
71    * Register the interfaces that the device uses to get information. If the
72    * Volume Interface is null, then absolute volume is disabled.
73    * TODO (apanicke): Add these to the constructor/factory so that each device
74    * is created valid and can't be accidentally interacted with when no
75    * interfaces are registered.
76    */
77   void RegisterInterfaces(MediaInterface* interface,
78                           A2dpInterface* a2dp_interface,
79                           VolumeInterface* volume_interface);
80 
81   /**
82    * Notify the device that metadata, play_status, and/or queue have updated
83    * via a boolean. Each boolean represents whether its respective content has
84    * updated.
85    */
86   virtual void SendMediaUpdate(bool metadata, bool play_status, bool queue);
87 
88   /**
89    * Notify the device that the available_player, addressed_player, or UIDs
90    * have updated via a boolean. Each boolean represents whether its respective
91    * content has updated.
92    */
93   virtual void SendFolderUpdate(bool available_player, bool addressed_player,
94                                 bool uids);
95 
96   // TODO (apanicke): Split the message handlers into two files. One
97   // for handling Browse Messages and the other for handling all other
98   // messages. This prevents the .cc file from getting bloated like it is
99   // now. The Device class will then become a state holder for each message
100   // and all the functions in these handler classes can be static since the
101   // device will be passed in. The extensions of the Device class can contain
102   // any interop handling for specific messages on specific devices.
103 
104   void MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt);
105   void BrowseMessageReceived(uint8_t label, std::shared_ptr<BrowsePacket> pkt);
106   void VendorPacketHandler(uint8_t label, std::shared_ptr<VendorPacket> pkt);
107 
108   /********************
109    * MESSAGE RESPONSES
110    ********************/
111   // CURRENT TRACK CHANGED
112   virtual void HandleTrackUpdate();
113   virtual void TrackChangedNotificationResponse(
114       uint8_t label, bool interim, std::string curr_song_id,
115       std::vector<SongInfo> song_list);
116 
117   // GET CAPABILITY
118   virtual void HandleGetCapabilities(
119       uint8_t label, const std::shared_ptr<GetCapabilitiesRequest>& pkt);
120 
121   // REGISTER NOTIFICATION
122   virtual void HandleNotification(
123       uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt);
124 
125   // PLAY STATUS CHANGED
126   virtual void HandlePlayStatusUpdate();
127 
128   // NOW PLAYING LIST CHANGED
129   virtual void HandleNowPlayingUpdate();
130   virtual void HandleNowPlayingNotificationResponse(
131       uint8_t label, bool interim, std::string curr_song_id,
132       std::vector<SongInfo> song_list);
133 
134   // PLAY POSITION CHANGED
135   virtual void HandlePlayPosUpdate();
136   virtual void PlaybackPosNotificationResponse(uint8_t label, bool interim,
137                                                PlayStatus status);
138 
139   // GET PLAY STATUS
140   virtual void GetPlayStatusResponse(uint8_t label, PlayStatus status);
141   virtual void PlaybackStatusNotificationResponse(uint8_t label, bool interim,
142                                                   PlayStatus status);
143 
144   // GET ELEMENT ATTRIBUTE
145   // TODO (apanicke): Add a Handler function for this so if a specific device
146   // needs to implement an interop fix, you only need to overload the one
147   // function.
148   virtual void GetElementAttributesResponse(
149       uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
150       SongInfo info);
151 
152   // AVAILABLE PLAYER CHANGED
153   virtual void HandleAvailablePlayerUpdate();
154 
155   // ADDRESSED PLAYER CHANGED
156   virtual void HandleAddressedPlayerUpdate();
157   virtual void RejectNotification();
158   virtual void AddressedPlayerNotificationResponse(
159       uint8_t label, bool interim, uint16_t curr_player,
160       std::vector<MediaPlayerInfo> /* unused */);
161 
162   // GET FOLDER ITEMS
163   virtual void HandleGetFolderItems(
164       uint8_t label, std::shared_ptr<GetFolderItemsRequest> request);
165   virtual void GetMediaPlayerListResponse(
166       uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
167       uint16_t curr_player, std::vector<MediaPlayerInfo> players);
168   virtual void GetVFSListResponse(uint8_t label,
169                                   std::shared_ptr<GetFolderItemsRequest> pkt,
170                                   std::vector<ListItem> items);
171   virtual void GetNowPlayingListResponse(
172       uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
173       std::string curr_song_id, std::vector<SongInfo> song_list);
174 
175   // GET TOTAL NUMBER OF ITEMS
176   virtual void HandleGetTotalNumberOfItems(
177       uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt);
178   virtual void GetTotalNumberOfItemsMediaPlayersResponse(
179       uint8_t label, uint16_t curr_player, std::vector<MediaPlayerInfo> list);
180   virtual void GetTotalNumberOfItemsVFSResponse(uint8_t label,
181                                                 std::vector<ListItem> items);
182   virtual void GetTotalNumberOfItemsNowPlayingResponse(
183       uint8_t label, std::string curr_song_id, std::vector<SongInfo> song_list);
184 
185   // GET ITEM ATTRIBUTES
186   virtual void HandleGetItemAttributes(
187       uint8_t label, std::shared_ptr<GetItemAttributesRequest> request);
188   virtual void GetItemAttributesNowPlayingResponse(
189       uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
190       std::string curr_media_id, std::vector<SongInfo> song_list);
191   virtual void GetItemAttributesVFSResponse(
192       uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
193       std::vector<ListItem> item_list);
194 
195   // SET BROWSED PLAYER
196   virtual void HandleSetBrowsedPlayer(
197       uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> request);
198   virtual void SetBrowsedPlayerResponse(
199       uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt, bool success,
200       std::string root_id, uint32_t num_items);
201 
202   // CHANGE PATH
203   virtual void HandleChangePath(uint8_t label,
204                                 std::shared_ptr<ChangePathRequest> request);
205   virtual void ChangePathResponse(uint8_t label,
206                                   std::shared_ptr<ChangePathRequest> request,
207                                   std::vector<ListItem> list);
208 
209   // PLAY ITEM
210   virtual void HandlePlayItem(uint8_t label,
211                               std::shared_ptr<PlayItemRequest> request);
212 
213   /********************
214    * MESSAGE REQUESTS
215    ********************/
216   // VOLUME CHANGED NOTIFICATION
217   virtual void RegisterVolumeChanged();
218   virtual void HandleVolumeChanged(
219       uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt);
220 
221   // SET VOLUME
222   virtual void SetVolume(int8_t volume);
223 
224   /**
225    * This function is called by Avrcp::ConnectionHandler to signify that
226    * the remote device was disconnected.
227    *
228    * TODO (apanicke): Prevent allowing responses to messages while the device is
229    * disconnected by using a weak pointer handle to the device when we separate
230    * out the message handling. Also separate the logic in the future when
231    * disconnecting only browsing (Though this shouldn't matter as if we are
232    * disconnecting browsing then we should be fully disconnecting the device).
233    */
234   void DeviceDisconnected();
235 
236   friend std::ostream& operator<<(std::ostream& out, const Device& c);
237 
238  private:
239   // This should always contain one item which represents the root id on the
240   // current player.
CurrentFolder()241   std::string CurrentFolder() const {
242     if (current_path_.empty()) return "";
243     return current_path_.top();
244   }
245 
send_message(uint8_t label,bool browse,std::unique_ptr<::bluetooth::PacketBuilder> message)246   void send_message(uint8_t label, bool browse,
247                     std::unique_ptr<::bluetooth::PacketBuilder> message) {
248     active_labels_.erase(label);
249     send_message_cb_.Run(label, browse, std::move(message));
250   }
251   base::WeakPtrFactory<Device> weak_ptr_factory_;
252 
253   // TODO (apanicke): Initialize all the variables in the constructor.
254   RawAddress address_;
255 
256   // Enables AVRCP 1.3 Compatibility mode. This disables any AVRCP 1.4+ features
257   // such as browsing and playlists but has the highest chance of working.
258   bool avrcp13_compatibility_ = false;
259   base::Callback<void(uint8_t label, bool browse,
260                       std::unique_ptr<::bluetooth::PacketBuilder> message)>
261       send_message_cb_;
262   uint16_t ctrl_mtu_;
263   uint16_t browse_mtu_;
264 
265   int curr_browsed_player_id_ = -1;
266 
267   std::stack<std::string> current_path_;
268 
269   // Notification Trackers
270   using Notification = std::pair<bool, uint8_t>;
271   Notification track_changed_ = Notification(false, 0);
272   Notification play_status_changed_ = Notification(false, 0);
273   Notification play_pos_changed_ = Notification(false, 0);
274   Notification now_playing_changed_ = Notification(false, 0);
275   Notification addr_player_changed_ = Notification(false, 0);
276   Notification avail_players_changed_ = Notification(false, 0);
277   Notification uids_changed_ = Notification(false, 0);
278 
279   MediaIdMap vfs_ids_;
280   MediaIdMap now_playing_ids_;
281 
282   uint32_t play_pos_interval_ = 0;
283 
284   SongInfo last_song_info_;
285   PlayStatus last_play_status_;
286 
287   base::CancelableClosure play_pos_update_cb_;
288 
289   MediaInterface* media_interface_ = nullptr;
290   A2dpInterface* a2dp_interface_ = nullptr;
291   VolumeInterface* volume_interface_ = nullptr;
292 
293   // Labels used for messages currently in flight.
294   std::set<uint8_t> active_labels_;
295 
296   int8_t volume_ = -1;
297   DISALLOW_COPY_AND_ASSIGN(Device);
298 };
299 
300 }  // namespace avrcp
301 }  // namespace bluetooth
302