普通文本  |  473行  |  16.02 KB

/*
 * 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_service.h"

#include <base/bind.h>
#include <base/logging.h>
#include <base/task/cancelable_task_tracker.h>
#include <base/threading/thread.h>
#include <mutex>
#include <sstream>

#include "btif_av.h"
#include "btif_common.h"
#include "device.h"
#include "stack/include/btu.h"

namespace bluetooth {
namespace avrcp {
// Static variables and interface definitions
AvrcpService* AvrcpService::instance_ = nullptr;
AvrcpService::ServiceInterfaceImpl* AvrcpService::service_interface_ = nullptr;

std::mutex jni_mutex_;
base::MessageLoop* jni_message_loop_ = nullptr;
base::CancelableTaskTracker task_tracker_;

void do_in_avrcp_jni(const base::Closure& task) {
  std::lock_guard<std::mutex> lock(jni_mutex_);

  if (jni_message_loop_ == nullptr) {
    LOG(WARNING) << __func__ << ": jni_message_loop_ is null";
    return;
  }

  task_tracker_.PostTask(jni_message_loop_->task_runner().get(), FROM_HERE,
                         task);
}

class A2dpInterfaceImpl : public A2dpInterface {
  RawAddress active_peer() override { return btif_av_source_active_peer(); }

  bool is_peer_in_silence_mode(const RawAddress& peer_address) override {
    return btif_av_is_peer_silenced(peer_address);
  }
} a2dp_interface_;

class AvrcpInterfaceImpl : public AvrcpInterface {
 public:
  uint16_t AddRecord(uint16_t service_uuid, const char* p_service_name,
                     const char* p_provider_name, uint16_t categories,
                     uint32_t sdp_handle, bool browse_supported,
                     uint16_t profile_version) override {
    return AVRC_AddRecord(service_uuid, p_service_name, p_provider_name,
                          categories, sdp_handle, browse_supported,
                          profile_version);
  }

  uint16_t FindService(uint16_t service_uuid, const RawAddress& bd_addr,
                       tAVRC_SDP_DB_PARAMS* p_db,
                       tAVRC_FIND_CBACK p_cback) override {
    return AVRC_FindService(service_uuid, bd_addr, p_db, p_cback);
  }

  uint16_t Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
                const RawAddress& bd_addr) override {
    return AVRC_Open(p_handle, p_ccb, bd_addr);
  }

  uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) override {
    return AVRC_OpenBrowse(handle, conn_role);
  }

  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);
  }
} avrcp_interface_;

class SdpInterfaceImpl : public SdpInterface {
 public:
  bool InitDiscoveryDb(tSDP_DISCOVERY_DB* a, uint32_t b, uint16_t c,
                       const bluetooth::Uuid* d, uint16_t e,
                       uint16_t* f) override {
    return SDP_InitDiscoveryDb(a, b, c, d, e, f);
  }

  bool ServiceSearchAttributeRequest(const RawAddress& a, tSDP_DISCOVERY_DB* b,
                                     tSDP_DISC_CMPL_CB* c) override {
    return SDP_ServiceSearchAttributeRequest(a, b, c);
  }

  tSDP_DISC_REC* FindServiceInDb(tSDP_DISCOVERY_DB* a, uint16_t b,
                                 t_sdp_disc_rec* c) override {
    return SDP_FindServiceInDb(a, b, c);
  }

  tSDP_DISC_ATTR* FindAttributeInRec(t_sdp_disc_rec* a, uint16_t b) override {
    return SDP_FindAttributeInRec(a, b);
  }

  bool FindProfileVersionInRec(t_sdp_disc_rec* a, uint16_t b,
                               uint16_t* c) override {
    return SDP_FindProfileVersionInRec(a, b, c);
  }
} sdp_interface_;

// A wrapper class for the media callbacks that handles thread
// switching/synchronization so the devices don't have to worry about it.
class MediaInterfaceWrapper : public MediaInterface {
 public:
  MediaInterfaceWrapper(MediaInterface* cb) : wrapped_(cb){};

  void SendKeyEvent(uint8_t key, KeyState state) override {
    do_in_avrcp_jni(base::Bind(&MediaInterface::SendKeyEvent,
                               base::Unretained(wrapped_), key, state));
  }

  void GetSongInfo(SongInfoCallback info_cb) override {
    auto cb_lambda = [](SongInfoCallback cb, SongInfo data) {
      do_in_main_thread(FROM_HERE, base::Bind(cb, data));
    };

    auto bound_cb = base::Bind(cb_lambda, info_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::GetSongInfo,
                               base::Unretained(wrapped_), bound_cb));
  }

  void GetPlayStatus(PlayStatusCallback status_cb) override {
    auto cb_lambda = [](PlayStatusCallback cb, PlayStatus status) {
      do_in_main_thread(FROM_HERE, base::Bind(cb, status));
    };

    auto bound_cb = base::Bind(cb_lambda, status_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::GetPlayStatus,
                               base::Unretained(wrapped_), bound_cb));
  }

  void GetNowPlayingList(NowPlayingCallback now_playing_cb) override {
    auto cb_lambda = [](NowPlayingCallback cb, std::string curr_media_id,
                        std::vector<SongInfo> song_list) {
      do_in_main_thread(FROM_HERE,
                        base::Bind(cb, curr_media_id, std::move(song_list)));
    };

    auto bound_cb = base::Bind(cb_lambda, now_playing_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::GetNowPlayingList,
                               base::Unretained(wrapped_), bound_cb));
  }

  void GetMediaPlayerList(MediaListCallback list_cb) override {
    auto cb_lambda = [](MediaListCallback cb, uint16_t curr_player,
                        std::vector<MediaPlayerInfo> player_list) {
      do_in_main_thread(FROM_HERE,
                        base::Bind(cb, curr_player, std::move(player_list)));
    };

    auto bound_cb = base::Bind(cb_lambda, list_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::GetMediaPlayerList,
                               base::Unretained(wrapped_), bound_cb));
  }

  void GetFolderItems(uint16_t player_id, std::string media_id,
                      FolderItemsCallback folder_cb) override {
    auto cb_lambda = [](FolderItemsCallback cb,
                        std::vector<ListItem> item_list) {
      do_in_main_thread(FROM_HERE, base::Bind(cb, std::move(item_list)));
    };

    auto bound_cb = base::Bind(cb_lambda, folder_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::GetFolderItems,
                               base::Unretained(wrapped_), player_id, media_id,
                               bound_cb));
  }

  void SetBrowsedPlayer(uint16_t player_id,
                        SetBrowsedPlayerCallback browse_cb) override {
    auto cb_lambda = [](SetBrowsedPlayerCallback cb, bool success,
                        std::string root_id, uint32_t num_items) {
      do_in_main_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items));
    };

    auto bound_cb = base::Bind(cb_lambda, browse_cb);

    do_in_avrcp_jni(base::Bind(&MediaInterface::SetBrowsedPlayer,
                               base::Unretained(wrapped_), player_id,
                               bound_cb));
  }

  void PlayItem(uint16_t player_id, bool now_playing,
                std::string media_id) override {
    do_in_avrcp_jni(base::Bind(&MediaInterface::PlayItem,
                               base::Unretained(wrapped_), player_id,
                               now_playing, media_id));
  }

  void SetActiveDevice(const RawAddress& address) override {
    do_in_avrcp_jni(base::Bind(&MediaInterface::SetActiveDevice,
                               base::Unretained(wrapped_), address));
  }

  void RegisterUpdateCallback(MediaCallbacks* callback) override {
    wrapped_->RegisterUpdateCallback(callback);
  }

  void UnregisterUpdateCallback(MediaCallbacks* callback) override {
    wrapped_->UnregisterUpdateCallback(callback);
  }

 private:
  MediaInterface* wrapped_;
};

// A wrapper class for the media callbacks that handles thread
// switching/synchronization so the devices don't have to worry about it.
class VolumeInterfaceWrapper : public VolumeInterface {
 public:
  VolumeInterfaceWrapper(VolumeInterface* interface) : wrapped_(interface){};

  void DeviceConnected(const RawAddress& bdaddr) override {
    do_in_avrcp_jni(
        base::Bind(static_cast<void (VolumeInterface::*)(const RawAddress&)>(
                       &VolumeInterface::DeviceConnected),
                   base::Unretained(wrapped_), bdaddr));
  }

  void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
    auto cb_lambda = [](VolumeChangedCb cb, int8_t volume) {
      do_in_main_thread(FROM_HERE, base::Bind(cb, volume));
    };

    auto bound_cb = base::Bind(cb_lambda, cb);

    do_in_avrcp_jni(base::Bind(static_cast<void (VolumeInterface::*)(
                                   const RawAddress&, VolumeChangedCb)>(
                                   &VolumeInterface::DeviceConnected),
                               base::Unretained(wrapped_), bdaddr, bound_cb));
  }

  void DeviceDisconnected(const RawAddress& bdaddr) override {
    do_in_avrcp_jni(base::Bind(&VolumeInterface::DeviceDisconnected,
                               base::Unretained(wrapped_), bdaddr));
  }

  void SetVolume(int8_t volume) override {
    do_in_avrcp_jni(base::Bind(&VolumeInterface::SetVolume,
                               base::Unretained(wrapped_), volume));
  }

 private:
  VolumeInterface* wrapped_;
};

void AvrcpService::Init(MediaInterface* media_interface,
                        VolumeInterface* volume_interface) {
  LOG(INFO) << "AVRCP Target Service started";

  // TODO (apanicke): Add a function that sets up the SDP records once we
  // remove the AVRCP SDP setup in AVDTP (bta_av_main.cc)

  media_interface_ = new MediaInterfaceWrapper(media_interface);
  media_interface->RegisterUpdateCallback(instance_);

  VolumeInterfaceWrapper* wrapped_volume_interface = nullptr;
  if (volume_interface != nullptr) {
    wrapped_volume_interface = new VolumeInterfaceWrapper(volume_interface);
  }

  volume_interface_ = wrapped_volume_interface;

  ConnectionHandler::Initialize(
      base::Bind(&AvrcpService::DeviceCallback, base::Unretained(instance_)),
      &avrcp_interface_, &sdp_interface_, wrapped_volume_interface);
  connection_handler_ = ConnectionHandler::Get();
}

void AvrcpService::Cleanup() {
  LOG(INFO) << "AVRCP Target Service stopped";

  connection_handler_->CleanUp();
  connection_handler_ = nullptr;
  if (volume_interface_ != nullptr) {
    delete volume_interface_;
  }
  delete media_interface_;
}

AvrcpService* AvrcpService::Get() {
  CHECK(instance_);
  return instance_;
}

ServiceInterface* AvrcpService::GetServiceInterface() {
  if (service_interface_ == nullptr) {
    service_interface_ = new ServiceInterfaceImpl();
  }

  return service_interface_;
}

void AvrcpService::ConnectDevice(const RawAddress& bdaddr) {
  LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();

  connection_handler_->ConnectDevice(bdaddr);
}

void AvrcpService::DisconnectDevice(const RawAddress& bdaddr) {
  LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
  connection_handler_->DisconnectDevice(bdaddr);
}

void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state,
                                   bool queue) {
  LOG(INFO) << __PRETTY_FUNCTION__ << " track_changed=" << track_changed
            << " : "
            << " play_state=" << play_state << " : "
            << " queue=" << queue;

  // This function may be called on any thread, we need to make sure that the
  // device update happens on the main thread.
  for (const auto& device :
       instance_->connection_handler_->GetListOfDevices()) {
    do_in_main_thread(FROM_HERE,
                      base::Bind(&Device::SendMediaUpdate, device.get()->Get(), track_changed, play_state, queue));
  }
}

void AvrcpService::SendFolderUpdate(bool available_players,
                                    bool addressed_players, bool uids) {
  LOG(INFO) << __PRETTY_FUNCTION__ << " available_players=" << available_players
            << " : "
            << " addressed_players=" << addressed_players << " : "
            << " uids=" << uids;

  // Ensure that the update is posted to the correct thread
  for (const auto& device :
       instance_->connection_handler_->GetListOfDevices()) {
    do_in_main_thread(FROM_HERE, base::Bind(&Device::SendFolderUpdate, device.get()->Get(), available_players,
                                            addressed_players, uids));
  }
}

// Send out the track changed info to update the playback state for each device
void AvrcpService::SendActiveDeviceChanged(const RawAddress& address) {
  SendMediaUpdate(false, true, false);
}

void AvrcpService::DeviceCallback(std::shared_ptr<Device> new_device) {
  if (new_device == nullptr) return;

  // TODO (apanicke): Pass the interfaces into the connection handler
  // so that the devices can be created with any interfaces they need.
  new_device->RegisterInterfaces(media_interface_, &a2dp_interface_,
                                 volume_interface_);
}

// Service Interface
void AvrcpService::ServiceInterfaceImpl::Init(
    MediaInterface* media_interface, VolumeInterface* volume_interface) {
  std::lock_guard<std::mutex> lock(service_interface_lock_);

  // TODO: This function should block until the service is completely up so
  // that its possible to call Get() on the service immediately after calling
  // init without issues.

  CHECK(instance_ == nullptr);
  instance_ = new AvrcpService();

  {
    std::lock_guard<std::mutex> jni_lock(jni_mutex_);
    jni_message_loop_ = get_jni_message_loop();
  }

  do_in_main_thread(FROM_HERE,
                    base::Bind(&AvrcpService::Init, base::Unretained(instance_),
                               media_interface, volume_interface));
}

bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
    const RawAddress& bdaddr) {
  std::lock_guard<std::mutex> lock(service_interface_lock_);
  CHECK(instance_ != nullptr);
  do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
                                          base::Unretained(instance_), bdaddr));
  return true;
}

bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(
    const RawAddress& bdaddr) {
  std::lock_guard<std::mutex> lock(service_interface_lock_);
  CHECK(instance_ != nullptr);
  do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
                                          base::Unretained(instance_), bdaddr));
  return true;
}

bool AvrcpService::ServiceInterfaceImpl::Cleanup() {
  std::lock_guard<std::mutex> lock(service_interface_lock_);

  if (instance_ == nullptr) return false;

  {
    std::lock_guard<std::mutex> jni_lock(jni_mutex_);
    task_tracker_.TryCancelAll();
    jni_message_loop_ = nullptr;
  }

  do_in_main_thread(FROM_HERE,
                    base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));

  // Setting instance to nullptr here is fine since it will be deleted on the
  // other thread.
  instance_ = nullptr;

  return true;
}

void AvrcpService::DebugDump(int fd) {
  if (instance_ == nullptr) {
    dprintf(fd, "\nAVRCP Target Service not started\n");
    return;
  }

  auto device_list = instance_->connection_handler_->GetListOfDevices();
  dprintf(fd, "\nAVRCP Target Native Service: %zu devices\n",
          device_list.size());

  std::stringstream stream;
  {
    ScopedIndent indent(stream);
    for (const auto& device : device_list) {
      stream << *device << std::endl;
    }
  }

  dprintf(fd, "%s", stream.str().c_str());
}

}  // namespace avrcp
}  // namespace bluetooth