Home | History | Annotate | Download | only in avrcp
      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:
    149   AttributeEntry(const Attribute& attribute, const std::string& value)
    150       : attribute_(attribute), value_(value) {}
    151 
    152   AttributeEntry(const Attribute& attribute) : attribute_(attribute) {}
    153 
    154   AttributeEntry(const AttributeEntry&) = default;
    155 
    156   Attribute attribute() const { return attribute_; }
    157 
    158   std::string value() const { return value_; }
    159 
    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 
    168   size_t size() const { return kHeaderSize() + value_.size(); }
    169 
    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 
    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 
    195   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 
    204   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 
    218   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 
    227   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 
    240   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 
    252   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
    263   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 
    278   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 
    305   MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
    306 
    307   MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
    308 
    309   MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
    310 
    311   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 
    326   ~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 
    340   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