123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "get_folder_items.h"
- namespace bluetooth {
- namespace avrcp {
- std::unique_ptr<GetFolderItemsResponseBuilder>
- GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status status,
- uint16_t uid_counter,
- size_t mtu) {
- std::unique_ptr<GetFolderItemsResponseBuilder> builder(
- new GetFolderItemsResponseBuilder(Scope::MEDIA_PLAYER_LIST, status,
- uid_counter, mtu));
- return builder;
- }
- std::unique_ptr<GetFolderItemsResponseBuilder>
- GetFolderItemsResponseBuilder::MakeVFSBuilder(Status status,
- uint16_t uid_counter,
- size_t mtu) {
- std::unique_ptr<GetFolderItemsResponseBuilder> builder(
- new GetFolderItemsResponseBuilder(Scope::VFS, status, uid_counter, mtu));
- return builder;
- }
- std::unique_ptr<GetFolderItemsResponseBuilder>
- GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status status,
- uint16_t uid_counter,
- size_t mtu) {
- std::unique_ptr<GetFolderItemsResponseBuilder> builder(
- new GetFolderItemsResponseBuilder(Scope::NOW_PLAYING, status, uid_counter,
- mtu));
- return builder;
- }
- size_t GetFolderItemsResponseBuilder::size() const {
- size_t len = BrowsePacket::kMinSize();
- len += 1; // Status
- // There is nothing other than the status in the packet if the status isn't
- // NO_ERROR
- if (status_ != Status::NO_ERROR || items_.size() == 0) return len;
- len += 2; // UID Counter
- len += 2; // Number of Items;
- for (const auto& item : items_) {
- len += item.size();
- }
- return len;
- }
- bool GetFolderItemsResponseBuilder::Serialize(
- const std::shared_ptr<::bluetooth::Packet>& pkt) {
- ReserveSpace(pkt, size());
- BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
- if (status_ == Status::NO_ERROR && items_.size() == 0) {
- // Return range out of bounds if there are zero items in the folder
- status_ = Status::RANGE_OUT_OF_BOUNDS;
- }
- AddPayloadOctets1(pkt, (uint8_t)status_); // Status
- if (status_ != Status::NO_ERROR) return true;
- AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
- uint16_t num_items = items_.size();
- AddPayloadOctets2(pkt, base::ByteSwap(num_items));
- for (const auto& item : items_) {
- PushMediaListItem(pkt, item);
- }
- return true;
- }
- bool GetFolderItemsResponseBuilder::AddMediaPlayer(MediaPlayerItem item) {
- CHECK(scope_ == Scope::MEDIA_PLAYER_LIST);
- if (size() + item.size() > mtu_) return false;
- items_.push_back(MediaListItem(item));
- return true;
- }
- bool GetFolderItemsResponseBuilder::AddSong(MediaElementItem item) {
- CHECK(scope_ == Scope::VFS || scope_ == Scope::NOW_PLAYING);
- if (size() + item.size() > mtu_) return false;
- items_.push_back(MediaListItem(item));
- return true;
- }
- bool GetFolderItemsResponseBuilder::AddFolder(FolderItem item) {
- CHECK(scope_ == Scope::VFS);
- if (size() + item.size() > mtu_) return false;
- items_.push_back(MediaListItem(item));
- return true;
- }
- void GetFolderItemsResponseBuilder::PushMediaListItem(
- const std::shared_ptr<::bluetooth::Packet>& pkt,
- const MediaListItem& item) {
- switch (item.type_) {
- case MediaListItem::PLAYER:
- PushMediaPlayerItem(pkt, item.player_);
- break;
- case MediaListItem::FOLDER:
- PushFolderItem(pkt, item.folder_);
- break;
- case MediaListItem::SONG:
- PushMediaElementItem(pkt, item.song_);
- break;
- }
- }
- void GetFolderItemsResponseBuilder::PushMediaPlayerItem(
- const std::shared_ptr<::bluetooth::Packet>& pkt,
- const MediaPlayerItem& item) {
- AddPayloadOctets1(pkt, 0x01); // Media Player Item
- uint16_t item_len = item.size() - 3;
- AddPayloadOctets2(pkt, base::ByteSwap(item_len)); // Item length
- AddPayloadOctets2(pkt, base::ByteSwap(item.id_)); // Player ID
- AddPayloadOctets1(pkt, 0x01); // Player Type
- AddPayloadOctets4(pkt, 0x00000000); // Player Subtype
- AddPayloadOctets1(
- pkt, 0x02); // Player Play Status // TODO: Add this as a passed field
- // Features
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0xb7);
- AddPayloadOctets1(pkt, 0x01);
- if (item.browsable_) {
- AddPayloadOctets1(pkt, 0x0C);
- AddPayloadOctets1(pkt, 0x0a);
- } else {
- AddPayloadOctets1(pkt, 0x04);
- AddPayloadOctets1(pkt, 0x00);
- }
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets1(pkt, 0x00);
- AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));
- uint16_t name_len = item.name_.size();
- AddPayloadOctets2(pkt, base::ByteSwap(name_len));
- for (const uint8_t& byte : item.name_) {
- AddPayloadOctets1(pkt, byte);
- }
- }
- void GetFolderItemsResponseBuilder::PushFolderItem(
- const std::shared_ptr<::bluetooth::Packet>& pkt, const FolderItem& item) {
- AddPayloadOctets1(pkt, 0x02); // Folder Item
- uint16_t item_len = item.size() - 3;
- AddPayloadOctets2(pkt, base::ByteSwap(item_len));
- AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
- AddPayloadOctets1(pkt, item.folder_type_);
- AddPayloadOctets1(pkt, item.is_playable_ ? 0x01 : 0x00);
- AddPayloadOctets2(pkt,
- base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
- uint16_t name_len = item.name_.size();
- AddPayloadOctets2(pkt, base::ByteSwap(name_len));
- for (const uint8_t& byte : item.name_) {
- AddPayloadOctets1(pkt, byte);
- }
- }
- void GetFolderItemsResponseBuilder::PushMediaElementItem(
- const std::shared_ptr<::bluetooth::Packet>& pkt,
- const MediaElementItem& item) {
- AddPayloadOctets1(pkt, 0x03); // Media Element Item
- uint16_t item_len = item.size() - 3;
- AddPayloadOctets2(pkt, base::ByteSwap(item_len));
- AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
- AddPayloadOctets1(pkt, 0x00); // Media Type Audio
- AddPayloadOctets2(pkt,
- base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
- uint16_t name_len = item.name_.size();
- AddPayloadOctets2(pkt, base::ByteSwap(name_len));
- for (const uint8_t& byte : item.name_) {
- AddPayloadOctets1(pkt, byte);
- }
- AddPayloadOctets1(pkt, (uint8_t)item.attributes_.size());
- for (const auto& entry : item.attributes_) {
- AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
- AddPayloadOctets2(pkt,
- base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
- std::string attr_val = entry.value();
- uint16_t attr_len = attr_val.size();
- AddPayloadOctets2(pkt, base::ByteSwap(attr_len));
- for (const uint8_t& byte : attr_val) {
- AddPayloadOctets1(pkt, byte);
- }
- }
- }
- Scope GetFolderItemsRequest::GetScope() const {
- auto it = begin() + BrowsePacket::kMinSize();
- return static_cast<Scope>(*it);
- }
- uint32_t GetFolderItemsRequest::GetStartItem() const {
- auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
- return it.extractBE<uint32_t>();
- }
- uint32_t GetFolderItemsRequest::GetEndItem() const {
- auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
- return it.extractBE<uint32_t>();
- }
- uint8_t GetFolderItemsRequest::GetNumAttributes() const {
- auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
- return *it;
- }
- std::vector<Attribute> GetFolderItemsRequest::GetAttributesRequested() const {
- auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
- size_t number_of_attributes = it.extract<uint8_t>();
- std::vector<Attribute> attribute_list;
- // No attributes requested
- if (number_of_attributes == 0xFF) return attribute_list;
- // TODO: If the number of attributes equals 0, then all attributes are
- // requested right now thats handled in the service itself, but it'd be nice
- // to have this function return a vector with all the attributes
- for (size_t i = 0; i < number_of_attributes; i++) {
- attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
- }
- return attribute_list;
- }
- bool GetFolderItemsRequest::IsValid() const {
- if (!BrowsePacket::IsValid()) return false;
- // The minimum size required to be valid
- if (size() < kMinSize()) return false;
- auto attr_count = GetNumAttributes();
- // No items requested
- if (attr_count == 0xFF) return true;
- auto attr_start = begin() + kMinSize();
- // Casting the int returned from end - attr_start should be fine. If an
- // overflow occurs we can definitly say the packet is invalid
- return (attr_count * sizeof(Attribute)) == (size_t)(end() - attr_start);
- }
- std::string GetFolderItemsRequest::ToString() const {
- std::stringstream ss;
- ss << "GetFolderItemsRequestPacket: " << std::endl;
- ss << " └ PDU = " << GetPdu() << std::endl;
- ss << " └ Length = " << GetLength() << std::endl;
- ss << " └ Scope = " << GetScope() << std::endl;
- ss << " └ Start Item = " << loghex(GetStartItem()) << std::endl;
- ss << " └ End Item = " << loghex(GetEndItem()) << std::endl;
- ss << " └ Attribute Count = " << loghex(GetNumAttributes()) << std::endl;
- ss << std::endl;
- return ss.str();
- }
- std::unique_ptr<GetFolderItemsRequestBuilder>
- GetFolderItemsRequestBuilder::MakeBuilder(
- Scope scope, uint32_t start_item, uint32_t end_item,
- const std::set<Attribute>& requested_attrs) {
- std::unique_ptr<GetFolderItemsRequestBuilder> builder(
- new GetFolderItemsRequestBuilder(scope, start_item, end_item,
- requested_attrs));
- return builder;
- }
- size_t GetFolderItemsRequestBuilder::size() const {
- size_t len = GetFolderItemsRequest::kMinSize();
- len += requested_attrs_.size() * sizeof(Attribute);
- return len;
- }
- bool GetFolderItemsRequestBuilder::Serialize(
- const std::shared_ptr<::bluetooth::Packet>& pkt) {
- ReserveSpace(pkt, size());
- BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
- AddPayloadOctets1(pkt, static_cast<uint8_t>(scope_));
- AddPayloadOctets4(pkt, base::ByteSwap(start_item_));
- AddPayloadOctets4(pkt, base::ByteSwap(end_item_));
- if (requested_attrs_.size() == 0) {
- // 0xFF is the value to signify that there are no attributes requested.
- AddPayloadOctets1(pkt, 0xFF);
- return true;
- }
- AddPayloadOctets1(pkt, requested_attrs_.size());
- for (const auto& attr : requested_attrs_) {
- AddPayloadOctets4(pkt, base::ByteSwap(static_cast<uint32_t>(attr)));
- }
- return true;
- }
- } // namespace avrcp
- } // namespace bluetooth
|