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

Commit c8b997e3 authored by Bailey Forrest's avatar Bailey Forrest Committed by Pavlin Radoslavov
Browse files

Implement A2DP source and AVRCP target binder servers

Bug: 64231556
Test: On device.
Change-Id: I57136d5550e8e52626a1e7eb26b7d8c02cd94eb5
parent e24716e7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -15,8 +15,10 @@ cc_defaults {
// ========================================================
btserviceDaemonSrc = [
    "a2dp_sink.cc",
    "a2dp_source.cc",
    "adapter.cc",
    "avrcp_control.cc",
    "avrcp_target.cc",
    "daemon.cc",
    "gatt_client.cc",
    "gatt_server.cc",
@@ -41,7 +43,9 @@ btserviceLinuxSrc = [

btserviceBinderDaemonSrc = [
    "ipc/binder/bluetooth_a2dp_sink_binder_server.cc",
    "ipc/binder/bluetooth_a2dp_source_binder_server.cc",
    "ipc/binder/bluetooth_avrcp_control_binder_server.cc",
    "ipc/binder/bluetooth_avrcp_target_binder_server.cc",
    "ipc/binder/bluetooth_binder_server.cc",
    "ipc/binder/bluetooth_gatt_client_binder_server.cc",
    "ipc/binder/bluetooth_gatt_server_binder_server.cc",
+216 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2017 Google, Inc.
//
//  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 "service/a2dp_source.h"

#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "service/logging_helpers.h"

#define PARSE_ADDR(str)                                        \
  ({                                                           \
    RawAddress tmp;                                            \
    if (!RawAddress::FromString((str), tmp)) {                 \
      LOG(ERROR) << "Invalid device address given: " << (str); \
      return false;                                            \
    }                                                          \
    tmp;                                                       \
  })

#define TRY_RET(expr, err_msg) \
  do {                         \
    if (!(expr)) {             \
      LOG(ERROR) << err_msg;   \
      return false;            \
    }                          \
    return true;               \
  } while (0)

#define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed")

using bluetooth::hal::BluetoothAvInterface;
using LockGuard = std::lock_guard<std::mutex>;

namespace bluetooth {

namespace {

btav_a2dp_codec_config_t CodecConfigToFluoride(const A2dpCodecConfig& config) {
  btav_a2dp_codec_config_t ret = {
      .codec_type = static_cast<btav_a2dp_codec_index_t>(config.codec_type()),
      .codec_priority =
          static_cast<btav_a2dp_codec_priority_t>(config.codec_priority()),
      .sample_rate =
          static_cast<btav_a2dp_codec_sample_rate_t>(config.sample_rate()),
      .bits_per_sample = static_cast<btav_a2dp_codec_bits_per_sample_t>(
          config.bits_per_sample()),
      .channel_mode =
          static_cast<btav_a2dp_codec_channel_mode_t>(config.channel_mode()),
      .codec_specific_1 = config.codec_specific_1(),
      .codec_specific_2 = config.codec_specific_2(),
      .codec_specific_3 = config.codec_specific_3(),
      .codec_specific_4 = config.codec_specific_4(),
  };

  return ret;
}

std::vector<btav_a2dp_codec_config_t> CodecConfigsToFluoride(
    const std::vector<A2dpCodecConfig>& configs) {
  std::vector<btav_a2dp_codec_config_t> ret;
  ret.reserve(configs.size());
  for (const auto& config : configs) {
    ret.push_back(CodecConfigToFluoride(config));
  }

  return ret;
}
A2dpCodecConfig FluorideCodecToCodec(const btav_a2dp_codec_config_t& config) {
  A2dpCodecConfig ret(config.codec_type, config.codec_priority,
                      config.sample_rate, config.bits_per_sample,
                      config.channel_mode, config.codec_specific_1,
                      config.codec_specific_2, config.codec_specific_3,
                      config.codec_specific_4);

  return ret;
}

std::vector<A2dpCodecConfig> FluorideCodecsToCodec(
    const std::vector<btav_a2dp_codec_config_t>& configs) {
  std::vector<A2dpCodecConfig> ret;
  ret.reserve(configs.size());
  for (const auto& config : configs) {
    ret.push_back(FluorideCodecToCodec(config));
  }

  return ret;
}

}  // namespace

// static
const int A2dpSource::kSingletonInstanceId = 0;

A2dpSource::A2dpSource(const Uuid& uuid) : app_identifier_(uuid) {
  hal::BluetoothAvInterface::Get()->AddA2dpSourceObserver(this);
}

A2dpSource::~A2dpSource() {
  hal::BluetoothAvInterface::Get()->RemoveA2dpSourceObserver(this);
}

const Uuid& A2dpSource::GetAppIdentifier() const { return app_identifier_; }

int A2dpSource::GetInstanceId() const { return kSingletonInstanceId; }

void A2dpSource::SetDelegate(Delegate* delegate) {
  LockGuard lock(delegate_mutex_);
  delegate_ = delegate;
}

bool A2dpSource::Enable(const std::vector<A2dpCodecConfig>& codec_priorities) {
  auto fluoride_priorities = CodecConfigsToFluoride(codec_priorities);
  LockGuard lock(mutex_);
  return hal::BluetoothAvInterface::Get()->A2dpSourceEnable(
      fluoride_priorities);
}

void A2dpSource::Disable() {
  LockGuard lock(mutex_);
  hal::BluetoothAvInterface::Get()->A2dpSourceDisable();
}

bool A2dpSource::Connect(const std::string& device_address) {
  RawAddress addr = PARSE_ADDR(device_address);
  LockGuard lock(mutex_);
  TRY_RET_FUNC(
      hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->connect(
          addr) == BT_STATUS_SUCCESS);
}

bool A2dpSource::Disconnect(const std::string& device_address) {
  RawAddress addr = PARSE_ADDR(device_address);
  LockGuard lock(mutex_);
  TRY_RET_FUNC(
      hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->disconnect(
          addr) == BT_STATUS_SUCCESS);
}

bool A2dpSource::ConfigCodec(
    const std::string& device_address,
    const std::vector<A2dpCodecConfig>& codec_preferences) {
  RawAddress addr = PARSE_ADDR(device_address);
  auto fluoride_preferences = CodecConfigsToFluoride(codec_preferences);
  LockGuard lock(mutex_);
  TRY_RET_FUNC(hal::BluetoothAvInterface::Get()
                   ->GetA2dpSourceHALInterface()
                   ->config_codec(addr, fluoride_preferences) ==
               BT_STATUS_SUCCESS);
}

void A2dpSource::ConnectionStateCallback(BluetoothAvInterface* iface,
                                         const RawAddress& bd_addr,
                                         btav_connection_state_t state) {
  auto device_address = BtAddrString(&bd_addr);
  LockGuard lock(delegate_mutex_);
  if (delegate_)
    delegate_->OnConnectionState(device_address, static_cast<int>(state));
}

void A2dpSource::AudioStateCallback(BluetoothAvInterface* iface,
                                    const RawAddress& bd_addr,
                                    btav_audio_state_t state) {
  auto device_address = BtAddrString(&bd_addr);
  LockGuard lock(delegate_mutex_);
  if (delegate_)
    delegate_->OnAudioState(device_address, static_cast<int>(state));
}

void A2dpSource::AudioConfigCallback(
    BluetoothAvInterface* iface, const RawAddress& bd_addr,
    const btav_a2dp_codec_config_t& codec_config_fluoride,
    const std::vector<btav_a2dp_codec_config_t>
        codecs_local_capabilities_fluoride,
    const std::vector<btav_a2dp_codec_config_t>
        codecs_selectable_capabilities_fluoride) {
  auto device_address = BtAddrString(&bd_addr);
  auto codec_config = FluorideCodecToCodec(codec_config_fluoride);
  auto codecs_local_capabilities =
      FluorideCodecsToCodec(codecs_local_capabilities_fluoride);
  auto codecs_selectable_capabilities =
      FluorideCodecsToCodec(codecs_selectable_capabilities_fluoride);
  LockGuard lock(delegate_mutex_);
  if (delegate_)
    delegate_->OnAudioConfig(device_address, codec_config,
                             codecs_local_capabilities,
                             codecs_selectable_capabilities);
}

// A2dpSourceFactory implementation
// ========================================================
A2dpSourceFactory::A2dpSourceFactory() = default;
A2dpSourceFactory::~A2dpSourceFactory() = default;

bool A2dpSourceFactory::RegisterInstance(const Uuid& uuid,
                                         const RegisterCallback& callback) {
  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();

  auto a2dp_source = base::WrapUnique(new A2dpSource(uuid));
  callback(BLE_STATUS_SUCCESS, uuid, std::move(a2dp_source));
  return true;
}

}  // namespace bluetooth
+116 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2017 Google, Inc.
//
//  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 <atomic>
#include <mutex>
#include <string>
#include <vector>

#include <base/macros.h>

#include "service/bluetooth_instance.h"
#include "service/common/bluetooth/a2dp_codec_config.h"
#include "service/hal/bluetooth_av_interface.h"

namespace bluetooth {

class A2dpSource : public BluetoothInstance,
                   private hal::BluetoothAvInterface::A2dpSourceObserver {
 public:
  // We only allow one instance of this object at a time.
  static const int kSingletonInstanceId;

  class Delegate {
   public:
    virtual void OnConnectionState(const std::string& device_address,
                                   int state) = 0;
    virtual void OnAudioState(const std::string& device_address, int state) = 0;
    virtual void OnAudioConfig(
        const std::string& device_address, A2dpCodecConfig codec_config,
        const std::vector<A2dpCodecConfig>& codecs_local_capabilities,
        const std::vector<A2dpCodecConfig>& codecs_selectable_capabilities) = 0;

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

  ~A2dpSource() override;

  void SetDelegate(Delegate* delegate);

  // BluetoothInstance implementation:
  const Uuid& GetAppIdentifier() const override;
  int GetInstanceId() const override;

  bool Enable(const std::vector<A2dpCodecConfig>& codec_priorities);
  void Disable();
  bool Connect(const std::string& device_address);
  bool Disconnect(const std::string& device_address);
  bool ConfigCodec(const std::string& device_address,
                   const std::vector<A2dpCodecConfig>& codec_preferences);

 private:
  friend class A2dpSourceFactory;

  explicit A2dpSource(const Uuid& uuid);

  // hal::bluetooth::hal::BluetoothAvInterface::Observer implementation:
  void ConnectionStateCallback(hal::BluetoothAvInterface* iface,
                               const RawAddress& bd_addr,
                               btav_connection_state_t state) override;
  void AudioStateCallback(hal::BluetoothAvInterface* iface,
                          const RawAddress& bd_addr,
                          btav_audio_state_t state) override;
  void AudioConfigCallback(
      hal::BluetoothAvInterface* iface, const RawAddress& bd_addr,
      const btav_a2dp_codec_config_t& codec_config,
      const std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
      const std::vector<btav_a2dp_codec_config_t>
          codecs_selectable_capabilities) override;

  // For |GetAppIdentifier|.
  const Uuid app_identifier_;

  std::mutex mutex_;

  // A second mutex is used only for |delegate_|. We cannot use |mutex_| because
  // it may cause a deadlock if the caller and Delegate both take the same lock
  // 'clock'.
  // In that scenario, the caller may take 'clock' first and will try to take
  // |mutex_| second. The callback will take |mutex_| first and invoke a
  // delegate function which attempts to take 'clock'.
  std::mutex delegate_mutex_;
  Delegate* delegate_ = nullptr;

  DISALLOW_COPY_AND_ASSIGN(A2dpSource);
};

class A2dpSourceFactory : public BluetoothInstanceFactory {
 public:
  A2dpSourceFactory();
  ~A2dpSourceFactory() override;

  // BluetoothInstanceFactory override:
  bool RegisterInstance(const Uuid& uuid,
                        const RegisterCallback& callback) override;

 private:
  DISALLOW_COPY_AND_ASSIGN(A2dpSourceFactory);
};

}  // namespace bluetooth
+18 −0
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@
#include <base/observer_list.h>

#include "service/a2dp_sink.h"
#include "service/a2dp_source.h"
#include "service/avrcp_control.h"
#include "service/avrcp_target.h"
#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
@@ -202,7 +204,9 @@ class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
    memset(&local_le_features_, 0, sizeof(local_le_features_));
    hal::BluetoothInterface::Get()->AddObserver(this);
    a2dp_sink_factory_.reset(new A2dpSinkFactory);
    a2dp_source_factory_.reset(new A2dpSourceFactory);
    avrcp_control_factory_.reset(new AvrcpControlFactory);
    avrcp_target_factory_.reset(new AvrcpTargetFactory);
    ble_client_factory_.reset(new LowEnergyClientFactory(*this));
    ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
    ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
@@ -466,10 +470,18 @@ class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
    return a2dp_sink_factory_.get();
  }

  A2dpSourceFactory* GetA2dpSourceFactory() const override {
    return a2dp_source_factory_.get();
  }

  AvrcpControlFactory* GetAvrcpControlFactory() const override {
    return avrcp_control_factory_.get();
  }

  AvrcpTargetFactory* GetAvrcpTargetFactory() const override {
    return avrcp_target_factory_.get();
  }

  LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
    return ble_client_factory_.get();
  }
@@ -764,9 +776,15 @@ class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
  // Factory used to create per-app A2dpSink instances.
  std::unique_ptr<A2dpSinkFactory> a2dp_sink_factory_;

  // Factory used to create per-app A2dpSource instances.
  std::unique_ptr<A2dpSourceFactory> a2dp_source_factory_;

  // Factory used to create per-app AvrcpControl instances.
  std::unique_ptr<AvrcpControlFactory> avrcp_control_factory_;

  // Factory used to create per-app AvrcpTarget instances.
  std::unique_ptr<AvrcpTargetFactory> avrcp_target_factory_;

  // Factory used to create per-app LowEnergyClient instances.
  std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;

+12 −0
Original line number Diff line number Diff line
@@ -28,7 +28,9 @@
namespace bluetooth {

class A2dpSinkFactory;
class A2dpSourceFactory;
class AvrcpControlFactory;
class AvrcpTargetFactory;
class GattClientFactory;
class GattServerFactory;
class LowEnergyAdvertiserFactory;
@@ -183,11 +185,21 @@ class Adapter {
  // operations.
  virtual A2dpSinkFactory* GetA2dpSinkFactory() const = 0;

  // Returns a pointer to the A2dpSourceFactory. This can be used to
  // register per-application A2dpSourceClient instances to perform A2DP source
  // operations.
  virtual A2dpSourceFactory* GetA2dpSourceFactory() const = 0;

  // Returns a pointer to the AvrcpControlFactory. This can be used to register
  // per-application AvrcpControlClient instances to perform AVRCP control
  // operations.
  virtual AvrcpControlFactory* GetAvrcpControlFactory() const = 0;

  // Returns a pointer to the AvrcpTargetFactory. This can be used to register
  // per-application AvrcpTargetClient instances to perform AVRCP target
  // operations.
  virtual AvrcpTargetFactory* GetAvrcpTargetFactory() const = 0;

  // Returns a pointer to the LowEnergyClientFactory. This can be used to
  // register per-application LowEnergyClient instances to perform BLE GAP
  // operations.
Loading