1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chromeos/dbus/bluetooth_media_client.h"
12 #include "chromeos/dbus/bluetooth_media_endpoint_service_provider.h"
13 #include "chromeos/dbus/bluetooth_media_transport_client.h"
14 #include "chromeos/dbus/dbus_thread_manager.h"
15 #include "chromeos/dbus/fake_bluetooth_media_client.h"
16 #include "chromeos/dbus/fake_bluetooth_media_endpoint_service_provider.h"
17 #include "chromeos/dbus/fake_bluetooth_media_transport_client.h"
18 #include "dbus/object_path.h"
19 #include "device/bluetooth/bluetooth_adapter.h"
20 #include "device/bluetooth/bluetooth_adapter_factory.h"
21 #include "device/bluetooth/bluetooth_audio_sink.h"
22 #include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using dbus::ObjectPath
;
26 using device::BluetoothAdapter
;
27 using device::BluetoothAdapterFactory
;
28 using device::BluetoothAudioSink
;
32 class TestAudioSinkObserver
: public BluetoothAudioSink::Observer
{
34 explicit TestAudioSinkObserver(scoped_refptr
<BluetoothAudioSink
> audio_sink
)
35 : state_changed_count_(0),
36 volume_changed_count_(0),
37 state_(audio_sink
->GetState()),
38 audio_sink_(audio_sink
) {
39 audio_sink_
->AddObserver(this);
42 ~TestAudioSinkObserver() override
{ audio_sink_
->RemoveObserver(this); }
44 void BluetoothAudioSinkStateChanged(
45 BluetoothAudioSink
* audio_sink
,
46 BluetoothAudioSink::State state
) override
{
47 ++state_changed_count_
;
50 void BluetoothAudioSinkVolumeChanged(BluetoothAudioSink
* audio_sink
,
51 uint16_t volume
) override
{
52 ++volume_changed_count_
;
55 int state_changed_count_
;
56 int volume_changed_count_
;
57 BluetoothAudioSink::State state_
;
60 scoped_refptr
<BluetoothAudioSink
> audio_sink_
;
63 class BluetoothAudioSinkChromeOSTest
: public testing::Test
{
65 void SetUp() override
{
66 DBusThreadManager::Initialize();
69 error_callback_count_
= 0;
71 // Initiates Delegate::TransportProperties with default values.
73 ObjectPath(FakeBluetoothMediaTransportClient::kTransportDevicePath
);
74 properties_
.uuid
= BluetoothMediaClient::kBluetoothAudioSinkUUID
;
75 properties_
.codec
= FakeBluetoothMediaTransportClient::kTransportCodec
;
76 properties_
.configuration
=
77 FakeBluetoothMediaTransportClient::kTransportConfiguration
;
78 properties_
.state
= BluetoothMediaTransportClient::kStateIdle
;
79 properties_
.delay
.reset(
80 new uint16_t(FakeBluetoothMediaTransportClient::kTransportDelay
));
81 properties_
.volume
.reset(
82 new uint16_t(FakeBluetoothMediaTransportClient::kTransportVolume
));
87 void TearDown() override
{
89 error_callback_count_
= 0;
91 // The adapter should outlive audio sink.
92 audio_sink_
= nullptr;
94 DBusThreadManager::Shutdown();
97 // Gets the existing Bluetooth adapter.
99 BluetoothAdapterFactory::GetAdapter(
100 base::Bind(&BluetoothAudioSinkChromeOSTest::GetAdapterCallback
,
101 base::Unretained(this)));
104 // Called whenever BluetoothAdapter is retrieved successfully.
105 void GetAdapterCallback(scoped_refptr
<BluetoothAdapter
> adapter
) {
108 ASSERT_NE(adapter_
.get(), nullptr);
109 ASSERT_TRUE(adapter_
->IsInitialized());
110 adapter_
->SetPowered(
112 base::Bind(&BluetoothAudioSinkChromeOSTest::Callback
,
113 base::Unretained(this)),
114 base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback
,
115 base::Unretained(this)));
116 ASSERT_TRUE(adapter_
->IsPresent());
117 ASSERT_TRUE(adapter_
->IsPowered());
118 EXPECT_EQ(callback_count_
, 1);
119 EXPECT_EQ(error_callback_count_
, 0);
121 // Resets callback_count_.
125 // Registers BluetoothAudioSinkChromeOS with default codec and capabilities.
126 void GetAudioSink() {
127 // Sets up valid codec and capabilities.
128 BluetoothAudioSink::Options options
;
129 ASSERT_EQ(options
.codec
, 0x00);
130 ASSERT_EQ(options
.capabilities
,
131 std::vector
<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
133 // Registers |audio_sink_| with valid codec and capabilities
134 adapter_
->RegisterAudioSink(
136 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback
,
137 base::Unretained(this)),
138 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback
,
139 base::Unretained(this)));
141 EXPECT_EQ(callback_count_
, 1);
142 EXPECT_EQ(error_callback_count_
, 0);
145 // Called whenever RegisterAudioSink is completed successfully.
146 void RegisterCallback(
147 scoped_refptr
<BluetoothAudioSink
> audio_sink
) {
149 audio_sink_
= audio_sink
;
150 ASSERT_NE(audio_sink_
.get(), nullptr);
151 ASSERT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_DISCONNECTED
);
154 // Called whenever RegisterAudioSink failed.
155 void RegisterErrorCallback(BluetoothAudioSink::ErrorCode error_code
) {
156 ++error_callback_count_
;
157 EXPECT_EQ(error_code
, BluetoothAudioSink::ERROR_NOT_REGISTERED
);
160 // Called whenever there capabilities are returned from SelectConfiguration.
161 void SelectConfigurationCallback(const std::vector
<uint8_t>& capabilities
) {
164 // |capabilities| should be the same as the capabilities for registering an
165 // audio sink in GetAudioSink().
166 EXPECT_EQ(capabilities
, std::vector
<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
169 // Generic callbacks.
174 void ErrorCallback() {
175 ++error_callback_count_
;
180 int error_callback_count_
;
182 base::MessageLoop message_loop_
;
184 scoped_refptr
<BluetoothAdapter
> adapter_
;
185 scoped_refptr
<BluetoothAudioSink
> audio_sink_
;
187 // The default property set used while calling SetConfiguration on a media
189 BluetoothMediaEndpointServiceProvider::Delegate::TransportProperties
193 TEST_F(BluetoothAudioSinkChromeOSTest
, RegisterSucceeded
) {
196 // Adds an observer for |audio_sink_|.
197 TestAudioSinkObserver
observer(audio_sink_
);
198 EXPECT_EQ(observer
.state_changed_count_
, 0);
199 EXPECT_EQ(observer
.volume_changed_count_
, 0);
202 TEST_F(BluetoothAudioSinkChromeOSTest
, RegisterFailedWithInvalidOptions
) {
203 // Sets options with an invalid codec and valid capabilities.
204 BluetoothAudioSink::Options options
;
205 options
.codec
= 0xff;
206 options
.capabilities
= std::vector
<uint8_t>({0x3f, 0xff, 0x12, 0x35});
208 adapter_
->RegisterAudioSink(
210 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback
,
211 base::Unretained(this)),
212 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback
,
213 base::Unretained(this)));
215 EXPECT_EQ(callback_count_
, 0);
216 EXPECT_EQ(error_callback_count_
, 1);
218 // Sets options with a valid codec and invalid capabilities.
219 options
.codec
= 0x00;
220 options
.capabilities
.clear();
221 adapter_
->RegisterAudioSink(
223 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback
,
224 base::Unretained(this)),
225 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback
,
226 base::Unretained(this)));
228 EXPECT_EQ(callback_count_
, 0);
229 EXPECT_EQ(error_callback_count_
, 2);
232 TEST_F(BluetoothAudioSinkChromeOSTest
, SelectConfiguration
) {
235 // Adds an observer for |audio_sink_|.
236 TestAudioSinkObserver
observer(audio_sink_
);
237 EXPECT_EQ(observer
.state_changed_count_
, 0);
238 EXPECT_EQ(observer
.volume_changed_count_
, 0);
240 // Simulates calling SelectConfiguration on the media endpoint object owned by
241 // |audio_sink_| with some fake capabilities.
242 BluetoothAudioSinkChromeOS
* audio_sink_chromeos
=
243 static_cast<BluetoothAudioSinkChromeOS
*>(audio_sink_
.get());
244 FakeBluetoothMediaEndpointServiceProvider
* media_endpoint
=
245 static_cast<FakeBluetoothMediaEndpointServiceProvider
*>(
246 audio_sink_chromeos
->GetEndpointServiceProvider());
247 ASSERT_NE(media_endpoint
, nullptr);
249 media_endpoint
->SelectConfiguration(
250 std::vector
<uint8_t>({0x21, 0x15, 0x33, 0x2C}),
251 base::Bind(&BluetoothAudioSinkChromeOSTest::SelectConfigurationCallback
,
252 base::Unretained(this)));
254 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_DISCONNECTED
);
255 EXPECT_EQ(callback_count_
, 2);
256 EXPECT_EQ(error_callback_count_
, 0);
257 EXPECT_EQ(observer
.state_changed_count_
, 0);
258 EXPECT_EQ(observer
.volume_changed_count_
, 0);
261 TEST_F(BluetoothAudioSinkChromeOSTest
, SetConfiguration
) {
264 // Adds an observer for |audio_sink_|.
265 TestAudioSinkObserver
observer(audio_sink_
);
266 EXPECT_EQ(observer
.state_changed_count_
, 0);
267 EXPECT_EQ(observer
.volume_changed_count_
, 0);
269 // Simulates calling SetConfiguration on the media endpoint object owned by
270 // |audio_sink_| with a fake transport path and a
271 // Delegate::TransportProperties structure.
272 BluetoothAudioSinkChromeOS
* audio_sink_chromeos
=
273 static_cast<BluetoothAudioSinkChromeOS
*>(audio_sink_
.get());
274 FakeBluetoothMediaEndpointServiceProvider
* media_endpoint
=
275 static_cast<FakeBluetoothMediaEndpointServiceProvider
*>(
276 audio_sink_chromeos
->GetEndpointServiceProvider());
277 ASSERT_NE(media_endpoint
, nullptr);
279 media_endpoint
->SetConfiguration(
280 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath
),
283 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_IDLE
);
284 EXPECT_EQ(callback_count_
, 1);
285 EXPECT_EQ(error_callback_count_
, 0);
286 EXPECT_EQ(observer
.state_changed_count_
, 1);
287 EXPECT_EQ(observer
.volume_changed_count_
, 1);
290 TEST_F(BluetoothAudioSinkChromeOSTest
, SetConfigurationWithUnexpectedState
) {
293 // Adds an observer for |audio_sink_|.
294 TestAudioSinkObserver
observer(audio_sink_
);
295 EXPECT_EQ(observer
.state_changed_count_
, 0);
296 EXPECT_EQ(observer
.volume_changed_count_
, 0);
298 // Simulates calling SetConfiguration on the media endpoint object owned by
299 // |audio_sink_| with a fake transport path and a
300 // Delegate::TransportProperties structure.
301 BluetoothAudioSinkChromeOS
* audio_sink_chromeos
=
302 static_cast<BluetoothAudioSinkChromeOS
*>(audio_sink_
.get());
303 FakeBluetoothMediaEndpointServiceProvider
* media_endpoint
=
304 static_cast<FakeBluetoothMediaEndpointServiceProvider
*>(
305 audio_sink_chromeos
->GetEndpointServiceProvider());
306 ASSERT_NE(media_endpoint
, nullptr);
308 // Set state of Delegate::TransportProperties with an unexpected value.
309 properties_
.state
= "active";
311 media_endpoint
->SetConfiguration(
312 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath
),
315 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_DISCONNECTED
);
316 EXPECT_EQ(callback_count_
, 1);
317 EXPECT_EQ(error_callback_count_
, 0);
318 EXPECT_EQ(observer
.state_changed_count_
, 0);
319 EXPECT_EQ(observer
.volume_changed_count_
, 0);
322 // Checks if the observer is notified while the media object is
323 // removed(invisible). Once the media object is removed, the audio sink is no
325 TEST_F(BluetoothAudioSinkChromeOSTest
, ObserverNotifiedWhenMediaRemoved
) {
328 // Adds an observer for |audio_sink_|.
329 TestAudioSinkObserver
observer(audio_sink_
);
330 EXPECT_EQ(observer
.state_changed_count_
, 0);
331 EXPECT_EQ(observer
.volume_changed_count_
, 0);
333 // Gets the media object and makes it invisible to see if the state of the
334 // audio sink changes accordingly.
335 FakeBluetoothMediaClient
* media
= static_cast<FakeBluetoothMediaClient
*>(
336 DBusThreadManager::Get()->GetBluetoothMediaClient());
337 media
->SetVisible(false);
339 BluetoothAudioSinkChromeOS
* audio_sink_chromeos
=
340 static_cast<BluetoothAudioSinkChromeOS
*>(audio_sink_
.get());
341 FakeBluetoothMediaEndpointServiceProvider
* media_endpoint
=
342 static_cast<FakeBluetoothMediaEndpointServiceProvider
*>(
343 audio_sink_chromeos
->GetEndpointServiceProvider());
345 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_INVALID
);
346 EXPECT_EQ(media_endpoint
, nullptr);
349 // Checks if the observer is notified while the media transport is
350 // removed(invisible). Once the media transport object is removed, the audio
351 // sink is disconnected.
352 TEST_F(BluetoothAudioSinkChromeOSTest
, ObserverNotifiedWhenTransportRemoved
) {
355 // Adds an observer for |audio_sink_|.
356 TestAudioSinkObserver
observer(audio_sink_
);
357 EXPECT_EQ(observer
.state_changed_count_
, 0);
358 EXPECT_EQ(observer
.volume_changed_count_
, 0);
360 // Simulates calling SetConfiguration on the media endpoint object owned by
361 // |audio_sink_| with a fake transport path and a
362 // Delegate::TransportProperties structure.
363 BluetoothAudioSinkChromeOS
* audio_sink_chromeos
=
364 static_cast<BluetoothAudioSinkChromeOS
*>(audio_sink_
.get());
365 FakeBluetoothMediaEndpointServiceProvider
* media_endpoint
=
366 static_cast<FakeBluetoothMediaEndpointServiceProvider
*>(
367 audio_sink_chromeos
->GetEndpointServiceProvider());
368 ASSERT_NE(media_endpoint
, nullptr);
370 media_endpoint
->SetConfiguration(
371 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath
),
374 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_IDLE
);
375 EXPECT_EQ(callback_count_
, 1);
376 EXPECT_EQ(error_callback_count_
, 0);
377 EXPECT_EQ(observer
.state_changed_count_
, 1);
378 EXPECT_EQ(observer
.volume_changed_count_
, 1);
380 // Gets the media transport object and makes it invalid to see if the state
381 // of the audio sink changes accordingly.
382 FakeBluetoothMediaTransportClient
* transport
=
383 static_cast<FakeBluetoothMediaTransportClient
*>(
384 DBusThreadManager::Get()->GetBluetoothMediaTransportClient());
386 transport
->SetValid(media_endpoint
->object_path(), false);
387 EXPECT_EQ(audio_sink_
->GetState(), BluetoothAudioSink::STATE_DISCONNECTED
);
388 EXPECT_NE(media_endpoint
, nullptr);
391 } // namespace chromeos