summaryrefslogtreecommitdiff
path: root/system/profile/avrcp/device.h
blob: 07e1cac7d24dce366ac1b12081860e11c465fd83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <iostream>
#include <memory>
#include <stack>

#include <base/bind.h>
#include <base/cancelable_callback.h>

#include "avrcp_internal.h"
#include "hardware/avrcp/avrcp.h"
#include "packet/avrcp/avrcp_browse_packet.h"
#include "packet/avrcp/avrcp_packet.h"
#include "packet/avrcp/capabilities_packet.h"
#include "packet/avrcp/change_path.h"
#include "packet/avrcp/get_element_attributes_packet.h"
#include "packet/avrcp/get_folder_items.h"
#include "packet/avrcp/get_item_attributes.h"
#include "packet/avrcp/get_total_number_of_items.h"
#include "packet/avrcp/play_item.h"
#include "packet/avrcp/register_notification_packet.h"
#include "packet/avrcp/set_addressed_player.h"
#include "packet/avrcp/set_browsed_player.h"
#include "packet/avrcp/vendor_packet.h"
#include "profile/avrcp/media_id_map.h"
#include "raw_address.h"

namespace bluetooth {
namespace avrcp {

/**
 * A class representing a connection with a remote AVRCP device. It holds all
 * the state and message handling for the device that it represents.
 */
// TODO (apanicke): Once we move over to having the individual message
// responders for Browse and Classic AVRCP Messages move the device around via a
// weak pointer.
class Device {
 public:
  /**
   * Device is friends with Avrcp::ConnectionHandler so that ConnectionHandler
   * can deliver messages to individual devices.
   */
  friend class ConnectionHandler;

  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);

  Device(const Device&) = delete;
  Device& operator=(const Device&) = delete;

  virtual ~Device() = default;

  /**
   * Gets a weak pointer to this device that is invalidated when the device is
   * disconnected.
   */
  base::WeakPtr<Device> Get();

  const RawAddress& GetAddress() const { return address_; };

  /**
   * Disconnects the AVRCP connection that this device represents.
   */
  bool Disconnect();

  /**
   * Set the status of the BIP obex client
   */
  void SetBipClientStatus(bool connected);

  /**
   * Returns true if the current device has a BIP OBEX client.
   */
  bool HasBipClient() const;

  /**
   * Returns true if the current device is silenced.
   */
  bool IsInSilenceMode() const;

  /**
   * Returns true if the current device is active.
   */
  bool IsActive() const;

  /**
   * Register the interfaces that the device uses to get information. If the
   * Volume Interface is null, then absolute volume is disabled.
   * TODO (apanicke): Add these to the constructor/factory so that each device
   * is created valid and can't be accidentally interacted with when no
   * interfaces are registered.
   */
  void RegisterInterfaces(MediaInterface* interface,
                          A2dpInterface* a2dp_interface,
                          VolumeInterface* volume_interface);

  /**
   * Set the maximum size of a AVRCP Browsing Packet. This is done after the
   * connection of the Browsing channel.
   */
  void SetBrowseMtu(uint16_t browse_mtu);

  /**
   * Notify the device that metadata, play_status, and/or queue have updated
   * via a boolean. Each boolean represents whether its respective content has
   * updated.
   */
  virtual void SendMediaUpdate(bool metadata, bool play_status, bool queue);

  /**
   * Notify the device that the available_player, addressed_player, or UIDs
   * have updated via a boolean. Each boolean represents whether its respective
   * content has updated.
   */
  virtual void SendFolderUpdate(bool available_player, bool addressed_player,
                                bool uids);

  // TODO (apanicke): Split the message handlers into two files. One
  // for handling Browse Messages and the other for handling all other
  // messages. This prevents the .cc file from getting bloated like it is
  // now. The Device class will then become a state holder for each message
  // and all the functions in these handler classes can be static since the
  // device will be passed in. The extensions of the Device class can contain
  // any interop handling for specific messages on specific devices.

  void MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt);
  void BrowseMessageReceived(uint8_t label, std::shared_ptr<BrowsePacket> pkt);
  void VendorPacketHandler(uint8_t label, std::shared_ptr<VendorPacket> pkt);

  /********************
   * MESSAGE RESPONSES
   ********************/
  // CURRENT TRACK CHANGED
  virtual void HandleTrackUpdate();
  virtual void TrackChangedNotificationResponse(
      uint8_t label, bool interim, std::string curr_song_id,
      std::vector<SongInfo> song_list);

  // GET CAPABILITY
  virtual void HandleGetCapabilities(
      uint8_t label, const std::shared_ptr<GetCapabilitiesRequest>& pkt);

  // REGISTER NOTIFICATION
  virtual void HandleNotification(
      uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt);

  // PLAY STATUS CHANGED
  virtual void HandlePlayStatusUpdate();

  // NOW PLAYING LIST CHANGED
  virtual void HandleNowPlayingUpdate();
  virtual void HandleNowPlayingNotificationResponse(
      uint8_t label, bool interim, std::string curr_song_id,
      std::vector<SongInfo> song_list);

  // PLAY POSITION CHANGED
  virtual void HandlePlayPosUpdate();
  virtual void PlaybackPosNotificationResponse(uint8_t label, bool interim,
                                               PlayStatus status);

  // GET PLAY STATUS
  virtual void GetPlayStatusResponse(uint8_t label, PlayStatus status);
  virtual void PlaybackStatusNotificationResponse(uint8_t label, bool interim,
                                                  PlayStatus status);

  // GET ELEMENT ATTRIBUTE
  // TODO (apanicke): Add a Handler function for this so if a specific device
  // needs to implement an interop fix, you only need to overload the one
  // function.
  virtual void GetElementAttributesResponse(
      uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
      SongInfo info);

  // AVAILABLE PLAYER CHANGED
  virtual void HandleAvailablePlayerUpdate();

  // ADDRESSED PLAYER CHANGED
  virtual void HandleAddressedPlayerUpdate();
  virtual void RejectNotification();
  virtual void AddressedPlayerNotificationResponse(
      uint8_t label, bool interim, uint16_t curr_player,
      std::vector<MediaPlayerInfo> /* unused */);

  // GET FOLDER ITEMS
  virtual void HandleGetFolderItems(
      uint8_t label, std::shared_ptr<GetFolderItemsRequest> request);
  virtual void GetMediaPlayerListResponse(
      uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
      uint16_t curr_player, std::vector<MediaPlayerInfo> players);
  virtual void GetVFSListResponse(uint8_t label,
                                  std::shared_ptr<GetFolderItemsRequest> pkt,
                                  std::vector<ListItem> items);
  virtual void GetNowPlayingListResponse(
      uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
      std::string curr_song_id, std::vector<SongInfo> song_list);

  // GET TOTAL NUMBER OF ITEMS
  virtual void HandleGetTotalNumberOfItems(
      uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt);
  virtual void GetTotalNumberOfItemsMediaPlayersResponse(
      uint8_t label, uint16_t curr_player, std::vector<MediaPlayerInfo> list);
  virtual void GetTotalNumberOfItemsVFSResponse(uint8_t label,
                                                std::vector<ListItem> items);
  virtual void GetTotalNumberOfItemsNowPlayingResponse(
      uint8_t label, std::string curr_song_id, std::vector<SongInfo> song_list);

  // GET ITEM ATTRIBUTES
  virtual void HandleGetItemAttributes(
      uint8_t label, std::shared_ptr<GetItemAttributesRequest> request);
  virtual void GetItemAttributesNowPlayingResponse(
      uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
      std::string curr_media_id, std::vector<SongInfo> song_list);
  virtual void GetItemAttributesVFSResponse(
      uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
      std::vector<ListItem> item_list);

  // SET BROWSED PLAYER
  virtual void HandleSetBrowsedPlayer(
      uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> request);
  virtual void SetBrowsedPlayerResponse(
      uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt, bool success,
      std::string root_id, uint32_t num_items);

  // CHANGE PATH
  virtual void HandleChangePath(uint8_t label,
                                std::shared_ptr<ChangePathRequest> request);
  virtual void ChangePathResponse(uint8_t label,
                                  std::shared_ptr<ChangePathRequest> request,
                                  std::vector<ListItem> list);

  // PLAY ITEM
  virtual void HandlePlayItem(uint8_t label,
                              std::shared_ptr<PlayItemRequest> request);

  // SET ADDRESSED PLAYER
  virtual void HandleSetAddressedPlayer(
      uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> request,
      uint16_t curr_player, std::vector<MediaPlayerInfo> players);

  /********************
   * MESSAGE REQUESTS
   ********************/
  // VOLUME CHANGED NOTIFICATION
  virtual void RegisterVolumeChanged();
  virtual void HandleVolumeChanged(
      uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt);

  // SET VOLUME
  virtual void SetVolume(int8_t volume);

  /**
   * This function is called by Avrcp::ConnectionHandler to signify that
   * the remote device was disconnected.
   *
   * TODO (apanicke): Prevent allowing responses to messages while the device is
   * disconnected by using a weak pointer handle to the device when we separate
   * out the message handling. Also separate the logic in the future when
   * disconnecting only browsing (Though this shouldn't matter as if we are
   * disconnecting browsing then we should be fully disconnecting the device).
   */
  void DeviceDisconnected();

  friend std::ostream& operator<<(std::ostream& out, const Device& c);

 private:
  // This should always contain one item which represents the root id on the
  // current player.
  std::string CurrentFolder() const {
    if (current_path_.empty()) return "";
    return current_path_.top();
  }

  void send_message(uint8_t label, bool browse,
                    std::unique_ptr<::bluetooth::PacketBuilder> message) {
    active_labels_.erase(label);
    send_message_cb_.Run(label, browse, std::move(message));
  }
  base::WeakPtrFactory<Device> weak_ptr_factory_;

  // TODO (apanicke): Initialize all the variables in the constructor.
  RawAddress address_;

  // Enables AVRCP 1.3 Compatibility mode. This disables any AVRCP 1.4+ features
  // such as browsing and playlists but has the highest chance of working.
  bool avrcp13_compatibility_ = false;
  base::Callback<void(uint8_t label, bool browse,
                      std::unique_ptr<::bluetooth::PacketBuilder> message)>
      send_message_cb_;
  uint16_t ctrl_mtu_;
  uint16_t browse_mtu_;
  bool has_bip_client_;

  int curr_browsed_player_id_ = -1;

  std::stack<std::string> current_path_;

  // Notification Trackers
  using Notification = std::pair<bool, uint8_t>;
  Notification track_changed_ = Notification(false, 0);
  Notification play_status_changed_ = Notification(false, 0);
  Notification play_pos_changed_ = Notification(false, 0);
  Notification now_playing_changed_ = Notification(false, 0);
  Notification addr_player_changed_ = Notification(false, 0);
  Notification avail_players_changed_ = Notification(false, 0);
  Notification uids_changed_ = Notification(false, 0);

  MediaIdMap vfs_ids_;
  MediaIdMap now_playing_ids_;

  uint32_t play_pos_interval_ = 0;

  SongInfo last_song_info_;
  PlayStatus last_play_status_;

  base::CancelableClosure play_pos_update_cb_;

  MediaInterface* media_interface_ = nullptr;
  A2dpInterface* a2dp_interface_ = nullptr;
  VolumeInterface* volume_interface_ = nullptr;

  // Labels used for messages currently in flight.
  std::set<uint8_t> active_labels_;

  int8_t volume_ = -1;
};

}  // namespace avrcp
}  // namespace bluetooth