summaryrefslogtreecommitdiffstats
path: root/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc')
-rw-r--r--device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc958
1 files changed, 958 insertions, 0 deletions
diff --git a/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc b/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
new file mode 100644
index 0000000..22918f7
--- /dev/null
+++ b/device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc
@@ -0,0 +1,958 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_audio_sink.h"
+#include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
+#include "device/bluetooth/dbus/bluetooth_media_client.h"
+#include "device/bluetooth/dbus/bluetooth_media_endpoint_service_provider.h"
+#include "device/bluetooth/dbus/bluetooth_media_transport_client.h"
+#include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/dbus/fake_bluetooth_media_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h"
+#include "device/bluetooth/dbus/fake_bluetooth_media_transport_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using dbus::ObjectPath;
+using device::BluetoothAdapter;
+using device::BluetoothAdapterFactory;
+using device::BluetoothAudioSink;
+
+namespace chromeos {
+
+class TestAudioSinkObserver : public BluetoothAudioSink::Observer {
+ public:
+ explicit TestAudioSinkObserver(scoped_refptr<BluetoothAudioSink> audio_sink)
+ : state_changed_count_(0),
+ volume_changed_count_(0),
+ total_read_(0),
+ state_(audio_sink->GetState()),
+ audio_sink_(audio_sink) {
+ audio_sink_->AddObserver(this);
+ }
+
+ ~TestAudioSinkObserver() override { audio_sink_->RemoveObserver(this); }
+
+ void BluetoothAudioSinkStateChanged(
+ BluetoothAudioSink* audio_sink,
+ BluetoothAudioSink::State state) override {
+ if (state == BluetoothAudioSink::STATE_IDLE)
+ total_read_ = 0;
+
+ ++state_changed_count_;
+ }
+
+ void BluetoothAudioSinkVolumeChanged(BluetoothAudioSink* audio_sink,
+ uint16_t volume) override {
+ ++volume_changed_count_;
+ }
+
+ void BluetoothAudioSinkDataAvailable(BluetoothAudioSink* audio_sink,
+ char* data,
+ size_t size,
+ uint16_t read_mtu) override {
+ total_read_ += size;
+ data_.clear();
+ data_.insert(data_.begin(), data, data + size);
+ read_mtu_ = read_mtu;
+ }
+
+ int state_changed_count_;
+ int volume_changed_count_;
+ int data_available_count_;
+ size_t total_read_;
+ std::vector<char> data_;
+ uint16_t read_mtu_;
+ BluetoothAudioSink::State state_;
+
+ private:
+ scoped_refptr<BluetoothAudioSink> audio_sink_;
+};
+
+class BluetoothAudioSinkChromeOSTest : public testing::Test {
+ public:
+ void SetUp() override {
+ bluez::BluezDBusManager::Initialize(NULL, true);
+
+ callback_count_ = 0;
+ error_callback_count_ = 0;
+
+ fake_media_ = static_cast<bluez::FakeBluetoothMediaClient*>(
+ bluez::BluezDBusManager::Get()->GetBluetoothMediaClient());
+ fake_transport_ = static_cast<bluez::FakeBluetoothMediaTransportClient*>(
+ bluez::BluezDBusManager::Get()->GetBluetoothMediaTransportClient());
+
+ // Initiates Delegate::TransportProperties with default values.
+ properties_.device = ObjectPath(
+ bluez::FakeBluetoothMediaTransportClient::kTransportDevicePath);
+ properties_.uuid = bluez::BluetoothMediaClient::kBluetoothAudioSinkUUID;
+ properties_.codec =
+ bluez::FakeBluetoothMediaTransportClient::kTransportCodec;
+ properties_.configuration =
+ bluez::FakeBluetoothMediaTransportClient::kTransportConfiguration;
+ properties_.state = bluez::BluetoothMediaTransportClient::kStateIdle;
+ properties_.delay.reset(new uint16_t(
+ bluez::FakeBluetoothMediaTransportClient::kTransportDelay));
+ properties_.volume.reset(new uint16_t(
+ bluez::FakeBluetoothMediaTransportClient::kTransportVolume));
+
+ GetAdapter();
+ }
+
+ void TearDown() override {
+ callback_count_ = 0;
+ error_callback_count_ = 0;
+ observer_.reset();
+
+ fake_media_->SetVisible(true);
+
+ // The adapter should outlive audio sink.
+ audio_sink_ = nullptr;
+ adapter_ = nullptr;
+ bluez::BluezDBusManager::Shutdown();
+ }
+
+ // 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;
+
+ ASSERT_NE(adapter_.get(), nullptr);
+ ASSERT_TRUE(adapter_->IsInitialized());
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ ASSERT_TRUE(adapter_->IsPresent());
+ ASSERT_TRUE(adapter_->IsPowered());
+ EXPECT_EQ(callback_count_, 1);
+ EXPECT_EQ(error_callback_count_, 0);
+
+ // Resets callback_count_.
+ --callback_count_;
+ }
+
+ // Registers BluetoothAudioSinkChromeOS with default codec and capabilities.
+ // If the audio sink is retrieved successfully, the state changes to
+ // STATE_DISCONNECTED.
+ 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)));
+
+ observer_.reset(new TestAudioSinkObserver(audio_sink_));
+ 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);
+ }
+
+ void GetFakeMediaEndpoint() {
+ BluetoothAudioSinkChromeOS* audio_sink_chromeos =
+ static_cast<BluetoothAudioSinkChromeOS*>(audio_sink_.get());
+ ASSERT_NE(audio_sink_chromeos, nullptr);
+
+ media_endpoint_ =
+ static_cast<bluez::FakeBluetoothMediaEndpointServiceProvider*>(
+ audio_sink_chromeos->GetEndpointServiceProvider());
+ }
+
+ // Called whenever RegisterAudioSink is completed successfully.
+ void RegisterCallback(
+ scoped_refptr<BluetoothAudioSink> audio_sink) {
+ ++callback_count_;
+ audio_sink_ = audio_sink;
+
+ GetFakeMediaEndpoint();
+ ASSERT_NE(media_endpoint_, nullptr);
+ fake_media_->SetEndpointRegistered(media_endpoint_, true);
+
+ ASSERT_NE(audio_sink_.get(), nullptr);
+ ASSERT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ }
+
+ // Called whenever RegisterAudioSink failed.
+ void RegisterErrorCallback(BluetoothAudioSink::ErrorCode error_code) {
+ ++error_callback_count_;
+ 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}));
+ }
+
+ void UnregisterErrorCallback(BluetoothAudioSink::ErrorCode error_code) {
+ ++error_callback_count_;
+ EXPECT_EQ(error_code, BluetoothAudioSink::ERROR_NOT_UNREGISTERED);
+ }
+
+ // Generic callbacks.
+ void Callback() {
+ ++callback_count_;
+ }
+
+ void ErrorCallback() {
+ ++error_callback_count_;
+ }
+
+ protected:
+ int callback_count_;
+ int error_callback_count_;
+
+ base::MessageLoopForIO message_loop_;
+
+ bluez::FakeBluetoothMediaClient* fake_media_;
+ bluez::FakeBluetoothMediaTransportClient* fake_transport_;
+ bluez::FakeBluetoothMediaEndpointServiceProvider* media_endpoint_;
+ scoped_ptr<TestAudioSinkObserver> observer_;
+ scoped_refptr<BluetoothAdapter> adapter_;
+ scoped_refptr<BluetoothAudioSink> audio_sink_;
+
+ // The default property set used while calling SetConfiguration on a media
+ // endpoint object.
+ bluez::BluetoothMediaEndpointServiceProvider::Delegate::TransportProperties
+ properties_;
+};
+
+TEST_F(BluetoothAudioSinkChromeOSTest, RegisterSucceeded) {
+ GetAudioSink();
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) {
+ // Sets options with an invalid codec and valid capabilities.
+ BluetoothAudioSink::Options options;
+ options.codec = 0xff;
+ 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)));
+
+ EXPECT_EQ(callback_count_, 0);
+ EXPECT_EQ(error_callback_count_, 1);
+
+ // Sets options with a valid codec and invalid capabilities.
+ options.codec = 0x00;
+ options.capabilities.clear();
+ adapter_->RegisterAudioSink(
+ options,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(callback_count_, 0);
+ EXPECT_EQ(error_callback_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, SelectConfiguration) {
+ GetAudioSink();
+
+ // Simulates calling SelectConfiguration on the media endpoint object owned by
+ // |audio_sink_| with some fake capabilities.
+ 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();
+
+ 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);
+
+ // Simulates calling SetConfiguration on the media endpoint object owned by
+ // |audio_sink_| with a fake transport path and a
+ // Delegate::TransportProperties structure.
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ 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();
+
+ 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);
+
+ // Set state of Delegate::TransportProperties with an unexpected value.
+ properties_.state = "pending";
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ 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);
+}
+
+// Checks if the observer is notified on media-removed event when the state of
+// |audio_sink_| is STATE_DISCONNECTED. Once the media object is removed, the
+// audio sink is no longer valid.
+TEST_F(BluetoothAudioSinkChromeOSTest, MediaRemovedDuringDisconnectedState) {
+ GetAudioSink();
+
+ // Gets the media object and makes it invisible to see if the state of the
+ // audio sink changes accordingly.
+ fake_media_->SetVisible(false);
+
+ GetFakeMediaEndpoint();
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(media_endpoint_, nullptr);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 0);
+}
+
+// Checks if the observer is notified on media-removed event when the state of
+// |audio_sink_| is STATE_IDLE. Once the media object is removed, the audio sink
+// is no longer valid.
+TEST_F(BluetoothAudioSinkChromeOSTest, MediaRemovedDuringIdleState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ // Gets the media object and makes it invisible to see if the state of the
+ // audio sink changes accordingly.
+ fake_media_->SetVisible(false);
+
+ GetFakeMediaEndpoint();
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(media_endpoint_, nullptr);
+
+ // The state becomes disconnted and then invalid, since the removal of
+ // transport object should happend before media becomes invisible.
+ // State: STATE_IDLE -> STATE_DISCONNECTED -> STATE_INVALID
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, MediaRemovedDuringActiveState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ message_loop_.RunUntilIdle();
+
+ // Acquire is called when the state of |audio_sink_| becomes STATE_PENDING,
+ // and Acquire will trigger state change. Therefore, the state will be
+ // STATE_ACTIVE right after STATE_PENDING.
+ // State: STATE_IDLE -> STATE_PENDING -> STATE_ACTIVE
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+
+ // Gets the media object and makes it invisible to see if the state of the
+ // audio sink changes accordingly.
+ fake_media_->SetVisible(false);
+
+ GetFakeMediaEndpoint();
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(media_endpoint_, nullptr);
+
+ // The state becomes disconnted and then invalid, since the removal of
+ // transport object should happend before media becomes invisible.
+ // State: STATE_ACTIVE -> STATE_DISCONNECTED -> STATE_INVALID
+ EXPECT_EQ(observer_->state_changed_count_, 5);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+// Checks if the observer is notified on transport-removed event when the state
+// of |audio_sink_| is STATE_IDEL. Once the media transport object is removed,
+// the audio sink is disconnected.
+TEST_F(BluetoothAudioSinkChromeOSTest, TransportRemovedDuringIdleState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ // Makes the transport object invalid to see if the state of the audio sink
+ // changes accordingly.
+ fake_transport_->SetValid(media_endpoint_, false);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_NE(media_endpoint_, nullptr);
+ EXPECT_EQ(observer_->state_changed_count_, 2);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, TransportRemovedDuringActiveState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ message_loop_.RunUntilIdle();
+
+ // Acquire is called when the state of |audio_sink_| becomes STATE_PENDING,
+ // and Acquire will trigger state change. Therefore, the state will be
+ // STATE_ACTIVE right after STATE_PENDING.
+ // State: STATE_IDLE -> STATE_PENDING -> STATE_ACTIVE
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+
+ // Makes the transport object invalid to see if the state of the audio sink
+ // changes accordingly.
+ fake_transport_->SetValid(media_endpoint_, false);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_NE(media_endpoint_, nullptr);
+ EXPECT_EQ(observer_->state_changed_count_, 4);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest,
+ AdapterPoweredChangedDuringDisconnectedState) {
+ GetAudioSink();
+
+ adapter_->SetPowered(
+ false,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_FALSE(adapter_->IsPowered());
+ 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);
+
+ adapter_->SetPowered(
+ true,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_TRUE(adapter_->IsPowered());
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_EQ(callback_count_, 3);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 0);
+ EXPECT_EQ(observer_->volume_changed_count_, 0);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, AdapterPoweredChangedDuringIdleState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ adapter_->SetPowered(
+ false,
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback,
+ base::Unretained(this)));
+ GetFakeMediaEndpoint();
+
+ EXPECT_TRUE(adapter_->IsPresent());
+ EXPECT_FALSE(adapter_->IsPowered());
+ EXPECT_NE(media_endpoint_, nullptr);
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
+ EXPECT_EQ(callback_count_, 3);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 2);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest,
+ UnregisterAudioSinkDuringDisconnectedState) {
+ GetAudioSink();
+
+ audio_sink_->Unregister(
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::UnregisterErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 0);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, UnregisterAudioSinkDuringIdleState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ audio_sink_->Unregister(
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::UnregisterErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(callback_count_, 3);
+ EXPECT_EQ(error_callback_count_, 0);
+
+ // The state becomes disconnted and then invalid, since the removal of
+ // transport object should happend before the unregistration of endpoint.
+ // State: STATE_IDLE -> STATE_DISCONNECTED -> STATE_INVALID
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, UnregisterAudioSinkDuringActiveState) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ message_loop_.RunUntilIdle();
+
+ // Acquire is called when the state of |audio_sink_| becomes STATE_PENDING,
+ // and Acquire will trigger state change. Therefore, the state will be
+ // STATE_ACTIVE right after STATE_PENDING.
+ // State: STATE_IDLE -> STATE_PENDING -> STATE_ACTIVE
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+
+ audio_sink_->Unregister(
+ base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAudioSinkChromeOSTest::UnregisterErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
+ EXPECT_EQ(callback_count_, 3);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 5);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, StateChanged) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ // Changes the current state of transport to pending.
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_PENDING);
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, VolumeChanged) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ // |kTransportVolume| is the initial volume of the transport, and this
+ // value is propagated to the audio sink via SetConfiguration.
+ EXPECT_EQ(audio_sink_->GetVolume(),
+ bluez::FakeBluetoothMediaTransportClient::kTransportVolume);
+
+ // Changes volume to a valid level.
+ fake_transport_->SetVolume(media_endpoint_->object_path(), 100);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 2);
+ EXPECT_EQ(audio_sink_->GetVolume(), 100);
+
+ // Changes volume to an invalid level.
+ fake_transport_->SetVolume(media_endpoint_->object_path(), 200);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 3);
+ EXPECT_EQ(audio_sink_->GetVolume(), BluetoothAudioSink::kInvalidVolume);
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, AcquireFD) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ std::vector<char> data_one(16, 0x12);
+ fake_transport_->WriteData(media_endpoint_->object_path(), data_one);
+
+ message_loop_.RunUntilIdle();
+
+ // Acquire is called when the state of |audio_sink_| becomes STATE_PENDING,
+ // and Acquire will trigger state change. Therefore, the state will be
+ // STATE_ACTIVE right after STATE_PENDING.
+ // State: STATE_IDLE -> STATE_PENDING -> STATE_ACTIVE
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->total_read_, data_one.size());
+ EXPECT_EQ(observer_->data_, data_one);
+ EXPECT_EQ(observer_->read_mtu_,
+ bluez::FakeBluetoothMediaTransportClient::kDefaultReadMtu);
+}
+
+// Tests the case where the remote device pauses and resume audio streaming.
+TEST_F(BluetoothAudioSinkChromeOSTest, PauseAndResume) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ std::vector<char> data_one(16, 0x12);
+ fake_transport_->WriteData(media_endpoint_->object_path(), data_one);
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(observer_->data_, data_one);
+ EXPECT_EQ(observer_->read_mtu_,
+ bluez::FakeBluetoothMediaTransportClient::kDefaultReadMtu);
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->total_read_, data_one.size());
+
+ // Simulates the situation where the remote device pauses and resume audio
+ // streaming.
+ fake_transport_->SetState(media_endpoint_->object_path(), "idle");
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(observer_->state_changed_count_, 4);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ std::vector<char> data_two(8, 0x10);
+ fake_transport_->WriteData(media_endpoint_->object_path(), data_two);
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(observer_->data_, data_two);
+ EXPECT_EQ(observer_->read_mtu_,
+ bluez::FakeBluetoothMediaTransportClient::kDefaultReadMtu);
+ EXPECT_EQ(observer_->state_changed_count_, 6);
+ EXPECT_EQ(observer_->total_read_, data_two.size());
+}
+
+TEST_F(BluetoothAudioSinkChromeOSTest, ContinuouslyStreaming) {
+ GetAudioSink();
+
+ 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);
+
+ media_endpoint_->SetConfiguration(
+ fake_transport_->GetTransportPath(media_endpoint_->object_path()),
+ properties_);
+
+ EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_IDLE);
+ EXPECT_EQ(callback_count_, 2);
+ EXPECT_EQ(error_callback_count_, 0);
+ EXPECT_EQ(observer_->state_changed_count_, 1);
+ EXPECT_EQ(observer_->volume_changed_count_, 1);
+
+ fake_transport_->SetState(media_endpoint_->object_path(), "pending");
+
+ std::vector<char> data_one(16, 0x12);
+ fake_transport_->WriteData(media_endpoint_->object_path(), data_one);
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(observer_->data_, data_one);
+ EXPECT_EQ(observer_->read_mtu_,
+ bluez::FakeBluetoothMediaTransportClient::kDefaultReadMtu);
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->total_read_, data_one.size());
+
+ std::vector<char> data_two(8, 0x10);
+ fake_transport_->WriteData(media_endpoint_->object_path(), data_two);
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(observer_->data_, data_two);
+ EXPECT_EQ(observer_->read_mtu_,
+ bluez::FakeBluetoothMediaTransportClient::kDefaultReadMtu);
+ EXPECT_EQ(observer_->state_changed_count_, 3);
+ EXPECT_EQ(observer_->total_read_, data_one.size() + data_two.size());
+}
+
+} // namespace chromeos