• 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 
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_APPLICATION_SETTING_ATTRIBUTES = 0x11,
54   GET_ELEMENT_ATTRIBUTES = 0x20,
55   GET_PLAY_STATUS = 0x30,
56   REGISTER_NOTIFICATION = 0x31,
57   SET_ABSOLUTE_VOLUME = 0x50,
58   SET_ADDRESSED_PLAYER = 0x60,
59   PLAY_ITEM = 0x74,
60 };
61 
62 enum class PacketType : uint8_t {
63   SINGLE = 0x00,
64 };
65 
66 enum class Capability : uint8_t {
67   COMPANY_ID = 0x02,
68   EVENTS_SUPPORTED = 0x03,
69 };
70 
71 // Found in AVRCP_v1.6.1 Section 28 Appendix H
72 enum class Event : uint8_t {
73   PLAYBACK_STATUS_CHANGED = 0x01,
74   TRACK_CHANGED = 0x02,
75   PLAYBACK_POS_CHANGED = 0x05,
76   PLAYER_APPLICATION_SETTING_CHANGED = 0x08,
77   NOW_PLAYING_CONTENT_CHANGED = 0x09,
78   AVAILABLE_PLAYERS_CHANGED = 0x0a,
79   ADDRESSED_PLAYER_CHANGED = 0x0b,
80   UIDS_CHANGED = 0x0c,
81   VOLUME_CHANGED = 0x0d,
82 };
83 
84 enum class Attribute : uint32_t {
85   TITLE = 0x01,
86   ARTIST_NAME = 0x02,
87   ALBUM_NAME = 0x03,
88   TRACK_NUMBER = 0x04,
89   TOTAL_NUMBER_OF_TRACKS = 0x05,
90   GENRE = 0x06,
91   PLAYING_TIME = 0x07,
92   DEFAULT_COVER_ART = 0x08,
93 };
94 
95 enum class Status : uint8_t {
96   INVALID_COMMAND = 0x00,
97   INVALID_PARAMETER = 0x01,
98   PARAMETER_CONTENT_ERROR = 0x02,
99   INTERNAL_ERROR = 0x03,
100   NO_ERROR = 0x04,
101   UIDS_CHANGED = 0x05,
102   RESERVED = 0x06,
103   INVALID_DIRECTION = 0x07,
104   NOT_A_DIRECTORY = 0x08,
105   DOES_NOT_EXIST = 0x09,
106   INVALID_SCOPE = 0x0a,
107   RANGE_OUT_OF_BOUNDS = 0xb,
108   FOLDER_ITEM_NOT_PLAYABLE = 0x0c,
109   MEDIA_IN_USE = 0x0d,
110   NOW_PLAYING_LIST_FULL = 0x0e,
111   SEARCH_NOT_SUPPORTED = 0x0f,
112   SEARCH_IN_PROGRESS = 0x10,
113   INVALID_PLAYER_ID = 0x11,
114   PLAYER_NOT_BROWSABLE = 0x12,
115   PLAYER_NOT_ADDRESSED = 0x13,
116   NO_VALID_SEARCH_RESULTS = 0x14,
117   NO_AVAILABLE_PLAYERS = 0x15,
118   ADDRESSED_PLAYER_CHANGED = 0x16,
119 };
120 
121 enum class BrowsePdu : uint8_t {
122   SET_BROWSED_PLAYER = 0x70,
123   GET_FOLDER_ITEMS = 0x71,
124   CHANGE_PATH = 0x72,
125   GET_ITEM_ATTRIBUTES = 0x73,
126   GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
127   GENERAL_REJECT = 0xa0,
128 };
129 
130 enum class Scope : uint8_t {
131   MEDIA_PLAYER_LIST = 0x00,
132   VFS = 0x01,
133   SEARCH = 0x02,
134   NOW_PLAYING = 0x03,
135 };
136 
137 enum class Direction : uint8_t {
138   UP = 0x00,
139   DOWN = 0x01,
140 };
141 
142 enum class KeyState : uint8_t {
143   PUSHED = 0x00,
144   RELEASED = 0x01,
145 };
146 
147 class AttributeEntry {
148  public:
AttributeEntry(const Attribute & attribute,const std::string & value)149   AttributeEntry(const Attribute& attribute, const std::string& value)
150       : attribute_(attribute), value_(value) {}
151 
AttributeEntry(const Attribute & attribute)152   AttributeEntry(const Attribute& attribute) : attribute_(attribute) {}
153 
154   AttributeEntry(const AttributeEntry&) = default;
155 
attribute()156   Attribute attribute() const { return attribute_; }
157 
value()158   std::string value() const { return value_; }
159 
kHeaderSize()160   static constexpr size_t kHeaderSize() {
161     size_t ret = 0;
162     ret += 4;  // Size of attribute field
163     ret += 2;  // Size of length field
164     ret += 2;  // Size of character encoding field
165     return ret;
166   }
167 
size()168   size_t size() const { return kHeaderSize() + value_.size(); }
169 
resize(size_t new_size)170   void resize(size_t new_size) {
171     new_size = new_size < kHeaderSize() ? 0 : new_size - kHeaderSize();
172     if (value_.size() > new_size) {
173       value_.resize(new_size);
174     }
175   }
176 
empty()177   bool empty() { return value_.empty(); }
178 
179   bool operator<(const AttributeEntry& rhs) const {
180     return attribute_ < rhs.attribute_;
181   }
182 
183  private:
184   Attribute attribute_;
185   std::string value_;
186 };
187 
188 constexpr size_t MAX_FIELD_LEN = 100;
189 
190 struct MediaPlayerItem {
191   uint16_t id_;
192   std::string name_;
193   bool browsable_;
194 
MediaPlayerItemMediaPlayerItem195   MediaPlayerItem(uint16_t id, const std::string& name, bool browsable)
196       : id_(id), name_(name), browsable_(browsable) {
197     if (name_.size() > MAX_FIELD_LEN) {
198       name_.resize(MAX_FIELD_LEN);
199     }
200   }
201 
202   MediaPlayerItem(const MediaPlayerItem&) = default;
203 
kHeaderSizeMediaPlayerItem204   static constexpr size_t kHeaderSize() {
205     size_t ret = 0;
206     ret += 1;   // Media Player Type
207     ret += 2;   // Item Length
208     ret += 2;   // Player Id
209     ret += 1;   // Player Type
210     ret += 4;   // Player Subtype
211     ret += 1;   // Play Status
212     ret += 16;  // Features
213     ret += 2;   // UTF-8 character set
214     ret += 2;   // Name Length
215     return ret;
216   }
217 
sizeMediaPlayerItem218   size_t size() const { return kHeaderSize() + name_.size(); }
219 };
220 
221 struct FolderItem {
222   uint64_t uid_;
223   uint8_t folder_type_;
224   bool is_playable_;
225   std::string name_;
226 
FolderItemFolderItem227   FolderItem(uint64_t uid, uint8_t folder_type, bool is_playable,
228              const std::string& name)
229       : uid_(uid),
230         folder_type_(folder_type),
231         is_playable_(is_playable),
232         name_(name) {
233     if (name_.size() > MAX_FIELD_LEN) {
234       name_.resize(MAX_FIELD_LEN);
235     }
236   }
237 
238   FolderItem(const FolderItem&) = default;
239 
kHeaderSizeFolderItem240   static constexpr size_t kHeaderSize() {
241     size_t ret = 0;
242     ret += 1;  // Folder Item Type
243     ret += 2;  // Item Length
244     ret += 8;  // Folder UID
245     ret += 1;  // Folder Type
246     ret += 1;  // Is Playable byte
247     ret += 2;  // UTF-8 Character Set
248     ret += 2;  // Name Length
249     return ret;
250   }
251 
sizeFolderItem252   size_t size() const { return kHeaderSize() + name_.size(); }
253 };
254 
255 // NOTE: We never use media type field because we only support audio types
256 struct MediaElementItem {
257   uint64_t uid_ = 0;
258   std::string name_;
259   std::set<AttributeEntry> attributes_;
260 
261   // Truncate the name and attribute fields so that we don't have a single item
262   // that can exceed the Browsing MTU
MediaElementItemMediaElementItem263   MediaElementItem(uint64_t uid, const std::string& name,
264                    std::set<AttributeEntry> attributes)
265       : uid_(uid), name_(name) {
266     if (name_.size() > MAX_FIELD_LEN) {
267       name_.resize(MAX_FIELD_LEN);
268     }
269 
270     for (AttributeEntry val : attributes) {
271       val.resize(MAX_FIELD_LEN);
272       attributes_.insert(val);
273     }
274   }
275 
276   MediaElementItem(const MediaElementItem&) = default;
277 
sizeMediaElementItem278   size_t size() const {
279     size_t ret = 0;
280     ret += 1;  // Media Element Item Type
281     ret += 2;  // Item Length
282     ret += 8;  // Item UID
283     ret += 1;  // Media Type
284     ret += 2;  // UTF-8 Character Set
285     ret += 2;  // Name Length
286     ret += name_.size();
287     ret += 1;  // Number of Attributes
288     for (const auto& entry : attributes_) {
289       ret += entry.size();
290     }
291 
292     return ret;
293   }
294 };
295 
296 struct MediaListItem {
297   enum : uint8_t { PLAYER = 0x01, FOLDER = 0x02, SONG = 0x03 } type_;
298 
299   union {
300     MediaPlayerItem player_;
301     FolderItem folder_;
302     MediaElementItem song_;
303   };
304 
MediaListItemMediaListItem305   MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
306 
MediaListItemMediaListItem307   MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
308 
MediaListItemMediaListItem309   MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
310 
MediaListItemMediaListItem311   MediaListItem(const MediaListItem& item) {
312     type_ = item.type_;
313     switch (item.type_) {
314       case PLAYER:
315         new (&player_) MediaPlayerItem(item.player_);
316         return;
317       case FOLDER:
318         new (&folder_) FolderItem(item.folder_);
319         return;
320       case SONG:
321         new (&song_) MediaElementItem(item.song_);
322         return;
323     }
324   }
325 
~MediaListItemMediaListItem326   ~MediaListItem() {
327     switch (type_) {
328       case PLAYER:
329         player_.~MediaPlayerItem();
330         return;
331       case FOLDER:
332         folder_.~FolderItem();
333         return;
334       case SONG:
335         song_.~MediaElementItem();
336         return;
337     }
338   }
339 
sizeMediaListItem340   size_t size() const {
341     switch (type_) {
342       case PLAYER:
343         return player_.size();
344       case FOLDER:
345         return folder_.size();
346       case SONG:
347         return song_.size();
348     }
349   }
350 };
351 
352 constexpr size_t AVCT_HDR_LEN = 3;
353 
354 }  // namespace avrcp
355 }  // namespace bluetooth