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 <set>
20 
21 #include <base/sys_byteorder.h>
22 
23 namespace bluetooth {
24 namespace avrcp {
25 
26 constexpr uint32_t BLUETOOTH_COMPANY_ID = 0x001958;
27 
28 constexpr uint8_t MAX_TRANSACTION_LABEL = 0xF;
29 
30 enum class CType : uint8_t {
31   CONTROL = 0x0,
32   STATUS = 0x1,
33   NOTIFY = 0x3,
34   NOT_IMPLEMENTED = 0x8,
35   ACCEPTED = 0x9,
36   REJECTED = 0xa,
37   STABLE = 0xc,
38   CHANGED = 0xd,
39   INTERIM = 0xf,
40 };
41 
42 enum class Opcode : uint8_t {
43   VENDOR = 0x00,
44   UNIT_INFO = 0x30,
45   SUBUNIT_INFO = 0x31,
46   PASS_THROUGH = 0x7c,
47 };
48 
49 // Found in AVRCP_v1.6.1 Section 4.5 Table 4.5
50 // Searching can be done in the spec by Camel Casing the constant name
51 enum class CommandPdu : uint8_t {
52   GET_CAPABILITIES = 0x10,
53   LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES = 0x11,
54   LIST_PLAYER_APPLICATION_SETTING_VALUES = 0x12,
55   GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE = 0x13,
56   SET_PLAYER_APPLICATION_SETTING_VALUE = 0x14,
57   GET_ELEMENT_ATTRIBUTES = 0x20,
58   GET_PLAY_STATUS = 0x30,
59   REGISTER_NOTIFICATION = 0x31,
60   SET_ABSOLUTE_VOLUME = 0x50,
61   SET_ADDRESSED_PLAYER = 0x60,
62   PLAY_ITEM = 0x74,
63 };
64 
65 enum class PacketType : uint8_t {
66   SINGLE = 0x00,
67 };
68 
69 enum class Capability : uint8_t {
70   COMPANY_ID = 0x02,
71   EVENTS_SUPPORTED = 0x03,
72 };
73 
74 // Found in AVRCP_v1.6.1 Section 28 Appendix H
75 enum class Event : uint8_t {
76   PLAYBACK_STATUS_CHANGED = 0x01,
77   TRACK_CHANGED = 0x02,
78   PLAYBACK_POS_CHANGED = 0x05,
79   PLAYER_APPLICATION_SETTING_CHANGED = 0x08,
80   NOW_PLAYING_CONTENT_CHANGED = 0x09,
81   AVAILABLE_PLAYERS_CHANGED = 0x0a,
82   ADDRESSED_PLAYER_CHANGED = 0x0b,
83   UIDS_CHANGED = 0x0c,
84   VOLUME_CHANGED = 0x0d,
85 };
86 
87 enum class Attribute : uint32_t {
88   TITLE = 0x01,
89   ARTIST_NAME = 0x02,
90   ALBUM_NAME = 0x03,
91   TRACK_NUMBER = 0x04,
92   TOTAL_NUMBER_OF_TRACKS = 0x05,
93   GENRE = 0x06,
94   PLAYING_TIME = 0x07,
95   DEFAULT_COVER_ART = 0x08,
96 };
97 
98 enum class Status : uint8_t {
99   INVALID_COMMAND = 0x00,
100   INVALID_PARAMETER = 0x01,
101   PARAMETER_CONTENT_ERROR = 0x02,
102   INTERNAL_ERROR = 0x03,
103   NO_ERROR = 0x04,
104   UIDS_CHANGED = 0x05,
105   RESERVED = 0x06,
106   INVALID_DIRECTION = 0x07,
107   NOT_A_DIRECTORY = 0x08,
108   DOES_NOT_EXIST = 0x09,
109   INVALID_SCOPE = 0x0a,
110   RANGE_OUT_OF_BOUNDS = 0xb,
111   FOLDER_ITEM_NOT_PLAYABLE = 0x0c,
112   MEDIA_IN_USE = 0x0d,
113   NOW_PLAYING_LIST_FULL = 0x0e,
114   SEARCH_NOT_SUPPORTED = 0x0f,
115   SEARCH_IN_PROGRESS = 0x10,
116   INVALID_PLAYER_ID = 0x11,
117   PLAYER_NOT_BROWSABLE = 0x12,
118   PLAYER_NOT_ADDRESSED = 0x13,
119   NO_VALID_SEARCH_RESULTS = 0x14,
120   NO_AVAILABLE_PLAYERS = 0x15,
121   ADDRESSED_PLAYER_CHANGED = 0x16,
122 };
123 
124 enum class BrowsePdu : uint8_t {
125   SET_BROWSED_PLAYER = 0x70,
126   GET_FOLDER_ITEMS = 0x71,
127   CHANGE_PATH = 0x72,
128   GET_ITEM_ATTRIBUTES = 0x73,
129   GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
130   GENERAL_REJECT = 0xa0,
131 };
132 
133 enum class Scope : uint8_t {
134   MEDIA_PLAYER_LIST = 0x00,
135   VFS = 0x01,
136   SEARCH = 0x02,
137   NOW_PLAYING = 0x03,
138 };
139 
140 enum class Direction : uint8_t {
141   UP = 0x00,
142   DOWN = 0x01,
143 };
144 
145 enum class KeyState : uint8_t {
146   PUSHED = 0x00,
147   RELEASED = 0x01,
148 };
149 
150 enum class PlayerAttribute : uint8_t {
151   EQUALIZER = 0x01,
152   REPEAT = 0x02,
153   SHUFFLE = 0x03,
154   SCAN = 0x04,
155 };
156 
157 enum class PlayerRepeatValue : uint8_t {
158   OFF = 0x01,
159   SINGLE = 0x02,
160   ALL = 0x03,
161   GROUP = 0x04,
162 };
163 
164 enum class PlayerShuffleValue : uint8_t {
165   OFF = 0x01,
166   ALL = 0x02,
167   GROUP = 0x03,
168 };
169 
170 class AttributeEntry {
171  public:
AttributeEntry(const Attribute & attribute,const std::string & value)172   AttributeEntry(const Attribute& attribute, const std::string& value)
173       : attribute_(attribute), value_(value) {}
174 
AttributeEntry(const Attribute & attribute)175   AttributeEntry(const Attribute& attribute) : attribute_(attribute) {}
176 
177   AttributeEntry(const AttributeEntry&) = default;
178 
attribute()179   Attribute attribute() const { return attribute_; }
180 
value()181   std::string value() const { return value_; }
182 
kHeaderSize()183   static constexpr size_t kHeaderSize() {
184     size_t ret = 0;
185     ret += 4;  // Size of attribute field
186     ret += 2;  // Size of length field
187     ret += 2;  // Size of character encoding field
188     return ret;
189   }
190 
size()191   size_t size() const { return kHeaderSize() + value_.size(); }
192 
resize(size_t new_size)193   void resize(size_t new_size) {
194     new_size = new_size < kHeaderSize() ? 0 : new_size - kHeaderSize();
195     if (value_.size() > new_size) {
196       value_.resize(new_size);
197     }
198   }
199 
empty()200   bool empty() { return value_.empty(); }
201 
202   bool operator<(const AttributeEntry& rhs) const {
203     return attribute_ < rhs.attribute_;
204   }
205 
206  private:
207   Attribute attribute_;
208   std::string value_;
209 };
210 
211 constexpr size_t MAX_FIELD_LEN = 100;
212 
213 struct MediaPlayerItem {
214   uint16_t id_;
215   std::string name_;
216   bool browsable_;
217 
MediaPlayerItemMediaPlayerItem218   MediaPlayerItem(uint16_t id, const std::string& name, bool browsable)
219       : id_(id), name_(name), browsable_(browsable) {
220     if (name_.size() > MAX_FIELD_LEN) {
221       name_.resize(MAX_FIELD_LEN);
222     }
223   }
224 
225   MediaPlayerItem(const MediaPlayerItem&) = default;
226 
kHeaderSizeMediaPlayerItem227   static constexpr size_t kHeaderSize() {
228     size_t ret = 0;
229     ret += 1;   // Media Player Type
230     ret += 2;   // Item Length
231     ret += 2;   // Player Id
232     ret += 1;   // Player Type
233     ret += 4;   // Player Subtype
234     ret += 1;   // Play Status
235     ret += 16;  // Features
236     ret += 2;   // UTF-8 character set
237     ret += 2;   // Name Length
238     return ret;
239   }
240 
sizeMediaPlayerItem241   size_t size() const { return kHeaderSize() + name_.size(); }
242 };
243 
244 struct FolderItem {
245   uint64_t uid_;
246   uint8_t folder_type_;
247   bool is_playable_;
248   std::string name_;
249 
FolderItemFolderItem250   FolderItem(uint64_t uid, uint8_t folder_type, bool is_playable,
251              const std::string& name)
252       : uid_(uid),
253         folder_type_(folder_type),
254         is_playable_(is_playable),
255         name_(name) {
256     if (name_.size() > MAX_FIELD_LEN) {
257       name_.resize(MAX_FIELD_LEN);
258     }
259   }
260 
261   FolderItem(const FolderItem&) = default;
262 
kHeaderSizeFolderItem263   static constexpr size_t kHeaderSize() {
264     size_t ret = 0;
265     ret += 1;  // Folder Item Type
266     ret += 2;  // Item Length
267     ret += 8;  // Folder UID
268     ret += 1;  // Folder Type
269     ret += 1;  // Is Playable byte
270     ret += 2;  // UTF-8 Character Set
271     ret += 2;  // Name Length
272     return ret;
273   }
274 
sizeFolderItem275   size_t size() const { return kHeaderSize() + name_.size(); }
276 };
277 
278 // NOTE: We never use media type field because we only support audio types
279 struct MediaElementItem {
280   uint64_t uid_ = 0;
281   std::string name_;
282   std::set<AttributeEntry> attributes_;
283 
284   // Truncate the name and attribute fields so that we don't have a single item
285   // that can exceed the Browsing MTU
MediaElementItemMediaElementItem286   MediaElementItem(uint64_t uid, const std::string& name,
287                    std::set<AttributeEntry> attributes)
288       : uid_(uid), name_(name) {
289     if (name_.size() > MAX_FIELD_LEN) {
290       name_.resize(MAX_FIELD_LEN);
291     }
292 
293     for (AttributeEntry val : attributes) {
294       val.resize(MAX_FIELD_LEN);
295       attributes_.insert(val);
296     }
297   }
298 
299   MediaElementItem(const MediaElementItem&) = default;
300 
sizeMediaElementItem301   size_t size() const {
302     size_t ret = 0;
303     ret += 1;  // Media Element Item Type
304     ret += 2;  // Item Length
305     ret += 8;  // Item UID
306     ret += 1;  // Media Type
307     ret += 2;  // UTF-8 Character Set
308     ret += 2;  // Name Length
309     ret += name_.size();
310     ret += 1;  // Number of Attributes
311     for (const auto& entry : attributes_) {
312       ret += entry.size();
313     }
314 
315     return ret;
316   }
317 };
318 
319 struct MediaListItem {
320   enum : uint8_t { PLAYER = 0x01, FOLDER = 0x02, SONG = 0x03 } type_;
321 
322   union {
323     MediaPlayerItem player_;
324     FolderItem folder_;
325     MediaElementItem song_;
326   };
327 
MediaListItemMediaListItem328   MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
329 
MediaListItemMediaListItem330   MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
331 
MediaListItemMediaListItem332   MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
333 
MediaListItemMediaListItem334   MediaListItem(const MediaListItem& item) {
335     type_ = item.type_;
336     switch (item.type_) {
337       case PLAYER:
338         new (&player_) MediaPlayerItem(item.player_);
339         return;
340       case FOLDER:
341         new (&folder_) FolderItem(item.folder_);
342         return;
343       case SONG:
344         new (&song_) MediaElementItem(item.song_);
345         return;
346     }
347   }
348 
~MediaListItemMediaListItem349   ~MediaListItem() {
350     switch (type_) {
351       case PLAYER:
352         player_.~MediaPlayerItem();
353         return;
354       case FOLDER:
355         folder_.~FolderItem();
356         return;
357       case SONG:
358         song_.~MediaElementItem();
359         return;
360     }
361   }
362 
sizeMediaListItem363   size_t size() const {
364     switch (type_) {
365       case PLAYER:
366         return player_.size();
367       case FOLDER:
368         return folder_.size();
369       case SONG:
370         return song_.size();
371     }
372   }
373 };
374 
375 constexpr size_t AVCT_HDR_LEN = 3;
376 
377 }  // namespace avrcp
378 }  // namespace bluetooth