summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authormcchou <mcchou@chromium.org>2015-02-17 16:21:11 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-18 00:21:59 +0000
commit016980f10044b64144293f9e1ba0ce4c5fddeda3 (patch)
treeee052114c6bde9341035489a35848b2f61659517 /device
parent1ff220bced57014ddeb99e321aa30f58efa15b15 (diff)
downloadchromium_src-016980f10044b64144293f9e1ba0ce4c5fddeda3.zip
chromium_src-016980f10044b64144293f9e1ba0ce4c5fddeda3.tar.gz
chromium_src-016980f10044b64144293f9e1ba0ce4c5fddeda3.tar.bz2
device/bluetooth:Implement BluetoothMediaEndpointServiceProvider delegate and media-related overrides.
This CL implements delegate overrides for BluetoothMediaEndpointServiceProvider and observer overrides for BluetoothMediaClient and BluetoothMediaTransportClient. These overrides will be called once a remote device connects to a local A2DP audio sink, and the state of the audio sink should become idle. The behaviors of FakeBluetoothMediaTransportClient, FakeBluetoothMediaEndpointServiceProvider and FakeMediaEndpointServiceProvider are also defined for connection-related tests in this CL. BUG=441581 TEST=device_unittests --gtest_filter=*AudioSink* Review URL: https://codereview.chromium.org/910023002 Cr-Commit-Position: refs/heads/master@{#316709}
Diffstat (limited to 'device')
-rw-r--r--device/bluetooth/bluetooth_audio_sink_chromeos.cc162
-rw-r--r--device/bluetooth/bluetooth_audio_sink_chromeos.h28
-rw-r--r--device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc259
3 files changed, 372 insertions, 77 deletions
diff --git a/device/bluetooth/bluetooth_audio_sink_chromeos.cc b/device/bluetooth/bluetooth_audio_sink_chromeos.cc
index 9623c78..7791563 100644
--- a/device/bluetooth/bluetooth_audio_sink_chromeos.cc
+++ b/device/bluetooth/bluetooth_audio_sink_chromeos.cc
@@ -5,9 +5,12 @@
#include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
#include <sstream>
+#include <vector>
+#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "dbus/message.h"
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
namespace {
@@ -38,18 +41,50 @@ BluetoothAudioSinkChromeOS::BluetoothAudioSinkChromeOS(
DCHECK(adapter_.get());
DCHECK(adapter_->IsPresent());
- StateChanged(device::BluetoothAudioSink::STATE_DISCONNECTED);
adapter_->AddObserver(this);
+
+ chromeos::BluetoothMediaClient* media =
+ DBusThreadManager::Get()->GetBluetoothMediaClient();
+ DCHECK(media);
+ media->AddObserver(this);
+
+ chromeos::BluetoothMediaTransportClient *transport =
+ chromeos::DBusThreadManager::Get()->GetBluetoothMediaTransportClient();
+ DCHECK(transport);
+ transport->AddObserver(this);
+
+ StateChanged(device::BluetoothAudioSink::STATE_DISCONNECTED);
}
BluetoothAudioSinkChromeOS::~BluetoothAudioSinkChromeOS() {
DCHECK(adapter_.get());
adapter_->RemoveObserver(this);
+
+ chromeos::BluetoothMediaClient* media =
+ DBusThreadManager::Get()->GetBluetoothMediaClient();
+ DCHECK(media);
+ media->RemoveObserver(this);
+
+ chromeos::BluetoothMediaTransportClient *transport =
+ chromeos::DBusThreadManager::Get()->GetBluetoothMediaTransportClient();
+ DCHECK(transport);
+ transport->RemoveObserver(this);
+
// TODO(mcchou): BUG=441581
// Unregister() should be called while media and media endpoint are still
// valid.
}
+void BluetoothAudioSinkChromeOS::Unregister(
+ const base::Closure& callback,
+ const device::BluetoothAudioSink::ErrorCallback& error_callback) {
+ // TODO(mcchou): BUG=441581
+ // Call UnregisterEndpoint on the media object with |media_path_| and clean
+ // |observers_| and transport_path_ and reset state_ and volume.
+ // Check whether the media endpoint is registered before invoking
+ // UnregisterEndpoint.
+}
+
void BluetoothAudioSinkChromeOS::AddObserver(
device::BluetoothAudioSink::Observer* observer) {
DCHECK(observer);
@@ -86,52 +121,88 @@ void BluetoothAudioSinkChromeOS::AdapterPresentChanged(
void BluetoothAudioSinkChromeOS::MediaRemoved(
const dbus::ObjectPath& object_path) {
// TODO(mcchou): BUG=441581
- // Check if |object_path| equals to |media_path_|. If true, change the state
- // of the audio sink, call StateChanged and reset the audio sink.
+ // Changes |state_| to STATE_INVALID or STATE_DISCONNECTED?
+ if (object_path == media_path_) {
+ StateChanged(device::BluetoothAudioSink::STATE_INVALID);
+ }
}
void BluetoothAudioSinkChromeOS::MediaTransportRemoved(
const dbus::ObjectPath& object_path) {
- // TODO(mcchou): BUG=441581
- // Check if |object_path| equals to |transport_path_|. If true, change the
- // state of the audio sink, call StateChanged and reset the audio sink.
// Whenever powered of |adapter_| turns false while present stays true, media
// transport object should be removed accordingly, and the state should be
// changed to STATE_DISCONNECTED.
+ if (object_path == transport_path_) {
+ StateChanged(device::BluetoothAudioSink::STATE_DISCONNECTED);
+ }
}
void BluetoothAudioSinkChromeOS::MediaTransportPropertyChanged(
const dbus::ObjectPath& object_path,
const std::string& property_name) {
- // TODO(mcchou): BUG=441581
- // Call StateChanged and VolumeChanged accordingly if there is any change on
- // state/volume.
+ if (object_path != transport_path_)
+ return;
+
+ // Retrieves the property set of the transport object with |object_path|.
+ chromeos::BluetoothMediaTransportClient::Properties* properties =
+ DBusThreadManager::Get()
+ ->GetBluetoothMediaTransportClient()
+ ->GetProperties(object_path);
+
+ // Dispatches a property changed event to the corresponding handler.
+ if (property_name == properties->state.name()) {
+ if (properties->state.value() ==
+ BluetoothMediaTransportClient::kStateIdle) {
+ StateChanged(device::BluetoothAudioSink::STATE_IDLE);
+ } else if (properties->state.value() ==
+ BluetoothMediaTransportClient::kStatePending) {
+ StateChanged(device::BluetoothAudioSink::STATE_PENDING);
+ } else if (properties->state.value() ==
+ BluetoothMediaTransportClient::kStateActive) {
+ StateChanged(device::BluetoothAudioSink::STATE_ACTIVE);
+ }
+ } else if (property_name == properties->volume.name()) {
+ VolumeChanged(properties->volume.value());
+ } else {
+ VLOG(1) << "Bluetooth audio sink: transport property " << property_name
+ << " changed";
+ }
}
void BluetoothAudioSinkChromeOS::SetConfiguration(
const dbus::ObjectPath& transport_path,
- const dbus::MessageReader& properties) {
- // TODO(mcchou): BUG=441581
- // Update |transport_path_| and store properties if needed.
+ const TransportProperties& properties) {
+ VLOG(1) << "Bluetooth audio sink: SetConfiguration called";
+ transport_path_ = transport_path;
+
+ // The initial state for a connection should be "idle".
+ if (properties.state != BluetoothMediaTransportClient::kStateIdle) {
+ VLOG(1) << "Bluetooth Audio Sink: unexpected state " << properties.state;
+ return;
+ }
+
+ // Updates |volume_| if the volume level is provided in |properties|.
+ if (properties.volume.get() != nullptr)
+ VolumeChanged(*properties.volume);
+
+ StateChanged(device::BluetoothAudioSink::STATE_IDLE);
}
void BluetoothAudioSinkChromeOS::SelectConfiguration(
const std::vector<uint8_t>& capabilities,
const SelectConfigurationCallback& callback) {
- // TODO(mcchou): BUG=441581
- // Use SelectConfigurationCallback to return the agreed capabilities.
VLOG(1) << "Bluetooth audio sink: SelectConfiguration called";
callback.Run(options_.capabilities);
}
void BluetoothAudioSinkChromeOS::ClearConfiguration(
const dbus::ObjectPath& transport_path) {
- // TODO(mcchou): BUG=441581
- // Reset the configuration to the default one and close IOBuffer.
+ VLOG(1) << "Bluetooth audio sink: ClearConfiguration called";
+ StateChanged(device::BluetoothAudioSink::STATE_DISCONNECTED);
}
-void BluetoothAudioSinkChromeOS::Release() {
- VLOG(1) << "Bluetooth audio sink: Release called";
+void BluetoothAudioSinkChromeOS::Released() {
+ VLOG(1) << "Bluetooth audio sink: Released called";
StateChanged(device::BluetoothAudioSink::STATE_INVALID);
}
@@ -139,10 +210,6 @@ void BluetoothAudioSinkChromeOS::Register(
const device::BluetoothAudioSink::Options& options,
const base::Closure& callback,
const device::BluetoothAudioSink::ErrorCallback& error_callback) {
- // TODO(mcchou): BUG=441581
- // Get Media object, initiate an Media Endpoint with options, and return the
- // audio sink via callback. Add the audio sink as observer of both Media and
- // Media Transport.
DCHECK(adapter_.get());
DCHECK_EQ(state_, device::BluetoothAudioSink::STATE_DISCONNECTED);
@@ -164,13 +231,12 @@ void BluetoothAudioSinkChromeOS::Register(
endpoint_properties.codec = options_.codec;
endpoint_properties.capabilities = options_.capabilities;
- // Gets Media object exported by D-Bus and registers the endpoint.
+ media_path_ = static_cast<BluetoothAdapterChromeOS*>(
+ adapter_.get())->object_path();
+
chromeos::BluetoothMediaClient* media =
DBusThreadManager::Get()->GetBluetoothMediaClient();
- BluetoothAdapterChromeOS* adapter_chromeos =
- static_cast<BluetoothAdapterChromeOS*>(adapter_.get());
- media->AddObserver(this);
- media_path_ = adapter_chromeos->object_path();
+ DCHECK(media);
media->RegisterEndpoint(
media_path_,
endpoint_path_,
@@ -181,14 +247,9 @@ void BluetoothAudioSinkChromeOS::Register(
weak_ptr_factory_.GetWeakPtr(), error_callback));
}
-void BluetoothAudioSinkChromeOS::Unregister(
- const base::Closure& callback,
- const device::BluetoothAudioSink::ErrorCallback& error_callback) {
- // TODO(mcchou): BUG=441581
- // Call UnregisterEndpoint on the media object with |media_path_| and clean
- // |observers_| and transport_path_ and reset state_ and volume.
- // Check whether the media endpoint is registered before invoking
- // UnregisterEndpoint.
+BluetoothMediaEndpointServiceProvider*
+ BluetoothAudioSinkChromeOS::GetEndpointServiceProvider() {
+ return media_endpoint_.get();
}
void BluetoothAudioSinkChromeOS::StateChanged(
@@ -201,18 +262,21 @@ void BluetoothAudioSinkChromeOS::StateChanged(
switch (state) {
case device::BluetoothAudioSink::STATE_INVALID: {
// TODO(mcchou): BUG=441581
- // Clean media, media transport and media endpoint.
+ ResetMedia();
+ ResetTransport();
+ ResetEndpoint();
break;
}
case device::BluetoothAudioSink::STATE_DISCONNECTED: {
// TODO(mcchou): BUG=441581
- // Clean media transport.
+ // Clean media transport and remove the audio sink from its observer list.
+ ResetTransport();
break;
}
case device::BluetoothAudioSink::STATE_IDLE: {
// TODO(mcchou): BUG=441581
- // Triggered by MediaTransportPropertyChanged. Stop watching on file
- // descriptor if there is one.
+ // Triggered by MediaTransportPropertyChanged and SetConfiguration.
+ // Stop watching on file descriptor if there is one.
break;
}
case device::BluetoothAudioSink::STATE_PENDING: {
@@ -258,8 +322,7 @@ void BluetoothAudioSinkChromeOS::OnRegisterFailed(
DCHECK(media_endpoint_.get());
VLOG(1) << "Bluetooth audio sink: " << error_name << ": " << error_message;
- endpoint_path_ = dbus::ObjectPath("");
- media_endpoint_ = nullptr;
+ ResetEndpoint();
error_callback.Run(device::BluetoothAudioSink::ERROR_NOT_REGISTERED);
}
@@ -271,4 +334,21 @@ void BluetoothAudioSinkChromeOS::ReadFromFD() {
// data. Notify |Observers_| while there is audio data available.
}
+void BluetoothAudioSinkChromeOS::ResetMedia() {
+ media_path_ = dbus::ObjectPath("");
+}
+
+void BluetoothAudioSinkChromeOS::ResetTransport() {
+ transport_path_ = dbus::ObjectPath("");
+ volume_ = 0;
+ read_mtu_ = 0;
+ write_mtu_ = 0;
+ fd_.PutValue(-1);
+}
+
+void BluetoothAudioSinkChromeOS::ResetEndpoint() {
+ endpoint_path_ = dbus::ObjectPath("");
+ media_endpoint_ = nullptr;
+}
+
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_audio_sink_chromeos.h b/device/bluetooth/bluetooth_audio_sink_chromeos.h
index 37994d3..3af285b 100644
--- a/device/bluetooth/bluetooth_audio_sink_chromeos.h
+++ b/device/bluetooth/bluetooth_audio_sink_chromeos.h
@@ -23,6 +23,8 @@
namespace chromeos {
+class BluetoothAudioSinkChromeOSTest;
+
class DEVICE_BLUETOOTH_EXPORT BluetoothAudioSinkChromeOS
: public device::BluetoothAudioSink,
public device::BluetoothAdapter::Observer,
@@ -34,6 +36,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAudioSinkChromeOS
scoped_refptr<device::BluetoothAdapter> adapter);
// device::BluetoothAudioSink overrides.
+ // Unregisters a BluetoothAudioSink. |callback| should handle
+ // the clean-up after the audio sink is deleted successfully, otherwise
+ // |error_callback| will be called.
+ void Unregister(
+ const base::Closure& callback,
+ const device::BluetoothAudioSink::ErrorCallback& error_callback) override;
void AddObserver(BluetoothAudioSink::Observer* observer) override;
void RemoveObserver(BluetoothAudioSink::Observer* observer) override;
device::BluetoothAudioSink::State GetState() const override;
@@ -53,12 +61,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAudioSinkChromeOS
// BluetoothMediaEndpointServiceProvider::Delegate overrides.
void SetConfiguration(const dbus::ObjectPath& transport_path,
- const dbus::MessageReader& properties) override;
+ const TransportProperties& properties) override;
void SelectConfiguration(
const std::vector<uint8_t>& capabilities,
const SelectConfigurationCallback& callback) override;
void ClearConfiguration(const dbus::ObjectPath& transport_path) override;
- void Release() override;
+ void Released() override;
// Registers a BluetoothAudioSink. User applications can use |options| to
// configure the audio sink. |callback| will be executed if the audio sink is
@@ -69,12 +77,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAudioSinkChromeOS
const base::Closure& callback,
const device::BluetoothAudioSink::ErrorCallback& error_callback);
- // Unregisters a BluetoothAudioSink. |callback| should handle
- // the clean-up after the audio sink is deleted successfully, otherwise
- // |error_callback| will be called.
- void Unregister(
- const base::Closure& callback,
- const device::BluetoothAudioSink::ErrorCallback& error_callback) override;
+ // Returns a pointer to the media endpoint object. This function should be
+ // used for testing purpose only.
+ BluetoothMediaEndpointServiceProvider* GetEndpointServiceProvider();
private:
~BluetoothAudioSinkChromeOS() override;
@@ -98,6 +103,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAudioSinkChromeOS
// notify |observer_| while the audio data is available.
void ReadFromFD();
+ // Helper functions to clean up media, media transport and media endpoint.
+ // Called when the |state_| changes to either STATE_INVALID or
+ // STATE_DISCONNECTED.
+ void ResetMedia();
+ void ResetTransport();
+ void ResetEndpoint();
+
// The connection state between the BluetoothAudioSinkChromeOS and the remote
// device.
device::BluetoothAudioSink::State state_;
diff --git a/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc b/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
index 5fcccfb..9aa727f 100644
--- a/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
@@ -8,7 +8,13 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "chromeos/dbus/bluetooth_media_client.h"
+#include "chromeos/dbus/bluetooth_media_endpoint_service_provider.h"
+#include "chromeos/dbus/bluetooth_media_transport_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_bluetooth_media_client.h"
+#include "chromeos/dbus/fake_bluetooth_media_endpoint_service_provider.h"
+#include "chromeos/dbus/fake_bluetooth_media_transport_client.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -16,6 +22,7 @@
#include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
#include "testing/gtest/include/gtest/gtest.h"
+using dbus::ObjectPath;
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
using device::BluetoothAudioSink;
@@ -56,12 +63,23 @@ class TestAudioSinkObserver : public BluetoothAudioSink::Observer {
class BluetoothAudioSinkChromeOSTest : public testing::Test {
public:
void SetUp() override {
- chromeos::DBusThreadManager::Initialize();
+ DBusThreadManager::Initialize();
callback_count_ = 0;
error_callback_count_ = 0;
- audio_sink_ = nullptr;
- adapter_ = nullptr;
+
+ // Initiates Delegate::TransportProperties with default values.
+ properties_.device =
+ ObjectPath(FakeBluetoothMediaTransportClient::kTransportDevicePath);
+ properties_.uuid = BluetoothMediaClient::kBluetoothAudioSinkUUID;
+ properties_.codec = FakeBluetoothMediaTransportClient::kTransportCodec;
+ properties_.configuration =
+ FakeBluetoothMediaTransportClient::kTransportConfiguration;
+ properties_.state = BluetoothMediaTransportClient::kStateIdle;
+ properties_.delay.reset(
+ new uint16_t(FakeBluetoothMediaTransportClient::kTransportDelay));
+ properties_.volume.reset(
+ new uint16_t(FakeBluetoothMediaTransportClient::kTransportVolume));
GetAdapter();
}
@@ -76,13 +94,14 @@ class BluetoothAudioSinkChromeOSTest : public testing::Test {
DBusThreadManager::Shutdown();
}
- // Get the existing Bluetooth adapter.
+ // Gets the existing Bluetooth adapter.
void GetAdapter() {
BluetoothAdapterFactory::GetAdapter(
base::Bind(&BluetoothAudioSinkChromeOSTest::GetAdapterCallback,
base::Unretained(this)));
}
+ // Called whenever BluetoothAdapter is retrieved successfully.
void GetAdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
adapter_ = adapter;
@@ -96,11 +115,33 @@ class BluetoothAudioSinkChromeOSTest : public testing::Test {
base::Unretained(this)));
ASSERT_TRUE(adapter_->IsPresent());
ASSERT_TRUE(adapter_->IsPowered());
- ASSERT_EQ(callback_count_, 1);
- ASSERT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+
+ // Resets callback_count_.
--callback_count_;
}
+ // Registers BluetoothAudioSinkChromeOS with default codec and capabilities.
+ void GetAudioSink() {
+ // Sets up valid codec and capabilities.
+ BluetoothAudioSink::Options options;
+ ASSERT_EQ(options.codec, 0x00);
+ ASSERT_EQ(options.capabilities,
+ std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
+
+ // Registers |audio_sink_| with valid codec and capabilities
+ adapter_->RegisterAudioSink(
+ options,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+ }
+
// Called whenever RegisterAudioSink is completed successfully.
void RegisterCallback(
scoped_refptr<BluetoothAudioSink> audio_sink) {
@@ -113,7 +154,16 @@ class BluetoothAudioSinkChromeOSTest : public testing::Test {
// Called whenever RegisterAudioSink failed.
void RegisterErrorCallback(BluetoothAudioSink::ErrorCode error_code) {
++error_callback_count_;
- ASSERT_EQ(error_code, BluetoothAudioSink::ERROR_NOT_REGISTERED);
+ EXPECT_EQ(error_code, BluetoothAudioSink::ERROR_NOT_REGISTERED);
+ }
+
+ // Called whenever there capabilities are returned from SelectConfiguration.
+ void SelectConfigurationCallback(const std::vector<uint8_t>& capabilities) {
+ ++callback_count_;
+
+ // |capabilities| should be the same as the capabilities for registering an
+ // audio sink in GetAudioSink().
+ EXPECT_EQ(capabilities, std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
}
// Generic callbacks.
@@ -128,31 +178,25 @@ class BluetoothAudioSinkChromeOSTest : public testing::Test {
protected:
int callback_count_;
int error_callback_count_;
+
base::MessageLoop message_loop_;
+
scoped_refptr<BluetoothAdapter> adapter_;
scoped_refptr<BluetoothAudioSink> audio_sink_;
+
+ // The default property set used while calling SetConfiguration on a media
+ // endpoint object.
+ BluetoothMediaEndpointServiceProvider::Delegate::TransportProperties
+ properties_;
};
TEST_F(BluetoothAudioSinkChromeOSTest, RegisterSucceeded) {
- // Sets up valid codec and capabilities.
- BluetoothAudioSink::Options options;
- ASSERT_EQ(options.codec, 0x00);
- ASSERT_EQ(options.capabilities,
- std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
- adapter_->RegisterAudioSink(
- options,
- base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
- base::Unretained(this)),
- base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
- base::Unretained(this)));
+ GetAudioSink();
- // Adds observer for the audio sink.
+ // Adds an observer for |audio_sink_|.
TestAudioSinkObserver observer(audio_sink_);
-
- ASSERT_EQ(callback_count_, 1);
- ASSERT_EQ(error_callback_count_, 0);
- ASSERT_EQ(observer.state_changed_count_, 0);
- ASSERT_EQ(observer.volume_changed_count_, 0);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
}
TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) {
@@ -168,8 +212,8 @@ TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) {
base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
base::Unretained(this)));
- ASSERT_EQ(callback_count_, 0);
- ASSERT_EQ(error_callback_count_, 1);
+ EXPECT_EQ(callback_count_, 0);
+ EXPECT_EQ(error_callback_count_, 1);
// Sets options with a valid codec and invalid capabilities.
options.codec = 0x00;
@@ -181,8 +225,167 @@ TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) {
base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
base::Unretained(this)));
- ASSERT_EQ(callback_count_, 0);
- ASSERT_EQ(error_callback_count_, 2);
+ EXPECT_EQ(callback_count_, 0);
+ EXPECT_EQ(error_callback_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, SelectConfiguration) {
+ GetAudioSink();
+
+ // Adds an observer for |audio_sink_|.
+ TestAudioSinkObserver observer(audio_sink_);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+
+ // Simulates calling SelectConfiguration on the media endpoint object owned by
+ // |audio_sink_| with some fake capabilities.
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ FakeBluetoothMediaEndpointServiceProvider* media_endpoint =
+ static_cast<FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+ ASSERT_NE(media_endpoint, nullptr);
+
+ media_endpoint->SelectConfiguration(
+ std::vector<uint8_t>({0x21, 0x15, 0x33, 0x2C}),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::SelectConfigurationCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, SetConfiguration) {
+ GetAudioSink();
+
+ // Adds an observer for |audio_sink_|.
+ TestAudioSinkObserver observer(audio_sink_);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+
+ // Simulates calling SetConfiguration on the media endpoint object owned by
+ // |audio_sink_| with a fake transport path and a
+ // Delegate::TransportProperties structure.
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ FakeBluetoothMediaEndpointServiceProvider* media_endpoint =
+ static_cast<FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+ ASSERT_NE(media_endpoint, nullptr);
+
+ media_endpoint->SetConfiguration(
+ ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer.state_changed_count_, 1);
+ EXPECT_EQ(observer.volume_changed_count_, 1);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, SetConfigurationWithUnexpectedState) {
+ GetAudioSink();
+
+ // Adds an observer for |audio_sink_|.
+ TestAudioSinkObserver observer(audio_sink_);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+
+ // Simulates calling SetConfiguration on the media endpoint object owned by
+ // |audio_sink_| with a fake transport path and a
+ // Delegate::TransportProperties structure.
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ FakeBluetoothMediaEndpointServiceProvider* media_endpoint =
+ static_cast<FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+ ASSERT_NE(media_endpoint, nullptr);
+
+ // Set state of Delegate::TransportProperties with an unexpected value.
+ properties_.state = "active";
+
+ media_endpoint->SetConfiguration(
+ ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+}
+
+// Checks if the observer is notified while the media object is
+// removed(invisible). Once the media object is removed, the audio sink is no
+// longer valid.
+TEST_F(BluetoothAudioSinkChromeOSTest, ObserverNotifiedWhenMediaRemoved) {
+ GetAudioSink();
+
+ // Adds an observer for |audio_sink_|.
+ TestAudioSinkObserver observer(audio_sink_);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+
+ // Gets the media object and makes it invisible to see if the state of the
+ // audio sink changes accordingly.
+ FakeBluetoothMediaClient* media = static_cast<FakeBluetoothMediaClient*>(
+ DBusThreadManager::Get()->GetBluetoothMediaClient());
+ media->SetVisible(false);
+
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ FakeBluetoothMediaEndpointServiceProvider* media_endpoint =
+ static_cast<FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(media_endpoint, nullptr);
+}
+
+// Checks if the observer is notified while the media transport is
+// removed(invisible). Once the media transport object is removed, the audio
+// sink is disconnected.
+TEST_F(BluetoothAudioSinkChromeOSTest, ObserverNotifiedWhenTransportRemoved) {
+ GetAudioSink();
+
+ // Adds an observer for |audio_sink_|.
+ TestAudioSinkObserver observer(audio_sink_);
+ EXPECT_EQ(observer.state_changed_count_, 0);
+ EXPECT_EQ(observer.volume_changed_count_, 0);
+
+ // Simulates calling SetConfiguration on the media endpoint object owned by
+ // |audio_sink_| with a fake transport path and a
+ // Delegate::TransportProperties structure.
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ FakeBluetoothMediaEndpointServiceProvider* media_endpoint =
+ static_cast<FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+ ASSERT_NE(media_endpoint, nullptr);
+
+ media_endpoint->SetConfiguration(
+ ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer.state_changed_count_, 1);
+ EXPECT_EQ(observer.volume_changed_count_, 1);
+
+ // Gets the media transport object and makes it invalid to see if the state
+ // of the audio sink changes accordingly.
+ FakeBluetoothMediaTransportClient* transport =
+ static_cast<FakeBluetoothMediaTransportClient*>(
+ DBusThreadManager::Get()->GetBluetoothMediaTransportClient());
+
+ transport->SetValid(media_endpoint->object_path(), false);
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_NE(media_endpoint, nullptr);
}
} // namespace chromeos