host_supported: true,
local_include_dirs: ["tests"],
srcs: [
- "tests/base/packet_test.cc",
- "tests/base/iterator_test.cc",
- "tests/base/packet_builder_test.cc",
+ "tests/avrcp/avrcp_browse_packet_test.cc",
"tests/avrcp/avrcp_packet_test.cc",
- "tests/avrcp/vendor_packet_test.cc",
+ "tests/avrcp/avrcp_reject_packet_test.cc",
+ "tests/avrcp/change_path_packet_test.cc",
"tests/avrcp/get_capabilities_packet_test.cc",
"tests/avrcp/get_element_attributes_packet_test.cc",
+ "tests/avrcp/get_folder_items_packet_test.cc",
+ "tests/avrcp/get_item_attributes_packet_test.cc",
"tests/avrcp/get_play_status_packet_test.cc",
+ "tests/avrcp/get_total_number_of_items_packet_test.cc",
"tests/avrcp/pass_through_packet_test.cc",
+ "tests/avrcp/play_item_packet_test.cc",
"tests/avrcp/register_notification_packet_test.cc",
- "tests/avrcp/avrcp_reject_packet_test.cc",
+ "tests/avrcp/set_browsed_player_packet_test.cc",
+ "tests/avrcp/vendor_packet_test.cc",
+ "tests/base/iterator_test.cc",
+ "tests/base/packet_builder_test.cc",
+ "tests/base/packet_test.cc",
],
static_libs: [
"libgmock",
"lib-bt-packets",
],
- cflags: ["-DBUILDCFG","-g"],
+ cflags: [
+ "-DBUILDCFG",
+ ],
}
export_include_dirs: ["."],
host_supported: true,
srcs: [
+ "avrcp_browse_packet.cc",
"avrcp_packet.cc",
- "vendor_packet.cc",
+ "avrcp_reject_packet.cc",
"capabilities_packet.cc",
+ "change_path.cc",
"get_element_attributes_packet.cc",
+ "get_folder_items.cc",
+ "get_item_attributes.cc",
"get_play_status_packet.cc",
+ "get_total_number_of_items.cc",
"pass_through_packet.cc",
+ "play_item.cc",
"register_notification_packet.cc",
- "avrcp_reject_packet.cc",
+ "set_browsed_player.cc",
+ "vendor_packet.cc",
],
static_libs: [
"lib-bt-packets-base",
--- /dev/null
+/*
+ * 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 "avrcp_browse_packet.h"
+
+#include <base/logging.h>
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<BrowsePacketBuilder> BrowsePacketBuilder::MakeBuilder(
+ BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload) {
+ std::unique_ptr<BrowsePacketBuilder> builder =
+ std::unique_ptr<BrowsePacketBuilder>(new BrowsePacketBuilder(pdu));
+
+ builder->payload_ = std::move(payload);
+
+ return builder;
+}
+
+size_t BrowsePacketBuilder::size() const {
+ return BrowsePacket::kMinSize() + payload_->size();
+}
+
+bool BrowsePacketBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ PushHeader(pkt, payload_->size());
+
+ return payload_->Serialize(pkt);
+}
+
+void BrowsePacketBuilder::PushHeader(
+ const std::shared_ptr<::bluetooth::Packet>& pkt, uint16_t length) {
+ AddPayloadOctets1(pkt, (uint8_t)pdu_);
+ AddPayloadOctets2(pkt, base::ByteSwap(length));
+}
+
+std::shared_ptr<BrowsePacket> BrowsePacket::Parse(
+ std::shared_ptr<::bluetooth::Packet> pkt) {
+ return std::shared_ptr<BrowsePacket>(new BrowsePacket(pkt));
+}
+
+BrowsePdu BrowsePacket::GetPdu() const {
+ return static_cast<BrowsePdu>(*begin());
+}
+
+uint16_t BrowsePacket::GetLength() const {
+ auto it = begin() + static_cast<size_t>(1);
+ return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool BrowsePacket::IsValid() const {
+ if (size() < kMinSize()) return false;
+ return size() == GetLength() + kMinSize();
+}
+
+std::string BrowsePacket::ToString() const {
+ std::stringstream ss;
+ ss << "AvrcpBrowsePacket: " << std::endl;
+ ss << " └ PDU = " << GetPdu() << std::endl;
+ ss << " └ Length = " << GetLength() << std::endl;
+ ss << " └ Payload =";
+ for (auto it = begin() + static_cast<size_t>(3); it != end(); it++) {
+ ss << " " << loghex(*it);
+ }
+ ss << std::endl;
+
+ return ss.str();
+}
+
+std::pair<size_t, size_t> BrowsePacket::GetPayloadIndecies() const {
+ return std::pair<size_t, size_t>(packet_start_index_ + 3, packet_end_index_);
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <iostream>
+
+#include "iterator.h"
+#include "packet.h"
+#include "packet_builder.h"
+
+#include "avrcp_common.h"
+#include "avrcp_logging_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class BrowsePacketBuilder : public ::bluetooth::PacketBuilder {
+ public:
+ virtual ~BrowsePacketBuilder() = default;
+
+ static std::unique_ptr<BrowsePacketBuilder> MakeBuilder(
+ BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+ BrowsePdu pdu_;
+ std::unique_ptr<::bluetooth::PacketBuilder> payload_;
+
+ void PushHeader(const std::shared_ptr<::bluetooth::Packet>& pkt,
+ uint16_t length);
+
+ BrowsePacketBuilder(BrowsePdu pdu) : pdu_(pdu){};
+};
+
+class BrowsePacket : public ::bluetooth::Packet {
+ public:
+ virtual ~BrowsePacket() = default;
+
+ static std::shared_ptr<BrowsePacket> Parse(
+ std::shared_ptr<::bluetooth::Packet> pkt);
+
+ /**
+ * Avrcp Browse Packet Layout
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * uint8_t[] payload_;
+ */
+ static constexpr size_t kMinSize() { return 3; }
+
+ BrowsePdu GetPdu() const;
+ uint16_t GetLength() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using ::bluetooth::Packet::Packet;
+
+ private:
+ virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+ DISALLOW_COPY_AND_ASSIGN(BrowsePacket);
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
#include <base/sys_byteorder.h>
+#include <map>
+
// This file contains the different AVRCP Constants
namespace bluetooth {
namespace avrcp {
GET_ELEMENT_ATTRIBUTES = 0x20,
GET_PLAY_STATUS = 0x30,
REGISTER_NOTIFICATION = 0x31,
+ SET_ADDRESSED_PLAYER = 0x60,
+ PLAY_ITEM = 0x74,
};
enum class PacketType : uint8_t {
enum class Attribute : uint32_t {
TITLE = 0x01,
- ARTIST_NAME,
- ALBUM_NAME,
- TRACK_NUMBER,
- TOTAL_NUMBER_OF_TRACKS,
- GENRE,
- PLAYING_TIME,
- DEFAULT_COVER_ART,
+ ARTIST_NAME = 0x02,
+ ALBUM_NAME = 0x03,
+ TRACK_NUMBER = 0x04,
+ TOTAL_NUMBER_OF_TRACKS = 0x05,
+ GENRE = 0x06,
+ PLAYING_TIME = 0x07,
+ DEFAULT_COVER_ART = 0x08,
};
enum class Status : uint8_t {
INVALID_COMMAND = 0x00,
- INVALID_PARAMETER,
- PARAMETER_CONTENT_ERROR,
- INTERNAL_ERROR,
- NO_ERROR,
- UIDS_CHANGED,
- RESERVED,
- INVALID_DIRECTION,
- NOT_A_DIRECTORY,
- DOES_NOT_EXIST,
- INVALID_SCOPE,
- RANGE_OUT_OF_BOUNDS,
- FOLDER_ITEM_NOT_PLAYABLE,
- MEDIA_IN_USE,
- NOW_PLAYING_LIST_FULL,
- SEARCH_NOT_SUPPORTED,
- SEARCH_IN_PROGRESS,
- INVALID_PLAYER_ID,
- PLAYER_NOT_BROWSABLE,
- PLAYER_NOT_ADDRESSED,
- NO_VALID_SEARCH_RESULTS,
- NO_AVAILABLE_PLAYERS,
- ADDRESSED_PLAYER_CHANGED,
+ INVALID_PARAMETER = 0x01,
+ PARAMETER_CONTENT_ERROR = 0x02,
+ INTERNAL_ERROR = 0x03,
+ NO_ERROR = 0x04,
+ UIDS_CHANGED = 0x05,
+ RESERVED = 0x06,
+ INVALID_DIRECTION = 0x07,
+ NOT_A_DIRECTORY = 0x08,
+ DOES_NOT_EXIST = 0x09,
+ INVALID_SCOPE = 0x0a,
+ RANGE_OUT_OF_BOUNDS = 0xb,
+ FOLDER_ITEM_NOT_PLAYABLE = 0x0c,
+ MEDIA_IN_USE = 0x0d,
+ NOW_PLAYING_LIST_FULL = 0x0e,
+ SEARCH_NOT_SUPPORTED = 0x0f,
+ SEARCH_IN_PROGRESS = 0x10,
+ INVALID_PLAYER_ID = 0x11,
+ PLAYER_NOT_BROWSABLE = 0x12,
+ PLAYER_NOT_ADDRESSED = 0x13,
+ NO_VALID_SEARCH_RESULTS = 0x14,
+ NO_AVAILABLE_PLAYERS = 0x15,
+ ADDRESSED_PLAYER_CHANGED = 0x16,
+};
+
+enum class BrowsePdu : uint8_t {
+ SET_BROWSED_PLAYER = 0x70,
+ GET_FOLDER_ITEMS = 0x71,
+ CHANGE_PATH = 0x72,
+ GET_ITEM_ATTRIBUTES = 0x73,
+ GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
+};
+
+enum class Scope : uint8_t {
+ MEDIA_PLAYER_LIST = 0x00,
+ VFS = 0x01,
+ SEARCH = 0x02,
+ NOW_PLAYING = 0x03,
+};
+
+enum class Direction : uint8_t {
+ UP = 0x00,
+ DOWN = 0x01,
};
using AttributeEntry = std::pair<Attribute, std::string>;
+struct MediaPlayerItem {
+ uint16_t id_;
+ std::string name_;
+ bool browsable_;
+
+ MediaPlayerItem(uint16_t id, std::string name, bool browsable)
+ : id_(id), name_(name), browsable_(browsable) {}
+
+ MediaPlayerItem(const MediaPlayerItem&) = default;
+
+ static size_t size(const MediaPlayerItem& item) {
+ size_t ret = 0;
+ ret += 1; // Media Player Type
+ ret += 2; // Item Length
+ ret += 2; // Player Id
+ ret += 1; // Player Type
+ ret += 4; // Player Subtype
+ ret += 1; // Play Status
+ ret += 16; // Features
+ ret += 2; // UTF-8 character set
+ ret += 2; // Name Length
+ ret += item.name_.size();
+ return ret;
+ }
+};
+
+struct FolderItem {
+ uint64_t uid_;
+ uint8_t folder_type_;
+ bool is_playable_;
+ std::string name_;
+
+ FolderItem(uint64_t uid, uint8_t folder_type, bool is_playable,
+ const std::string& name)
+ : uid_(uid),
+ folder_type_(folder_type),
+ is_playable_(is_playable),
+ name_(name) {}
+
+ FolderItem(const FolderItem&) = default;
+
+ static size_t size(const FolderItem& item) {
+ size_t ret = 0;
+ ret += 1; // Folder Item Type
+ ret += 2; // Item Length
+ ret += 8; // Folder UID
+ ret += 1; // Folder Type
+ ret += 1; // Is Playable byte
+ ret += 2; // UTF-8 Character Set
+ ret += 2; // Name Length
+ ret += item.name_.size();
+ return ret;
+ }
+};
+
+// NOTE: We never use media type field because we only support audio types
+struct MediaElementItem {
+ uint64_t uid_ = 0;
+ std::string name_;
+ std::map<Attribute, std::string> attributes_;
+
+ MediaElementItem(uint64_t uid, std::string name,
+ std::map<Attribute, std::string> attributes)
+ : uid_(uid), name_(name), attributes_(attributes) {}
+
+ MediaElementItem(const MediaElementItem&) = default;
+
+ static size_t size(const MediaElementItem& item) {
+ size_t ret = 0;
+ ret += 1; // Media Element Item Type
+ ret += 2; // Item Length
+ ret += 8; // Item UID
+ ret += 1; // Media Type
+ ret += 2; // UTF-8 Character Set
+ ret += 2; // Name Length
+ ret += item.name_.size();
+ ret += 1; // Number of Attributes
+ for (auto it = item.attributes_.begin(); it != item.attributes_.end();
+ it++) {
+ ret += 4; // Attribute ID
+ ret += 2; // UTF-8 Character Set
+ ret += 2; // Attribute Length
+ ret += it->second.size();
+ }
+
+ return ret;
+ }
+};
+
+struct MediaListItem {
+ enum : uint8_t { PLAYER = 0x01, FOLDER = 0x02, SONG = 0x03 } type_;
+
+ union {
+ MediaPlayerItem player_;
+ FolderItem folder_;
+ MediaElementItem song_;
+ };
+
+ MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
+
+ MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
+
+ MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
+
+ MediaListItem(const MediaListItem& item) {
+ type_ = item.type_;
+ switch (item.type_) {
+ case PLAYER:
+ new (&player_) MediaPlayerItem(item.player_);
+ return;
+ case FOLDER:
+ new (&folder_) FolderItem(item.folder_);
+ return;
+ case SONG:
+ new (&song_) MediaElementItem(item.song_);
+ return;
+ }
+ }
+
+ ~MediaListItem() {
+ switch (type_) {
+ case PLAYER:
+ player_.~MediaPlayerItem();
+ return;
+ case FOLDER:
+ folder_.~FolderItem();
+ return;
+ case SONG:
+ song_.~MediaElementItem();
+ return;
+ }
+ }
+
+ static size_t size(const MediaListItem& item) {
+ switch (item.type_) {
+ case PLAYER:
+ return MediaPlayerItem::size(item.player_);
+ case FOLDER:
+ return FolderItem::size(item.folder_);
+ case SONG:
+ return MediaElementItem::size(item.song_);
+ }
+ }
+};
+
} // namespace avrcp
} // namespace bluetooth
\ No newline at end of file
CASE_RETURN_TEXT(CommandPdu::GET_ELEMENT_ATTRIBUTES);
CASE_RETURN_TEXT(CommandPdu::GET_PLAY_STATUS);
CASE_RETURN_TEXT(CommandPdu::REGISTER_NOTIFICATION);
+ CASE_RETURN_TEXT(CommandPdu::SET_ADDRESSED_PLAYER);
+ CASE_RETURN_TEXT(CommandPdu::PLAY_ITEM);
default:
return "Unknown Command PDU: " + loghex(pdu);
}
return os << StatusText(status);
}
+inline std::string BrowsePduText(const BrowsePdu& pdu) {
+ switch (pdu) {
+ CASE_RETURN_TEXT(BrowsePdu::SET_BROWSED_PLAYER);
+ CASE_RETURN_TEXT(BrowsePdu::GET_FOLDER_ITEMS);
+ CASE_RETURN_TEXT(BrowsePdu::CHANGE_PATH);
+ CASE_RETURN_TEXT(BrowsePdu::GET_ITEM_ATTRIBUTES);
+ default:
+ return "Unknown Browse Pdu: " + loghex(pdu);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const BrowsePdu& pdu) {
+ return os << BrowsePduText(pdu);
+}
+
+inline std::string ScopeText(const Scope& scope) {
+ switch (scope) {
+ CASE_RETURN_TEXT(Scope::MEDIA_PLAYER_LIST);
+ CASE_RETURN_TEXT(Scope::VFS);
+ CASE_RETURN_TEXT(Scope::SEARCH);
+ CASE_RETURN_TEXT(Scope::NOW_PLAYING);
+ default:
+ return "Unknown Scope: " + loghex(scope);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Scope& pdu) {
+ return os << ScopeText(pdu);
+}
+
+inline std::string DirectionText(const Direction& dir) {
+ switch (dir) {
+ CASE_RETURN_TEXT(Direction::UP);
+ CASE_RETURN_TEXT(Direction::DOWN);
+ default:
+ return "Unknown Direction: " + loghex(dir);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Direction& dir) {
+ return os << DirectionText(dir);
+}
+
} // namespace avrcp
} // namespace bluetooth
\ No newline at end of file
size_t PacketBuilder::size() const {
// The size of the header for an Packet is 3
- return payload_->size() + Packet::kHeaderSize();
+ return payload_->size() + Packet::kMinSize();
}
bool PacketBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
return static_cast<Opcode>(value);
}
-bool Packet::IsValid() const { return size() >= kHeaderSize(); }
+bool Packet::IsValid() const { return size() >= kMinSize(); }
std::string Packet::ToString() const {
std::stringstream ss;
* Opcode opcode_;
* uint8_t[] payload_;
*/
- static constexpr size_t kHeaderSize() { return 3; };
+ static constexpr size_t kMinSize() { return 3; };
// Getter Functions
CType GetCType() const;
return builder;
}
-size_t RejectBuilder::size() const { return VendorPacket::kHeaderSize() + 1; }
+size_t RejectBuilder::size() const { return VendorPacket::kMinSize() + 1; }
bool RejectBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
ReserveSpace(pkt, size());
}
size_t GetCapabilitiesRequestBuilder::size() const {
- return GetCapabilitiesRequest::kHeaderSize();
+ return GetCapabilitiesRequest::kMinSize();
}
bool GetCapabilitiesRequestBuilder::Serialize(
}
Capability GetCapabilitiesRequest::GetCapabilityRequested() const {
- auto value = *(begin() + VendorPacket::kHeaderSize());
+ auto value = *(begin() + VendorPacket::kMinSize());
return static_cast<Capability>(value);
}
bool GetCapabilitiesRequest::IsValid() const {
if (!VendorPacket::IsValid()) return false;
- return (size() == VendorPacket::kHeaderSize() + 1);
+ return (size() == VendorPacket::kMinSize() + 1);
}
std::string GetCapabilitiesRequest::ToString() const {
size_t capability_count = elements_.size();
size_t capability_size = capability_ == Capability::COMPANY_ID ? 3 : 1;
- return GetCapabilitiesResponse::kHeaderSize() +
+ return GetCapabilitiesResponse::kMinSize() +
(capability_count * capability_size);
}
PacketBuilder::PushHeader(pkt);
// Push the avrcp vendor command headers
- uint16_t parameter_count = size() - VendorPacket::kHeaderSize();
+ uint16_t parameter_count = size() - VendorPacket::kMinSize();
VendorPacketBuilder::PushHeader(pkt, parameter_count);
// Push the capability, capability count, and elements
* GetCapabilitiesRequestPacket:
* uint8_t capability_requested:
*/
- static constexpr size_t kHeaderSize() {
- return VendorPacket::kHeaderSize() + 1;
- };
+ static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; };
// Getter Functions
Capability GetCapabilityRequested() const;
* uint8_t company_id[3];
* } capability_array[];
*/
- static constexpr size_t kHeaderSize() {
- return VendorPacket::kHeaderSize() + 2;
- };
+ static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 2; };
// TODO: Implement these for AVRCP Controller
// virtual uint8_t GetCapabilityReturned() const;
--- /dev/null
+/*
+ * 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 "change_path.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<ChangePathResponseBuilder>
+ChangePathResponseBuilder::MakeBuilder(Status status,
+ uint32_t num_items_in_folder) {
+ std::unique_ptr<ChangePathResponseBuilder> builder(
+ new ChangePathResponseBuilder(status, num_items_in_folder));
+
+ return builder;
+}
+
+size_t ChangePathResponseBuilder::size() const {
+ size_t len = BrowsePacket::kMinSize();
+ len += 1; // Status
+ if (status_ != Status::NO_ERROR) return len;
+
+ len += 4; // Number of items in folder
+ return len;
+}
+
+bool ChangePathResponseBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+ AddPayloadOctets1(pkt, (uint8_t)status_);
+ if (status_ != Status::NO_ERROR) return true;
+
+ AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+ return true;
+}
+
+uint16_t ChangePathRequest::GetUidCounter() const {
+ auto it = begin() + BrowsePacket::kMinSize();
+ return base::ByteSwap(it.extract<uint16_t>());
+}
+
+Direction ChangePathRequest::GetDirection() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(2);
+ return static_cast<Direction>(*it);
+}
+
+uint64_t ChangePathRequest::GetUid() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(3);
+ return base::ByteSwap(it.extract<uint64_t>());
+}
+
+bool ChangePathRequest::IsValid() const {
+ if (!BrowsePacket::IsValid()) return false;
+ // Change path request packets are always the same size
+ return size() == kMinSize();
+}
+
+std::string ChangePathRequest::ToString() const {
+ std::stringstream ss;
+ ss << "ChangePathRequestPacket: " << std::endl;
+ ss << " └ PDU = " << GetPdu() << std::endl;
+ ss << " └ Length = " << GetLength() << std::endl;
+ ss << " └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+ ss << " └ Direction = " << GetDirection() << std::endl;
+ ss << " └ UID Requested = " << loghex(GetUid()) << std::endl;
+ ss << std::endl;
+
+ return ss.str();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class ChangePathResponseBuilder : public BrowsePacketBuilder {
+ public:
+ virtual ~ChangePathResponseBuilder() = default;
+
+ static std::unique_ptr<ChangePathResponseBuilder> MakeBuilder(
+ Status status, uint32_t num_items_in_folder);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+ Status status_;
+ uint32_t num_items_in_folder_;
+
+ ChangePathResponseBuilder(Status status, uint32_t num_items_in_folder)
+ : BrowsePacketBuilder(BrowsePdu::CHANGE_PATH),
+ status_(status),
+ num_items_in_folder_(num_items_in_folder) {}
+};
+
+class ChangePathRequest : public BrowsePacket {
+ public:
+ virtual ~ChangePathRequest() = default;
+
+ /**
+ * Avrcp Change Path Packet Layout
+ * BrowsePacket:
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * ChangePathRequest:
+ * uint16_t uid_counter_;
+ * uint8_t direction_;
+ * uint64_t folder_uid_;
+ */
+ static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 11; }
+
+ uint16_t GetUidCounter() const;
+ Direction GetDirection() const;
+ uint64_t GetUid() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using BrowsePacket::BrowsePacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
namespace avrcp {
uint64_t GetElementAttributesRequest::GetIdentifier() const {
- auto it = begin() + VendorPacket::kHeaderSize();
+ auto it = begin() + VendorPacket::kMinSize();
return it.extract<uint64_t>();
}
uint8_t GetElementAttributesRequest::GetNumAttributes() const {
- auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(8);
+ auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
return it.extract<uint8_t>();
}
std::vector<Attribute> GetElementAttributesRequest::GetAttributesRequested()
const {
- auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(8);
+ auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
size_t number_of_attributes = it.extract<uint8_t>();
bool GetElementAttributesRequest::IsValid() const {
if (!VendorPacket::IsValid()) return false;
- if (size() < kHeaderSize()) return false;
+ if (size() < kMinSize()) return false;
size_t num_attributes = GetNumAttributes();
- auto attr_start =
- begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(9);
+ auto attr_start = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
// Casting the int returned from end - attr_start should be fine. If an
// overflow occurs we can definitly say the packet is invalid
attr_list_size += attribute_entry.second.length();
}
- return VendorPacket::kHeaderSize() + 1 + attr_list_size;
+ return VendorPacket::kMinSize() + 1 + attr_list_size;
}
bool GetElementAttributesResponseBuilder::Serialize(
PacketBuilder::PushHeader(pkt);
- VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kHeaderSize());
+ VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
AddPayloadOctets1(pkt, entries_.size());
for (auto attribute_entry : entries_) {
* uint8_t number_of_attributes;
* uint32_t attributes_requested[];
*/
- static constexpr size_t kHeaderSize() {
- return VendorPacket::kHeaderSize() + 9;
- }
+ static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 9; }
// Getter Functions
uint64_t GetIdentifier() const;
--- /dev/null
+/*
+ * 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) {
+ std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+ new GetFolderItemsResponseBuilder(Scope::MEDIA_PLAYER_LIST, status,
+ uid_counter));
+
+ return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeVFSBuilder(Status status,
+ uint16_t uid_counter) {
+ std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+ new GetFolderItemsResponseBuilder(Scope::VFS, status, uid_counter));
+
+ return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status status,
+ uint16_t uid_counter) {
+ std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+ new GetFolderItemsResponseBuilder(Scope::NOW_PLAYING, status,
+ uid_counter));
+
+ 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 += MediaListItem::size(item);
+ }
+
+ 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;
+}
+
+void GetFolderItemsResponseBuilder::AddMediaPlayer(MediaPlayerItem item) {
+ CHECK(scope_ == Scope::MEDIA_PLAYER_LIST);
+ items_.push_back(MediaListItem(item));
+}
+
+void GetFolderItemsResponseBuilder::AddSong(MediaElementItem item) {
+ CHECK(scope_ == Scope::VFS || scope_ == Scope::NOW_PLAYING);
+ items_.push_back(MediaListItem(item));
+}
+
+void GetFolderItemsResponseBuilder::AddFolder(FolderItem item) {
+ CHECK(scope_ == Scope::VFS);
+ items_.push_back(MediaListItem(item));
+}
+
+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 = MediaPlayerItem::size(item) - 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 = FolderItem::size(item) - 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 = MediaElementItem::size(item) - 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& attribute : item.attributes_) {
+ AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)attribute.first));
+ AddPayloadOctets2(pkt,
+ base::ByteSwap((uint16_t)0x006a)); // UTF-8 Character Set
+
+ std::string attr_val = attribute.second;
+ 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 base::ByteSwap(it.extract<uint32_t>());
+}
+
+uint32_t GetFolderItemsRequest::GetEndItem() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
+ return base::ByteSwap(it.extract<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)base::ByteSwap(it.extract<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();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetFolderItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+ virtual ~GetFolderItemsResponseBuilder() = default;
+ static std::unique_ptr<GetFolderItemsResponseBuilder> MakePlayerListBuilder(
+ Status status, uint16_t uid_counter);
+ static std::unique_ptr<GetFolderItemsResponseBuilder> MakeVFSBuilder(
+ Status status, uint16_t uid_counter);
+ static std::unique_ptr<GetFolderItemsResponseBuilder> MakeNowPlayingBuilder(
+ Status status, uint16_t uid_counter);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ void AddMediaPlayer(MediaPlayerItem item);
+ void AddSong(MediaElementItem item);
+ void AddFolder(FolderItem item);
+
+ protected:
+ Scope scope_;
+ std::vector<MediaListItem> items_;
+ Status status_;
+ uint16_t uid_counter_;
+
+ GetFolderItemsResponseBuilder(Scope scope, Status status,
+ uint16_t uid_counter)
+ : BrowsePacketBuilder(BrowsePdu::GET_FOLDER_ITEMS),
+ scope_(scope),
+ status_(status),
+ uid_counter_(uid_counter){};
+
+ private:
+ void PushMediaListItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+ const MediaListItem& item);
+ void PushMediaPlayerItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+ const MediaPlayerItem& item);
+ void PushMediaElementItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+ const MediaElementItem& item);
+ void PushFolderItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+ const FolderItem& item);
+};
+
+class GetFolderItemsRequest : public BrowsePacket {
+ public:
+ virtual ~GetFolderItemsRequest() = default;
+
+ /**
+ * Avrcp Change Path Packet Layout
+ * BrowsePacket:
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * GetFolderItemsRequest:
+ * uint8_t scope_;
+ * uint32_t start_item_;
+ * uint32_t end_item_;
+ * uint8_t attr_count_;
+ * uint32_t[] attr_requested_;
+ */
+ static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 10; }
+
+ Scope GetScope() const;
+ uint32_t GetStartItem() const;
+ uint32_t GetEndItem() const;
+ uint8_t GetNumAttributes() const;
+ std::vector<Attribute> GetAttributesRequested() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using BrowsePacket::BrowsePacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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_item_attributes.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetItemAttributesResponseBuilder>
+GetItemAttributesResponseBuilder::MakeBuilder(Status status) {
+ std::unique_ptr<GetItemAttributesResponseBuilder> builder(
+ new GetItemAttributesResponseBuilder(status));
+
+ return builder;
+}
+
+GetItemAttributesResponseBuilder*
+GetItemAttributesResponseBuilder::AddAttributeEntry(AttributeEntry entry) {
+ CHECK(entries_.size() < 0xFF);
+ entries_.insert(entry);
+ return this;
+}
+
+GetItemAttributesResponseBuilder*
+GetItemAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
+ std::string value) {
+ return AddAttributeEntry(AttributeEntry(attribute, value));
+}
+
+size_t GetItemAttributesResponseBuilder::size() const {
+ size_t len = BrowsePacket::kMinSize();
+ len += 1; // Status
+ if (status_ != Status::NO_ERROR) return len;
+
+ len += 1; // Number of attributes
+ for (const auto& attribute_entry : entries_) {
+ len += 4; // Size of attr entry
+ len += 2; // Size of value length field
+ len += 2; // Size of character encoding
+ len += attribute_entry.second.length();
+ }
+ return len;
+}
+
+bool GetItemAttributesResponseBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+ AddPayloadOctets1(pkt, (uint8_t)status_);
+ if (status_ != Status::NO_ERROR) return true;
+
+ AddPayloadOctets1(pkt, entries_.size());
+ for (auto attribute_entry : entries_) {
+ AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)attribute_entry.first));
+ uint16_t character_set = 0x006a; // UTF-8
+ AddPayloadOctets2(pkt, base::ByteSwap(character_set));
+ uint16_t value_length = attribute_entry.second.length();
+ AddPayloadOctets2(pkt, base::ByteSwap(value_length));
+ for (const uint8_t& byte : attribute_entry.second) {
+ AddPayloadOctets1(pkt, byte);
+ }
+ }
+
+ return true;
+}
+
+Scope GetItemAttributesRequest::GetScope() const {
+ auto it = begin() + BrowsePacket::kMinSize();
+ return static_cast<Scope>(*it);
+}
+
+uint64_t GetItemAttributesRequest::GetUid() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
+ return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t GetItemAttributesRequest::GetUidCounter() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+ return base::ByteSwap(it.extract<uint16_t>());
+}
+
+uint8_t GetItemAttributesRequest::GetNumAttributes() const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+ return *it;
+}
+
+std::vector<Attribute> GetItemAttributesRequest::GetAttributesRequested()
+ const {
+ auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+ size_t number_of_attributes = it.extract<uint8_t>();
+
+ std::vector<Attribute> attribute_list;
+ for (size_t i = 0; i < number_of_attributes; i++) {
+ attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+ }
+
+ return attribute_list;
+}
+
+bool GetItemAttributesRequest::IsValid() const {
+ if (!BrowsePacket::IsValid()) return false;
+ if (size() < kMinSize()) return false;
+
+ // Casting the int returned from end - attr_start should be fine. If an
+ // overflow occurs we can definitly say the packet is invalid
+ return (GetNumAttributes() * sizeof(Attribute)) == (size() - kMinSize());
+}
+
+std::string GetItemAttributesRequest::ToString() const {
+ std::stringstream ss;
+ ss << "GetItemAttributesRequestPacket: " << std::endl;
+ ss << " └ PDU = " << GetPdu() << std::endl;
+ ss << " └ Length = " << GetLength() << std::endl;
+ ss << " └ Scope = " << GetScope() << std::endl;
+ ss << " └ UID Requested = " << loghex(GetUid()) << std::endl;
+ ss << " └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+ ss << " └ Num Attributes = " << loghex(GetNumAttributes()) << std::endl;
+
+ auto attr_list = GetAttributesRequested();
+ ss << " └ Attribute List: Size: " << attr_list.size() << std::endl;
+ for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
+ ss << " └ " << loghex((uint32_t)(*it)) << std::endl;
+ }
+ ss << std::endl;
+
+ return ss.str();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <map>
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetItemAttributesResponseBuilder : public BrowsePacketBuilder {
+ public:
+ virtual ~GetItemAttributesResponseBuilder() = default;
+
+ static std::unique_ptr<GetItemAttributesResponseBuilder> MakeBuilder(
+ Status status);
+
+ GetItemAttributesResponseBuilder* AddAttributeEntry(AttributeEntry entry);
+ GetItemAttributesResponseBuilder* AddAttributeEntry(Attribute, std::string);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+ Status status_;
+ std::map<Attribute, std::string> entries_;
+
+ GetItemAttributesResponseBuilder(Status status)
+ : BrowsePacketBuilder(BrowsePdu::GET_ITEM_ATTRIBUTES), status_(status) {}
+};
+
+class GetItemAttributesRequest : public BrowsePacket {
+ public:
+ virtual ~GetItemAttributesRequest() = default;
+
+ /**
+ * Avrcp Change Path Packet Layout
+ * BrowsePacket:
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * GetItemAttributesRequest:
+ * uint8_t scope_;
+ * uint64_t uid_;
+ * uint16_t uid_counter_;
+ * uint8_t attr_count_;
+ * uint32_t[] attr_requested_;
+ */
+ static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 12; }
+
+ Scope GetScope() const;
+ uint64_t GetUid() const;
+ uint16_t GetUidCounter() const;
+ uint8_t GetNumAttributes()
+ const; // If this value is zero, then all attributes are requested
+ std::vector<Attribute> GetAttributesRequested() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using BrowsePacket::BrowsePacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
}
size_t GetPlayStatusResponseBuilder::size() const {
- return VendorPacket::kHeaderSize() + 4 + 4 + 1;
+ return VendorPacket::kMinSize() + 4 + 4 + 1;
}
bool GetPlayStatusResponseBuilder::Serialize(
PacketBuilder::PushHeader(pkt);
// Push the avrcp vendor command headers
- uint16_t parameter_count = size() - VendorPacket::kHeaderSize();
+ uint16_t parameter_count = size() - VendorPacket::kMinSize();
VendorPacketBuilder::PushHeader(pkt, parameter_count);
AddPayloadOctets4(pkt, base::ByteSwap(song_length_));
* uint8_t packet_type;
* uint16_t param_length = 0;
*/
+ static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; }
// Overloaded Functions
virtual bool IsValid() const override;
--- /dev/null
+/*
+ * 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_total_number_of_items.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetTotalNumberOfItemsResponseBuilder>
+GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status status, uint16_t uid_counter, uint32_t num_items_in_folder) {
+ std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> builder(
+ new GetTotalNumberOfItemsResponseBuilder(status, uid_counter,
+ num_items_in_folder));
+
+ return builder;
+}
+
+size_t GetTotalNumberOfItemsResponseBuilder::size() const {
+ size_t len = BrowsePacket::kMinSize();
+ len += 1; // Status
+
+ if (status_ != Status::NO_ERROR) return len;
+
+ len += 2; // UID Counter
+ len += 4; // Number of items in folder
+ return len;
+}
+
+bool GetTotalNumberOfItemsResponseBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+ AddPayloadOctets1(pkt, (uint8_t)status_);
+
+ if (status_ != Status::NO_ERROR) return true;
+ AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+ AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+ return true;
+}
+
+Scope GetTotalNumberOfItemsRequest::GetScope() const {
+ auto it = begin() + BrowsePacket::kMinSize();
+ return static_cast<Scope>(*it);
+}
+
+bool GetTotalNumberOfItemsRequest::IsValid() const {
+ if (!BrowsePacket::IsValid()) return false;
+ return size() == kMinSize();
+}
+
+std::string GetTotalNumberOfItemsRequest::ToString() const {
+ std::stringstream ss;
+ ss << "GetTotalNumberOfItemsRequest: " << std::endl;
+ ss << " └ PDU = " << GetPdu() << std::endl;
+ ss << " └ Length = " << GetLength() << std::endl;
+ ss << " └ Scope = " << GetScope() << std::endl;
+ ss << std::endl;
+
+ return ss.str();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetTotalNumberOfItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+ virtual ~GetTotalNumberOfItemsResponseBuilder() = default;
+
+ static std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> MakeBuilder(
+ Status status, uint16_t uid_counter, uint32_t num_items_in_folder);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+ Status status_;
+ uint16_t uid_counter_;
+ uint32_t num_items_in_folder_;
+
+ GetTotalNumberOfItemsResponseBuilder(Status status, uint16_t uid_counter,
+ uint32_t num_items_in_folder)
+ : BrowsePacketBuilder(BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS),
+ status_(status),
+ uid_counter_(uid_counter),
+ num_items_in_folder_(num_items_in_folder){};
+};
+
+class GetTotalNumberOfItemsRequest : public BrowsePacket {
+ public:
+ virtual ~GetTotalNumberOfItemsRequest() = default;
+
+ /**
+ * AVRCP Get Total Number Of Items Packet Layout
+ * BrowsePacket:
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * GetTotalNumberOfItemsRequest:
+ * uint8_t scope_;
+ */
+ static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 1; }
+
+ Scope GetScope() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using BrowsePacket::BrowsePacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
}
size_t PassThroughPacketBuilder::size() const {
- return PassThroughPacket::kHeaderSize();
+ return PassThroughPacket::kMinSize();
}
bool PassThroughPacketBuilder::Serialize(
}
bool PassThroughPacket::GetPushed() const {
- return (*(begin() + Packet::kHeaderSize()) & 0b10000000) == 0;
+ return (*(begin() + Packet::kMinSize()) & 0b10000000) == 0;
}
uint8_t PassThroughPacket::GetOperationId() const {
- return *(begin() + Packet::kHeaderSize()) & 0b01111111;
+ return *(begin() + Packet::kMinSize()) & 0b01111111;
}
-bool PassThroughPacket::IsValid() const { return (size() == kHeaderSize()); }
+bool PassThroughPacket::IsValid() const { return size() == kMinSize(); }
std::string PassThroughPacket::ToString() const {
std::stringstream ss;
* uint8_t opperation_id : 7;
* uint8_t data_length;
*/
- static constexpr size_t kHeaderSize() { return Packet::kHeaderSize() + 2; }
+ static constexpr size_t kMinSize() { return Packet::kMinSize() + 2; }
// Getter Functions
bool GetPushed() const;
--- /dev/null
+/*
+ * 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 "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<PlayItemResponseBuilder> PlayItemResponseBuilder::MakeBuilder(
+ Status status) {
+ std::unique_ptr<PlayItemResponseBuilder> builder(
+ new PlayItemResponseBuilder(status));
+
+ return builder;
+}
+
+size_t PlayItemResponseBuilder::size() const {
+ size_t len = VendorPacket::kMinSize();
+ len += 1; // Status
+ return len;
+}
+
+bool PlayItemResponseBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ PacketBuilder::PushHeader(pkt);
+
+ VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+ AddPayloadOctets1(pkt, (uint8_t)status_);
+
+ return true;
+}
+
+Scope PlayItemRequest::GetScope() const {
+ auto it = begin() + VendorPacket::kMinSize();
+ return static_cast<Scope>(*it);
+}
+
+uint64_t PlayItemRequest::GetUid() const {
+ auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+ return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t PlayItemRequest::GetUidCounter() const {
+ auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
+ return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool PlayItemRequest::IsValid() const {
+ if (!VendorPacket::IsValid()) return false;
+ return size() == kMinSize();
+}
+
+std::string PlayItemRequest::ToString() const {
+ std::stringstream ss;
+ ss << "PlayItemRequest: " << std::endl;
+ ss << " └ cType = " << GetCType() << std::endl;
+ ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+ ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+ ss << " └ OpCode = " << GetOpcode() << std::endl;
+ ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
+ ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
+ ss << " └ PacketType = " << GetPacketType() << std::endl;
+ ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+ ss << " └ Scope = " << GetScope() << std::endl;
+ ss << " └ UID = " << loghex(GetUid()) << std::endl;
+ ss << " └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
+ ss << std::endl;
+
+ return ss.str();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class PlayItemResponseBuilder : public VendorPacketBuilder {
+ public:
+ virtual ~PlayItemResponseBuilder() = default;
+
+ static std::unique_ptr<PlayItemResponseBuilder> MakeBuilder(Status status);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+ Status status_;
+
+ PlayItemResponseBuilder(Status status)
+ : VendorPacketBuilder(CType::ACCEPTED, CommandPdu::PLAY_ITEM,
+ PacketType::SINGLE),
+ status_(status){};
+};
+
+class PlayItemRequest : public VendorPacket {
+ public:
+ virtual ~PlayItemRequest() = default;
+
+ /**
+ * AVRCP Play Item Request Packet Layout
+ * AvrcpPacket:
+ * CType c_type_;
+ * uint8_t subunit_type_ : 5;
+ * uint8_t subunit_id_ : 3;
+ * Opcode opcode_;
+ * VendorPacket:
+ * uint8_t company_id[3];
+ * uint8_t command_pdu;
+ * uint8_t packet_type;
+ * uint16_t parameter_length;
+ * PlayItemRequest:
+ * uint8_t scope_;
+ * uint64_t uid_;
+ * uint16_t uid_counter_;
+ */
+ static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 11; }
+
+ Scope GetScope() const;
+ uint64_t GetUid() const;
+ uint16_t GetUidCounter() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using VendorPacket::VendorPacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
else if (event_ == Event::PLAYBACK_POS_CHANGED)
data_size = 4;
- return VendorPacket::kHeaderSize() + 1 + data_size;
+ return VendorPacket::kMinSize() + 1 + data_size;
}
bool RegisterNotificationResponseBuilder::Serialize(
}
Event RegisterNotificationRequest::GetEventRegistered() const {
- auto value = *(begin() + VendorPacket::kHeaderSize());
+ auto value = *(begin() + VendorPacket::kMinSize());
return static_cast<Event>(value);
}
uint32_t RegisterNotificationRequest::GetInterval() const {
- auto it = begin() + VendorPacket::kHeaderSize() + static_cast<size_t>(1);
+ auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
return base::ByteSwap(it.extract<uint32_t>());
}
bool RegisterNotificationRequest::IsValid() const {
- return (size() == kHeaderSize());
+ return (size() == kMinSize());
}
std::string RegisterNotificationRequest::ToString() const {
* uint8_t event_id;
* uint32_t interval; // Only used for PLAYBACK_POS_CHANGED
*/
- static constexpr size_t kHeaderSize() {
- return VendorPacket::kHeaderSize() + 5;
- }
+ static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 5; }
// Getter Functions
Event GetEventRegistered() const;
--- /dev/null
+/*
+ * 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 "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetBrowsedPlayerResponseBuilder>
+SetBrowsedPlayerResponseBuilder::MakeBuilder(Status status,
+ uint16_t uid_counter,
+ uint32_t num_items_in_folder,
+ uint8_t folder_depth,
+ std::string folder_name) {
+ std::unique_ptr<SetBrowsedPlayerResponseBuilder> builder(
+ new SetBrowsedPlayerResponseBuilder(
+ status, uid_counter, num_items_in_folder, folder_depth, folder_name));
+
+ return builder;
+}
+
+size_t SetBrowsedPlayerResponseBuilder::size() const {
+ size_t len = BrowsePacket::kMinSize();
+ len += 1; // Status
+
+ // If the status isn't success the rest of the fields are ommited
+ if (status_ != Status::NO_ERROR) return len;
+
+ len += 2; // UID Counter
+ len += 4; // Number of items in folder
+ len += 2; // UTF-8 Character Set
+ len += 1; // Folder Depth
+
+ // This is only included if the folder returned isn't the root folder
+ if (folder_depth_ != 0) {
+ len += 2; // Folder Name Size;
+ len += folder_name_.size(); // Folder Name
+ }
+
+ return len;
+}
+
+bool SetBrowsedPlayerResponseBuilder::Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) {
+ ReserveSpace(pkt, size());
+
+ BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+ AddPayloadOctets1(pkt, (uint8_t)status_);
+
+ if (status_ != Status::NO_ERROR) return true;
+ AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+ AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+ AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a)); // UTF-8
+ AddPayloadOctets1(pkt, folder_depth_);
+
+ // Skip adding the folder name if the folder depth is 0
+ if (folder_depth_ == 0) return true;
+ uint16_t folder_name_len = folder_name_.size();
+ AddPayloadOctets2(pkt, base::ByteSwap(folder_name_len));
+ for (auto it = folder_name_.begin(); it != folder_name_.end(); it++) {
+ AddPayloadOctets1(pkt, *it);
+ }
+
+ return true;
+}
+
+uint16_t SetBrowsedPlayerRequest::GetPlayerId() const {
+ auto it = begin() + BrowsePacket::kMinSize();
+ return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool SetBrowsedPlayerRequest::IsValid() const {
+ if (!BrowsePacket::IsValid()) return false;
+ return size() == kMinSize();
+}
+
+std::string SetBrowsedPlayerRequest::ToString() const {
+ std::stringstream ss;
+ ss << "SetBrowsedPlayerRequestPacket: " << std::endl;
+ ss << " └ PDU = " << GetPdu() << std::endl;
+ ss << " └ Length = " << GetLength() << std::endl;
+ ss << " └ Player ID = " << loghex(GetPlayerId()) << std::endl;
+ ss << std::endl;
+
+ return ss.str();
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetBrowsedPlayerResponseBuilder : public BrowsePacketBuilder {
+ public:
+ virtual ~SetBrowsedPlayerResponseBuilder() = default;
+
+ static std::unique_ptr<SetBrowsedPlayerResponseBuilder> MakeBuilder(
+ Status status, uint16_t uid_counter, uint32_t num_items_in_folder,
+ uint8_t folder_depth, std::string folder_name);
+
+ virtual size_t size() const override;
+ virtual bool Serialize(
+ const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+ Status status_;
+ uint16_t uid_counter_;
+ uint32_t num_items_in_folder_;
+ uint8_t folder_depth_;
+ std::string folder_name_;
+
+ SetBrowsedPlayerResponseBuilder(Status status, uint16_t uid_counter,
+ uint32_t num_items_in_folder,
+ uint8_t folder_depth, std::string folder_name)
+ : BrowsePacketBuilder(BrowsePdu::SET_BROWSED_PLAYER),
+ status_(status),
+ uid_counter_(uid_counter),
+ num_items_in_folder_(num_items_in_folder),
+ folder_depth_(folder_depth),
+ folder_name_(folder_name) {}
+};
+
+class SetBrowsedPlayerRequest : public BrowsePacket {
+ public:
+ virtual ~SetBrowsedPlayerRequest() = default;
+
+ /**
+ * Avrcp Change Path Packet Layout
+ * BrowsePacket:
+ * uint8_t pdu_;
+ * uint16_t length_;
+ * GetFolderItemsRequest:
+ * uint16_t player_id_;
+ */
+ static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 2; }
+
+ uint16_t GetPlayerId() const;
+
+ virtual bool IsValid() const override;
+ virtual std::string ToString() const override;
+
+ protected:
+ using BrowsePacket::BrowsePacket;
+};
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
}
size_t VendorPacketBuilder::size() const {
- return VendorPacket::kHeaderSize() + payload_->size();
+ return VendorPacket::kMinSize() + payload_->size();
}
bool VendorPacketBuilder::Serialize(
}
uint32_t VendorPacket::GetCompanyId() const {
- return PullCompanyId(begin() + Packet::kHeaderSize());
+ return PullCompanyId(begin() + Packet::kMinSize());
}
CommandPdu VendorPacket::GetCommandPdu() const {
- auto value = *(begin() + Packet::kHeaderSize() + static_cast<size_t>(3));
+ auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(3));
return static_cast<CommandPdu>(value);
}
PacketType VendorPacket::GetPacketType() const {
- auto value = *(begin() + Packet::kHeaderSize() + static_cast<size_t>(4));
+ auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(4));
return static_cast<PacketType>(value);
}
uint16_t VendorPacket::GetParameterLength() const {
- auto it = begin() + Packet::kHeaderSize() + static_cast<size_t>(5);
+ auto it = begin() + Packet::kMinSize() + static_cast<size_t>(5);
// Swap to little endian
return base::ByteSwap(it.extract<uint16_t>());
}
bool VendorPacket::IsValid() const {
- if (size() < VendorPacket::kHeaderSize()) return false;
+ if (size() < VendorPacket::kMinSize()) return false;
- auto start = begin() + VendorPacket::kHeaderSize();
+ auto start = begin() + VendorPacket::kMinSize();
// Even if end is less than start and a sign extension occurs, thats fine as
// its pretty definitive proof that the packet is poorly formated
return GetParameterLength() == (end() - start);
class VendorPacketBuilder : public avrcp::PacketBuilder {
public:
+ virtual ~VendorPacketBuilder() = default;
+
static std::unique_ptr<VendorPacketBuilder> MakeBuilder(
CType ctype, CommandPdu pdu, PacketType packet_type,
std::unique_ptr<::bluetooth::PacketBuilder> payload);
* uint16_t parameter_length;
* uint8_t[] payload;
*/
- static constexpr size_t kHeaderSize() { return Packet::kHeaderSize() + 7; };
+ static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; };
// Getter Functions
uint32_t GetCompanyId() const;
#include "avrcp/get_play_status_packet.h"
#include "avrcp/pass_through_packet.h"
#include "avrcp/register_notification_packet.h"
-#include "avrcp/vendor_packet.h"
\ No newline at end of file
+#include "avrcp/vendor_packet.h"
+
+#include "avrcp/avrcp_browse_packet.h"
+#include "avrcp/change_path.h"
+#include "avrcp/get_folder_items.h"
+#include "avrcp/get_item_attributes.h"
+#include "avrcp/get_total_number_of_items.h"
+#include "avrcp/play_item.h"
+#include "avrcp/set_browsed_player.h"
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_browse_packet.h"
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+ static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+ std::vector<uint8_t> data) {
+ std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+ return builder;
+ };
+
+ // Make all the utility functions public
+ using PacketBuilder::ReserveSpace;
+ using PacketBuilder::AddPayloadOctets1;
+ using PacketBuilder::AddPayloadOctets2;
+ using PacketBuilder::AddPayloadOctets3;
+ using PacketBuilder::AddPayloadOctets4;
+ using PacketBuilder::AddPayloadOctets6;
+ using PacketBuilder::AddPayloadOctets8;
+
+ size_t size() const override { return data_.size(); };
+
+ bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+ ReserveSpace(pkt, size());
+
+ for (uint8_t byte : data_) {
+ AddPayloadOctets1(pkt, byte);
+ }
+
+ return true;
+ }
+
+ TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+ std::vector<uint8_t> data_;
+};
+
+namespace avrcp {
+
+using TestBrowsePacket = TestPacketType<BrowsePacket>;
+
+TEST(AvrcpBrowsePacketBuilderTest, buildPacketTest) {
+ std::vector<uint8_t> get_folder_items_request_payload = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+ auto payload_builder =
+ TestPacketBuilder::MakeBuilder(get_folder_items_request_payload);
+
+ auto builder = BrowsePacketBuilder::MakeBuilder(BrowsePdu::GET_FOLDER_ITEMS,
+ std::move(payload_builder));
+
+ ASSERT_EQ(builder->size(), get_folder_items_request.size());
+
+ auto test_packet = TestBrowsePacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_request);
+}
+
+TEST(AvrcpBrowsePacketTest, gettersTest) {
+ auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+ ASSERT_EQ(test_browse_packet->GetPdu(), BrowsePdu::GET_FOLDER_ITEMS);
+ ASSERT_EQ(test_browse_packet->GetLength(), 10u);
+}
+
+TEST(AvrcpBrowsePacketTest, payloadBoundsTest) {
+ auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+ std::vector<uint8_t> get_folder_items_request_payload = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+
+ // Make a folder items payload packet out of the payload of the browse packet
+ auto get_folder_items_payload = TestBrowsePacket::Make(test_browse_packet);
+
+ for (size_t i = 0; i < get_folder_items_request_payload.size(); i++) {
+ ASSERT_EQ((*get_folder_items_payload)[i],
+ get_folder_items_request_payload[i]);
+ }
+}
+
+TEST(AvrcpBrowsePacketTest, validTest) {
+ auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+ ASSERT_TRUE(test_browse_packet->IsValid());
+}
+
+TEST(AvrcpBrowsePacketTest, invalidTest) {
+ auto packet_copy = get_folder_items_request;
+ packet_copy.push_back(0x00);
+ auto test_browse_packet = TestBrowsePacket::Make(packet_copy);
+ ASSERT_FALSE(test_browse_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01};
+ test_browse_packet = TestBrowsePacket::Make(short_packet);
+ ASSERT_FALSE(test_browse_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
* limitations under the License.
*/
-#include <base/logging.h>
-
-#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "avrcp_packet.h"
std::vector<uint8_t> get_cap_payload_data = {0x00, 0x19, 0x58, 0x10,
0x00, 0x00, 0x01, 0x03};
+
auto get_cap_payload_packet = TestAvrcpPacket::Make(test_avrcp_packet);
// We are unable to do a direct vector compare here as one of the packets is
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_reject_packet.h"
// AVRCP packets pulled from wireshark
namespace {
-// An ACL packet containing an AVRCP Get Capabilities Request
-std::vector<uint8_t> get_capabilities_request_acl_packet = {
- 0x04, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x4c, 0x00, 0x10, 0x11, 0x0e,
- 0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
-
-// Offset into the ACL packet where the Get Capabilities Request data starts
-size_t get_capabilities_request_data_offset = 11;
-
// AVRCP Get Capabilities Request packet
std::vector<uint8_t> get_capabilities_request = {
0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
std::vector<uint8_t> reject_player_app_settings_response = {
0x0a, 0x48, 0x00, 0x00, 0x19, 0x58, 0x11, 0x00, 0x00, 0x01, 0x00};
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+// scope = 0x00 (Media Player List)
+// start_item = 0x00
+// end_item = 0x03
+// attributes_requested: none
+std::vector<uint8_t> get_folder_items_request = {0x71, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00};
+
+// AVRCP Browse Get Folder Items Request packet for vfs with
+// the following data:
+// scope = 0x01 (VFS)
+// start_item = 0x00
+// end_item = 0x05
+// attributes_requested: TITLE
+std::vector<uint8_t> get_folder_items_request_vfs = {
+ 0x71, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01};
+
+// AVRCP Browse Get Folder Items Response packet with range out of bounds error
+std::vector<uint8_t> get_folder_items_error_response = {0x71, 0x00, 0x01, 0x0b};
+
+// AVRCP Browse Get Folder Items Response packet for media players
+// Contains one media player with the following fields:
+// id = 0x0001
+// name = "com.google.android.music"
+// browsing_supported = true
+std::vector<uint8_t> get_folder_items_media_player_response = {
+ 0x71, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x34,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xb7, 0x01, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6a, 0x00, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63};
+
+// AVRCP Browse Get Folder Items Response packet with one folder
+// with the following fields:
+// uid = 0x0000000000000001
+// type = 0x00 (Mixed);
+// name = "Test Folder"
+// is_playable = true
+std::vector<uint8_t> get_folder_items_folder_response = {
+ 0x71, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x6a, 0x00,
+ 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72};
+
+// AVRCP Browse Get Folder Items Response packet with one song
+// with the following fields:
+// uid = 0x0000000000000002
+// name = "Test Title"
+// attribute[TITLE] = "Test Title"
+std::vector<uint8_t> get_folder_items_song_response = {
+ 0x71, 0x00, 0x32, 0x04, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x2a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x6a,
+ 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c,
+ 0x65, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x0a, 0x54,
+ 0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c, 0x65};
+
+// AVRCP Browse Change Path Request down to folder with UID 0x0000000000000002
+std::vector<uint8_t> change_path_request = {0x72, 0x00, 0x0b, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Response with two items in current folder
+std::vector<uint8_t> change_path_response = {0x72, 0x00, 0x05, 0x04,
+ 0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Response with an error of invalid direction
+std::vector<uint8_t> change_path_error_response = {0x72, 0x00, 0x01, 0x07};
+
+// AVRCP Get Item Attributes request with all attributes requested
+// with the following fields:
+// scope = 0x03 (Now Playing List)
+// uid_counter = 0x0000
+// uid = 0x0000000000000001
+std::vector<uint8_t> get_item_attributes_request_all_attributes = {
+ 0x73, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07};
+
+// AVRCP Get Item Attributes Response with the following attributes:
+// title = "Test Song"
+// artist = "Test Artist"
+// album = "Test Album"
+std::vector<uint8_t> get_item_attributes_song_response = {
+ 0x73, 0x00, 0x38, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00,
+ 0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x6a, 0x00, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41,
+ 0x72, 0x74, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00,
+ 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x62, 0x75, 0x6d};
+
+// AVRCP Set Browsed Player Request with player_id = 2
+std::vector<uint8_t> set_browsed_player_request = {0x70, 0x00, 0x02, 0x00,
+ 0x02};
+
+// AVRCP Set Browsed Player Response with num items = 4 and depth = 0
+std::vector<uint8_t> set_browsed_player_response = {
+ 0x70, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00};
+
+// AVRCP Get Total Number of Items Request with Scope = Now Playing List
+std::vector<uint8_t> get_total_number_of_items_request = {0x75, 0x00, 0x01,
+ 0x03};
+
+// AVRCP Get Total number of Items Response with 5 items in folder
+std::vector<uint8_t> get_total_number_of_items_response = {
+ 0x75, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05};
+
+// AVRCP Play Item Request with scope = Now Playing and
+// UID = 0x0000000000000003
+std::vector<uint8_t> play_item_request = {
+ 0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x74, 0x00, 0x00, 0x0b, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
+
+// AVRCP Play Item Response
+std::vector<uint8_t> play_item_response = {0x09, 0x48, 0x00, 0x00, 0x19, 0x58,
+ 0x74, 0x00, 0x00, 0x01, 0x04};
+
} // namespace
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "change_path.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestChangePathReqPacket = TestPacketType<ChangePathRequest>;
+
+TEST(ChangePathResponseBuilderTest, builderTest) {
+ auto builder = ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, 2);
+ ASSERT_EQ(builder->size(), change_path_response.size());
+
+ auto test_packet = TestChangePathReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), change_path_response);
+}
+
+TEST(ChangePathResponseBuilderTest, builderErrorStatusTest) {
+ // NOTE: The num items in folder field doesn't matter when the status is
+ // not NO_ERROR
+ auto builder =
+ ChangePathResponseBuilder::MakeBuilder(Status::INVALID_DIRECTION, 2);
+ ASSERT_EQ(builder->size(), change_path_error_response.size());
+
+ auto test_packet = TestChangePathReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), change_path_error_response);
+}
+
+TEST(ChangePathRequestTest, getterTest) {
+ auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+
+ ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+ ASSERT_EQ(test_packet->GetDirection(), Direction::DOWN);
+ ASSERT_EQ(test_packet->GetUid(), 0x0000000000000002u);
+}
+
+TEST(ChangePathRequestTest, validTest) {
+ auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+ ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(ChangePathRequestTest, invalidTest) {
+ auto packet_copy = change_path_request;
+ packet_copy.push_back(0x00);
+ auto test_packet = TestChangePathReqPacket::Make(packet_copy);
+ ASSERT_FALSE(test_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+ test_packet = TestChangePathReqPacket::Make(short_packet);
+ ASSERT_FALSE(test_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_test_packets.h"
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_test_packets.h"
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_folder_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetFolderItemsReqPacket = TestPacketType<GetFolderItemsRequest>;
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerSizeTest) {
+ auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+ Status::NO_ERROR, 0x0000);
+ // If there are no items, then the only data in the packet is the status
+ ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+ auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+ builder->AddMediaPlayer(player);
+ ASSERT_EQ(builder->size(), get_folder_items_media_player_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerAddTest) {
+ auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+ Status::NO_ERROR, 0x0000);
+ auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+ builder->AddMediaPlayer(player);
+
+ auto test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_media_player_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderSizeTest) {
+ auto builder =
+ GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+ ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+ auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+ builder->AddFolder(folder);
+ ASSERT_EQ(builder->size(), get_folder_items_folder_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderAddTest) {
+ auto builder =
+ GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+ auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+ builder->AddFolder(folder);
+
+ auto test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_folder_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongSizeTest) {
+ auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+ Status::NO_ERROR, 0x0000);
+ ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+ std::map<Attribute, std::string> attributes;
+ attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+ auto song = MediaElementItem(0x02, "Test Title", attributes);
+ builder->AddSong(song);
+ ASSERT_EQ(builder->size(), get_folder_items_song_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongAddTest) {
+ auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+ Status::NO_ERROR, 0x0000);
+ std::map<Attribute, std::string> attributes;
+ attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+ auto song = MediaElementItem(0x02, "Test Title", attributes);
+ builder->AddSong(song);
+
+ auto test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_song_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderNoItemsTest) {
+ auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+ Status::NO_ERROR, 0x0000);
+ auto test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+ builder =
+ GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+ test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+ builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+ Status::NO_ERROR, 0x0000);
+ test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderErrorStatusTest) {
+ std::vector<uint8_t> get_folder_items_inv_scope = {0x71, 0x00, 0x01, 0x0a};
+
+ auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+ Status::INVALID_SCOPE, 0x0000);
+
+ // Check that the status remains INVALID_SCOPE even though there are zero
+ // items
+ auto test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+
+ auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+ builder->AddMediaPlayer(player);
+
+ // Check to make sure that even though we added an item, it doesn't get
+ // written to the packet
+ test_packet = TestGetFolderItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderDeathTest) {
+ auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+ auto folder = FolderItem(0x01, 0x00, true, "test folder");
+ auto song =
+ MediaElementItem(0x01, "test song", std::map<Attribute, std::string>());
+
+ auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+ Status::NO_ERROR, 0x0000);
+ ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+ ASSERT_DEATH(builder->AddSong(song),
+ "scope_ == Scope::VFS \\|\\| scope_ == Scope::NOW_PLAYING");
+
+ builder =
+ GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR, 0x0000);
+ ASSERT_DEATH(builder->AddMediaPlayer(player),
+ "scope_ == Scope::MEDIA_PLAYER_LIST");
+
+ builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+ Status::NO_ERROR, 0x0000);
+ ASSERT_DEATH(builder->AddMediaPlayer(player),
+ "scope_ == Scope::MEDIA_PLAYER_LIST");
+ ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+}
+
+TEST(GetFolderItemsRequestTest, getterTest) {
+ auto test_packet =
+ TestGetFolderItemsReqPacket::Make(get_folder_items_request_vfs);
+
+ ASSERT_EQ(test_packet->GetScope(), Scope::VFS);
+ ASSERT_EQ(test_packet->GetStartItem(), 0x00000000u);
+ ASSERT_EQ(test_packet->GetEndItem(), 0x00000005u);
+ ASSERT_EQ(test_packet->GetNumAttributes(), 1);
+
+ std::vector<Attribute> attribute_list = {Attribute::TITLE};
+ ASSERT_EQ(test_packet->GetAttributesRequested(), attribute_list);
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_item_attributes.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetItemAttrsReqPacket = TestPacketType<GetItemAttributesRequest>;
+
+TEST(GetItemAttributesResponseBuilderTest, builderSizeTest) {
+ auto builder =
+ GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR);
+ ASSERT_EQ(builder->size(), 5u);
+
+ builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+ ASSERT_EQ(builder->size(), 22u);
+
+ builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+ ASSERT_EQ(builder->size(), 41u);
+
+ builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+ ASSERT_EQ(builder->size(), get_item_attributes_song_response.size());
+}
+
+TEST(GetItemAttributesResponseBuilderTest, builderTest) {
+ auto builder =
+ GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR);
+ builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+ builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+ builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+
+ auto test_packet = TestGetItemAttrsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_item_attributes_song_response);
+}
+
+TEST(GetItemAttributesResponseBuilderTest, errorStatusTest) {
+ std::vector<uint8_t> does_not_exist_status = {0x73, 0x00, 0x01, 0x09};
+ auto builder =
+ GetItemAttributesResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST);
+ ASSERT_EQ(builder->size(), does_not_exist_status.size());
+
+ auto test_packet = TestGetItemAttrsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), does_not_exist_status);
+}
+
+TEST(GetItemAttributesRequestTest, getterTest) {
+ auto test_packet = TestGetItemAttrsReqPacket::Make(
+ get_item_attributes_request_all_attributes);
+
+ ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+ ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+ ASSERT_EQ(test_packet->GetUid(), 0x0000000000000001u);
+ ASSERT_EQ(test_packet->GetNumAttributes(), 7);
+ std::vector<Attribute> attrs_requested = {Attribute::TITLE,
+ Attribute::ARTIST_NAME,
+ Attribute::ALBUM_NAME,
+ Attribute::TRACK_NUMBER,
+ Attribute::TOTAL_NUMBER_OF_TRACKS,
+ Attribute::GENRE,
+ Attribute::PLAYING_TIME};
+ ASSERT_EQ(test_packet->GetAttributesRequested(), attrs_requested);
+}
+
+TEST(GetItemAttributesRequestTest, validTest) {
+ auto test_packet = TestGetItemAttrsReqPacket::Make(
+ get_item_attributes_request_all_attributes);
+ ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetItemAttributesRequestTest, invalidTest) {
+ auto packet_copy = get_item_attributes_request_all_attributes;
+ packet_copy.push_back(0x00);
+ auto test_packet = TestGetItemAttrsReqPacket::Make(packet_copy);
+ ASSERT_FALSE(test_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07};
+ test_packet = TestGetItemAttrsReqPacket::Make(short_packet);
+ ASSERT_FALSE(test_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_test_packets.h"
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_total_number_of_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetTotalNumItemsReqPacket =
+ TestPacketType<GetTotalNumberOfItemsRequest>;
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, builderTest) {
+ auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0x0000u, 0x00000005u);
+ ASSERT_EQ(builder->size(), get_total_number_of_items_response.size());
+
+ auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), get_total_number_of_items_response);
+}
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, errorStatusTest) {
+ std::vector<uint8_t> inv_scope_status_packet = {0x75, 0x00, 0x01, 0x0a};
+ auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::INVALID_SCOPE, 0x1234u, 0x56789abcu);
+ ASSERT_EQ(builder->size(), inv_scope_status_packet.size());
+
+ auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), inv_scope_status_packet);
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, getterTest) {
+ auto test_packet =
+ TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+ ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, validTest) {
+ auto test_packet =
+ TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+ ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, invalidTest) {
+ auto packet_copy = get_total_number_of_items_request;
+ packet_copy.push_back(0x00);
+ auto test_packet = TestGetTotalNumItemsReqPacket::Make(packet_copy);
+ ASSERT_FALSE(test_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03};
+ ASSERT_FALSE(test_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_test_packets.h"
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestPlayItemReqPacket = TestPacketType<PlayItemRequest>;
+
+TEST(PlayItemResponseBuilderTest, builderTest) {
+ auto builder = PlayItemResponseBuilder::MakeBuilder(Status::NO_ERROR);
+ ASSERT_EQ(builder->size(), play_item_response.size());
+
+ auto test_packet = TestPlayItemReqPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), play_item_response);
+}
+
+TEST(PlayItemResponseTest, getterTest) {
+ auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+ ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+ ASSERT_EQ(test_packet->GetUid(), 0x0000000000000003u);
+ ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+}
+
+TEST(PlayItemResponseTest, validTest) {
+ auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+ ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(PlayItemResponseTest, invalidTest) {
+ auto packet_copy = play_item_request;
+ packet_copy.push_back(0x00);
+ auto test_packet = TestPlayItemReqPacket::Make(packet_copy);
+ ASSERT_FALSE(test_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+ test_packet = TestPlayItemReqPacket::Make(short_packet);
+ ASSERT_FALSE(test_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
* limitations under the License.
*/
-#include <base/logging.h>
-
#include <gtest/gtest.h>
#include "avrcp_test_packets.h"
--- /dev/null
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetBrowsedPlayerPacket = TestPacketType<SetBrowsedPlayerRequest>;
+
+TEST(SetBrowsedPlayerResponseBuilder, builderTest) {
+ auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR,
+ 0x0000, 4, 0, "");
+ ASSERT_EQ(builder->size(), set_browsed_player_response.size());
+
+ auto test_packet = TestSetBrowsedPlayerPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), set_browsed_player_response);
+}
+
+TEST(SetBrowsedPlayerResponseBuilder, errorStatusTest) {
+ std::vector<uint8_t> player_not_browsable_status = {0x70, 0x00, 0x01, 0x12};
+ auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+ Status::PLAYER_NOT_BROWSABLE, 0x1234, 5, 6, "Field Not Used");
+ ASSERT_EQ(builder->size(), player_not_browsable_status.size());
+
+ auto test_packet = TestSetBrowsedPlayerPacket::Make();
+ builder->Serialize(test_packet);
+ ASSERT_EQ(test_packet->GetData(), player_not_browsable_status);
+}
+
+TEST(SetBrowsedPlayerRequestTest, getterTest) {
+ auto test_packet =
+ TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+
+ ASSERT_EQ(test_packet->GetPlayerId(), 0x0002u);
+}
+
+TEST(SetBrowsedPlayerRequestTest, validTest) {
+ auto test_packet =
+ TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+ ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetBrowsedPlayerRequestTest, invalidTest) {
+ auto packet_copy = set_browsed_player_request;
+ packet_copy.push_back(0x00);
+ auto test_packet = TestSetBrowsedPlayerPacket::Make(packet_copy);
+ ASSERT_FALSE(test_packet->IsValid());
+
+ std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+ test_packet = TestSetBrowsedPlayerPacket::Make(short_packet);
+ ASSERT_FALSE(test_packet->IsValid());
+}
+
+} // namespace avrcp
+} // namespace bluetooth
\ No newline at end of file
* limitations under the License.
*/
-#include <base/logging.h>
+#include <tuple>
#include <gtest/gtest.h>
-#include <tuple>
#include "avrcp_test_packets.h"
#include "packet_test_helper.h"
* limitations under the License.
*/
-#include <base/logging.h>
#include <gtest/gtest.h>
#include <memory>
* limitations under the License.
*/
-#include <base/logging.h>
#include <gtest/gtest.h>
#include "packet.h"
SOONG_UI_BASH = 'build/soong/soong_ui.bash'
-
def str2bool(argument, default=False):
""" Convert a string to a booleen value. """
argument = str(argument)