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

Commit 0a048351 authored by Ajay Panicker's avatar Ajay Panicker
Browse files

Add the AVRCP Device class for the AVRCP Refactor

The AVRCP Device class handles all the state tracking for each connected
device as well as handling all the different message responses.

Bug: 68854188
Test: run_host_unit_tests.py && run_unit_tests.sh net_test_avrcp
Change-Id: Ic39337eff3e404ca3c2d96f48e79948fac83d7cb
parent 6a556082
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
cc_library_headers {
    name: "avrcp_headers",
    include_dirs: ["packages/modules/Bluetooth/system/internal_include"],
    export_include_dirs: ["./hardware/avrcp/"],
    header_libs: ["internal_include_headers"],
    export_header_lib_headers: ["internal_include_headers"],
    vendor_available: true,
    host_supported: true,
}

cc_library_headers {
    name: "libbluetooth_headers",
    header_libs: [
+188 −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 <map>
#include <string>

#include <base/bind.h>

#include "avrcp_common.h"
#include "avrcp_logging_helper.h"
#include "raw_address.h"

namespace bluetooth {
namespace avrcp {

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

enum PlayState : uint8_t {
  STOPPED = 0x00,
  PLAYING,
  PAUSED,
  FWD_SEEK,
  REV_SEEK,
  ERROR = 0xFF,
};

struct PlayStatus {
  uint32_t position;
  uint32_t duration;
  PlayState state;
};

struct MediaPlayerInfo {
  uint16_t id;
  std::string name;
  bool browsing_supported;
};

struct FolderInfo {
  std::string media_id;
  bool is_playable;
  std::string name;
};

// TODO (apanicke): Convert this to a union
struct ListItem {
  enum : uint8_t {
    FOLDER,
    SONG,
  } type;

  FolderInfo folder;
  SongInfo song;
};

class MediaCallbacks {
 public:
  virtual void SendMediaUpdate(bool track_changed, bool play_state, bool queue);
  virtual void SendFolderUpdate(bool available_players, bool addressed_players,
                                bool uids_changed);
  virtual void SendActiveDeviceChanged(const RawAddress& address);
  virtual ~MediaCallbacks() = default;
};

// The classes below are used by the JNI and are loaded dynamically with the
// Bluetooth library. All classes must be pure virtual otherwise a compiler
// error occurs when trying to link the function implementation.

// MediaInterface defines the class that the AVRCP Service uses in order
// communicate with the media layer. The media layer will define its own
// implementation of this object and register it with the service using
// Avrcp::ServiceInterface::Init(). At this point the AVRCP Service will
// call RegisterUpdateCallbacks() to provide an handle to use to send
// notifications about changes in the Media Interface.
//
// NOTES: The current implementation has the native service handle all the
// thread switching. It will call the interface functions on the btif/jni
// thread and the callback will post its results to the bta thread.
// In the future the interface the JNI registered with the
// service should post all its tasks to the JNI thread itself so that the native
// service isn't aware of the thread the interface functions need to be called
// on. It can then supply callbacks that post results to the correct thread
// allowing the threading model to be totally encapsulated and allow correct
// behavior in case the threading model changes on either side.
class MediaInterface {
 public:
  virtual void SendKeyEvent(uint8_t key, uint8_t status) = 0;

  using SongInfoCallback = base::Callback<void(SongInfo)>;
  virtual void GetSongInfo(SongInfoCallback info_cb) = 0;

  using PlayStatusCallback = base::Callback<void(PlayStatus)>;
  virtual void GetPlayStatus(PlayStatusCallback status_cb) = 0;

  // Contains the current queue and the media ID of the currently playing item
  // in the queue
  using NowPlayingCallback =
      base::Callback<void(std::string, std::vector<SongInfo>)>;
  virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) = 0;

  // TODO (apanicke): Use a map with the ID as the key instead of vector
  // in follow up cleanup patches. This allows simplification of the
  // MediaPlayerInfo object
  using MediaListCallback =
      base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
  virtual void GetMediaPlayerList(MediaListCallback list_cb) = 0;

  using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
  virtual void GetFolderItems(uint16_t player_id, std::string media_id,
                              FolderItemsCallback folder_cb) = 0;

  using SetBrowsedPlayerCallback = base::Callback<void(
      bool success, std::string root_id, uint32_t num_items)>;
  virtual void SetBrowsedPlayer(uint16_t player_id,
                                SetBrowsedPlayerCallback browse_cb) = 0;

  virtual void PlayItem(uint16_t player_id, bool now_playing,
                        std::string media_id) = 0;

  virtual void SetActiveDevice(const RawAddress& address) = 0;

  virtual void RegisterUpdateCallback(MediaCallbacks* callback) = 0;

  virtual void UnregisterUpdateCallback(MediaCallbacks* callback) = 0;

  MediaInterface() = default;
  virtual ~MediaInterface() = default;
};

class VolumeInterface {
 public:
  // TODO (apanicke): Investigate the best value type for volume. Right now it
  // is a value from 0-127 because thats what AVRCP uses.
  using VolumeChangedCb = base::Callback<void(int8_t volume)>;

  // Indicate that a device has been connected that does not support absolute
  // volume.
  virtual void DeviceConnected(const RawAddress& bdaddr) = 0;

  // Indicate that a device has been connected that does support absolute
  // volume. The callback will be immediately called with the current volume
  // which will be sent to the device.
  virtual void DeviceConnected(const RawAddress& bdaddr,
                               VolumeChangedCb cb) = 0;

  // Indicate that a device has been disconnected from AVRCP. Will unregister
  // any callbacks if absolute volume is supported.
  virtual void DeviceDisconnected(const RawAddress& bdaddr) = 0;

  virtual void SetVolume(int8_t volume) = 0;

  virtual ~VolumeInterface() = default;
};

class ServiceInterface {
 public:
  // mediaInterface can not be null. If volumeInterface is null then Absolute
  // Volume is disabled.
  virtual void Init(MediaInterface* mediaInterface,
                    VolumeInterface* volumeInterface) = 0;
  virtual bool ConnectDevice(const RawAddress& bdaddr) = 0;
  virtual bool DisconnectDevice(const RawAddress& bdaddr) = 0;
  virtual bool Cleanup() = 0;

 protected:
  virtual ~ServiceInterface() = default;
};

}  // namespace avrcp
}  // namespace bluetooth
 No newline at end of file
+4 −3
Original line number Diff line number Diff line
@@ -16,16 +16,17 @@

#pragma once

#include <base/sys_byteorder.h>

#include <map>

// This file contains the different AVRCP Constants
#include <base/sys_byteorder.h>

namespace bluetooth {
namespace avrcp {

constexpr uint32_t BLUETOOTH_COMPANY_ID = 0x001958;

constexpr uint8_t MAX_TRANSACTION_LABEL = 0xF;

enum class CType : uint8_t {
  CONTROL = 0x0,
  STATUS = 0x1,
+14 −23
Original line number Diff line number Diff line
@@ -23,17 +23,7 @@
#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
#include "bt_trace.h"

namespace bluetooth {
namespace avrcp {
@@ -53,7 +43,7 @@ inline std::string CTypeText(const CType& type) {
    CASE_RETURN_TEXT(CType::CHANGED);
    CASE_RETURN_TEXT(CType::INTERIM);
    default:
      return "Unknown CType: " + loghex(type);
      return "Unknown CType: " + loghex((uint8_t)type);
  }
}

@@ -68,7 +58,7 @@ inline std::string OpcodeText(const Opcode& opcode) {
    CASE_RETURN_TEXT(Opcode::SUBUNIT_INFO);
    CASE_RETURN_TEXT(Opcode::PASS_THROUGH);
    default:
      return "Unknown Opcode: " + loghex(opcode);
      return "Unknown Opcode: " + loghex((uint8_t)opcode);
  }
}

@@ -83,10 +73,11 @@ inline std::string CommandPduText(const CommandPdu& pdu) {
    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_ABSOLUTE_VOLUME);
    CASE_RETURN_TEXT(CommandPdu::SET_ADDRESSED_PLAYER);
    CASE_RETURN_TEXT(CommandPdu::PLAY_ITEM);
    default:
      return "Unknown Command PDU: " + loghex(pdu);
      return "Unknown Command PDU: " + loghex((uint8_t)pdu);
  }
}

@@ -98,7 +89,7 @@ inline std::string PacketTypeText(const PacketType& type) {
  switch (type) {
    CASE_RETURN_TEXT(PacketType::SINGLE);
    default:
      return "Unknown Packet Type: " + loghex(type);
      return "Unknown Packet Type: " + loghex((uint8_t)type);
  }
}

@@ -111,7 +102,7 @@ inline std::string CapabilityText(const Capability& cap) {
    CASE_RETURN_TEXT(Capability::COMPANY_ID);
    CASE_RETURN_TEXT(Capability::EVENTS_SUPPORTED);
    default:
      return "Unknown Capability: " + loghex(cap);
      return "Unknown Capability: " + loghex((uint8_t)cap);
  }
}

@@ -131,7 +122,7 @@ inline std::string EventText(const Event& event) {
    CASE_RETURN_TEXT(Event::UIDS_CHANGED);
    CASE_RETURN_TEXT(Event::VOLUME_CHANGED);
    default:
      return "Unknown Event: " + loghex(event);
      return "Unknown Event: " + loghex((uint8_t)event);
  }
}

@@ -150,7 +141,7 @@ inline std::string AttributeText(const Attribute& attr) {
    CASE_RETURN_TEXT(Attribute::PLAYING_TIME);
    CASE_RETURN_TEXT(Attribute::DEFAULT_COVER_ART);
    default:
      return "Unknown Attribute Value: " + loghex(attr);
      return "Unknown Attribute Value: " + loghex((uint32_t)attr);
  }
}

@@ -184,7 +175,7 @@ inline std::string StatusText(const Status& status) {
    CASE_RETURN_TEXT(Status::NO_AVAILABLE_PLAYERS);
    CASE_RETURN_TEXT(Status::ADDRESSED_PLAYER_CHANGED);
    default:
      return "Unknown Status: " + loghex(status);
      return "Unknown Status: " + loghex((uint8_t)status);
  }
}

@@ -199,7 +190,7 @@ inline std::string BrowsePduText(const BrowsePdu& pdu) {
    CASE_RETURN_TEXT(BrowsePdu::CHANGE_PATH);
    CASE_RETURN_TEXT(BrowsePdu::GET_ITEM_ATTRIBUTES);
    default:
      return "Unknown Browse Pdu: " + loghex(pdu);
      return "Unknown Browse PDU: " + loghex((uint8_t)pdu);
  }
}

@@ -214,7 +205,7 @@ inline std::string ScopeText(const Scope& scope) {
    CASE_RETURN_TEXT(Scope::SEARCH);
    CASE_RETURN_TEXT(Scope::NOW_PLAYING);
    default:
      return "Unknown Scope: " + loghex(scope);
      return "Unknown Scope: " + loghex((uint8_t)scope);
  }
}

@@ -227,7 +218,7 @@ inline std::string DirectionText(const Direction& dir) {
    CASE_RETURN_TEXT(Direction::UP);
    CASE_RETURN_TEXT(Direction::DOWN);
    default:
      return "Unknown Direction: " + loghex(dir);
      return "Unknown Direction: " + loghex((uint8_t)dir);
  }
}

+6 −0
Original line number Diff line number Diff line
cc_library_headers {
    name: "internal_include_headers",
    export_include_dirs: ["./"],
    vendor_available: true,
    host_supported: true,
}
 No newline at end of file
Loading