Implement A2DP sink and AVRCP controller binder server
Also added bonded device management because this is needed for A2DP to
work with most devices.
Bug: 32657860
Test: Run on device, modified tests pass.
Change-Id: I862e41b6594b7cec9f61094d300577574cc8bbc6
diff --git a/service/Android.bp b/service/Android.bp
index d24e0fa..42be835 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -14,11 +14,15 @@
// Source variables
// ========================================================
btserviceDaemonSrc = [
+ "a2dp_sink.cc",
"adapter.cc",
+ "avrcp_control.cc",
"daemon.cc",
"gatt_client.cc",
"gatt_server.cc",
"gatt_server_old.cc",
+ "hal/bluetooth_av_interface.cc",
+ "hal/bluetooth_avrcp_interface.cc",
"hal/bluetooth_gatt_interface.cc",
"hal/bluetooth_interface.cc",
"ipc/ipc_handler.cc",
@@ -36,6 +40,8 @@
]
btserviceBinderDaemonSrc = [
+ "ipc/binder/bluetooth_a2dp_sink_binder_server.cc",
+ "ipc/binder/bluetooth_avrcp_control_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",
@@ -49,8 +55,10 @@
// Main unit test sources. These get built for host and target.
// ========================================================
btserviceBaseTestSrc = [
+ "hal/fake_bluetooth_av_interface.cc",
"hal/fake_bluetooth_gatt_interface.cc",
"hal/fake_bluetooth_interface.cc",
+ "test/a2dp_sink_unittest.cc",
"test/adapter_unittest.cc",
"test/advertise_data_unittest.cc",
"test/fake_hal_util.cc",
@@ -109,6 +117,7 @@
"libgmock",
"liblog",
"libbluetooth-types",
+ "libutils",
],
host_supported: true,
target: {
@@ -124,7 +133,6 @@
],
shared_libs: [
"libbinder",
- "libutils",
],
},
host: {
diff --git a/service/a2dp_sink.cc b/service/a2dp_sink.cc
new file mode 100644
index 0000000..4d59c7c
--- /dev/null
+++ b/service/a2dp_sink.cc
@@ -0,0 +1,154 @@
+//
+// Copyright 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_sink.h"
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+
+#include "service/logging_helpers.h"
+
+using bluetooth::hal::BluetoothAvInterface;
+
+namespace bluetooth {
+
+// static
+const int A2dpSink::kSingletonInstanceId = 0;
+
+A2dpSink::A2dpSink(const Uuid& uuid) : app_identifier_(uuid) {
+ hal::BluetoothAvInterface::Get()->AddA2dpSinkObserver(this);
+}
+
+A2dpSink::~A2dpSink() {
+ hal::BluetoothAvInterface::Get()->RemoveA2dpSinkObserver(this);
+}
+
+const Uuid& A2dpSink::GetAppIdentifier() const { return app_identifier_; }
+
+int A2dpSink::GetInstanceId() const { return kSingletonInstanceId; }
+
+void A2dpSink::SetDelegate(Delegate* delegate) {
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool A2dpSink::Enable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return hal::BluetoothAvInterface::Get()->A2dpSinkEnable();
+}
+
+void A2dpSink::Disable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()->A2dpSinkDisable();
+}
+
+bool A2dpSink::Connect(const std::string& device_address) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status =
+ hal::BluetoothAvInterface::Get()->GetA2dpSinkHALInterface()->connect(
+ addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to connect";
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpSink::Disconnect(const std::string& device_address) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status =
+ hal::BluetoothAvInterface::Get()->GetA2dpSinkHALInterface()->disconnect(
+ addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disconnect";
+ return false;
+ }
+
+ return true;
+}
+
+void A2dpSink::SetAudioFocusState(int focus_state) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()
+ ->GetA2dpSinkHALInterface()
+ ->set_audio_focus_state(focus_state);
+}
+
+void A2dpSink::SetAudioTrackGain(float gain) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()
+ ->GetA2dpSinkHALInterface()
+ ->set_audio_track_gain(gain);
+}
+
+void A2dpSink::ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+
+ if (delegate_)
+ delegate_->OnConnectionState(device_address, static_cast<int>(state));
+}
+
+void A2dpSink::AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+
+ if (delegate_)
+ delegate_->OnAudioState(device_address, static_cast<int>(state));
+}
+
+void A2dpSink::AudioConfigCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnAudioConfig(device_address, sample_rate, channel_count);
+}
+
+// A2dpSinkFactory implementation
+// ========================================================
+A2dpSinkFactory::A2dpSinkFactory() = default;
+A2dpSinkFactory::~A2dpSinkFactory() = default;
+
+bool A2dpSinkFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
+
+ auto a2dp_sink = base::WrapUnique(new A2dpSink(uuid));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(a2dp_sink));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/a2dp_sink.h b/service/a2dp_sink.h
new file mode 100644
index 0000000..7a62805
--- /dev/null
+++ b/service/a2dp_sink.h
@@ -0,0 +1,103 @@
+//
+// 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/hal/bluetooth_av_interface.h"
+
+namespace bluetooth {
+
+class A2dpSink : public BluetoothInstance,
+ private hal::BluetoothAvInterface::A2dpSinkObserver {
+ 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,
+ uint32_t sample_rate, uint8_t channel_count) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ ~A2dpSink() override;
+
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothInstance implementation:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable();
+ void Disable();
+ bool Connect(const std::string& device_address);
+ bool Disconnect(const std::string& device_address);
+ void SetAudioFocusState(int focus_state);
+ void SetAudioTrackGain(float gain);
+
+ private:
+ friend class A2dpSinkFactory;
+
+ explicit A2dpSink(const Uuid& uuid);
+
+ // hal::bluetooth::hal::BluetoothAvInterface::Observer implementation:
+ void ConnectionStateCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) override;
+ void AudioStateCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) override;
+ void AudioConfigCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr, uint32_t sample_rate,
+ uint8_t channel_count) override;
+
+ // See getters above for documentation.
+ const Uuid app_identifier_;
+
+ std::mutex mutex_;
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(A2dpSink);
+};
+
+class A2dpSinkFactory : public BluetoothInstanceFactory {
+ public:
+ A2dpSinkFactory();
+ ~A2dpSinkFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/adapter.cc b/service/adapter.cc
index 853ffdf..abda22d 100644
--- a/service/adapter.cc
+++ b/service/adapter.cc
@@ -24,6 +24,8 @@
#include <base/logging.h>
#include <base/observer_list.h>
+#include "service/a2dp_sink.h"
+#include "service/avrcp_control.h"
#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
@@ -33,11 +35,97 @@
#include "service/low_energy_client.h"
#include "service/low_energy_scanner.h"
+using android::String16;
using std::lock_guard;
using std::mutex;
namespace bluetooth {
+namespace {
+
+RemoteDeviceProps ParseRemoteDeviceProps(int num_properties,
+ bt_property_t* properties) {
+ android::String16 name;
+ android::String16 address;
+ std::vector<Uuid> service_uuids;
+ int32_t device_class = 0;
+ int32_t device_type = 0;
+ int32_t rssi = 0;
+
+ for (int i = 0; i < num_properties; ++i) {
+ bt_property_t* property = properties + i;
+ switch (property->type) {
+ case BT_PROPERTY_BDNAME: {
+ if (property->len < 0) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_BDNAME";
+ break;
+ }
+ bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
+ name = String16(reinterpret_cast<char*>(hal_name->name));
+ break;
+ }
+ case BT_PROPERTY_BDADDR: {
+ if (property->len != sizeof(RawAddress)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_BDADDR";
+ break;
+ }
+ std::string remote_bdaddr_str =
+ BtAddrString(reinterpret_cast<RawAddress*>(property->val));
+ address = String16(remote_bdaddr_str.c_str(), remote_bdaddr_str.size());
+ break;
+ }
+ case BT_PROPERTY_UUIDS: {
+ if (property->len < 0) {
+ NOTREACHED() << "Negative length on BT_PROPERTY_UUIDS:";
+ break;
+ }
+ if (property->len % sizeof(Uuid::UUID128Bit) != 0) {
+ NOTREACHED() << "Trailing bytes on BT_PROPERTY_UUIDS:";
+ }
+ auto uuids = static_cast<const Uuid::UUID128Bit*>(property->val);
+
+ for (size_t i = 0; i < property->len / sizeof(Uuid::UUID128Bit); ++i) {
+ service_uuids.push_back(Uuid::From128BitLE(uuids[i]));
+ }
+ break;
+ }
+ case BT_PROPERTY_CLASS_OF_DEVICE: {
+ if (property->len != sizeof(int32_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_CLASS_OF_DEVICE";
+ break;
+ }
+ device_class = *reinterpret_cast<const int32_t*>(property->val);
+ break;
+ }
+ case BT_PROPERTY_TYPE_OF_DEVICE: {
+ if (property->len != sizeof(int32_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_TYPE_OF_DEVICE";
+ break;
+ }
+ device_type = *reinterpret_cast<const int32_t*>(property->val);
+ break;
+ }
+ case BT_PROPERTY_REMOTE_RSSI: {
+ if (property->len != sizeof(int8_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_REMOTE_RSSI";
+ break;
+ }
+ rssi = *reinterpret_cast<const int8_t*>(property->val);
+ break;
+ }
+ default:
+ VLOG(1) << "Unhandled adapter property: "
+ << BtPropertyText(property->type);
+ break;
+ }
+ }
+
+ return RemoteDeviceProps(name, address, service_uuids, device_class,
+ device_type, rssi);
+}
+
+} // namespace
+
// static
const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
// static
@@ -69,6 +157,41 @@
// Default implementation does nothing
}
+void Adapter::Observer::OnScanEnableChanged(Adapter* adapter,
+ bool scan_enabled) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnSspRequest(Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnBondStateChanged(Adapter* adapter, int status,
+ const std::string& device_address,
+ int state) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnGetBondedDevices(
+ Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnGetRemoteDeviceProperties(
+ Adapter* adapter, int status, const std::string& device_address,
+ const RemoteDeviceProps& properties) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnDeviceFound(Adapter* adapter,
+ const RemoteDeviceProps& properties) {
+ // Default implementation does nothing
+}
+
// The real Adapter implementation used in production.
class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
public:
@@ -78,6 +201,8 @@
name_(kDefaultName) {
memset(&local_le_features_, 0, sizeof(local_le_features_));
hal::BluetoothInterface::Get()->AddObserver(this);
+ a2dp_sink_factory_.reset(new A2dpSinkFactory);
+ avrcp_control_factory_.reset(new AvrcpControlFactory);
ble_client_factory_.reset(new LowEnergyClientFactory(*this));
ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
@@ -183,6 +308,84 @@
std::string GetAddress() const override { return address_.Get(); }
+ bool SetScanMode(int scan_mode) override {
+ switch (scan_mode) {
+ case BT_SCAN_MODE_NONE:
+ case BT_SCAN_MODE_CONNECTABLE:
+ case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ break;
+ default:
+ LOG(ERROR) << "Unknown scan mode: " << scan_mode;
+ return false;
+ }
+
+ auto bd_scanmode = static_cast<bt_scan_mode_t>(scan_mode);
+
+ if (!SetAdapterProperty(BT_PROPERTY_ADAPTER_SCAN_MODE, &bd_scanmode,
+ sizeof(bd_scanmode))) {
+ LOG(ERROR) << "Failed to set scan mode to : " << scan_mode;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool SetScanEnable(bool scan_enable) override {
+ if (scan_enable) {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->start_discovery();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to enable scanning";
+ return false;
+ }
+ } else {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->cancel_discovery();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disable scanning";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool SspReply(const std::string& device_address, int variant, bool accept,
+ int32_t pass_key) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->ssp_reply(
+ &addr, static_cast<bt_ssp_variant_t>(variant), accept, pass_key);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send SSP response - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CreateBond(const std::string& device_address, int transport) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->create_bond(
+ &addr, transport);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to create bond - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
bool IsMultiAdvertisementSupported() override {
lock_guard<mutex> lock(local_le_features_lock_);
return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
@@ -209,6 +412,64 @@
kMinOffloadedScanStorageBytes;
}
+ bool GetBondedDevices() override {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_property(
+ BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to get bonded devices. Status: "
+ << BtStatusText(static_cast<bt_status_t>(status));
+ return false;
+ }
+
+ return true;
+ }
+
+ bool RemoveBond(const std::string& device_address) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->remove_bond(&addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send remove bond - status: "
+ << BtStatusText(static_cast<bt_status_t>(status));
+ return false;
+ }
+
+ return true;
+ }
+
+ bool GetRemoteDeviceProperties(const std::string& device_address) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()
+ ->GetHALInterface()
+ ->get_remote_device_properties(&addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send GetRemoteDeviceProperties - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
+ A2dpSinkFactory* GetA2dpSinkFactory() const override {
+ return a2dp_sink_factory_.get();
+ }
+
+ AvrcpControlFactory* GetAvrcpControlFactory() const override {
+ return avrcp_control_factory_.get();
+ }
+
LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
return ble_client_factory_.get();
}
@@ -257,6 +518,16 @@
if (status != BT_STATUS_SUCCESS) {
LOG(ERROR) << "status: " << BtStatusText(status);
+
+ for (int i = 0; i < num_properties; ++i) {
+ bt_property_t* property = properties + i;
+ if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetBondedDevices(this, status, {});
+ }
+ }
+ }
return;
}
@@ -290,6 +561,29 @@
LOG(INFO) << "Supported LE features updated";
break;
}
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES: {
+ if (property->len < 0) {
+ NOTREACHED() << "Negative property length";
+ break;
+ }
+ auto addrs = reinterpret_cast<const RawAddress*>(property->val);
+ if (property->len % sizeof(addrs[0]) != 0) {
+ LOG(ERROR) << "Invalid property length: " << property->len;
+ // TODO(bcf): Seems to be a bug where we hit this somewhat
+ // frequently.
+ break;
+ }
+ std::vector<std::string> str_addrs;
+
+ for (size_t i = 0; i < property->len / sizeof(addrs[0]); ++i)
+ str_addrs.push_back(BtAddrString(addrs + i));
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetBondedDevices(this, status, str_addrs);
+ }
+ break;
+ }
default:
VLOG(1) << "Unhandled adapter property: "
<< BtPropertyText(property->type);
@@ -300,9 +594,84 @@
}
}
- void SSPRequestCallback(RawAddress*, bt_bdname_t*, uint32_t, bt_ssp_variant_t,
+ void RemoteDevicePropertiesCallback(bt_status_t status,
+ RawAddress* remote_bdaddr,
+ int num_properties,
+ bt_property_t* properties) override {
+ std::string device_address = BtAddrString(remote_bdaddr);
+ if (status != BT_STATUS_SUCCESS) {
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetRemoteDeviceProperties(this, status, device_address,
+ RemoteDeviceProps());
+ }
+ return;
+ }
+
+ RemoteDeviceProps props =
+ ParseRemoteDeviceProps(num_properties, properties);
+
+ std::string remote_bdaddr_str = BtAddrString(remote_bdaddr);
+ android::String16 address =
+ String16(remote_bdaddr_str.c_str(), remote_bdaddr_str.size());
+ props.set_address(address);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetRemoteDeviceProperties(this, status, device_address, props);
+ }
+ }
+
+ void DeviceFoundCallback(int num_properties,
+ bt_property_t* properties) override {
+ RemoteDeviceProps props =
+ ParseRemoteDeviceProps(num_properties, properties);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnDeviceFound(this, props);
+ }
+ }
+
+ void DiscoveryStateChangedCallback(bt_discovery_state_t state) override {
+ bool enabled = false;
+ switch (state) {
+ case BT_DISCOVERY_STOPPED:
+ enabled = false;
+ break;
+ case BT_DISCOVERY_STARTED:
+ enabled = true;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnScanEnableChanged(this, enabled);
+ }
+ }
+
+ void SSPRequestCallback(RawAddress* remote_bdaddr, bt_bdname_t* bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant,
uint32_t pass_key) override {
- LOG(INFO) << "Passkey is: " << pass_key;
+ std::string device_address = BtAddrString(remote_bdaddr);
+ std::string name = reinterpret_cast<char*>(bd_name->name);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnSspRequest(this, device_address, name, cod, pairing_variant,
+ pass_key);
+ }
+ }
+
+ void BondStateChangedCallback(bt_status_t status, RawAddress* remote_bdaddr,
+ bt_bond_state_t state) override {
+ std::string device_address = BtAddrString(remote_bdaddr);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnBondStateChanged(this, status, device_address, state);
+ }
}
void AclStateChangedCallback(bt_status_t status,
@@ -392,6 +761,12 @@
std::mutex connected_devices_lock_;
std::unordered_set<std::string> connected_devices_;
+ // Factory used to create per-app A2dpSink instances.
+ std::unique_ptr<A2dpSinkFactory> a2dp_sink_factory_;
+
+ // Factory used to create per-app AvrcpControl instances.
+ std::unique_ptr<AvrcpControlFactory> avrcp_control_factory_;
+
// Factory used to create per-app LowEnergyClient instances.
std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
diff --git a/service/adapter.h b/service/adapter.h
index 3becaae..032f1d9 100644
--- a/service/adapter.h
+++ b/service/adapter.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// Copyright (C) 2015 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,13 +17,18 @@
#pragma once
#include <memory>
+#include <string>
+#include <vector>
#include <base/macros.h>
#include "service/common/bluetooth/adapter_state.h"
+#include "service/common/bluetooth/remote_device_props.h"
namespace bluetooth {
+class A2dpSinkFactory;
+class AvrcpControlFactory;
class GattClientFactory;
class GattServerFactory;
class LowEnergyAdvertiserFactory;
@@ -61,6 +66,34 @@
// true and vice versa.
virtual void OnDeviceConnectionStateChanged(
Adapter* adapter, const std::string& device_address, bool connected);
+
+ // Called when scanning is enabled or disabled.
+ virtual void OnScanEnableChanged(Adapter* adapter, bool scan_enabled);
+
+ // Called when a SSP pairing request comes from a remote device.
+ virtual void OnSspRequest(Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key);
+
+ // Called when a remote device bond state changes.
+ virtual void OnBondStateChanged(Adapter* adapter, int status,
+ const std::string& device_address,
+ int state);
+
+ // Called in response to |GetBondedDevices|.
+ virtual void OnGetBondedDevices(
+ Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices);
+
+ // Called in response to |GetRemoteDeviceProperties|.
+ virtual void OnGetRemoteDeviceProperties(Adapter* adapter, int status,
+ const std::string& device_address,
+ const RemoteDeviceProps& props);
+
+ // Called when a device is found through scanning.
+ virtual void OnDeviceFound(Adapter* adapter,
+ const RemoteDeviceProps& props);
};
// Returns an Adapter implementation to be used in production. Don't use these
@@ -103,6 +136,19 @@
// Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
virtual std::string GetAddress() const = 0;
+ // Set discoverability mode.
+ virtual bool SetScanMode(int scan_mode) = 0;
+
+ // Enable or disable discoverability.
+ virtual bool SetScanEnable(bool scan_enable) = 0;
+
+ // Reply to an SSP request received in |OnSspRequest|.
+ virtual bool SspReply(const std::string& device_address, int variant,
+ bool accept, int32_t pass_key) = 0;
+
+ // Create a bond with device specified by |device_address|.
+ virtual bool CreateBond(const std::string& device_address, int transport) = 0;
+
// Returns true if the local adapter supports the Low-Energy
// multi-advertisement feature.
virtual bool IsMultiAdvertisementSupported() = 0;
@@ -122,6 +168,26 @@
// Returns true if hardware-backed batch scanning is supported.
virtual bool IsOffloadedScanBatchingSupported() = 0;
+ // When the stack call completes, |OnGetBondedDevices| will be called.
+ virtual bool GetBondedDevices() = 0;
+
+ // When the stack call completets, |OnBondStateChanged| will be called.
+ virtual bool RemoveBond(const std::string& device_address) = 0;
+
+ // When the stack call completets, |OnGetRemoteDeviceProperties| will be
+ // called.
+ virtual bool GetRemoteDeviceProperties(const std::string& device_address) = 0;
+
+ // Returns a pointer to the A2dpSinkFactory. This can be used to
+ // register per-application A2dpSinkClient instances to perform A2DP sink
+ // operations.
+ virtual A2dpSinkFactory* GetA2dpSinkFactory() 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 LowEnergyClientFactory. This can be used to
// register per-application LowEnergyClient instances to perform BLE GAP
// operations.
diff --git a/service/avrcp_control.cc b/service/avrcp_control.cc
new file mode 100644
index 0000000..7692400
--- /dev/null
+++ b/service/avrcp_control.cc
@@ -0,0 +1,232 @@
+//
+// Copyright 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/avrcp_control.h"
+
+#include <cerrno>
+#include <climits>
+#include <string>
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+#include <base/strings/string_number_conversions.h>
+
+#include "service/logging_helpers.h"
+
+#include "stack/include/avrc_defs.h"
+
+using android::String16;
+
+namespace bluetooth {
+
+AvrcpControl::AvrcpControl(const Uuid& uuid, int control_id)
+ : app_identifier_(uuid), control_id_(control_id) {
+ hal::BluetoothAvrcpInterface::Get()->AddControlObserver(this);
+}
+
+AvrcpControl::~AvrcpControl() {
+ hal::BluetoothAvrcpInterface::Get()->RemoveControlObserver(this);
+}
+
+const Uuid& AvrcpControl::GetAppIdentifier() const { return app_identifier_; }
+
+int AvrcpControl::GetInstanceId() const { return control_id_; }
+
+void AvrcpControl::SetDelegate(Delegate* delegate) {
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool AvrcpControl::Enable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return hal::BluetoothAvrcpInterface::Get()->AvrcpControlEnable();
+}
+
+void AvrcpControl::Disable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvrcpInterface::Get()->AvrcpControlDisable();
+}
+
+bool AvrcpControl::SendPassThroughCommand(const std::string& device_address,
+ uint8_t key_code, bool key_pressed) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ uint8_t key_state = key_pressed ? AVRC_STATE_PRESS : AVRC_STATE_RELEASE;
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->send_pass_through_cmd(addr, key_code, key_state);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send passthrough command";
+ return false;
+ }
+
+ return true;
+}
+
+bool AvrcpControl::SetAbsVolumeResponse(const std::string& device_address,
+ int32_t abs_vol, int32_t label) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->set_volume_rsp(addr, abs_vol, label);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send set absolute volume response";
+ return false;
+ }
+
+ return true;
+}
+
+bool AvrcpControl::RegisterForAbsVolumeCallbackResponse(
+ const std::string& device_address, int32_t response_type, int32_t abs_vol,
+ int32_t label) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->register_abs_vol_rsp(
+ addr, static_cast<btrc_notification_type_t>(response_type),
+ abs_vol, label);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR)
+ << "Failed to send send register for absolute volume change callback";
+ return false;
+ }
+
+ return true;
+}
+
+void AvrcpControl::ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnConnectionState(rc_connect, bt_connect, device_address);
+}
+
+void AvrcpControl::CtrlSetabsvolCmdCallback(const RawAddress& bd_addr,
+ uint8_t abs_vol, uint8_t label) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnSetAbsVolumeRequest(device_address, abs_vol, label);
+}
+
+void AvrcpControl::CtrlRegisternotificationAbsVolCallback(
+ const RawAddress& bd_addr, uint8_t label) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnRegisterForAbsVolumeCallbackRequest(device_address, label);
+}
+
+void AvrcpControl::CtrlTrackChangedCallback(const RawAddress& bd_addr,
+ uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ std::string device_address = BtAddrString(&bd_addr);
+
+ String16 title;
+ String16 artist;
+ String16 album;
+ String16 genre;
+ int track_num = -1;
+ int num_tracks = -1;
+ int play_time = -1;
+
+ for (size_t i = 0; i < num_attr; ++i) {
+ auto attr_text = reinterpret_cast<char*>(p_attrs[i].text);
+ switch (p_attrs[i].attr_id) {
+ case BTRC_MEDIA_ATTR_ID_TITLE:
+ title = String16(attr_text);
+ break;
+ case BTRC_MEDIA_ATTR_ID_ARTIST:
+ artist = String16(attr_text);
+ break;
+ case BTRC_MEDIA_ATTR_ID_ALBUM:
+ album = String16(attr_text);
+ break;
+ case BTRC_MEDIA_ATTR_ID_TRACK_NUM:
+ if (!base::StringToInt(attr_text, &track_num)) {
+ LOG(ERROR) << "Failed to parse track number";
+ }
+ break;
+ case BTRC_MEDIA_ATTR_ID_NUM_TRACKS:
+ if (!base::StringToInt(attr_text, &num_tracks)) {
+ LOG(ERROR) << "Failed to parse number of tracks";
+ }
+ break;
+ case BTRC_MEDIA_ATTR_ID_GENRE:
+ genre = String16(attr_text);
+ break;
+ case BTRC_MEDIA_ATTR_ID_PLAYING_TIME:
+ if (!base::StringToInt(attr_text, &play_time)) {
+ LOG(ERROR) << "Failed to parse playing time";
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ const AvrcpMediaAttr attr(title, artist, album, genre, track_num, num_tracks,
+ play_time);
+
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_) delegate_->OnTrackChanged(device_address, attr);
+}
+
+// AvrcpControlFactory implementation
+// ========================================================
+
+AvrcpControlFactory::AvrcpControlFactory() = default;
+AvrcpControlFactory::~AvrcpControlFactory() = default;
+
+bool AvrcpControlFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
+
+ int control_id = next_control_id_++;
+ std::unique_ptr<AvrcpControl> hf_client(new AvrcpControl(uuid, control_id));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(hf_client));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/avrcp_control.h b/service/avrcp_control.h
new file mode 100644
index 0000000..7cde24d
--- /dev/null
+++ b/service/avrcp_control.h
@@ -0,0 +1,135 @@
+//
+// 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 "base/macros.h"
+
+#include "bluetooth/uuid.h"
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/avrcp_media_attr.h"
+#include "service/common/bluetooth/service.h"
+#include "service/hal/bluetooth_avrcp_interface.h"
+
+namespace bluetooth {
+
+class AvrcpControl : public BluetoothInstance,
+ private hal::BluetoothAvrcpInterface::ControlObserver {
+ public:
+ class Delegate {
+ public:
+ virtual void OnConnectionState(bool rc_connect, bool bt_connect,
+ const std::string& device_address) = 0;
+
+ virtual void OnTrackChanged(const std::string& device_address,
+ const AvrcpMediaAttr& attr) = 0;
+
+ virtual void OnSetAbsVolumeRequest(const std::string& device_address,
+ int32_t abs_vol, int32_t label) = 0;
+
+ virtual void OnRegisterForAbsVolumeCallbackRequest(
+ const std::string& device_address, int32_t label) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // The destructor automatically unregisters this instance from the stack.
+ ~AvrcpControl() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // AvrcpControl instance.
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothClientInstace overrides:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable();
+ void Disable();
+
+ // Send a remote control button command. Commands which can be sent
+ // are defined here:
+ // http://1394ta.org/wp-content/uploads/2015/07/2007001.pdf
+ bool SendPassThroughCommand(const std::string& device_address,
+ uint8_t key_code, bool key_pressed);
+
+ // Send a response to a request to change absolute volume.
+ bool SetAbsVolumeResponse(const std::string& device_address, int32_t abs_vol,
+ int32_t label);
+
+ // Send a response to a register for absolute volume change callback.
+ bool RegisterForAbsVolumeCallbackResponse(const std::string& device_address,
+ int32_t response_type,
+ int32_t abs_vol, int32_t label);
+
+ private:
+ friend class AvrcpControlFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ AvrcpControl(const Uuid& uuid, int control_id);
+
+ // hal::BluetoothAvrcpInterface::ControlObserver implementation:
+ void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) override;
+ void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr, uint8_t abs_vol,
+ uint8_t label) override;
+ void CtrlRegisternotificationAbsVolCallback(const RawAddress& bd_addr,
+ uint8_t label) override;
+ void CtrlTrackChangedCallback(const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) override;
+
+ // See getters for documentation.
+ const Uuid app_identifier_;
+ const int control_id_;
+
+ // Mutex that synchronizes access to the entries below.
+ std::mutex mutex_;
+
+ // Raw handle to the Delegate, which must outlive this AvrcpControl instance.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(AvrcpControl);
+};
+
+// AvrcpControlFactory is used to register and obtain a per-application
+// AvrcpControl
+// instance. Users should call RegisterClient to obtain their own unique
+// AvrcpControl instance that has been registered with the Bluetooth stack.
+class AvrcpControlFactory
+ : public BluetoothInstanceFactory,
+ private hal::BluetoothAvrcpInterface::ControlObserver {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ AvrcpControlFactory();
+ ~AvrcpControlFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ std::atomic<int> next_control_id_{0};
+ DISALLOW_COPY_AND_ASSIGN(AvrcpControlFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/client/main.cc b/service/client/main.cc
index e3b4c92..e89d701 100644
--- a/service/client/main.cc
+++ b/service/client/main.cc
@@ -161,6 +161,60 @@
return Status::ok();
}
+ Status OnSspRequest(const String16& device_address,
+ const String16& device_name, int32_t cod,
+ int32_t pairing_variant, int32_t pass_key) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnGetBondedDevices(
+ int32_t status,
+ const ::std::vector<String16>& device_addresses) override {
+ BeginAsyncOut();
+ std::cout << "Bonded devices:\n";
+ for (const auto& device_address : device_addresses) {
+ std::cout << " " << device_address << "\n";
+ }
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ Status OnBondStateChanged(int32_t status, const String16& device_address,
+ int32_t state) override {
+ BeginAsyncOut();
+ std::cout << COLOR_BOLDWHITE "Device address: " << COLOR_BOLDYELLOW "["
+ << device_address << " bond state: " << state << " ] "
+ << COLOR_BOLDWHITE "- status: "
+ << (status == 0 ? "SUCCESS" : "FAIL") << COLOR_OFF;
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ Status OnGetRemoteDeviceProperties(
+ int32_t status, const String16& device_address,
+ const android::bluetooth::BluetoothRemoteDeviceProps& props) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnDeviceFound(
+ const android::bluetooth::BluetoothRemoteDeviceProps& props) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnDeviceConnectionStateChanged(const String16& device_address,
+ bool connected) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnScanEnableChanged(bool scan_enabled) override {
+ // no-op
+ return Status::ok();
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
};
diff --git a/service/common/Android.bp b/service/common/Android.bp
index b3fbfc4..b481d19 100644
--- a/service/common/Android.bp
+++ b/service/common/Android.bp
@@ -12,8 +12,10 @@
"bluetooth/adapter_state.cc",
"bluetooth/advertise_data.cc",
"bluetooth/advertise_settings.cc",
+ "bluetooth/avrcp_media_attr.cc",
"bluetooth/characteristic.cc",
"bluetooth/descriptor.cc",
+ "bluetooth/remote_device_props.cc",
"bluetooth/scan_filter.cc",
"bluetooth/scan_result.cc",
"bluetooth/scan_settings.cc",
@@ -38,6 +40,10 @@
header_libs: [ "libbluetooth_headers" ],
srcs: [
"android/bluetooth/IBluetooth.aidl",
+ "android/bluetooth/IBluetoothA2dpSink.aidl",
+ "android/bluetooth/IBluetoothA2dpSinkCallback.aidl",
+ "android/bluetooth/IBluetoothAvrcpControl.aidl",
+ "android/bluetooth/IBluetoothAvrcpControlCallback.aidl",
"android/bluetooth/IBluetoothCallback.aidl",
"android/bluetooth/IBluetoothGattClient.aidl",
"android/bluetooth/IBluetoothGattClientCallback.aidl",
@@ -51,10 +57,12 @@
"android/bluetooth/IBluetoothLowEnergyCallback.aidl",
"android/bluetooth/advertise_data.cc",
"android/bluetooth/advertise_settings.cc",
+ "android/bluetooth/bluetooth_avrcp_media_attr.cc",
"android/bluetooth/bluetooth_gatt_characteristic.cc",
"android/bluetooth/bluetooth_gatt_descriptor.cc",
"android/bluetooth/bluetooth_gatt_included_service.cc",
"android/bluetooth/bluetooth_gatt_service.cc",
+ "android/bluetooth/bluetooth_remote_device_props.cc",
"android/bluetooth/scan_filter.cc",
"android/bluetooth/scan_result.cc",
"android/bluetooth/scan_settings.cc",
diff --git a/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl b/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl
new file mode 100644
index 0000000..03355ac
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpMediaAttr cpp_header "android/bluetooth/bluetooth_avrcp_media_attr.h";
diff --git a/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl b/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl
new file mode 100644
index 0000000..db80295
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothRemoteDeviceProps cpp_header "android/bluetooth/bluetooth_remote_device_props.h";
diff --git a/service/common/android/bluetooth/IBluetooth.aidl b/service/common/android/bluetooth/IBluetooth.aidl
index cc1e015..9223afb 100644
--- a/service/common/android/bluetooth/IBluetooth.aidl
+++ b/service/common/android/bluetooth/IBluetooth.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -22,6 +22,8 @@
import android.bluetooth.IBluetoothLeScanner;
import android.bluetooth.IBluetoothGattClient;
import android.bluetooth.IBluetoothGattServer;
+import android.bluetooth.IBluetoothA2dpSink;
+import android.bluetooth.IBluetoothAvrcpControl;
import android.bluetooth.UUID;
@@ -36,6 +38,17 @@
UUID[] GetUUIDs();
boolean SetName(String name);
String GetName();
+ boolean SetScanMode(int scan_mode);
+ boolean SetScanEnable(boolean scan_enable);
+ boolean SspReply(
+ String device_address,
+ int variant,
+ boolean accept,
+ int passkey);
+ boolean CreateBond(String device_address, int transport);
+ boolean GetBondedDevices();
+ boolean RemoveBond(String device_address);
+ boolean GetRemoteDeviceProperties(String device_address);
void RegisterCallback(IBluetoothCallback callback);
void UnregisterCallback(IBluetoothCallback callback);
@@ -47,4 +60,6 @@
IBluetoothLeScanner GetLeScannerInterface();
IBluetoothGattClient GetGattClientInterface();
IBluetoothGattServer GetGattServerInterface();
+ IBluetoothA2dpSink GetA2dpSinkInterface();
+ IBluetoothAvrcpControl GetAvrcpControlInterface();
}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSink.aidl b/service/common/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..dec7d28
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothA2dpSinkCallback;
+
+interface IBluetoothA2dpSink {
+ boolean Register(in IBluetoothA2dpSinkCallback callback);
+ void Unregister();
+
+ boolean Enable();
+ boolean Disable();
+ boolean Connect(String device_address);
+ boolean Disconnect(String device_address);
+ boolean SetAudioFocusState(int state);
+ boolean SetAudioTrackGain(float gain);
+}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl b/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl
new file mode 100644
index 0000000..e12be24
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothA2dpSinkCallback {
+ void OnRegistered(int status);
+ void OnConnectionState(String device_address, int state);
+ void OnAudioState(String device_address, int state);
+ void OnAudioConfig(String device_address, int sample_rate, int channel_count);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl b/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl
new file mode 100644
index 0000000..0e65a71
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothAvrcpControlCallback;
+
+interface IBluetoothAvrcpControl {
+ boolean Register(in IBluetoothAvrcpControlCallback callback);
+ void Unregister(int id);
+ void UnregisterAll();
+
+ boolean Enable(int id);
+ boolean Disable(int id);
+
+ boolean SendPassThroughCommand(int id, String device_address,
+ int key_code, boolean key_pressed);
+
+ boolean SetAbsVolumeResponse(int id, String device_address, int abs_vol,
+ int label);
+
+ boolean RegisterForAbsVolumeCallbackResponse(int id, String device_address,
+ int response_type, int abs_vol, int label);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl b/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl
new file mode 100644
index 0000000..68f0db2
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAvrcpMediaAttr;
+
+oneway interface IBluetoothAvrcpControlCallback {
+ void OnRegistered(int status, int id);
+ void OnConnectionState(
+ boolean rc_connect,
+ boolean bt_connect,
+ String device_address);
+
+ void OnTrackChanged(String device_address, in BluetoothAvrcpMediaAttr track_info);
+ void OnSetAbsVolumeRequest(String device_address, int abs_vol, int label);
+ void OnRegisterForAbsVolumeCallbackRequest(String device_address, int label);
+}
diff --git a/service/common/android/bluetooth/IBluetoothCallback.aidl b/service/common/android/bluetooth/IBluetoothCallback.aidl
index 96b7cdc..a83d5d8 100644
--- a/service/common/android/bluetooth/IBluetoothCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -16,6 +16,26 @@
package android.bluetooth;
+import android.bluetooth.BluetoothRemoteDeviceProps;
+
oneway interface IBluetoothCallback {
- void OnBluetoothStateChange(int prev_state, int new_state);
+ void OnBluetoothStateChange(int prev_state, int new_state);
+ void OnScanEnableChanged(boolean scan_enabled);
+ void OnDeviceConnectionStateChanged(
+ String device_address,
+ boolean connected);
+ void OnSspRequest(
+ String device_address,
+ String device_name,
+ int cod,
+ int pairing_variant,
+ int pass_key);
+ void OnGetBondedDevices(int status, in String[] device_addresses);
+ void OnBondStateChanged(int status, String device_address, int state);
+ void OnGetRemoteDeviceProperties(
+ int status,
+ String device_address,
+ in BluetoothRemoteDeviceProps props);
+ void OnDeviceFound(
+ in BluetoothRemoteDeviceProps props);
}
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc
new file mode 100644
index 0000000..18c10b1
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc
@@ -0,0 +1,84 @@
+//
+// Copyright 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 "android/bluetooth/bluetooth_avrcp_media_attr.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothAvrcpMediaAttr::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeString16(title_);
+ if (status != OK) return status;
+
+ status = parcel->writeString16(artist_);
+ if (status != OK) return status;
+
+ status = parcel->writeString16(album_);
+ if (status != OK) return status;
+
+ status = parcel->writeString16(genre_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(track_num_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(num_tracks_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(play_time_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothAvrcpMediaAttr::readFromParcel(const Parcel* parcel) {
+ status_t status = parcel->readString16(&title_);
+ if (status != OK) return status;
+
+ status = parcel->readString16(&artist_);
+ if (status != OK) return status;
+
+ status = parcel->readString16(&album_);
+ if (status != OK) return status;
+
+ status = parcel->readString16(&genre_);
+ if (status != OK) return status;
+
+ int32_t tmp;
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ track_num_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ num_tracks_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ play_time_ = tmp;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h
new file mode 100644
index 0000000..d41fef6
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h
@@ -0,0 +1,57 @@
+//
+// 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/avrcp_media_attr.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothAvrcpMediaAttr : public Parcelable,
+ public ::bluetooth::AvrcpMediaAttr {
+ public:
+ BluetoothAvrcpMediaAttr() = default;
+ BluetoothAvrcpMediaAttr(const ::bluetooth::AvrcpMediaAttr& other)
+ : ::bluetooth::AvrcpMediaAttr(other) {} // NOLINT(implicit)
+ BluetoothAvrcpMediaAttr(const BluetoothAvrcpMediaAttr& other)
+ : ::bluetooth::AvrcpMediaAttr(other) {} // NOLINT(implicit)
+ ~BluetoothAvrcpMediaAttr() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_remote_device_props.cc b/service/common/android/bluetooth/bluetooth_remote_device_props.cc
new file mode 100644
index 0000000..190fa94
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_remote_device_props.cc
@@ -0,0 +1,86 @@
+//
+// Copyright 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 "android/bluetooth/bluetooth_remote_device_props.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include "android/bluetooth/uuid.h"
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothRemoteDeviceProps::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeString16(name_);
+ if (status != OK) return status;
+
+ status = parcel->writeString16(address_);
+ if (status != OK) return status;
+
+ std::vector<UUID> uuids;
+ for (const auto& uuid : service_uuids_) {
+ uuids.push_back(uuid);
+ }
+
+ status = parcel->writeParcelableVector(uuids);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(device_class_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(device_type_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(rssi_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothRemoteDeviceProps::readFromParcel(const Parcel* parcel) {
+ status_t status = parcel->readString16(&name_);
+ if (status != OK) return status;
+
+ status = parcel->readString16(&address_);
+ if (status != OK) return status;
+
+ std::vector<UUID> uuids;
+ status = parcel->readParcelableVector(&uuids);
+ if (status != OK) return status;
+
+ for (const auto& uuid : uuids) {
+ service_uuids_.push_back(uuid.uuid);
+ }
+
+ status = parcel->readInt32(&device_class_);
+ if (status != OK) return status;
+
+ status = parcel->readInt32(&device_type_);
+ if (status != OK) return status;
+
+ status = parcel->readInt32(&rssi_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_remote_device_props.h b/service/common/android/bluetooth/bluetooth_remote_device_props.h
new file mode 100644
index 0000000..e2ad346
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_remote_device_props.h
@@ -0,0 +1,57 @@
+//
+// 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/remote_device_props.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothRemoteDeviceProps : public Parcelable,
+ public ::bluetooth::RemoteDeviceProps {
+ public:
+ BluetoothRemoteDeviceProps() = default;
+ BluetoothRemoteDeviceProps(const ::bluetooth::RemoteDeviceProps& other)
+ : ::bluetooth::RemoteDeviceProps(other) {} // NOLINT(implicit)
+ BluetoothRemoteDeviceProps(const BluetoothRemoteDeviceProps& other)
+ : ::bluetooth::RemoteDeviceProps(other) {} // NOLINT(implicit)
+ ~BluetoothRemoteDeviceProps() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/bluetooth/avrcp_media_attr.cc b/service/common/bluetooth/avrcp_media_attr.cc
new file mode 100644
index 0000000..652ee6c
--- /dev/null
+++ b/service/common/bluetooth/avrcp_media_attr.cc
@@ -0,0 +1,38 @@
+//
+// Copyright 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 "bluetooth/avrcp_media_attr.h"
+
+using android::String16;
+
+namespace bluetooth {
+
+AvrcpMediaAttr::AvrcpMediaAttr() = default;
+AvrcpMediaAttr::AvrcpMediaAttr(const AvrcpMediaAttr& other) = default;
+AvrcpMediaAttr::AvrcpMediaAttr(const String16& title, const String16& artist,
+ const String16& album, const String16& genre,
+ int track_num, int num_tracks, int play_time)
+ : title_(title),
+ artist_(artist),
+ album_(album),
+ genre_(genre),
+ track_num_(track_num),
+ num_tracks_(num_tracks),
+ play_time_(play_time) {}
+
+AvrcpMediaAttr::~AvrcpMediaAttr() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_media_attr.h b/service/common/bluetooth/avrcp_media_attr.h
new file mode 100644
index 0000000..7ae69e2
--- /dev/null
+++ b/service/common/bluetooth/avrcp_media_attr.h
@@ -0,0 +1,51 @@
+//
+// 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 <utils/String16.h>
+
+namespace bluetooth {
+
+class AvrcpMediaAttr {
+ public:
+ AvrcpMediaAttr();
+ AvrcpMediaAttr(const AvrcpMediaAttr& other);
+ AvrcpMediaAttr(const android::String16& title,
+ const android::String16& artist,
+ const android::String16& album, const android::String16& genre,
+ int track_num, int num_tracks, int play_time);
+ ~AvrcpMediaAttr();
+
+ const android::String16& title() const { return title_; }
+ const android::String16& artist() const { return artist_; }
+ const android::String16& album() const { return album_; }
+ const android::String16& genre() const { return genre_; }
+ int track_num() const { return track_num_; }
+ int num_tracks() const { return num_tracks_; }
+ int play_time() const { return play_time_; }
+
+ protected:
+ android::String16 title_;
+ android::String16 artist_;
+ android::String16 album_;
+ android::String16 genre_;
+ int track_num_ = -1;
+ int num_tracks_ = -1;
+ int play_time_ = -1;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/remote_device_props.cc b/service/common/bluetooth/remote_device_props.cc
new file mode 100644
index 0000000..61ee462
--- /dev/null
+++ b/service/common/bluetooth/remote_device_props.cc
@@ -0,0 +1,38 @@
+//
+// Copyright 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 "bluetooth/remote_device_props.h"
+
+using android::String16;
+
+namespace bluetooth {
+
+RemoteDeviceProps::RemoteDeviceProps() = default;
+RemoteDeviceProps::RemoteDeviceProps(const RemoteDeviceProps& other) = default;
+RemoteDeviceProps::RemoteDeviceProps(const android::String16& name,
+ const android::String16& address,
+ const std::vector<Uuid>& service_uuids,
+ int32_t device_class, int32_t device_type,
+ int32_t rssi)
+ : name_(name),
+ address_(address),
+ service_uuids_(service_uuids),
+ device_class_(device_class),
+ device_type_(device_type),
+ rssi_(rssi) {}
+RemoteDeviceProps::~RemoteDeviceProps() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/remote_device_props.h b/service/common/bluetooth/remote_device_props.h
new file mode 100644
index 0000000..f6997ff
--- /dev/null
+++ b/service/common/bluetooth/remote_device_props.h
@@ -0,0 +1,55 @@
+//
+// 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 <vector>
+
+#include <utils/String16.h>
+
+#include "bluetooth/uuid.h"
+
+namespace bluetooth {
+
+class RemoteDeviceProps {
+ public:
+ RemoteDeviceProps();
+ RemoteDeviceProps(const RemoteDeviceProps& other);
+ RemoteDeviceProps(const android::String16& name,
+ const android::String16& address,
+ const std::vector<Uuid>& service_uuids,
+ int32_t device_class, int32_t device_type, int32_t rssi);
+ ~RemoteDeviceProps();
+
+ void set_address(const android::String16& address) { address_ = address; }
+
+ const android::String16& name() const { return name_; }
+ const android::String16& address() const { return address_; }
+ const std::vector<Uuid>& service_uuids() const { return service_uuids_; }
+ int32_t device_class() const { return device_class_; }
+ int32_t device_type() const { return device_type_; }
+ int32_t rssi() const { return rssi_; }
+
+ protected:
+ android::String16 name_;
+ android::String16 address_;
+ std::vector<Uuid> service_uuids_;
+ int32_t device_class_ = -1;
+ int32_t device_type_ = -1;
+ int32_t rssi_ = -1;
+};
+
+} // namespace bluetooth
diff --git a/service/daemon.cc b/service/daemon.cc
index 86a3b5a..a64c2d8 100644
--- a/service/daemon.cc
+++ b/service/daemon.cc
@@ -22,6 +22,8 @@
#include <base/run_loop.h>
#include "service/adapter.h"
+#include "service/hal/bluetooth_av_interface.h"
+#include "service/hal/bluetooth_avrcp_interface.h"
#include "service/hal/bluetooth_gatt_interface.h"
#include "service/hal/bluetooth_interface.h"
#include "service/ipc/ipc_manager.h"
@@ -69,6 +71,10 @@
if (!hal::BluetoothGattInterface::Initialize()) goto failed;
+ if (!hal::BluetoothAvInterface::Initialize()) goto failed;
+
+ if (!hal::BluetoothAvrcpInterface::Initialize()) goto failed;
+
return true;
failed:
@@ -81,6 +87,10 @@
hal::BluetoothGattInterface::CleanUp();
if (hal::BluetoothInterface::IsInitialized())
hal::BluetoothInterface::CleanUp();
+ if (hal::BluetoothAvInterface::IsInitialized())
+ hal::BluetoothAvInterface::CleanUp();
+ if (hal::BluetoothAvrcpInterface::IsInitialized())
+ hal::BluetoothAvrcpInterface::CleanUp();
}
void CleanUpBluetoothStack() {
diff --git a/service/hal/bluetooth_av_interface.cc b/service/hal/bluetooth_av_interface.cc
new file mode 100644
index 0000000..8901e73
--- /dev/null
+++ b/service/hal/bluetooth_av_interface.cc
@@ -0,0 +1,364 @@
+//
+// Copyright 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/hal/bluetooth_av_interface.h"
+
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+BluetoothAvInterface* g_interface = nullptr;
+
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+shared_mutex_impl g_instance_lock;
+
+base::ObserverList<BluetoothAvInterface::A2dpSourceObserver>*
+GetA2dpSourceObservers();
+base::ObserverList<BluetoothAvInterface::A2dpSinkObserver>*
+GetA2dpSinkObservers();
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+} // namespace
+
+void SourceConnectionStateCallback(const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.ConnectionStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SourceAudioStateCallback(const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.AudioStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SourceAudioConfigCallback(
+ const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config,
+ std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+ std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.AudioConfigCallback(g_interface, bd_addr, codec_config,
+ codecs_local_capabilities,
+ codecs_selectable_capabilities);
+ }
+}
+
+void SinkConnectionStateCallback(const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.ConnectionStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SinkAudioStateCallback(const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.AudioStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SinkAudioConfigCallback(const RawAddress& bd_addr, uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.AudioConfigCallback(g_interface, bd_addr, sample_rate,
+ channel_count);
+ }
+}
+
+btav_source_callbacks_t av_source_callbacks = {
+ .size = sizeof(btav_source_callbacks_t),
+ .connection_state_cb = SourceConnectionStateCallback,
+ .audio_state_cb = SourceAudioStateCallback,
+ .audio_config_cb = SourceAudioConfigCallback,
+};
+
+btav_sink_callbacks_t av_sink_callbacks = {
+ .size = sizeof(btav_sink_callbacks_t),
+ .connection_state_cb = SinkConnectionStateCallback,
+ .audio_state_cb = SinkAudioStateCallback,
+ .audio_config_cb = SinkAudioConfigCallback,
+};
+
+class BluetoothAvInterfaceImpl : public BluetoothAvInterface {
+ public:
+ BluetoothAvInterfaceImpl() = default;
+ ~BluetoothAvInterfaceImpl() override {
+ A2dpSinkDisable();
+ A2dpSourceDisable();
+ }
+
+ bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) override {
+ if (source_enabled_) {
+ return true;
+ }
+
+ // Right now we only support one connected audio device.
+ int max_connected_audio_devices = 1;
+ if (hal_source_iface_->init(
+ &av_source_callbacks, max_connected_audio_devices,
+ std::move(codec_priorities)) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL A2DP source interface";
+ return false;
+ }
+ source_enabled_ = true;
+ return true;
+ }
+
+ void A2dpSourceDisable() override {
+ if (!source_enabled_) {
+ return;
+ }
+
+ hal_source_iface_->cleanup();
+ source_enabled_ = false;
+ }
+
+ bool A2dpSinkEnable() override {
+ if (sink_enabled_) {
+ return true;
+ }
+ if (hal_sink_iface_->init(&av_sink_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL A2DP sink interface";
+ return false;
+ }
+ sink_enabled_ = true;
+ return true;
+ }
+
+ void A2dpSinkDisable() override {
+ if (!sink_enabled_) {
+ return;
+ }
+ hal_sink_iface_->cleanup();
+ sink_enabled_ = false;
+ }
+
+ void AddA2dpSourceObserver(A2dpSourceObserver* observer) override {
+ a2dp_source_observers_.AddObserver(observer);
+ }
+
+ void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) override {
+ a2dp_source_observers_.RemoveObserver(observer);
+ }
+
+ void AddA2dpSinkObserver(A2dpSinkObserver* observer) override {
+ a2dp_sink_observers_.AddObserver(observer);
+ }
+
+ void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) override {
+ a2dp_sink_observers_.RemoveObserver(observer);
+ }
+
+ const btav_source_interface_t* GetA2dpSourceHALInterface() override {
+ return hal_source_iface_;
+ }
+
+ const btav_sink_interface_t* GetA2dpSinkHALInterface() override {
+ return hal_sink_iface_;
+ }
+
+ bool Initialize() {
+ const bt_interface_t* bt_iface =
+ BluetoothInterface::Get()->GetHALInterface();
+ CHECK(bt_iface);
+
+ const auto* hal_source_iface =
+ reinterpret_cast<const btav_source_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID));
+ if (!hal_source_iface) {
+ LOG(ERROR) << "Failed to obtain A2DP source interface handle";
+ return false;
+ }
+
+ const auto* hal_sink_iface = reinterpret_cast<const btav_sink_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_SINK_ID));
+ if (!hal_sink_iface) {
+ LOG(ERROR) << "Failed to obtain A2DP sink interface handle";
+ return false;
+ }
+
+ hal_sink_iface_ = hal_sink_iface;
+ hal_source_iface_ = hal_source_iface;
+
+ // Only initialize the sink interface.
+ return A2dpSinkEnable();
+ }
+
+ base::ObserverList<A2dpSourceObserver>* source_observers() {
+ return &a2dp_source_observers_;
+ }
+
+ base::ObserverList<A2dpSinkObserver>* sink_observers() {
+ return &a2dp_sink_observers_;
+ }
+
+ private:
+ base::ObserverList<A2dpSourceObserver> a2dp_source_observers_;
+ base::ObserverList<A2dpSinkObserver> a2dp_sink_observers_;
+
+ const btav_source_interface_t* hal_source_iface_ = nullptr;
+ const btav_sink_interface_t* hal_sink_iface_ = nullptr;
+
+ bool source_enabled_ = false;
+ bool sink_enabled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothAvInterface::A2dpSourceObserver>*
+GetA2dpSourceObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvInterfaceImpl*>(g_interface)
+ ->source_observers();
+}
+
+base::ObserverList<BluetoothAvInterface::A2dpSinkObserver>*
+GetA2dpSinkObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvInterfaceImpl*>(g_interface)->sink_observers();
+}
+
+} // namespace
+
+void BluetoothAvInterface::A2dpSourceObserver::ConnectionStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSourceObserver::AudioStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSourceObserver::AudioConfigCallback(
+ 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) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::ConnectionStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::AudioStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::AudioConfigCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ uint32_t sample_rate, uint8_t channel_count) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothAvInterface::Initialize() {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_interface);
+
+ auto impl = base::MakeUnique<BluetoothAvInterfaceImpl>();
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothAvInterface";
+ return false;
+ }
+
+ g_interface = impl.release();
+ return true;
+}
+
+// static
+void BluetoothAvInterface::CleanUp() {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+
+ delete g_interface;
+ g_interface = nullptr;
+}
+
+// static
+bool BluetoothAvInterface::IsInitialized() {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ return g_interface != nullptr;
+}
+
+// static
+void BluetoothAvInterface::InitializeForTesting(
+ BluetoothAvInterface* test_instance) {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_interface);
+
+ g_interface = test_instance;
+}
+
+// static
+BluetoothAvInterface* BluetoothAvInterface::Get() {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+ return g_interface;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_av_interface.h b/service/hal/bluetooth_av_interface.h
new file mode 100644
index 0000000..9346143
--- /dev/null
+++ b/service/hal/bluetooth_av_interface.h
@@ -0,0 +1,96 @@
+//
+// 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 <base/macros.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+
+#include <vector>
+
+namespace bluetooth {
+namespace hal {
+
+class BluetoothAvInterface {
+ public:
+ class A2dpSourceObserver {
+ public:
+ virtual void ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state);
+ virtual void AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state);
+ virtual void AudioConfigCallback(
+ 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);
+
+ protected:
+ virtual ~A2dpSourceObserver() = default;
+ };
+
+ class A2dpSinkObserver {
+ public:
+ virtual void ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state);
+ virtual void AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state);
+ virtual void AudioConfigCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ uint32_t sample_rate,
+ uint8_t channel_count);
+
+ protected:
+ virtual ~A2dpSinkObserver() = default;
+ };
+
+ static bool Initialize();
+ static void CleanUp();
+ static bool IsInitialized();
+ static void InitializeForTesting(BluetoothAvInterface* test_instance);
+
+ static BluetoothAvInterface* Get();
+
+ virtual bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) = 0;
+ virtual void A2dpSourceDisable() = 0;
+ virtual bool A2dpSinkEnable() = 0;
+ virtual void A2dpSinkDisable() = 0;
+
+ virtual void AddA2dpSourceObserver(A2dpSourceObserver* observer) = 0;
+ virtual void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) = 0;
+ virtual void AddA2dpSinkObserver(A2dpSinkObserver* observer) = 0;
+ virtual void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) = 0;
+
+ virtual const btav_source_interface_t* GetA2dpSourceHALInterface() = 0;
+ virtual const btav_sink_interface_t* GetA2dpSinkHALInterface() = 0;
+
+ protected:
+ BluetoothAvInterface() = default;
+ virtual ~BluetoothAvInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_avrcp_interface.cc b/service/hal/bluetooth_avrcp_interface.cc
new file mode 100644
index 0000000..02e7316
--- /dev/null
+++ b/service/hal/bluetooth_avrcp_interface.cc
@@ -0,0 +1,891 @@
+//
+// Copyright 2015 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/hal/bluetooth_avrcp_interface.h"
+
+#include <mutex>
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::mutex;
+using std::shared_lock;
+using std::unique_lock;
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothAvrcpInterface instance.
+BluetoothAvrcpInterface* g_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+// TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_mutex_impl g_instance_lock;
+
+// Helper for obtaining the observer lists. This is forward declared here
+// and defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothAvrcpInterface::TargetObserver>*
+GetTargetObservers();
+
+base::ObserverList<BluetoothAvrcpInterface::ControlObserver>*
+GetControlObservers();
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+void RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.RemoteFeaturesCallback(bd_addr, features);
+ }
+}
+
+void GetPlayStatusCallback(const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayStatusCallback(bd_addr);
+ }
+}
+
+void ListPlayerAppAttrCallback(const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ListPlayerAppAttrCallback(bd_addr);
+ }
+}
+
+void ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ListPlayerAppValuesCallback(attr_id, bd_addr);
+ }
+}
+
+void GetPlayerAppValueCallback(uint8_t num_attr, btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppValueCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppAttrsTextCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void GetPlayerAppValuesTextCallback(uint8_t attr_id, uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppValuesTextCallback(attr_id, num_val, p_vals, bd_addr);
+ }
+}
+
+void SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetPlayerAppValueCallback(p_vals, bd_addr);
+ }
+}
+
+void GetElementAttrCallback(uint8_t num_attr, btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetElementAttrCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void RegisterNotificationCallback(btrc_event_id_t event_id, uint32_t param,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.RegisterNotificationCallback(event_id, param, bd_addr);
+ }
+}
+
+void VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.VolumeChangeCallback(volume, ctype, bd_addr);
+ }
+}
+
+void PassthroughCmdCallback(int id, int key_state, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.PassthroughCmdCallback(id, key_state, bd_addr);
+ }
+}
+
+void SetAddressedPlayerCallback(uint16_t player_id, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetAddressedPlayerCallback(player_id, bd_addr);
+ }
+}
+
+void SetBrowsedPlayerCallback(uint16_t player_id, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetBrowsedPlayerCallback(player_id, bd_addr);
+ }
+}
+
+void GetFolderItemsCallback(uint8_t scope, uint32_t start_item,
+ uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetFolderItemsCallback(scope, start_item, end_item, num_attr,
+ p_attr_ids, bd_addr);
+ }
+}
+
+void ChangePathCallback(uint8_t direction, uint8_t* folder_uid,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ChangePathCallback(direction, folder_uid, bd_addr);
+ }
+}
+
+void GetItemAttrCallback(uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ uint8_t num_attr, btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetItemAttrCallback(scope, uid, uid_counter, num_attr, p_attrs,
+ bd_addr);
+ }
+}
+
+void PlayItemCallback(uint8_t scope, uint16_t uid_counter, uint8_t* uid,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.PlayItemCallback(scope, uid_counter, uid, bd_addr);
+ }
+}
+
+void GetTotalNumOfItemsCallback(uint8_t scope, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetTotalNumOfItemsCallback(scope, bd_addr);
+ }
+}
+
+void SearchCallback(uint16_t charset_id, uint16_t str_len, uint8_t* p_str,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SearchCallback(str_len, p_str, bd_addr);
+ }
+}
+
+void AddToNowPlayingCallback(uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.AddToNowPlayingCallback(scope, uid, uid_counter, bd_addr);
+ }
+}
+
+void PassthroughRspCallback(const RawAddress& bd_addr, int id, int key_state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.PassthroughRspCallback(bd_addr, id, key_state);
+ }
+}
+
+void GroupnavigationRspCallback(int id, int key_state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.GroupnavigationRspCallback(id, key_state);
+ }
+}
+
+void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.ConnectionStateCallback(rc_connect, bt_connect, bd_addr);
+ }
+}
+
+void CtrlGetrcfeaturesCallback(const RawAddress& bd_addr, int features) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlGetrcfeaturesCallback(bd_addr, features);
+ }
+}
+
+void CtrlSetplayerapplicationsettingRspCallback(const RawAddress& bd_addr,
+ uint8_t accepted) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetplayerapplicationsettingRspCallback(bd_addr, accepted);
+ }
+}
+
+void CtrlPlayerapplicationsettingCallback(
+ const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+ btrc_player_app_ext_attr_t* ext_attrs) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayerapplicationsettingCallback(bd_addr, num_attr, app_attrs,
+ num_ext_attr, ext_attrs);
+ }
+}
+
+void CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& bd_addr, const btrc_player_settings_t& vals) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayerapplicationsettingChangedCallback(bd_addr, vals);
+ }
+}
+
+void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr, uint8_t abs_vol,
+ uint8_t label) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetabsvolCmdCallback(bd_addr, abs_vol, label);
+ }
+}
+
+void CtrlRegisternotificationAbsVolCallback(const RawAddress& bd_addr,
+ uint8_t label) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlRegisternotificationAbsVolCallback(bd_addr, label);
+ }
+}
+
+void CtrlTrackChangedCallback(const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlTrackChangedCallback(bd_addr, num_attr, p_attrs);
+ }
+}
+
+void CtrlPlayPositionChangedCallback(const RawAddress& bd_addr,
+ uint32_t song_len, uint32_t song_pos) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayPositionChangedCallback(bd_addr, song_len, song_pos);
+ }
+}
+
+void CtrlPlayStatusChangedCallback(const RawAddress& bd_addr,
+ btrc_play_status_t play_status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayStatusChangedCallback(bd_addr, play_status);
+ }
+}
+
+void CtrlGetFolderItemsCallback(const RawAddress& bd_addr, btrc_status_t status,
+ const btrc_folder_items_t* folder_items,
+ uint8_t count) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlGetFolderItemsCallback(bd_addr, status, folder_items, count);
+ }
+}
+
+void CtrlChangePathCallback(const RawAddress& bd_addr, uint32_t count) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlChangePathCallback(bd_addr, count);
+ }
+}
+
+void CtrlSetBrowsedPlayerCallback(const RawAddress& bd_addr, uint8_t num_items,
+ uint8_t depth) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetBrowsedPlayerCallback(bd_addr, num_items, depth);
+ }
+}
+
+void CtrlSetAddressedPlayerCallback(const RawAddress& bd_addr, uint8_t status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetAddressedPlayerCallback(bd_addr, status);
+ }
+}
+
+btrc_callbacks_t target_callbacks = {
+ .size = sizeof(btrc_callbacks_t),
+ .remote_features_cb = RemoteFeaturesCallback,
+ .get_play_status_cb = GetPlayStatusCallback,
+ .list_player_app_attr_cb = ListPlayerAppAttrCallback,
+ .list_player_app_values_cb = ListPlayerAppValuesCallback,
+ .get_player_app_value_cb = GetPlayerAppValueCallback,
+ .get_player_app_attrs_text_cb = GetPlayerAppAttrsTextCallback,
+ .get_player_app_values_text_cb = GetPlayerAppValuesTextCallback,
+ .set_player_app_value_cb = SetPlayerAppValueCallback,
+ .get_element_attr_cb = GetElementAttrCallback,
+ .register_notification_cb = RegisterNotificationCallback,
+ .volume_change_cb = VolumeChangeCallback,
+ .passthrough_cmd_cb = PassthroughCmdCallback,
+ .set_addressed_player_cb = SetAddressedPlayerCallback,
+ .set_browsed_player_cb = SetBrowsedPlayerCallback,
+ .get_folder_items_cb = GetFolderItemsCallback,
+ .change_path_cb = ChangePathCallback,
+ .get_item_attr_cb = GetItemAttrCallback,
+ .play_item_cb = PlayItemCallback,
+ .get_total_num_of_items_cb = GetTotalNumOfItemsCallback,
+ .search_cb = SearchCallback,
+ .add_to_now_playing_cb = AddToNowPlayingCallback,
+};
+
+btrc_ctrl_callbacks_t control_callbacks = {
+ .size = sizeof(btrc_ctrl_callbacks_t),
+ .passthrough_rsp_cb = PassthroughRspCallback,
+ .groupnavigation_rsp_cb = GroupnavigationRspCallback,
+ .connection_state_cb = ConnectionStateCallback,
+ .getrcfeatures_cb = CtrlGetrcfeaturesCallback,
+ .setplayerappsetting_rsp_cb = CtrlSetplayerapplicationsettingRspCallback,
+ .playerapplicationsetting_cb = CtrlPlayerapplicationsettingCallback,
+ .playerapplicationsetting_changed_cb =
+ CtrlPlayerapplicationsettingChangedCallback,
+ .setabsvol_cmd_cb = CtrlSetabsvolCmdCallback,
+ .registernotification_absvol_cb = CtrlRegisternotificationAbsVolCallback,
+ .track_changed_cb = CtrlTrackChangedCallback,
+ .play_position_changed_cb = CtrlPlayPositionChangedCallback,
+ .play_status_changed_cb = CtrlPlayStatusChangedCallback,
+ .get_folder_items_cb = CtrlGetFolderItemsCallback,
+ .change_folder_path_cb = CtrlChangePathCallback,
+ .set_browsed_player_cb = CtrlSetBrowsedPlayerCallback,
+ .set_addressed_player_cb = CtrlSetAddressedPlayerCallback,
+};
+
+} // namespace
+
+// BluetoothAvrcpInterface implementation for production.
+class BluetoothAvrcpInterfaceImpl : public BluetoothAvrcpInterface {
+ public:
+ BluetoothAvrcpInterfaceImpl() : control_iface_(nullptr) {}
+
+ ~BluetoothAvrcpInterfaceImpl() override {
+ if (control_iface_) control_iface_->cleanup();
+ }
+
+ bool AvrcpControlEnable() override {
+ if (control_enabled_) {
+ return true;
+ }
+
+ if (control_iface_->init(&control_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL AVRCP control interface";
+ return false;
+ }
+
+ control_enabled_ = true;
+ return true;
+ }
+
+ void AvrcpControlDisable() override {
+ if (!control_enabled_) {
+ return;
+ }
+
+ control_iface_->cleanup();
+ control_enabled_ = false;
+ }
+
+ bool AvrcpTargetEnable() override {
+ if (target_enabled_) {
+ return true;
+ }
+
+ if (target_iface_->init(&target_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL AVRCP target interface";
+ return false;
+ }
+
+ target_enabled_ = true;
+ return true;
+ }
+
+ void AvrcpTargetDisable() override {
+ if (!target_enabled_) {
+ return;
+ }
+
+ target_iface_->cleanup();
+ target_enabled_ = false;
+ }
+
+ void AddTargetObserver(TargetObserver* observer) override {
+ target_observers_.AddObserver(observer);
+ }
+
+ void RemoveTargetObserver(TargetObserver* observer) override {
+ target_observers_.RemoveObserver(observer);
+ }
+
+ void AddControlObserver(ControlObserver* observer) override {
+ control_observers_.AddObserver(observer);
+ }
+
+ void RemoveControlObserver(ControlObserver* observer) override {
+ control_observers_.RemoveObserver(observer);
+ }
+
+ const btrc_interface_t* GetTargetHALInterface() const override {
+ return target_iface_;
+ }
+
+ const btrc_ctrl_interface_t* GetControlHALInterface() const override {
+ return control_iface_;
+ }
+
+ // Initialize the interface.
+ bool Initialize() {
+ const bt_interface_t* bt_iface =
+ BluetoothInterface::Get()->GetHALInterface();
+ CHECK(bt_iface);
+
+ auto* target_iface = reinterpret_cast<const btrc_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_AV_RC_ID));
+ if (!target_iface) {
+ LOG(ERROR) << "Failed to obtain HAL AVRCP target interface handle";
+ return false;
+ }
+
+ auto* control_iface = reinterpret_cast<const btrc_ctrl_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID));
+ if (!control_iface) {
+ LOG(ERROR) << "Failed to obtain HAL AVRCP control interface handle";
+ return false;
+ }
+
+ control_iface_ = control_iface;
+ target_iface_ = target_iface;
+
+ // Only initialize the control interface.
+ return AvrcpControlEnable();
+ }
+
+ base::ObserverList<TargetObserver>* target_observers() {
+ return &target_observers_;
+ }
+
+ base::ObserverList<ControlObserver>* control_observers() {
+ return &control_observers_;
+ }
+
+ private:
+ // List of observers that are interested in notifications from us.
+ // We're not using a base::ObserverListThreadSafe, which it posts observer
+ // events automatically on the origin threads, as we want to avoid that
+ // overhead and simply forward the events to the upper layer.
+ base::ObserverList<TargetObserver> target_observers_;
+ base::ObserverList<ControlObserver> control_observers_;
+
+ // The HAL handle obtained from the shared library. We hold a weak reference
+ // to this since the actual data resides in the shared Bluetooth library.
+ const btrc_interface_t* target_iface_ = nullptr;
+ const btrc_ctrl_interface_t* control_iface_ = nullptr;
+
+ bool control_enabled_ = false;
+ bool target_enabled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothAvrcpInterface::TargetObserver>*
+GetTargetObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvrcpInterfaceImpl*>(g_interface)
+ ->target_observers();
+}
+
+base::ObserverList<BluetoothAvrcpInterface::ControlObserver>*
+GetControlObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvrcpInterfaceImpl*>(g_interface)
+ ->control_observers();
+}
+
+} // namespace
+
+void BluetoothAvrcpInterface::TargetObserver::RemoteFeaturesCallback(
+ const RawAddress& bd_addr, btrc_remote_features_t features) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayStatusCallback(
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ListPlayerAppAttrCallback(
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ListPlayerAppValuesCallback(
+ btrc_player_attr_t attr_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppValueCallback(
+ uint8_t num_attr, btrc_player_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppAttrsTextCallback(
+ uint8_t num_attr, btrc_player_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppValuesTextCallback(
+ uint8_t attr_id, uint8_t num_val, uint8_t* p_vals,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetPlayerAppValueCallback(
+ btrc_player_settings_t* p_vals, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetElementAttrCallback(
+ uint8_t num_attr, btrc_media_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::RegisterNotificationCallback(
+ btrc_event_id_t event_id, uint32_t param, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::VolumeChangeCallback(
+ uint8_t volume, uint8_t ctype, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::PassthroughCmdCallback(
+ int id, int key_state, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetAddressedPlayerCallback(
+ uint16_t player_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetBrowsedPlayerCallback(
+ uint16_t player_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetFolderItemsCallback(
+ uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ChangePathCallback(
+ uint8_t direction, uint8_t* folder_uid, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetItemAttrCallback(
+ uint8_t scope, uint8_t* uid, uint16_t uid_counter, uint8_t num_attr,
+ btrc_media_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::PlayItemCallback(
+ uint8_t scope, uint16_t uid_counter, uint8_t* uid,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetTotalNumOfItemsCallback(
+ uint8_t scope, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SearchCallback(
+ uint16_t str_len, uint8_t* p_str, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::AddToNowPlayingCallback(
+ uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::PassthroughRspCallback(
+ const RawAddress& /* bd_addr */, int /* id */, int /* key_state */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::GroupnavigationRspCallback(
+ int /* id */, int /* key_state */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::ConnectionStateCallback(
+ bool /* rc_connect */, bool /* bt_connect */,
+ const RawAddress& /* bd_addr */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlGetrcfeaturesCallback(
+ const RawAddress& /* bd_addr */, int /* features */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlSetplayerapplicationsettingRspCallback(const RawAddress& /* bd_addr */,
+ uint8_t /* accepted */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlPlayerapplicationsettingCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* num_attr */,
+ btrc_player_app_attr_t* /* app_attrs */, uint8_t /* num_ext_attr */,
+ btrc_player_app_ext_attr_t* /* ext_attrs */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& /* bd_addr*/,
+ const btrc_player_settings_t& /* vals */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetabsvolCmdCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* abs_vol */,
+ uint8_t /* label */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlRegisternotificationAbsVolCallback(const RawAddress& /* bd_addr */,
+ uint8_t /* label */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlTrackChangedCallback(
+ const RawAddress& /*bd_addr */, uint8_t /* num_attr */,
+ btrc_element_attr_val_t* /* p_attrs */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlPlayPositionChangedCallback(
+ const RawAddress& /* bd_addr */, uint32_t /* song_len */,
+ uint32_t /* song_pos */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlPlayStatusChangedCallback(
+ const RawAddress& /* bd_addr */, btrc_play_status_t /* play_status */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlGetFolderItemsCallback(
+ const RawAddress& /* bd_addr */, btrc_status_t /* status */,
+ const btrc_folder_items_t* /*folder_items */, uint8_t /* count */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlChangePathCallback(
+ const RawAddress& /* bd_addr */, uint32_t /* count */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetBrowsedPlayerCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* num_items */,
+ uint8_t /* depth */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetAddressedPlayerCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* status */) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothAvrcpInterface::Initialize() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_interface);
+
+ std::unique_ptr<BluetoothAvrcpInterfaceImpl> impl(
+ new BluetoothAvrcpInterfaceImpl());
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothAvrcpInterface";
+ return false;
+ }
+
+ g_interface = impl.release();
+
+ return true;
+}
+
+// static
+void BluetoothAvrcpInterface::CleanUp() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+
+ delete g_interface;
+ g_interface = nullptr;
+}
+
+// static
+bool BluetoothAvrcpInterface::IsInitialized() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+
+ return g_interface != nullptr;
+}
+
+// static
+BluetoothAvrcpInterface* BluetoothAvrcpInterface::Get() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+ return g_interface;
+}
+
+// static
+void BluetoothAvrcpInterface::InitializeForTesting(
+ BluetoothAvrcpInterface* test_instance) {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_interface);
+
+ g_interface = test_instance;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_avrcp_interface.h b/service/hal/bluetooth_avrcp_interface.h
new file mode 100644
index 0000000..08d6989
--- /dev/null
+++ b/service/hal/bluetooth_avrcp_interface.h
@@ -0,0 +1,179 @@
+//
+// 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 <base/macros.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_rc.h>
+
+namespace bluetooth {
+namespace hal {
+
+class BluetoothAvrcpInterface {
+ public:
+ // The HAL interface doesn't allow registering "user data" that carries
+ // context beyond the callback parameters, forcing implementations to deal
+ // with global variables. The *Observer interface is to redirect these events
+ // to interested parties in an object-oriented manner.
+ class TargetObserver {
+ public:
+ virtual ~TargetObserver() = default;
+
+ virtual void RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features);
+ virtual void GetPlayStatusCallback(const RawAddress& bd_addr);
+ virtual void ListPlayerAppAttrCallback(const RawAddress& bd_addr);
+ virtual void ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppValueCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppValuesTextCallback(uint8_t attr_id,
+ uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr);
+ virtual void SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr);
+ virtual void GetElementAttrCallback(uint8_t num_attr,
+ btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void RegisterNotificationCallback(btrc_event_id_t event_id,
+ uint32_t param,
+ const RawAddress& bd_addr);
+ virtual void VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr);
+ virtual void PassthroughCmdCallback(int id, int key_state,
+ const RawAddress& bd_addr);
+ virtual void SetAddressedPlayerCallback(uint16_t player_id,
+ const RawAddress& bd_addr);
+ virtual void SetBrowsedPlayerCallback(uint16_t player_id,
+ const RawAddress& bd_addr);
+ virtual void GetFolderItemsCallback(uint8_t scope, uint32_t start_item,
+ uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids,
+ const RawAddress& bd_addr);
+ virtual void ChangePathCallback(uint8_t direction, uint8_t* folder_uid,
+ const RawAddress& bd_addr);
+ virtual void GetItemAttrCallback(uint8_t scope, uint8_t* uid,
+ uint16_t uid_counter, uint8_t num_attr,
+ btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void PlayItemCallback(uint8_t scope, uint16_t uid_counter,
+ uint8_t* uid, const RawAddress& bd_addr);
+ virtual void GetTotalNumOfItemsCallback(uint8_t scope,
+ const RawAddress& bd_addr);
+ virtual void SearchCallback(uint16_t str_len, uint8_t* p_str,
+ const RawAddress& bd_addr);
+ virtual void AddToNowPlayingCallback(uint8_t scope, uint8_t* uid,
+ uint16_t uid_counter,
+ const RawAddress& bd_addr);
+ };
+
+ class ControlObserver {
+ public:
+ virtual ~ControlObserver() = default;
+
+ virtual void PassthroughRspCallback(const RawAddress& bd_addr, int id,
+ int key_state);
+ virtual void GroupnavigationRspCallback(int id, int key_state);
+ virtual void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr);
+ virtual void CtrlGetrcfeaturesCallback(const RawAddress& bd_addr,
+ int features);
+ virtual void CtrlSetplayerapplicationsettingRspCallback(
+ const RawAddress& bd_addr, uint8_t accepted);
+ virtual void CtrlPlayerapplicationsettingCallback(
+ const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+ btrc_player_app_ext_attr_t* ext_attrs);
+ virtual void CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& bd_addr, const btrc_player_settings_t& p_vals);
+ virtual void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr,
+ uint8_t abs_vol, uint8_t label);
+ virtual void CtrlRegisternotificationAbsVolCallback(
+ const RawAddress& bd_addr, uint8_t label);
+ virtual void CtrlTrackChangedCallback(const RawAddress& bd_addr,
+ uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs);
+ virtual void CtrlPlayPositionChangedCallback(const RawAddress& bd_addr,
+ uint32_t song_len,
+ uint32_t song_pos);
+ virtual void CtrlPlayStatusChangedCallback(const RawAddress& bd_addr,
+ btrc_play_status_t play_status);
+ virtual void CtrlGetFolderItemsCallback(
+ const RawAddress& bd_addr, btrc_status_t status,
+ const btrc_folder_items_t* folder_items, uint8_t count);
+ virtual void CtrlChangePathCallback(const RawAddress& bd_addr,
+ uint32_t count);
+ virtual void CtrlSetBrowsedPlayerCallback(const RawAddress& bd_addr,
+ uint8_t num_items, uint8_t depth);
+ virtual void CtrlSetAddressedPlayerCallback(const RawAddress& bd_addr,
+ uint8_t status);
+ };
+
+ // Initialize and clean up the BluetoothInterface singleton. Returns false if
+ // the underlying HAL interface failed to initialize, and true on success.
+ static bool Initialize();
+
+ // Shuts down and cleans up the interface. CleanUp must be called on the same
+ // thread that called Initialize.
+ static void CleanUp();
+
+ // Returns true if the interface was initialized and a global singleton has
+ // been created.
+ static bool IsInitialized();
+
+ // Initialize for testing. Use this to inject a test version of
+ // BluetoothAvrcpInterface. To be used from unit tests only.
+ static void InitializeForTesting(BluetoothAvrcpInterface* test_instance);
+
+ // Returns the BluetoothAvrcpInterface singleton. If the interface has
+ // not been initialized, returns nullptr. This method is thread-safe, in that
+ // it will block if the internal lock is being held by another thread. Don't
+ // call this re-entrantly from an observer event as this may cause a deadlock.
+ static BluetoothAvrcpInterface* Get();
+
+ virtual bool AvrcpControlEnable() = 0;
+ virtual void AvrcpControlDisable() = 0;
+ virtual bool AvrcpTargetEnable() = 0;
+ virtual void AvrcpTargetDisable() = 0;
+
+ // Thread-safety is guaranteed by ObserverList.
+ virtual void AddTargetObserver(TargetObserver* observer) = 0;
+ virtual void RemoveTargetObserver(TargetObserver* observer) = 0;
+
+ // Thread-safety is guaranteed by ObserverList.
+ virtual void AddControlObserver(ControlObserver* observer) = 0;
+ virtual void RemoveControlObserver(ControlObserver* observer) = 0;
+
+ // The HAL module pointers provided by the shared Bluetooth library
+ virtual const btrc_interface_t* GetTargetHALInterface() const = 0;
+ virtual const btrc_ctrl_interface_t* GetControlHALInterface() const = 0;
+
+ protected:
+ BluetoothAvrcpInterface() = default;
+ virtual ~BluetoothAvrcpInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_interface.cc b/service/hal/bluetooth_interface.cc
index 9296966..a08fb7b 100644
--- a/service/hal/bluetooth_interface.cc
+++ b/service/hal/bluetooth_interface.cc
@@ -98,6 +98,13 @@
status, remote_bd_addr, num_properties, properties));
}
+void DeviceFoundCallback(int num_properties, bt_property_t* properties) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << " Device found.";
+ FOR_EACH_BLUETOOTH_OBSERVER(DeviceFoundCallback(num_properties, properties));
+}
+
void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
shared_lock<shared_mutex_impl> lock(g_instance_lock);
VERIFY_INTERFACE_OR_RETURN();
@@ -190,7 +197,7 @@
AdapterStateChangedCallback,
AdapterPropertiesCallback,
RemoteDevicePropertiesCallback,
- nullptr, /* device_found_cb */
+ DeviceFoundCallback,
DiscoveryStateChangedCallback,
PinRequestCallback,
SSPRequestCallback,
@@ -309,6 +316,11 @@
// Do nothing.
}
+void BluetoothInterface::Observer::DeviceFoundCallback(
+ int /* num_properties */, bt_property_t* /* properties */) {
+ // Do nothing.
+}
+
void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
bt_discovery_state_t /* state */) {
// Do nothing.
diff --git a/service/hal/bluetooth_interface.h b/service/hal/bluetooth_interface.h
index 897835f..a1c8e62 100644
--- a/service/hal/bluetooth_interface.h
+++ b/service/hal/bluetooth_interface.h
@@ -57,6 +57,8 @@
RawAddress* remote_bd_addr,
int num_properties,
bt_property_t* properties);
+ virtual void DeviceFoundCallback(int num_properties,
+ bt_property_t* properties);
virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
virtual void PinRequestCallback(RawAddress* remote_bd_addr,
bt_bdname_t* bd_name, uint32_t cod,
diff --git a/service/hal/fake_bluetooth_av_interface.cc b/service/hal/fake_bluetooth_av_interface.cc
new file mode 100644
index 0000000..39a6331
--- /dev/null
+++ b/service/hal/fake_bluetooth_av_interface.cc
@@ -0,0 +1,151 @@
+//
+// Copyright 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/hal/fake_bluetooth_av_interface.h"
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+// The global test handler instances. We have to have globals since the HAL
+// interface methods all have to be global and their signatures don't allow us
+// to pass in user_data.
+std::shared_ptr<FakeBluetoothAvInterface::TestA2dpSinkHandler>
+ g_a2dp_sink_handler;
+
+bt_status_t FakeInit(btav_sink_callbacks_t* callbacks) {
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t FakeConnect(const RawAddress& bd_addr) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->Connect(bd_addr);
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDisconnect(const RawAddress& bd_addr) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->Disconnect(bd_addr);
+ return BT_STATUS_FAIL;
+}
+
+void FakeCleanup(void) {}
+
+void FakeSetAudioFocusState(int focus_state) {
+ if (g_a2dp_sink_handler)
+ return g_a2dp_sink_handler->SetAudioFocusState(focus_state);
+}
+
+void FakeSetAudioTrackGain(float gain) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->SetAudioTrackGain(gain);
+}
+
+btav_source_interface_t fake_a2dp_source_interface = {
+ .size = sizeof(btav_source_interface_t),
+ .init = nullptr,
+ .connect = nullptr,
+ .disconnect = nullptr,
+ .config_codec = nullptr,
+ .cleanup = nullptr,
+};
+
+btav_sink_interface_t fake_a2dp_sink_interface = {
+ .size = sizeof(btav_sink_interface_t),
+ .init = FakeInit,
+ .connect = FakeConnect,
+ .disconnect = FakeDisconnect,
+ .cleanup = FakeCleanup,
+ .set_audio_focus_state = FakeSetAudioFocusState,
+ .set_audio_track_gain = FakeSetAudioTrackGain,
+};
+
+} // namespace
+
+FakeBluetoothAvInterface::FakeBluetoothAvInterface(
+ std::shared_ptr<TestA2dpSinkHandler> a2dp_sink_handler) {
+ CHECK(!g_a2dp_sink_handler);
+
+ if (a2dp_sink_handler) g_a2dp_sink_handler = a2dp_sink_handler;
+}
+
+FakeBluetoothAvInterface::~FakeBluetoothAvInterface() {
+ g_a2dp_sink_handler = nullptr;
+}
+
+void FakeBluetoothAvInterface::NotifyConnectionState(
+ const RawAddress& bda, btav_connection_state_t state) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.ConnectionStateCallback(this, bda, state);
+ }
+}
+void FakeBluetoothAvInterface::NotifyAudioState(const RawAddress& bda,
+ btav_audio_state_t state) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.AudioStateCallback(this, bda, state);
+ }
+}
+void FakeBluetoothAvInterface::NotifyAudioConfig(const RawAddress& bda,
+ uint32_t sample_rate,
+ uint8_t channel_count) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.AudioConfigCallback(this, bda, sample_rate, channel_count);
+ }
+}
+
+bool FakeBluetoothAvInterface::A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) {
+ return true;
+}
+
+void FakeBluetoothAvInterface::A2dpSourceDisable() {}
+
+bool FakeBluetoothAvInterface::A2dpSinkEnable() { return true; }
+
+void FakeBluetoothAvInterface::A2dpSinkDisable() {}
+
+void FakeBluetoothAvInterface::AddA2dpSourceObserver(
+ A2dpSourceObserver* observer) {
+ CHECK(observer);
+ a2dp_source_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothAvInterface::RemoveA2dpSourceObserver(
+ A2dpSourceObserver* observer) {
+ CHECK(observer);
+ a2dp_source_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothAvInterface::AddA2dpSinkObserver(A2dpSinkObserver* observer) {
+ CHECK(observer);
+ a2dp_sink_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothAvInterface::RemoveA2dpSinkObserver(
+ A2dpSinkObserver* observer) {
+ CHECK(observer);
+ a2dp_sink_observers_.RemoveObserver(observer);
+}
+
+const btav_source_interface_t*
+FakeBluetoothAvInterface::GetA2dpSourceHALInterface() {
+ return &fake_a2dp_source_interface;
+}
+
+const btav_sink_interface_t*
+FakeBluetoothAvInterface::GetA2dpSinkHALInterface() {
+ return &fake_a2dp_sink_interface;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/fake_bluetooth_av_interface.h b/service/hal/fake_bluetooth_av_interface.h
new file mode 100644
index 0000000..c979434
--- /dev/null
+++ b/service/hal/fake_bluetooth_av_interface.h
@@ -0,0 +1,82 @@
+//
+// 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 <base/macros.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_av_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothAvInterface : public BluetoothAvInterface {
+ public:
+ // Handles HAL Bluetooth A2DP sink API calls for testing. Test code can
+ // provide a fake or mock implementation of this and all calls will be routed
+ // to it.
+ class TestA2dpSinkHandler {
+ public:
+ virtual bt_status_t Connect(RawAddress bda) = 0;
+ virtual bt_status_t Disconnect(RawAddress bda) = 0;
+ virtual void SetAudioFocusState(int focus_state) = 0;
+ virtual void SetAudioTrackGain(float gain) = 0;
+
+ protected:
+ virtual ~TestA2dpSinkHandler() = default;
+ };
+
+ // Constructs the fake with the given handlers. Implementations can
+ // provide their own handlers or simply pass "nullptr" for the default
+ // behavior in which BT_STATUS_FAIL will be returned from all calls.
+ FakeBluetoothAvInterface(
+ std::shared_ptr<TestA2dpSinkHandler> a2dp_sink_handler);
+ ~FakeBluetoothAvInterface();
+
+ // The methods below can be used to notify observers with certain events and
+ // given parameters.
+
+ // A2DP sink callbacks
+ void NotifyConnectionState(const RawAddress& bda,
+ btav_connection_state_t state);
+ void NotifyAudioState(const RawAddress& bda, btav_audio_state_t state);
+ void NotifyAudioConfig(const RawAddress& bda, uint32_t sample_rate,
+ uint8_t channel_count);
+
+ // BluetoothAvInterface overrides:
+ bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) override;
+ void A2dpSourceDisable() override;
+ bool A2dpSinkEnable() override;
+ void A2dpSinkDisable() override;
+ void AddA2dpSourceObserver(A2dpSourceObserver* observer) override;
+ void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) override;
+ void AddA2dpSinkObserver(A2dpSinkObserver* observer) override;
+ void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) override;
+ const btav_source_interface_t* GetA2dpSourceHALInterface() override;
+ const btav_sink_interface_t* GetA2dpSinkHALInterface() override;
+
+ private:
+ base::ObserverList<A2dpSourceObserver> a2dp_source_observers_;
+ base::ObserverList<A2dpSinkObserver> a2dp_sink_observers_;
+ std::shared_ptr<TestA2dpSinkHandler> scanner_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothAvInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc
new file mode 100644
index 0000000..1609aa8
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc
@@ -0,0 +1,222 @@
+//
+// Copyright 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/ipc/binder/bluetooth_a2dp_sink_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+
+using android::bluetooth::IBluetoothA2dpSinkCallback;
+
+namespace ipc {
+namespace binder {
+
+BluetoothA2dpSinkBinderServer::BluetoothA2dpSinkBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter);
+}
+
+Status BluetoothA2dpSinkBinderServer::Register(
+ const android::sp<IBluetoothA2dpSinkCallback>& callback,
+ bool* _aidl_return) {
+ auto factory = adapter_->GetA2dpSinkFactory();
+ *_aidl_return = RegisterInstanceBase(callback, factory);
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Unregister() {
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Enable(bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Enable()) {
+ LOG(ERROR) << "Failed to enable";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Disable(bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->Disable();
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Connect(const String16& device_address,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Connect(String8(device_address).string())) {
+ LOG(ERROR) << "Failed to connect";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Disconnect(const String16& device_address,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Disconnect(String8(device_address).string())) {
+ LOG(ERROR) << "Failed to connect";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::SetAudioFocusState(int focus_state,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->SetAudioFocusState(focus_state);
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::SetAudioTrackGain(float gain,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->SetAudioTrackGain(gain);
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+void BluetoothA2dpSinkBinderServer::OnConnectionState(
+ const std::string& device_address, int state) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnConnectionState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSinkBinderServer::OnAudioState(
+ const std::string& device_address, int state) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnAudioState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSinkBinderServer::OnAudioConfig(
+ const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnAudioConfig(String16(device_address.c_str()), sample_rate,
+ channel_count);
+}
+
+bool BluetoothA2dpSinkBinderServer::HasInstance() {
+ return GetA2dpSink() != nullptr;
+}
+
+android::sp<IBluetoothA2dpSinkCallback>
+BluetoothA2dpSinkBinderServer::GetA2dpSinkCallback() {
+ auto cb = GetCallback(bluetooth::A2dpSink::kSingletonInstanceId);
+ return android::sp<IBluetoothA2dpSinkCallback>(
+ static_cast<IBluetoothA2dpSinkCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::A2dpSink>
+BluetoothA2dpSinkBinderServer::GetA2dpSink() {
+ return std::static_pointer_cast<bluetooth::A2dpSink>(
+ GetInstance(bluetooth::A2dpSink::kSingletonInstanceId));
+}
+
+void BluetoothA2dpSinkBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " instance ID: " << instance->GetInstanceId()
+ << " status: " << status;
+ bluetooth::A2dpSink* a2dp_sink = static_cast<bluetooth::A2dpSink*>(instance);
+ a2dp_sink->SetDelegate(this);
+
+ android::sp<IBluetoothA2dpSinkCallback> cb(
+ static_cast<IBluetoothA2dpSinkCallback*>(callback.get()));
+ cb->OnRegistered(status);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h
new file mode 100644
index 0000000..e18af54
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h
@@ -0,0 +1,86 @@
+//
+// 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 <map>
+#include <string>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/BnBluetoothA2dpSink.h>
+#include <android/bluetooth/IBluetoothA2dpSinkCallback.h>
+
+#include "service/a2dp_sink.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothA2dpSinkBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothA2dpSink,
+ public bluetooth::A2dpSink::Delegate {
+ public:
+ explicit BluetoothA2dpSinkBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothA2dpSinkBinderServer() override = default;
+
+ // IBluetoothA2dpSink implementation:
+ android::binder::Status Register(
+ const android::sp<android::bluetooth::IBluetoothA2dpSinkCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Enable(bool* _aidl_return) override;
+ android::binder::Status Disable(bool* _aidl_return) override;
+ android::binder::Status Unregister() override;
+ android::binder::Status Connect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status Disconnect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status SetAudioFocusState(int state,
+ bool* _aidl_return) override;
+ android::binder::Status SetAudioTrackGain(float gain,
+ bool* _aidl_return) override;
+
+ // bluetooth::bluetooth::A2dpSink::Delegate implementation:
+ void OnConnectionState(const std::string& device_address, int state) override;
+ void OnAudioState(const std::string& device_address, int state) override;
+ void OnAudioConfig(const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) override;
+
+ bool HasInstance();
+
+ private:
+ android::sp<android::bluetooth::IBluetoothA2dpSinkCallback>
+ GetA2dpSinkCallback();
+ std::shared_ptr<bluetooth::A2dpSink> GetA2dpSink();
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothA2dpSinkBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc b/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc
new file mode 100644
index 0000000..d816859
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc
@@ -0,0 +1,236 @@
+//
+// Copyright 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/ipc/binder/bluetooth_avrcp_control_binder_server.h"
+
+#include <string>
+
+#include "base/logging.h"
+
+#include "service/adapter.h"
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+using android::bluetooth::IBluetoothAvrcpControlCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothAvrcpControlBinderServer::BluetoothAvrcpControlBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+Status BluetoothAvrcpControlBinderServer::Register(
+ const android::sp<IBluetoothAvrcpControlCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+
+ bluetooth::AvrcpControlFactory* gatt_client_factory =
+ adapter_->GetAvrcpControlFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, gatt_client_factory);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Unregister(int32_t id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(id);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Enable(int32_t id,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->Enable()) {
+ LOG(ERROR) << "Failed to enable";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Disable(int32_t id,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ avrcp_control->Disable();
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::SendPassThroughCommand(
+ int32_t id, const String16& device_address, int32_t key_code,
+ bool key_pressed, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->SendPassThroughCommand(String8(device_address).string(),
+ key_code, key_pressed)) {
+ LOG(ERROR) << "Failed to send pass through command";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+android::binder::Status BluetoothAvrcpControlBinderServer::SetAbsVolumeResponse(
+ int32_t id, const android::String16& device_address, int32_t abs_vol,
+ int32_t label, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->SetAbsVolumeResponse(String8(device_address).string(),
+ abs_vol, label)) {
+ LOG(ERROR) << "Failed to send set absolute volume response";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+android::binder::Status
+BluetoothAvrcpControlBinderServer::RegisterForAbsVolumeCallbackResponse(
+ int32_t id, const android::String16& device_address, int32_t response_type,
+ int32_t abs_vol, int32_t label, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->RegisterForAbsVolumeCallbackResponse(
+ String8(device_address).string(), response_type, abs_vol, label)) {
+ LOG(ERROR)
+ << "Failed to send register for absolute volume callback response";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+void BluetoothAvrcpControlBinderServer::OnConnectionState(
+ bool rc_connect, bool bt_connect, const std::string& device_address) {
+ auto func = [rc_connect, bt_connect, &device_address](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnConnectionState(rc_connect, bt_connect,
+ String16(device_address.c_str()));
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnTrackChanged(
+ const std::string& device_address, const bluetooth::AvrcpMediaAttr& attr) {
+ auto binder_attr = android::bluetooth::BluetoothAvrcpMediaAttr(attr);
+
+ auto func = [&device_address, &binder_attr](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnTrackChanged(String16(device_address.c_str()),
+ binder_attr);
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnSetAbsVolumeRequest(
+ const std::string& device_address, int32_t abs_vol, int32_t label) {
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ auto func = [&addr_s16, abs_vol, label](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnSetAbsVolumeRequest(addr_s16, abs_vol, label);
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnRegisterForAbsVolumeCallbackRequest(
+ const std::string& device_address, int32_t label) {
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ auto func = [&addr_s16, label](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnRegisterForAbsVolumeCallbackRequest(addr_s16, label);
+ };
+
+ ForEachCallback(func);
+}
+
+std::shared_ptr<bluetooth::AvrcpControl>
+BluetoothAvrcpControlBinderServer::GetAvrcpControl(int id) {
+ return std::static_pointer_cast<bluetooth::AvrcpControl>(GetInstance(id));
+}
+
+void BluetoothAvrcpControlBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " client ID: " << instance->GetInstanceId()
+ << " status: " << status;
+
+ bluetooth::AvrcpControl* avrcp_control =
+ static_cast<bluetooth::AvrcpControl*>(instance);
+ avrcp_control->SetDelegate(this);
+
+ android::sp<IBluetoothAvrcpControlCallback> cb(
+ static_cast<IBluetoothAvrcpControlCallback*>(callback.get()));
+ cb->OnRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_control_binder_server.h b/service/ipc/binder/bluetooth_avrcp_control_binder_server.h
new file mode 100644
index 0000000..11cf1f3
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_control_binder_server.h
@@ -0,0 +1,89 @@
+//
+// 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 <map>
+#include <string>
+
+#include "base/macros.h"
+
+#include "android/bluetooth/BnBluetoothAvrcpControl.h"
+#include "android/bluetooth/IBluetoothAvrcpControlCallback.h"
+
+#include "service/avrcp_control.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothAvrcpControlBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothAvrcpControl,
+ public bluetooth::AvrcpControl::Delegate {
+ public:
+ explicit BluetoothAvrcpControlBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothAvrcpControlBinderServer() override = default;
+
+ // IBluetoothAvrcpControl implementation:
+ android::binder::Status Register(
+ const android::sp<::android::bluetooth::IBluetoothAvrcpControlCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Unregister(int32_t id) override;
+ android::binder::Status UnregisterAll() override;
+ android::binder::Status Enable(int32_t id, bool* _aidl_return) override;
+ android::binder::Status Disable(int32_t id, bool* _aidl_return) override;
+ android::binder::Status SendPassThroughCommand(
+ int32_t id, const android::String16& device_address, int32_t key_code,
+ bool key_pressed, bool* _aidl_return) override;
+ android::binder::Status SetAbsVolumeResponse(
+ int32_t id, const android::String16& device_address, int32_t abs_vol,
+ int32_t label, bool* _aidl_return) override;
+ android::binder::Status RegisterForAbsVolumeCallbackResponse(
+ int32_t id, const android::String16& device_address,
+ int32_t response_type, int32_t abs_vol, int32_t label,
+ bool* _aidl_return) override;
+
+ private:
+ // bluetooth::bluetooth::AvrcpControl::Delegate implementation:
+ void OnConnectionState(bool rc_connect, bool bt_connect,
+ const std::string& device_address) override;
+ void OnTrackChanged(const std::string& device_address,
+ const bluetooth::AvrcpMediaAttr& attr) override;
+ void OnSetAbsVolumeRequest(const std::string& device_address, int32_t abs_vol,
+ int32_t label) override;
+ void OnRegisterForAbsVolumeCallbackRequest(const std::string& device_address,
+ int32_t label) override;
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ std::shared_ptr<bluetooth::AvrcpControl> GetAvrcpControl(int id);
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpControlBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_binder_server.cc b/service/ipc/binder/bluetooth_binder_server.cc
index 2d32cee..30090ee 100644
--- a/service/ipc/binder/bluetooth_binder_server.cc
+++ b/service/ipc/binder/bluetooth_binder_server.cc
@@ -18,6 +18,8 @@
#include <base/logging.h>
+#include "service/ipc/binder/bluetooth_a2dp_sink_binder_server.h"
+#include "service/ipc/binder/bluetooth_avrcp_control_binder_server.h"
#include "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
#include "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
#include "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
@@ -107,6 +109,59 @@
return Status::ok();
}
+Status BluetoothBinderServer::SetScanMode(int32_t scan_mode,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SetScanMode(scan_mode);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::SetScanEnable(bool scan_enable,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SetScanEnable(scan_enable);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::SspReply(
+ const ::android::String16& device_address, int32_t variant, bool accept,
+ int32_t passkey, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SspReply(String8(device_address).string(), variant,
+ accept, passkey);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::CreateBond(
+ const ::android::String16& device_address, int32_t transport,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return =
+ adapter_->CreateBond(String8(device_address).string(), transport);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetBondedDevices(bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->GetBondedDevices();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::RemoveBond(
+ const ::android::String16& device_address, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->RemoveBond(String8(device_address).string());
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetRemoteDeviceProperties(
+ const ::android::String16& device_address, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return =
+ adapter_->GetRemoteDeviceProperties(String8(device_address).string());
+ return Status::ok();
+}
+
Status BluetoothBinderServer::RegisterCallback(
const ::android::sp<IBluetoothCallback>& callback) {
VLOG(2) << __func__;
@@ -136,6 +191,29 @@
return Status::ok();
}
+Status BluetoothBinderServer::GetA2dpSinkInterface(
+ ::android::sp<IBluetoothA2dpSink>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothA2dpSink interface while disabled";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink_interface_.get())
+ a2dp_sink_interface_ = new BluetoothA2dpSinkBinderServer(adapter_);
+
+ if (a2dp_sink_interface_->HasInstance()) {
+ LOG(ERROR) << "Only one A2dpSink interface allowed at a time";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ *_aidl_return = a2dp_sink_interface_;
+ return Status::ok();
+}
+
Status BluetoothBinderServer::GetLowEnergyInterface(
::android::sp<IBluetoothLowEnergy>* _aidl_return) {
VLOG(2) << __func__;
@@ -222,6 +300,24 @@
return Status::ok();
}
+Status BluetoothBinderServer::GetAvrcpControlInterface(
+ ::android::sp<IBluetoothAvrcpControl>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR)
+ << "Cannot obtain IBluetoothAvrcpControl interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!avrcp_control_interface_.get())
+ avrcp_control_interface_ = new BluetoothAvrcpControlBinderServer(adapter_);
+
+ *_aidl_return = avrcp_control_interface_;
+ return Status::ok();
+}
+
android::status_t BluetoothBinderServer::dump(
int fd, const android::Vector<android::String16>& args) {
VLOG(2) << __func__ << " called with fd " << fd;
@@ -249,5 +345,97 @@
});
}
+void BluetoothBinderServer::OnDeviceConnectionStateChanged(
+ bluetooth::Adapter* adapter, const std::string& device_address,
+ bool connected) {
+ CHECK_EQ(adapter, adapter_);
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ callbacks_.ForEach([&addr_s16, connected](IBluetoothCallback* callback) {
+ callback->OnDeviceConnectionStateChanged(addr_s16, connected);
+ });
+}
+
+void BluetoothBinderServer::OnScanEnableChanged(bluetooth::Adapter* adapter,
+ bool scan_enabled) {
+ CHECK_EQ(adapter, adapter_);
+ callbacks_.ForEach([scan_enabled](IBluetoothCallback* callback) {
+ callback->OnScanEnableChanged(scan_enabled);
+ });
+}
+
+void BluetoothBinderServer::OnSspRequest(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name,
+ int cod, int pairing_variant,
+ int pass_key) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received ssp request: device_address: " << device_address
+ << ", device_name: " << device_name << ", cod: " << cod
+ << ", pairing_variant: " << pairing_variant
+ << ", pass_key: " << pass_key;
+
+ android::String16 addr_s16(device_address.c_str());
+ android::String16 name_s16(device_name.c_str());
+ callbacks_.ForEach([&addr_s16, &name_s16, cod, pairing_variant,
+ pass_key](IBluetoothCallback* callback) {
+ callback->OnSspRequest(addr_s16, name_s16, cod, pairing_variant, pass_key);
+ });
+}
+
+void BluetoothBinderServer::OnBondStateChanged(
+ bluetooth::Adapter* adapter, int status, const std::string& device_address,
+ int state) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " "
+ << "status: " << status << ", device_address: " << device_address
+ << ", state: " << state;
+ android::String16 addr_s16(device_address.c_str(), device_address.size());
+ callbacks_.ForEach([status, &addr_s16, state](IBluetoothCallback* callback) {
+ callback->OnBondStateChanged(status, addr_s16, state);
+ });
+}
+
+void BluetoothBinderServer::OnGetBondedDevices(
+ bluetooth::Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__;
+ std::vector<android::String16> devices_s16;
+ devices_s16.reserve(bonded_devices.size());
+ for (const auto& device : bonded_devices)
+ devices_s16.emplace_back(device.c_str(), device.size());
+
+ callbacks_.ForEach([status, &devices_s16](IBluetoothCallback* callback) {
+ callback->OnGetBondedDevices(status, devices_s16);
+ });
+}
+
+void BluetoothBinderServer::OnGetRemoteDeviceProperties(
+ bluetooth::Adapter* adapter, int status, const std::string& device_address,
+ const bluetooth::RemoteDeviceProps& properties) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " "
+ << "status: " << status << ", device_address: " << device_address;
+ android::String16 addr_s16(device_address.c_str(), device_address.size());
+ auto binder_props =
+ android::bluetooth::BluetoothRemoteDeviceProps(properties);
+ callbacks_.ForEach(
+ [status, &addr_s16, &binder_props](IBluetoothCallback* callback) {
+ callback->OnGetRemoteDeviceProperties(status, addr_s16, binder_props);
+ });
+}
+
+void BluetoothBinderServer::OnDeviceFound(
+ bluetooth::Adapter* adapter,
+ const bluetooth::RemoteDeviceProps& properties) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " ";
+ auto binder_props =
+ android::bluetooth::BluetoothRemoteDeviceProps(properties);
+ callbacks_.ForEach([&binder_props](IBluetoothCallback* callback) {
+ callback->OnDeviceFound(binder_props);
+ });
+}
+
} // namespace binder
} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_binder_server.h b/service/ipc/binder/bluetooth_binder_server.h
index b03a815..1388626 100644
--- a/service/ipc/binder/bluetooth_binder_server.h
+++ b/service/ipc/binder/bluetooth_binder_server.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// Copyright (C) 2015 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,14 +24,16 @@
#include <utils/Vector.h>
#include <android/bluetooth/BnBluetooth.h>
+#include <android/bluetooth/IBluetoothA2dpSink.h>
+#include <android/bluetooth/IBluetoothAvrcpControl.h>
#include <android/bluetooth/IBluetoothCallback.h>
#include <android/bluetooth/IBluetoothGattClient.h>
#include <android/bluetooth/IBluetoothGattServer.h>
#include <android/bluetooth/IBluetoothLeAdvertiser.h>
#include <android/bluetooth/IBluetoothLeScanner.h>
#include <android/bluetooth/IBluetoothLowEnergy.h>
-#include <bluetooth/uuid.h>
+#include "bluetooth/uuid.h"
#include "service/adapter.h"
#include "service/ipc/binder/remote_callback_list.h"
@@ -39,16 +41,20 @@
using android::binder::Status;
using android::bluetooth::BnBluetooth;
+using android::bluetooth::IBluetoothA2dpSink;
+using android::bluetooth::IBluetoothAvrcpControl;
using android::bluetooth::IBluetoothCallback;
using android::bluetooth::IBluetoothGattClient;
using android::bluetooth::IBluetoothGattServer;
-using android::bluetooth::IBluetoothLowEnergy;
using android::bluetooth::IBluetoothLeAdvertiser;
using android::bluetooth::IBluetoothLeScanner;
+using android::bluetooth::IBluetoothLowEnergy;
namespace ipc {
namespace binder {
+class BluetoothA2dpSinkBinderServer;
+
// Implements the server side of the IBluetooth Binder interface.
class BluetoothBinderServer : public BnBluetooth,
public bluetooth::Adapter::Observer {
@@ -68,12 +74,25 @@
::std::vector<::android::bluetooth::UUID>* _aidl_return) override;
Status SetName(const ::android::String16& name, bool* _aidl_return) override;
Status GetName(::android::String16* _aidl_return) override;
+ Status SetScanMode(int32_t scan_mode, bool* _aidl_return) override;
+ Status SetScanEnable(bool scan_enable, bool* _aidl_return) override;
+ Status SspReply(const ::android::String16& device_address, int32_t variant,
+ bool accept, int32_t passkey, bool* _aidl_return) override;
+ Status CreateBond(const ::android::String16& device_address,
+ int32_t transport, bool* _aidl_return) override;
+ Status GetBondedDevices(bool* _aidl_return) override;
+ Status RemoveBond(const ::android::String16& device_address,
+ bool* _aidl_return) override;
+ Status GetRemoteDeviceProperties(const ::android::String16& device_address,
+ bool* _aidl_return) override;
Status RegisterCallback(
const ::android::sp<IBluetoothCallback>& callback) override;
Status UnregisterCallback(
const ::android::sp<IBluetoothCallback>& callback) override;
Status IsMultiAdvertisementSupported(bool* _aidl_return) override;
+ Status GetA2dpSinkInterface(
+ ::android::sp<IBluetoothA2dpSink>* _aidl_return) override;
Status GetLowEnergyInterface(
::android::sp<IBluetoothLowEnergy>* _aidl_return) override;
Status GetLeAdvertiserInterface(
@@ -84,6 +103,8 @@
::android::sp<IBluetoothGattClient>* _aidl_return) override;
Status GetGattServerInterface(
::android::sp<IBluetoothGattServer>* _aidl_return) override;
+ Status GetAvrcpControlInterface(
+ ::android::sp<IBluetoothAvrcpControl>* _aidl_return) override;
android::status_t dump(
int fd, const android::Vector<android::String16>& args) override;
@@ -93,10 +114,39 @@
bluetooth::AdapterState prev_state,
bluetooth::AdapterState new_state) override;
+ void OnDeviceConnectionStateChanged(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ bool connected) override;
+
+ void OnScanEnableChanged(bluetooth::Adapter* adapter,
+ bool scan_enabled) override;
+
+ void OnSspRequest(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key) override;
+
+ void OnBondStateChanged(bluetooth::Adapter* adapter, int status,
+ const std::string& device_address,
+ int state) override;
+ void OnGetBondedDevices(
+ bluetooth::Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) override;
+ void OnGetRemoteDeviceProperties(
+ bluetooth::Adapter* adapter, int status,
+ const std::string& device_address,
+ const bluetooth::RemoteDeviceProps& properties) override;
+ void OnDeviceFound(bluetooth::Adapter* adapter,
+ const bluetooth::RemoteDeviceProps& properties) override;
+
private:
bluetooth::Adapter* adapter_; // weak
RemoteCallbackList<IBluetoothCallback> callbacks_;
+ // The IBluetoothA2dpSink interface handle. This is lazily initialized on the
+ // first call to GetA2dpSinkInterface().
+ android::sp<BluetoothA2dpSinkBinderServer> a2dp_sink_interface_;
+
// The IBluetoothLowEnergy interface handle. This is lazily initialized on the
// first call to GetLowEnergyInterface().
android::sp<IBluetoothLowEnergy> low_energy_interface_;
@@ -117,6 +167,10 @@
// the first call to GetGattServerInterface().
android::sp<IBluetoothGattServer> gatt_server_interface_;
+ // The IBluetoothAvrcpControl interface handle. This is lazily initialized on
+ // the first call to GetAvrcpControlInterface().
+ android::sp<IBluetoothAvrcpControl> avrcp_control_interface_;
+
DISALLOW_COPY_AND_ASSIGN(BluetoothBinderServer);
};
diff --git a/service/ipc/binder/interface_with_instances_base.cc b/service/ipc/binder/interface_with_instances_base.cc
index ba24657..1716bbd 100644
--- a/service/ipc/binder/interface_with_instances_base.cc
+++ b/service/ipc/binder/interface_with_instances_base.cc
@@ -86,6 +86,16 @@
id_to_instance_.clear();
}
+void InterfaceWithInstancesBase::ForEachCallback(
+ const std::function<void(IInterface*)>& func) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(maps_lock_);
+ for (auto& pair : id_to_instance_) {
+ auto cb = id_to_cb_.Get(pair.first);
+ func(cb.get());
+ }
+}
+
android::sp<IInterface> InterfaceWithInstancesBase::GetCallback(
int instance_id) {
return id_to_cb_.Get(instance_id);
diff --git a/service/ipc/binder/interface_with_instances_base.h b/service/ipc/binder/interface_with_instances_base.h
index 90224b6..05f2817 100644
--- a/service/ipc/binder/interface_with_instances_base.h
+++ b/service/ipc/binder/interface_with_instances_base.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// Copyright (C) 2015 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@
#include <unordered_map>
#include <base/macros.h>
-#include <bluetooth/uuid.h>
+#include "bluetooth/uuid.h"
#include "service/bluetooth_instance.h"
#include "service/ipc/binder/remote_callback_map.h"
@@ -57,6 +57,8 @@
// Unregisters all registered instances.
void UnregisterAllBase();
+ void ForEachCallback(const std::function<void(IInterface*)>& func);
+
// Returns a handle to the lock used to synchronize access to the internal
// data structures. Subclasses should acquire this before accessing the maps.
std::mutex* maps_lock() { return &maps_lock_; }
diff --git a/service/test/a2dp_sink_unittest.cc b/service/test/a2dp_sink_unittest.cc
new file mode 100644
index 0000000..06fb88e
--- /dev/null
+++ b/service/test/a2dp_sink_unittest.cc
@@ -0,0 +1,271 @@
+//
+// Copyright 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/a2dp_sink.h"
+#include "service/hal/fake_bluetooth_av_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockA2dpSinkHandler
+ : public hal::FakeBluetoothAvInterface::TestA2dpSinkHandler {
+ public:
+ MockA2dpSinkHandler() = default;
+ ~MockA2dpSinkHandler() override = default;
+
+ MOCK_METHOD1(Connect, bt_status_t(RawAddress));
+ MOCK_METHOD1(Disconnect, bt_status_t(RawAddress));
+ MOCK_METHOD1(SetAudioFocusState, void(int));
+ MOCK_METHOD1(SetAudioTrackGain, void(float));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockA2dpSinkHandler);
+};
+
+class TestDelegate : public A2dpSink::Delegate {
+ public:
+ TestDelegate() = default;
+ ~TestDelegate() override = default;
+
+ struct RequestData {
+ std::string device_address;
+ int state = -1;
+ uint32_t sample_rate = 0;
+ uint8_t channel_count = 0;
+ int count = 0;
+ };
+
+ // A2dpSink::Delegate implementation:
+ void OnConnectionState(const std::string& device_address,
+ int state) override {
+ ++connection_state_.count;
+ connection_state_.device_address = device_address;
+ connection_state_.state = state;
+ }
+ void OnAudioState(const std::string& device_address, int state) override {
+ ++audio_state_.count;
+ audio_state_.device_address = device_address;
+ audio_state_.state = state;
+ }
+ void OnAudioConfig(const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) override {
+ ++audio_config_.count;
+ audio_config_.device_address = device_address;
+ audio_config_.sample_rate = sample_rate;
+ audio_config_.channel_count = channel_count;
+ }
+
+ const RequestData& connection_state() const { return connection_state_; }
+ const RequestData& audio_state() const { return audio_state_; }
+ const RequestData& audio_config() const { return audio_config_; }
+
+ private:
+ RequestData connection_state_;
+ RequestData audio_state_;
+ RequestData audio_config_;
+};
+
+class A2dpSinkTest : public ::testing::Test {
+ public:
+ A2dpSinkTest() = default;
+ ~A2dpSinkTest() override = default;
+
+ void SetUp() override {
+ mock_handler_.reset(new MockA2dpSinkHandler());
+ fake_hal_av_iface_ = new hal::FakeBluetoothAvInterface(mock_handler_);
+ hal::BluetoothAvInterface::InitializeForTesting(fake_hal_av_iface_);
+ factory_.reset(new A2dpSinkFactory());
+ }
+
+ void TearDown() override {
+ factory_.reset();
+ hal::BluetoothAvInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothAvInterface* fake_hal_av_iface_;
+ std::shared_ptr<MockA2dpSinkHandler> mock_handler_;
+ std::unique_ptr<A2dpSinkFactory> factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkTest);
+};
+
+class A2dpSinkPostRegisterTest : public A2dpSinkTest {
+ public:
+ A2dpSinkPostRegisterTest() = default;
+ ~A2dpSinkPostRegisterTest() override = default;
+
+ void SetUp() override {
+ A2dpSinkTest::SetUp();
+ Uuid uuid = Uuid::GetRandom();
+ auto callback = [&](BLEStatus status, const Uuid& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_client.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ a2dp_sink_ = std::unique_ptr<A2dpSink>(
+ static_cast<A2dpSink*>(in_client.release()));
+ };
+
+ factory_->RegisterInstance(uuid, callback);
+ }
+
+ void TearDown() override {
+ a2dp_sink_ = nullptr;
+ A2dpSinkTest::TearDown();
+ }
+
+ protected:
+ void Connect(const std::string& addr) {
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));
+
+ EXPECT_CALL(*mock_handler_, Connect(hal_addr))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ EXPECT_TRUE(a2dp_sink_->Connect(addr));
+ }
+
+ void Disconnect(const std::string& addr) {
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));
+
+ EXPECT_CALL(*mock_handler_, Disconnect(hal_addr))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ EXPECT_TRUE(a2dp_sink_->Disconnect(addr));
+ }
+
+ std::unique_ptr<A2dpSink> a2dp_sink_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkPostRegisterTest);
+};
+
+TEST_F(A2dpSinkTest, RegisterA2dpSink) {
+ // These will be asynchronously populate with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ Uuid cb_uuid;
+ std::unique_ptr<A2dpSink> a2dp_sink;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const Uuid& uuid,
+ std::unique_ptr<BluetoothInstance> in_a2dp_sink) {
+ status = in_status;
+ cb_uuid = uuid;
+ a2dp_sink = std::unique_ptr<A2dpSink>(
+ static_cast<A2dpSink*>(in_a2dp_sink.release()));
+ callback_count++;
+ };
+
+ Uuid uuid0 = Uuid::GetRandom();
+
+ // This should always succeed.
+ EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(1, callback_count);
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ ASSERT_TRUE(a2dp_sink.get() !=
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(bluetooth::A2dpSink::kSingletonInstanceId,
+ a2dp_sink->GetInstanceId());
+ EXPECT_EQ(uuid0, a2dp_sink->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+TEST_F(A2dpSinkPostRegisterTest, Connect) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ Connect(kTestAddr);
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, SetAudioFocusState) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ static const int kFocusState = 2;
+ Connect(kTestAddr);
+
+ EXPECT_CALL(*mock_handler_, SetAudioFocusState(kFocusState));
+ a2dp_sink_->SetAudioFocusState(kFocusState);
+
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, SetAudioTrackGain) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ static const float kTrackGain = 0.5;
+ Connect(kTestAddr);
+
+ EXPECT_CALL(*mock_handler_, SetAudioTrackGain(kTrackGain));
+ a2dp_sink_->SetAudioTrackGain(kTrackGain);
+
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, CallbackTest) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(kTestAddr, hal_addr));
+
+ TestDelegate delegate;
+ a2dp_sink_->SetDelegate(&delegate);
+ Connect(kTestAddr);
+
+ // OnConnectionState
+ const int kConnectionState = 2;
+ EXPECT_EQ(0, delegate.connection_state().count);
+ fake_hal_av_iface_->NotifyConnectionState(
+ hal_addr, static_cast<btav_connection_state_t>(kConnectionState));
+ EXPECT_EQ(1, delegate.connection_state().count);
+ EXPECT_EQ(kTestAddr, delegate.connection_state().device_address);
+ EXPECT_EQ(kConnectionState, delegate.connection_state().state);
+
+ // OnAudioState
+ const int kAudioState = 1;
+ EXPECT_EQ(0, delegate.audio_state().count);
+ fake_hal_av_iface_->NotifyAudioState(
+ hal_addr, static_cast<btav_audio_state_t>(kAudioState));
+ EXPECT_EQ(1, delegate.audio_state().count);
+ EXPECT_EQ(kTestAddr, delegate.audio_state().device_address);
+ EXPECT_EQ(kAudioState, delegate.audio_state().state);
+
+ // OnAudioConfig
+ const uint32_t kSampleRate = 44100;
+ const uint32_t kChannelCount = 2;
+ EXPECT_EQ(0, delegate.audio_config().count);
+ fake_hal_av_iface_->NotifyAudioConfig(hal_addr, kSampleRate, kChannelCount);
+ EXPECT_EQ(1, delegate.audio_config().count);
+ EXPECT_EQ(kTestAddr, delegate.audio_config().device_address);
+ EXPECT_EQ(kSampleRate, delegate.audio_config().sample_rate);
+ EXPECT_EQ(kChannelCount, delegate.audio_config().channel_count);
+
+ Disconnect(kTestAddr);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/service/test/mock_adapter.h b/service/test/mock_adapter.h
index 4b93792..ff64ab1 100644
--- a/service/test/mock_adapter.h
+++ b/service/test/mock_adapter.h
@@ -37,11 +37,22 @@
MOCK_CONST_METHOD0(GetName, std::string());
MOCK_METHOD1(SetName, bool(const std::string&));
MOCK_CONST_METHOD0(GetAddress, std::string());
+ MOCK_METHOD1(SetScanMode, bool(int));
+ MOCK_METHOD1(SetScanEnable, bool(bool));
+ MOCK_METHOD4(SspReply, bool(const std::string&, int, bool, int32_t));
+ MOCK_METHOD2(CreateBond,
+ bool(const std::string& device_address, int transport));
MOCK_METHOD0(IsMultiAdvertisementSupported, bool());
MOCK_METHOD1(IsDeviceConnected, bool(const std::string&));
MOCK_METHOD0(GetTotalNumberOfTrackableAdvertisements, int());
MOCK_METHOD0(IsOffloadedFilteringSupported, bool());
MOCK_METHOD0(IsOffloadedScanBatchingSupported, bool());
+ MOCK_METHOD0(GetBondedDevices, bool());
+ MOCK_METHOD1(RemoveBond, bool(const std::string&));
+ MOCK_METHOD1(GetRemoteDeviceProperties,
+ bool(const std::string& device_address));
+ MOCK_CONST_METHOD0(GetA2dpSinkFactory, A2dpSinkFactory*());
+ MOCK_CONST_METHOD0(GetAvrcpControlFactory, AvrcpControlFactory*());
MOCK_CONST_METHOD0(GetLowEnergyClientFactory, LowEnergyClientFactory*());
MOCK_CONST_METHOD0(GetLeAdvertiserFactory, LowEnergyAdvertiserFactory*());
MOCK_CONST_METHOD0(GetLeScannerFactory, LowEnergyScannerFactory*());