get_folder_items.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. #include "get_folder_items.h"
  17. namespace bluetooth {
  18. namespace avrcp {
  19. std::unique_ptr<GetFolderItemsResponseBuilder>
  20. GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status status,
  21. uint16_t uid_counter,
  22. size_t mtu) {
  23. std::unique_ptr<GetFolderItemsResponseBuilder> builder(
  24. new GetFolderItemsResponseBuilder(Scope::MEDIA_PLAYER_LIST, status,
  25. uid_counter, mtu));
  26. return builder;
  27. }
  28. std::unique_ptr<GetFolderItemsResponseBuilder>
  29. GetFolderItemsResponseBuilder::MakeVFSBuilder(Status status,
  30. uint16_t uid_counter,
  31. size_t mtu) {
  32. std::unique_ptr<GetFolderItemsResponseBuilder> builder(
  33. new GetFolderItemsResponseBuilder(Scope::VFS, status, uid_counter, mtu));
  34. return builder;
  35. }
  36. std::unique_ptr<GetFolderItemsResponseBuilder>
  37. GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status status,
  38. uint16_t uid_counter,
  39. size_t mtu) {
  40. std::unique_ptr<GetFolderItemsResponseBuilder> builder(
  41. new GetFolderItemsResponseBuilder(Scope::NOW_PLAYING, status, uid_counter,
  42. mtu));
  43. return builder;
  44. }
  45. size_t GetFolderItemsResponseBuilder::size() const {
  46. size_t len = BrowsePacket::kMinSize();
  47. len += 1; // Status
  48. // There is nothing other than the status in the packet if the status isn't
  49. // NO_ERROR
  50. if (status_ != Status::NO_ERROR || items_.size() == 0) return len;
  51. len += 2; // UID Counter
  52. len += 2; // Number of Items;
  53. for (const auto& item : items_) {
  54. len += item.size();
  55. }
  56. return len;
  57. }
  58. bool GetFolderItemsResponseBuilder::Serialize(
  59. const std::shared_ptr<::bluetooth::Packet>& pkt) {
  60. ReserveSpace(pkt, size());
  61. BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
  62. if (status_ == Status::NO_ERROR && items_.size() == 0) {
  63. // Return range out of bounds if there are zero items in the folder
  64. status_ = Status::RANGE_OUT_OF_BOUNDS;
  65. }
  66. AddPayloadOctets1(pkt, (uint8_t)status_); // Status
  67. if (status_ != Status::NO_ERROR) return true;
  68. AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
  69. uint16_t num_items = items_.size();
  70. AddPayloadOctets2(pkt, base::ByteSwap(num_items));
  71. for (const auto& item : items_) {
  72. PushMediaListItem(pkt, item);
  73. }
  74. return true;
  75. }
  76. bool GetFolderItemsResponseBuilder::AddMediaPlayer(MediaPlayerItem item) {
  77. CHECK(scope_ == Scope::MEDIA_PLAYER_LIST);
  78. if (size() + item.size() > mtu_) return false;
  79. items_.push_back(MediaListItem(item));
  80. return true;
  81. }
  82. bool GetFolderItemsResponseBuilder::AddSong(MediaElementItem item) {
  83. CHECK(scope_ == Scope::VFS || scope_ == Scope::NOW_PLAYING);
  84. if (size() + item.size() > mtu_) return false;
  85. items_.push_back(MediaListItem(item));
  86. return true;
  87. }
  88. bool GetFolderItemsResponseBuilder::AddFolder(FolderItem item) {
  89. CHECK(scope_ == Scope::VFS);
  90. if (size() + item.size() > mtu_) return false;
  91. items_.push_back(MediaListItem(item));
  92. return true;
  93. }
  94. void GetFolderItemsResponseBuilder::PushMediaListItem(
  95. const std::shared_ptr<::bluetooth::Packet>& pkt,
  96. const MediaListItem& item) {
  97. switch (item.type_) {
  98. case MediaListItem::PLAYER:
  99. PushMediaPlayerItem(pkt, item.player_);
  100. break;
  101. case MediaListItem::FOLDER:
  102. PushFolderItem(pkt, item.folder_);
  103. break;
  104. case MediaListItem::SONG:
  105. PushMediaElementItem(pkt, item.song_);
  106. break;
  107. }
  108. }
  109. void GetFolderItemsResponseBuilder::PushMediaPlayerItem(
  110. const std::shared_ptr<::bluetooth::Packet>& pkt,
  111. const MediaPlayerItem& item) {
  112. AddPayloadOctets1(pkt, 0x01); // Media Player Item
  113. uint16_t item_len = item.size() - 3;
  114. AddPayloadOctets2(pkt, base::ByteSwap(item_len)); // Item length
  115. AddPayloadOctets2(pkt, base::ByteSwap(item.id_)); // Player ID
  116. AddPayloadOctets1(pkt, 0x01); // Player Type
  117. AddPayloadOctets4(pkt, 0x00000000); // Player Subtype
  118. AddPayloadOctets1(
  119. pkt, 0x02); // Player Play Status // TODO: Add this as a passed field
  120. // Features
  121. AddPayloadOctets1(pkt, 0x00);
  122. AddPayloadOctets1(pkt, 0x00);
  123. AddPayloadOctets1(pkt, 0x00);
  124. AddPayloadOctets1(pkt, 0x00);
  125. AddPayloadOctets1(pkt, 0x00);
  126. AddPayloadOctets1(pkt, 0xb7);
  127. AddPayloadOctets1(pkt, 0x01);
  128. if (item.browsable_) {
  129. AddPayloadOctets1(pkt, 0x0C);
  130. AddPayloadOctets1(pkt, 0x0a);
  131. } else {
  132. AddPayloadOctets1(pkt, 0x04);
  133. AddPayloadOctets1(pkt, 0x00);
  134. }
  135. AddPayloadOctets1(pkt, 0x00);
  136. AddPayloadOctets1(pkt, 0x00);
  137. AddPayloadOctets1(pkt, 0x00);
  138. AddPayloadOctets1(pkt, 0x00);
  139. AddPayloadOctets1(pkt, 0x00);
  140. AddPayloadOctets1(pkt, 0x00);
  141. AddPayloadOctets1(pkt, 0x00);
  142. AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));
  143. uint16_t name_len = item.name_.size();
  144. AddPayloadOctets2(pkt, base::ByteSwap(name_len));
  145. for (const uint8_t& byte : item.name_) {
  146. AddPayloadOctets1(pkt, byte);
  147. }
  148. }
  149. void GetFolderItemsResponseBuilder::PushFolderItem(
  150. const std::shared_ptr<::bluetooth::Packet>& pkt, const FolderItem& item) {
  151. AddPayloadOctets1(pkt, 0x02); // Folder Item
  152. uint16_t item_len = item.size() - 3;
  153. AddPayloadOctets2(pkt, base::ByteSwap(item_len));
  154. AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
  155. AddPayloadOctets1(pkt, item.folder_type_);
  156. AddPayloadOctets1(pkt, item.is_playable_ ? 0x01 : 0x00);
  157. AddPayloadOctets2(pkt,
  158. base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
  159. uint16_t name_len = item.name_.size();
  160. AddPayloadOctets2(pkt, base::ByteSwap(name_len));
  161. for (const uint8_t& byte : item.name_) {
  162. AddPayloadOctets1(pkt, byte);
  163. }
  164. }
  165. void GetFolderItemsResponseBuilder::PushMediaElementItem(
  166. const std::shared_ptr<::bluetooth::Packet>& pkt,
  167. const MediaElementItem& item) {
  168. AddPayloadOctets1(pkt, 0x03); // Media Element Item
  169. uint16_t item_len = item.size() - 3;
  170. AddPayloadOctets2(pkt, base::ByteSwap(item_len));
  171. AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
  172. AddPayloadOctets1(pkt, 0x00); // Media Type Audio
  173. AddPayloadOctets2(pkt,
  174. base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
  175. uint16_t name_len = item.name_.size();
  176. AddPayloadOctets2(pkt, base::ByteSwap(name_len));
  177. for (const uint8_t& byte : item.name_) {
  178. AddPayloadOctets1(pkt, byte);
  179. }
  180. AddPayloadOctets1(pkt, (uint8_t)item.attributes_.size());
  181. for (const auto& entry : item.attributes_) {
  182. AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
  183. AddPayloadOctets2(pkt,
  184. base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
  185. std::string attr_val = entry.value();
  186. uint16_t attr_len = attr_val.size();
  187. AddPayloadOctets2(pkt, base::ByteSwap(attr_len));
  188. for (const uint8_t& byte : attr_val) {
  189. AddPayloadOctets1(pkt, byte);
  190. }
  191. }
  192. }
  193. Scope GetFolderItemsRequest::GetScope() const {
  194. auto it = begin() + BrowsePacket::kMinSize();
  195. return static_cast<Scope>(*it);
  196. }
  197. uint32_t GetFolderItemsRequest::GetStartItem() const {
  198. auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
  199. return it.extractBE<uint32_t>();
  200. }
  201. uint32_t GetFolderItemsRequest::GetEndItem() const {
  202. auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
  203. return it.extractBE<uint32_t>();
  204. }
  205. uint8_t GetFolderItemsRequest::GetNumAttributes() const {
  206. auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
  207. return *it;
  208. }
  209. std::vector<Attribute> GetFolderItemsRequest::GetAttributesRequested() const {
  210. auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
  211. size_t number_of_attributes = it.extract<uint8_t>();
  212. std::vector<Attribute> attribute_list;
  213. // No attributes requested
  214. if (number_of_attributes == 0xFF) return attribute_list;
  215. // TODO: If the number of attributes equals 0, then all attributes are
  216. // requested right now thats handled in the service itself, but it'd be nice
  217. // to have this function return a vector with all the attributes
  218. for (size_t i = 0; i < number_of_attributes; i++) {
  219. attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
  220. }
  221. return attribute_list;
  222. }
  223. bool GetFolderItemsRequest::IsValid() const {
  224. if (!BrowsePacket::IsValid()) return false;
  225. // The minimum size required to be valid
  226. if (size() < kMinSize()) return false;
  227. auto attr_count = GetNumAttributes();
  228. // No items requested
  229. if (attr_count == 0xFF) return true;
  230. auto attr_start = begin() + kMinSize();
  231. // Casting the int returned from end - attr_start should be fine. If an
  232. // overflow occurs we can definitly say the packet is invalid
  233. return (attr_count * sizeof(Attribute)) == (size_t)(end() - attr_start);
  234. }
  235. std::string GetFolderItemsRequest::ToString() const {
  236. std::stringstream ss;
  237. ss << "GetFolderItemsRequestPacket: " << std::endl;
  238. ss << " └ PDU = " << GetPdu() << std::endl;
  239. ss << " └ Length = " << GetLength() << std::endl;
  240. ss << " └ Scope = " << GetScope() << std::endl;
  241. ss << " └ Start Item = " << loghex(GetStartItem()) << std::endl;
  242. ss << " └ End Item = " << loghex(GetEndItem()) << std::endl;
  243. ss << " └ Attribute Count = " << loghex(GetNumAttributes()) << std::endl;
  244. ss << std::endl;
  245. return ss.str();
  246. }
  247. std::unique_ptr<GetFolderItemsRequestBuilder>
  248. GetFolderItemsRequestBuilder::MakeBuilder(
  249. Scope scope, uint32_t start_item, uint32_t end_item,
  250. const std::set<Attribute>& requested_attrs) {
  251. std::unique_ptr<GetFolderItemsRequestBuilder> builder(
  252. new GetFolderItemsRequestBuilder(scope, start_item, end_item,
  253. requested_attrs));
  254. return builder;
  255. }
  256. size_t GetFolderItemsRequestBuilder::size() const {
  257. size_t len = GetFolderItemsRequest::kMinSize();
  258. len += requested_attrs_.size() * sizeof(Attribute);
  259. return len;
  260. }
  261. bool GetFolderItemsRequestBuilder::Serialize(
  262. const std::shared_ptr<::bluetooth::Packet>& pkt) {
  263. ReserveSpace(pkt, size());
  264. BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
  265. AddPayloadOctets1(pkt, static_cast<uint8_t>(scope_));
  266. AddPayloadOctets4(pkt, base::ByteSwap(start_item_));
  267. AddPayloadOctets4(pkt, base::ByteSwap(end_item_));
  268. if (requested_attrs_.size() == 0) {
  269. // 0xFF is the value to signify that there are no attributes requested.
  270. AddPayloadOctets1(pkt, 0xFF);
  271. return true;
  272. }
  273. AddPayloadOctets1(pkt, requested_attrs_.size());
  274. for (const auto& attr : requested_attrs_) {
  275. AddPayloadOctets4(pkt, base::ByteSwap(static_cast<uint32_t>(attr)));
  276. }
  277. return true;
  278. }
  279. } // namespace avrcp
  280. } // namespace bluetooth