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