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

Commit 3d75d1dc authored by Ajay Panicker's avatar Ajay Panicker
Browse files

Add MTU Handling for AVRCP Packets

Bug: 77241554
Test: Run host native tests net_test_avrcp and net_test_btpacket
Change-Id: If32aa506dc8f99220ef35efeb4d77a1023767afe
parent 0f5a1da4
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -61,12 +61,20 @@ class AvrcpInterfaceImpl : public AvrcpInterface {
    return AVRC_OpenBrowse(handle, conn_role);
  }

  uint16_t CloseBrowse(uint8_t handle) override {
    return AVRC_CloseBrowse(handle);
  uint16_t GetPeerMtu(uint8_t handle) override {
    return AVCT_GetPeerMtu(handle);
  }

  uint16_t GetBrowseMtu(uint8_t handle) override {
    return AVCT_GetBrowseMtu(handle);
  }

  uint16_t Close(uint8_t handle) override { return AVRC_Close(handle); }

  uint16_t CloseBrowse(uint8_t handle) override {
    return AVRC_CloseBrowse(handle);
  }

  uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
                  BT_HDR* p_pkt) override {
    return AVRC_MsgReq(handle, label, ctype, p_pkt);
+2 −2
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

#pragma once

#include <map>
#include <set>
#include <string>

#include <base/bind.h>
@@ -29,7 +29,7 @@ namespace avrcp {

struct SongInfo {
  std::string media_id;  // This gets converted to a UID in the native service
  std::map<Attribute, std::string> attributes;
  std::set<AttributeEntry> attributes;
};

enum PlayState : uint8_t {
+86 −26
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

#pragma once

#include <map>
#include <set>

#include <base/sys_byteorder.h>

@@ -137,19 +137,64 @@ enum class Direction : uint8_t {
  DOWN = 0x01,
};

using AttributeEntry = std::pair<Attribute, std::string>;
class AttributeEntry {
 public:
  AttributeEntry(const Attribute& attribute, const std::string& value)
      : attribute_(attribute), value_(value) {}

  AttributeEntry(const Attribute& attribute) : attribute_(attribute) {}

  AttributeEntry(const AttributeEntry&) = default;

  Attribute attribute() const { return attribute_; }

  std::string value() const { return value_; }

  static constexpr size_t kHeaderSize() {
    size_t ret = 0;
    ret += 4;  // Size of attribute field
    ret += 2;  // Size of length field
    ret += 2;  // Size of character encoding field
    return ret;
  }

  size_t size() const { return kHeaderSize() + value_.size(); }

  void resize(size_t new_size) {
    new_size = new_size < kHeaderSize() ? 0 : new_size - kHeaderSize();
    if (value_.size() > new_size) {
      value_.resize(new_size);
    }
  }

  bool empty() { return value_.empty(); }

  bool operator<(const AttributeEntry& rhs) const {
    return attribute_ < rhs.attribute_;
  }

 private:
  Attribute attribute_;
  std::string value_;
};

constexpr size_t MAX_FIELD_LEN = 100;

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(uint16_t id, const std::string& name, bool browsable)
      : id_(id), name_(name), browsable_(browsable) {
    if (name_.size() > MAX_FIELD_LEN) {
      name_.resize(MAX_FIELD_LEN);
    }
  }

  MediaPlayerItem(const MediaPlayerItem&) = default;

  static size_t size(const MediaPlayerItem& item) {
  static constexpr size_t kHeaderSize() {
    size_t ret = 0;
    ret += 1;   // Media Player Type
    ret += 2;   // Item Length
@@ -160,9 +205,10 @@ struct MediaPlayerItem {
    ret += 16;  // Features
    ret += 2;   // UTF-8 character set
    ret += 2;   // Name Length
    ret += item.name_.size();
    return ret;
  }

  size_t size() const { return kHeaderSize() + name_.size(); }
};

struct FolderItem {
@@ -176,11 +222,15 @@ struct FolderItem {
      : uid_(uid),
        folder_type_(folder_type),
        is_playable_(is_playable),
        name_(name) {}
        name_(name) {
    if (name_.size() > MAX_FIELD_LEN) {
      name_.resize(MAX_FIELD_LEN);
    }
  }

  FolderItem(const FolderItem&) = default;

  static size_t size(const FolderItem& item) {
  static constexpr size_t kHeaderSize() {
    size_t ret = 0;
    ret += 1;  // Folder Item Type
    ret += 2;  // Item Length
@@ -189,24 +239,36 @@ struct FolderItem {
    ret += 1;  // Is Playable byte
    ret += 2;  // UTF-8 Character Set
    ret += 2;  // Name Length
    ret += item.name_.size();
    return ret;
  }

  size_t size() const { return kHeaderSize() + name_.size(); }
};

// 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_;
  std::set<AttributeEntry> attributes_;

  // Truncate the name and attribute fields so that we don't have a single item
  // that can exceed the Browsing MTU
  MediaElementItem(uint64_t uid, const std::string& name,
                   std::set<AttributeEntry> attributes)
      : uid_(uid), name_(name) {
    if (name_.size() > MAX_FIELD_LEN) {
      name_.resize(MAX_FIELD_LEN);
    }

  MediaElementItem(uint64_t uid, std::string name,
                   std::map<Attribute, std::string> attributes)
      : uid_(uid), name_(name), attributes_(attributes) {}
    for (AttributeEntry val : attributes) {
      val.resize(MAX_FIELD_LEN);
      attributes_.insert(val);
    }
  }

  MediaElementItem(const MediaElementItem&) = default;

  static size_t size(const MediaElementItem& item) {
  size_t size() const {
    size_t ret = 0;
    ret += 1;  // Media Element Item Type
    ret += 2;  // Item Length
@@ -214,14 +276,10 @@ struct MediaElementItem {
    ret += 1;  // Media Type
    ret += 2;  // UTF-8 Character Set
    ret += 2;  // Name Length
    ret += item.name_.size();
    ret += 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();
    for (const auto& entry : attributes_) {
      ret += entry.size();
    }

    return ret;
@@ -272,17 +330,19 @@ struct MediaListItem {
    }
  }

  static size_t size(const MediaListItem& item) {
    switch (item.type_) {
  size_t size() const {
    switch (type_) {
      case PLAYER:
        return MediaPlayerItem::size(item.player_);
        return player_.size();
      case FOLDER:
        return FolderItem::size(item.folder_);
        return folder_.size();
      case SONG:
        return MediaElementItem::size(item.song_);
        return song_.size();
    }
  }
};

constexpr size_t AVCT_HDR_LEN = 3;

}  // namespace avrcp
}  // namespace bluetooth
 No newline at end of file
+18 −14
Original line number Diff line number Diff line
@@ -83,25 +83,32 @@ std::string GetElementAttributesRequest::ToString() const {
}

std::unique_ptr<GetElementAttributesResponseBuilder>
GetElementAttributesResponseBuilder::MakeBuilder() {
GetElementAttributesResponseBuilder::MakeBuilder(size_t mtu) {
  std::unique_ptr<GetElementAttributesResponseBuilder> builder(
      new GetElementAttributesResponseBuilder());
      new GetElementAttributesResponseBuilder(mtu));

  return builder;
}

GetElementAttributesResponseBuilder*
GetElementAttributesResponseBuilder::AddAttributeEntry(AttributeEntry entry) {
bool GetElementAttributesResponseBuilder::AddAttributeEntry(
    AttributeEntry entry) {
  CHECK_LT(entries_.size(), size_t(0xFF))
      << __func__ << ": attribute entry overflow";

  entries_.insert(entry);
  size_t remaining_space = mtu_ - size();
  if (entry.size() > remaining_space) {
    entry.resize(remaining_space);
  }

  return this;
  if (entry.empty()) {
    return false;
  }

GetElementAttributesResponseBuilder*
GetElementAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
  entries_.insert(entry);
  return true;
}

bool GetElementAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
                                                            std::string value) {
  return AddAttributeEntry(AttributeEntry(attribute, value));
}
@@ -109,11 +116,8 @@ GetElementAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
size_t GetElementAttributesResponseBuilder::size() const {
  size_t attr_list_size = 0;

  for (auto attribute_entry : entries_) {
    attr_list_size += 4;  // Size of attr entry
    attr_list_size += 2;  // Size of value length field
    attr_list_size += 2;  // Size of character encoding
    attr_list_size += attribute_entry.second.length();
  for (auto& attribute_entry : entries_) {
    attr_list_size += attribute_entry.size();
  }

  return VendorPacket::kMinSize() + 1 + attr_list_size;
+10 −8
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

#pragma once

#include <map>
#include <set>
#include "vendor_packet.h"

namespace bluetooth {
@@ -62,22 +62,24 @@ class GetElementAttributesResponseBuilder : public VendorPacketBuilder {
 public:
  virtual ~GetElementAttributesResponseBuilder() = default;

  static std::unique_ptr<GetElementAttributesResponseBuilder> MakeBuilder();
  static std::unique_ptr<GetElementAttributesResponseBuilder> MakeBuilder(
      size_t mtu);

  GetElementAttributesResponseBuilder* AddAttributeEntry(AttributeEntry entry);
  GetElementAttributesResponseBuilder* AddAttributeEntry(Attribute attribute,
                                                         std::string value);
  bool AddAttributeEntry(AttributeEntry entry);
  bool AddAttributeEntry(Attribute attribute, std::string value);

  virtual size_t size() const override;
  virtual bool Serialize(
      const std::shared_ptr<::bluetooth::Packet>& pkt) override;

 private:
  std::map<Attribute, std::string> entries_;
  std::set<AttributeEntry> entries_;
  size_t mtu_;

  GetElementAttributesResponseBuilder()
  GetElementAttributesResponseBuilder(size_t mtu)
      : VendorPacketBuilder(CType::STABLE, CommandPdu::GET_ELEMENT_ATTRIBUTES,
                            PacketType::SINGLE){};
                            PacketType::SINGLE),
        mtu_(mtu){};
};

}  // namespace avrcp
Loading