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

Commit 7e9dad4f authored by Ajay Panicker's avatar Ajay Panicker Committed by android-build-merger
Browse files

Merge "Add AVRCP Browse packets to the completed packets."

am: dfbe6202

Change-Id: Idcfb9df419b035f7f4a7fe335b4a97bab00db29a
parents 9e3f79a5 dfbe6202
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -18,21 +18,30 @@ cc_test {
    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",
    ],
}
+9 −2
Original line number Diff line number Diff line
@@ -4,14 +4,21 @@ cc_library_static {
    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",
+91 −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 "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
+84 −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/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
+198 −29
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include <base/sys_byteorder.h>

#include <map>

// This file contains the different AVRCP Constants
namespace bluetooth {
namespace avrcp {
@@ -50,6 +52,8 @@ enum class CommandPdu : uint8_t {
  GET_ELEMENT_ATTRIBUTES = 0x20,
  GET_PLAY_STATUS = 0x30,
  REGISTER_NOTIFICATION = 0x31,
  SET_ADDRESSED_PLAYER = 0x60,
  PLAY_ITEM = 0x74,
};

enum class PacketType : uint8_t {
@@ -76,42 +80,207 @@ enum class Event : 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
Loading