Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79542e70 authored by Ajay Panicker's avatar Ajay Panicker Committed by android-build-merger
Browse files

Add Packet class as alternative to BT_HDR

am: 2fd97704

Change-Id: If25a3b85486b871b99919429d37efc265a0b601c
parents 1a64f320 2fd97704
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
cc_library_static {
    name: "lib-bt-packets",
    host_supported: true,
    export_include_dirs: [
        "./include",
        "./",
    ],
    whole_static_libs: [
        "lib-bt-packets-base",
        "lib-bt-packets-avrcp",
    ],
}

cc_test {
    name: "net_test_btpackets",
    defaults: ["fluoride_defaults"],
    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_packet_test.cc",
        "tests/avrcp/vendor_packet_test.cc",
        "tests/avrcp/get_capabilities_packet_test.cc",
        "tests/avrcp/get_element_attributes_packet_test.cc",
        "tests/avrcp/get_play_status_packet_test.cc",
        "tests/avrcp/pass_through_packet_test.cc",
        "tests/avrcp/register_notification_packet_test.cc",
        "tests/avrcp/avrcp_reject_packet_test.cc",
    ],
    static_libs: [
        "libgmock",
        "lib-bt-packets",
    ],
    cflags: ["-DBUILDCFG","-g"],
}
 No newline at end of file
+26 −0
Original line number Diff line number Diff line
cc_library_static {
    name: "lib-bt-packets-avrcp",
    export_include_dirs: ["."],
    host_supported: true,
    srcs: [
        "avrcp_packet.cc",
        "vendor_packet.cc",
        "capabilities_packet.cc",
        "get_element_attributes_packet.cc",
        "get_play_status_packet.cc",
        "pass_through_packet.cc",
        "register_notification_packet.cc",
        "avrcp_reject_packet.cc",
    ],
    shared_libs: [
        "libchrome",
    ],
    static_libs: [
        "lib-bt-packets-base",
    ],
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
    ],
}
+117 −0
Original line number Diff line number Diff line
/*
 * 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/sys_byteorder.h>

// This file contains the different AVRCP Constants
namespace bluetooth {
namespace avrcp {

constexpr uint32_t BLUETOOTH_COMPANY_ID = 0x001958;

enum class CType : uint8_t {
  CONTROL = 0x0,
  STATUS = 0x1,
  NOTIFY = 0x3,
  ACCEPTED = 0x9,
  REJECTED = 0xa,
  STABLE = 0xc,
  CHANGED = 0xd,
  INTERIM = 0xf,
};

enum class Opcode : uint8_t {
  VENDOR = 0x00,
  UNIT_INFO = 0x30,
  SUBUNIT_INFO = 0x31,
  PASS_THROUGH = 0x7c,
};

// Found in AVRCP_v1.6.1 Section 4.5 Table 4.5
// Searching can be done in the spec by Camel Casing the constant name
enum class CommandPdu : uint8_t {
  GET_CAPABILITIES = 0x10,
  LIST_APPLICATION_SETTING_ATTRIBUTES = 0x11,
  GET_ELEMENT_ATTRIBUTES = 0x20,
  GET_PLAY_STATUS = 0x30,
  REGISTER_NOTIFICATION = 0x31,
};

enum class PacketType : uint8_t {
  SINGLE = 0x00,
};

enum class Capability : uint8_t {
  COMPANY_ID = 0x02,
  EVENTS_SUPPORTED = 0x03,
};

// Found in AVRCP_v1.6.1 Section 28 Appendix H
enum class Event : uint8_t {
  PLAYBACK_STATUS_CHANGED = 0x01,
  TRACK_CHANGED = 0x02,
  PLAYBACK_POS_CHANGED = 0x05,
  PLAYER_APPLICATION_SETTING_CHANGED = 0x08,
  NOW_PLAYING_CONTENT_CHANGED = 0x09,
  AVAILABLE_PLAYERS_CHANGED = 0x0a,
  ADDRESSED_PLAYER_CHANGED = 0x0b,
  UIDS_CHANGED = 0x0c,
  VOLUME_CHANGED = 0x0d,
};

enum class Attribute : uint32_t {
  TITLE = 0x01,
  ARTIST_NAME,
  ALBUM_NAME,
  TRACK_NUMBER,
  TOTAL_NUMBER_OF_TRACKS,
  GENRE,
  PLAYING_TIME,
  DEFAULT_COVER_ART,
};

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,
};

using AttributeEntry = std::pair<Attribute, std::string>;

}  // namespace avrcp
}  // namespace bluetooth
 No newline at end of file
+194 −0
Original line number Diff line number Diff line
/*
 * 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 <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>

#include "avrcp_common.h"

// We have our own definition of loghex to avoid dependencies
namespace {
template <typename T>
std::string loghex(T x) {
  std::stringstream tmp;
  tmp << "0x" << std::internal << std::hex << std::setfill('0')
      << std::setw(sizeof(T) * 2) << (unsigned int)x;
  return tmp.str();
}
}  // namespace

namespace bluetooth {
namespace avrcp {

#define CASE_RETURN_TEXT(code) \
  case code:                   \
    return #code

inline std::string CTypeText(const CType& type) {
  switch (type) {
    CASE_RETURN_TEXT(CType::CONTROL);
    CASE_RETURN_TEXT(CType::STATUS);
    CASE_RETURN_TEXT(CType::NOTIFY);
    CASE_RETURN_TEXT(CType::ACCEPTED);
    CASE_RETURN_TEXT(CType::REJECTED);
    CASE_RETURN_TEXT(CType::STABLE);
    CASE_RETURN_TEXT(CType::CHANGED);
    CASE_RETURN_TEXT(CType::INTERIM);
    default:
      return "Unknown CType: " + loghex(type);
  }
}

inline std::ostream& operator<<(std::ostream& os, const CType& type) {
  return os << CTypeText(type);
}

inline std::string OpcodeText(const Opcode& opcode) {
  switch (opcode) {
    CASE_RETURN_TEXT(Opcode::VENDOR);
    CASE_RETURN_TEXT(Opcode::UNIT_INFO);
    CASE_RETURN_TEXT(Opcode::SUBUNIT_INFO);
    CASE_RETURN_TEXT(Opcode::PASS_THROUGH);
    default:
      return "Unknown Opcode: " + loghex(opcode);
  }
}

inline std::ostream& operator<<(std::ostream& os, const Opcode& opcode) {
  return os << OpcodeText(opcode);
}

inline std::string CommandPduText(const CommandPdu& pdu) {
  switch (pdu) {
    CASE_RETURN_TEXT(CommandPdu::GET_CAPABILITIES);
    CASE_RETURN_TEXT(CommandPdu::LIST_APPLICATION_SETTING_ATTRIBUTES);
    CASE_RETURN_TEXT(CommandPdu::GET_ELEMENT_ATTRIBUTES);
    CASE_RETURN_TEXT(CommandPdu::GET_PLAY_STATUS);
    CASE_RETURN_TEXT(CommandPdu::REGISTER_NOTIFICATION);
    default:
      return "Unknown Command PDU: " + loghex(pdu);
  }
}

inline std::ostream& operator<<(std::ostream& os, const CommandPdu& pdu) {
  return os << CommandPduText(pdu);
}

inline std::string PacketTypeText(const PacketType& type) {
  switch (type) {
    CASE_RETURN_TEXT(PacketType::SINGLE);
    default:
      return "Unknown Packet Type: " + loghex(type);
  }
}

inline std::ostream& operator<<(std::ostream& os, const PacketType& type) {
  return os << PacketTypeText(type);
}

inline std::string CapabilityText(const Capability& cap) {
  switch (cap) {
    CASE_RETURN_TEXT(Capability::COMPANY_ID);
    CASE_RETURN_TEXT(Capability::EVENTS_SUPPORTED);
    default:
      return "Unknown Capability: " + loghex(cap);
  }
}

inline std::ostream& operator<<(std::ostream& os, const Capability& cap) {
  return os << CapabilityText(cap);
}

inline std::string EventText(const Event& event) {
  switch (event) {
    CASE_RETURN_TEXT(Event::PLAYBACK_STATUS_CHANGED);
    CASE_RETURN_TEXT(Event::TRACK_CHANGED);
    CASE_RETURN_TEXT(Event::PLAYBACK_POS_CHANGED);
    CASE_RETURN_TEXT(Event::PLAYER_APPLICATION_SETTING_CHANGED);
    CASE_RETURN_TEXT(Event::NOW_PLAYING_CONTENT_CHANGED);
    CASE_RETURN_TEXT(Event::AVAILABLE_PLAYERS_CHANGED);
    CASE_RETURN_TEXT(Event::ADDRESSED_PLAYER_CHANGED);
    CASE_RETURN_TEXT(Event::UIDS_CHANGED);
    CASE_RETURN_TEXT(Event::VOLUME_CHANGED);
    default:
      return "Unknown Event: " + loghex(event);
  }
}

inline std::ostream& operator<<(std::ostream& os, const Event& event) {
  return os << EventText(event);
}

inline std::string AttributeText(const Attribute& attr) {
  switch (attr) {
    CASE_RETURN_TEXT(Attribute::TITLE);
    CASE_RETURN_TEXT(Attribute::ARTIST_NAME);
    CASE_RETURN_TEXT(Attribute::ALBUM_NAME);
    CASE_RETURN_TEXT(Attribute::TRACK_NUMBER);
    CASE_RETURN_TEXT(Attribute::TOTAL_NUMBER_OF_TRACKS);
    CASE_RETURN_TEXT(Attribute::GENRE);
    CASE_RETURN_TEXT(Attribute::PLAYING_TIME);
    CASE_RETURN_TEXT(Attribute::DEFAULT_COVER_ART);
    default:
      return "Unknown Attribute Value: " + loghex(attr);
  }
}

inline std::ostream& operator<<(std::ostream& os, const Attribute& attr) {
  return os << AttributeText(attr);
}

inline std::string StatusText(const Status& status) {
  switch (status) {
    CASE_RETURN_TEXT(Status::INVALID_COMMAND);
    CASE_RETURN_TEXT(Status::INVALID_PARAMETER);
    CASE_RETURN_TEXT(Status::PARAMETER_CONTENT_ERROR);
    CASE_RETURN_TEXT(Status::INTERNAL_ERROR);
    CASE_RETURN_TEXT(Status::NO_ERROR);
    CASE_RETURN_TEXT(Status::UIDS_CHANGED);
    CASE_RETURN_TEXT(Status::RESERVED);
    CASE_RETURN_TEXT(Status::INVALID_DIRECTION);
    CASE_RETURN_TEXT(Status::NOT_A_DIRECTORY);
    CASE_RETURN_TEXT(Status::DOES_NOT_EXIST);
    CASE_RETURN_TEXT(Status::INVALID_SCOPE);
    CASE_RETURN_TEXT(Status::RANGE_OUT_OF_BOUNDS);
    CASE_RETURN_TEXT(Status::FOLDER_ITEM_NOT_PLAYABLE);
    CASE_RETURN_TEXT(Status::MEDIA_IN_USE);
    CASE_RETURN_TEXT(Status::NOW_PLAYING_LIST_FULL);
    CASE_RETURN_TEXT(Status::SEARCH_NOT_SUPPORTED);
    CASE_RETURN_TEXT(Status::SEARCH_IN_PROGRESS);
    CASE_RETURN_TEXT(Status::INVALID_PLAYER_ID);
    CASE_RETURN_TEXT(Status::PLAYER_NOT_BROWSABLE);
    CASE_RETURN_TEXT(Status::PLAYER_NOT_ADDRESSED);
    CASE_RETURN_TEXT(Status::NO_VALID_SEARCH_RESULTS);
    CASE_RETURN_TEXT(Status::NO_AVAILABLE_PLAYERS);
    CASE_RETURN_TEXT(Status::ADDRESSED_PLAYER_CHANGED);
    default:
      return "Unknown Status: " + loghex(status);
  }
}

inline std::ostream& operator<<(std::ostream& os, const Status& status) {
  return os << StatusText(status);
}

}  // namespace avrcp
}  // namespace bluetooth
 No newline at end of file
+117 −0
Original line number Diff line number Diff line
/*
 * 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 <iomanip>
#include <sstream>
#include <type_traits>

#include "avrcp_packet.h"

namespace bluetooth {
namespace avrcp {

std::unique_ptr<PacketBuilder> PacketBuilder::MakeBuilder(
    CType type, uint8_t subunit_type, uint8_t subunit_id, Opcode opcode,
    std::unique_ptr<::bluetooth::PacketBuilder> payload) {
  std::unique_ptr<PacketBuilder> builder = std::unique_ptr<PacketBuilder>(
      new PacketBuilder(type, subunit_type, subunit_id, opcode));

  builder->payload_ = std::move(payload);

  return builder;
}

size_t PacketBuilder::size() const {
  // The size of the header for an Packet is 3
  return payload_->size() + Packet::kHeaderSize();
}

bool PacketBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
  ReserveSpace(pkt, size());

  // Push the header for the packet
  PushHeader(pkt);

  // Push the payload for the packet
  return payload_->Serialize(pkt);
}

void PacketBuilder::PushHeader(
    const std::shared_ptr<::bluetooth::Packet>& pkt) {
  AddPayloadOctets1(pkt, static_cast<uint8_t>(c_type_));
  AddPayloadOctets1(pkt, (subunit_type_ << 3) | subunit_id_);
  AddPayloadOctets1(pkt, static_cast<uint8_t>(opcode_));
}

bool PacketBuilder::PushCompanyId(
    const std::shared_ptr<::bluetooth::Packet>& pkt, uint32_t company_id) {
  company_id = base::ByteSwap(company_id);
  for (int i = 0; i < 3; i++) {
    company_id >>= 8;
    AddPayloadOctets1(pkt, company_id & 0xFF);
  }

  return true;
}

std::shared_ptr<Packet> Packet::Parse(
    std::shared_ptr<::bluetooth::Packet> pkt) {
  return std::shared_ptr<Packet>(new Packet(pkt));
}

CType Packet::GetCType() const {
  auto value = *begin() & 0x0F;
  return static_cast<CType>(value);
}

uint8_t Packet::GetSubunitType() const {
  return *(begin() + static_cast<size_t>(1)) >> 3;
}

uint8_t Packet::GetSubunitId() const {
  return *(begin() + static_cast<size_t>(1)) & 0b00000111;
}

Opcode Packet::GetOpcode() const {
  auto value = *(begin() + static_cast<size_t>(2));
  return static_cast<Opcode>(value);
}

bool Packet::IsValid() const { return size() >= kHeaderSize(); }

std::string Packet::ToString() const {
  std::stringstream ss;
  ss << "avrcp::Packet: " << 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 << "  └ 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> Packet::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
Loading