Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: device/bluetooth/bluetooth_audio_sink_chromeos_unittest.cc

Issue 910023002: device/bluetooth:Implement BluetoothMediaEndpointServiceProvider delegate and media-related overrid… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moved the addition/removal of all types of observer to constructor/destructor. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « device/bluetooth/bluetooth_audio_sink_chromeos.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h" 9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.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"
11 #include "chromeos/dbus/dbus_thread_manager.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"
12 #include "dbus/object_path.h" 18 #include "dbus/object_path.h"
13 #include "device/bluetooth/bluetooth_adapter.h" 19 #include "device/bluetooth/bluetooth_adapter.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h" 20 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "device/bluetooth/bluetooth_audio_sink.h" 21 #include "device/bluetooth/bluetooth_audio_sink.h"
16 #include "device/bluetooth/bluetooth_audio_sink_chromeos.h" 22 #include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
17 #include "testing/gtest/include/gtest/gtest.h" 23 #include "testing/gtest/include/gtest/gtest.h"
18 24
25 using dbus::ObjectPath;
19 using device::BluetoothAdapter; 26 using device::BluetoothAdapter;
20 using device::BluetoothAdapterFactory; 27 using device::BluetoothAdapterFactory;
21 using device::BluetoothAudioSink; 28 using device::BluetoothAudioSink;
22 29
23 namespace chromeos { 30 namespace chromeos {
24 31
25 class TestAudioSinkObserver : public BluetoothAudioSink::Observer { 32 class TestAudioSinkObserver : public BluetoothAudioSink::Observer {
26 public: 33 public:
27 explicit TestAudioSinkObserver(scoped_refptr<BluetoothAudioSink> audio_sink) 34 explicit TestAudioSinkObserver(scoped_refptr<BluetoothAudioSink> audio_sink)
28 : state_changed_count_(0), 35 : state_changed_count_(0),
(...skipping 20 matching lines...) Expand all
49 int volume_changed_count_; 56 int volume_changed_count_;
50 BluetoothAudioSink::State state_; 57 BluetoothAudioSink::State state_;
51 58
52 private: 59 private:
53 scoped_refptr<BluetoothAudioSink> audio_sink_; 60 scoped_refptr<BluetoothAudioSink> audio_sink_;
54 }; 61 };
55 62
56 class BluetoothAudioSinkChromeOSTest : public testing::Test { 63 class BluetoothAudioSinkChromeOSTest : public testing::Test {
57 public: 64 public:
58 void SetUp() override { 65 void SetUp() override {
59 chromeos::DBusThreadManager::Initialize(); 66 DBusThreadManager::Initialize();
60 67
61 callback_count_ = 0; 68 callback_count_ = 0;
62 error_callback_count_ = 0; 69 error_callback_count_ = 0;
63 audio_sink_ = nullptr; 70
64 adapter_ = nullptr; 71 // Initiates Delegate::TransportProperties with default values.
72 properties_.device =
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));
65 83
66 GetAdapter(); 84 GetAdapter();
67 } 85 }
68 86
69 void TearDown() override { 87 void TearDown() override {
70 callback_count_ = 0; 88 callback_count_ = 0;
71 error_callback_count_ = 0; 89 error_callback_count_ = 0;
72 90
73 // The adapter should outlive audio sink. 91 // The adapter should outlive audio sink.
74 audio_sink_ = nullptr; 92 audio_sink_ = nullptr;
75 adapter_ = nullptr; 93 adapter_ = nullptr;
76 DBusThreadManager::Shutdown(); 94 DBusThreadManager::Shutdown();
77 } 95 }
78 96
79 // Get the existing Bluetooth adapter. 97 // Gets the existing Bluetooth adapter.
80 void GetAdapter() { 98 void GetAdapter() {
81 BluetoothAdapterFactory::GetAdapter( 99 BluetoothAdapterFactory::GetAdapter(
82 base::Bind(&BluetoothAudioSinkChromeOSTest::GetAdapterCallback, 100 base::Bind(&BluetoothAudioSinkChromeOSTest::GetAdapterCallback,
83 base::Unretained(this))); 101 base::Unretained(this)));
84 } 102 }
85 103
104 // Called whenever BluetoothAdapter is retrieved successfully.
86 void GetAdapterCallback(scoped_refptr<BluetoothAdapter> adapter) { 105 void GetAdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
87 adapter_ = adapter; 106 adapter_ = adapter;
88 107
89 ASSERT_NE(adapter_.get(), nullptr); 108 ASSERT_NE(adapter_.get(), nullptr);
90 ASSERT_TRUE(adapter_->IsInitialized()); 109 ASSERT_TRUE(adapter_->IsInitialized());
91 adapter_->SetPowered( 110 adapter_->SetPowered(
92 true, 111 true,
93 base::Bind(&BluetoothAudioSinkChromeOSTest::Callback, 112 base::Bind(&BluetoothAudioSinkChromeOSTest::Callback,
94 base::Unretained(this)), 113 base::Unretained(this)),
95 base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback, 114 base::Bind(&BluetoothAudioSinkChromeOSTest::ErrorCallback,
96 base::Unretained(this))); 115 base::Unretained(this)));
97 ASSERT_TRUE(adapter_->IsPresent()); 116 ASSERT_TRUE(adapter_->IsPresent());
98 ASSERT_TRUE(adapter_->IsPowered()); 117 ASSERT_TRUE(adapter_->IsPowered());
99 ASSERT_EQ(callback_count_, 1); 118 EXPECT_EQ(callback_count_, 1);
100 ASSERT_EQ(error_callback_count_, 0); 119 EXPECT_EQ(error_callback_count_, 0);
120
121 // Resets callback_count_.
101 --callback_count_; 122 --callback_count_;
102 } 123 }
103 124
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}));
132
133 // Registers |audio_sink_| with valid codec and capabilities
134 adapter_->RegisterAudioSink(
135 options,
136 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
137 base::Unretained(this)),
138 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
139 base::Unretained(this)));
140
141 EXPECT_EQ(callback_count_, 1);
142 EXPECT_EQ(error_callback_count_, 0);
143 }
144
104 // Called whenever RegisterAudioSink is completed successfully. 145 // Called whenever RegisterAudioSink is completed successfully.
105 void RegisterCallback( 146 void RegisterCallback(
106 scoped_refptr<BluetoothAudioSink> audio_sink) { 147 scoped_refptr<BluetoothAudioSink> audio_sink) {
107 ++callback_count_; 148 ++callback_count_;
108 audio_sink_ = audio_sink; 149 audio_sink_ = audio_sink;
109 ASSERT_NE(audio_sink_.get(), nullptr); 150 ASSERT_NE(audio_sink_.get(), nullptr);
110 ASSERT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED); 151 ASSERT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
111 } 152 }
112 153
113 // Called whenever RegisterAudioSink failed. 154 // Called whenever RegisterAudioSink failed.
114 void RegisterErrorCallback(BluetoothAudioSink::ErrorCode error_code) { 155 void RegisterErrorCallback(BluetoothAudioSink::ErrorCode error_code) {
115 ++error_callback_count_; 156 ++error_callback_count_;
116 ASSERT_EQ(error_code, BluetoothAudioSink::ERROR_NOT_REGISTERED); 157 EXPECT_EQ(error_code, BluetoothAudioSink::ERROR_NOT_REGISTERED);
158 }
159
160 // Called whenever there capabilities are returned from SelectConfiguration.
161 void SelectConfigurationCallback(const std::vector<uint8_t>& capabilities) {
162 ++callback_count_;
163
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}));
117 } 167 }
118 168
119 // Generic callbacks. 169 // Generic callbacks.
120 void Callback() { 170 void Callback() {
121 ++callback_count_; 171 ++callback_count_;
122 } 172 }
123 173
124 void ErrorCallback() { 174 void ErrorCallback() {
125 ++error_callback_count_; 175 ++error_callback_count_;
126 } 176 }
127 177
128 protected: 178 protected:
129 int callback_count_; 179 int callback_count_;
130 int error_callback_count_; 180 int error_callback_count_;
181
131 base::MessageLoop message_loop_; 182 base::MessageLoop message_loop_;
183
132 scoped_refptr<BluetoothAdapter> adapter_; 184 scoped_refptr<BluetoothAdapter> adapter_;
133 scoped_refptr<BluetoothAudioSink> audio_sink_; 185 scoped_refptr<BluetoothAudioSink> audio_sink_;
186
187 // The default property set used while calling SetConfiguration on a media
188 // endpoint object.
189 BluetoothMediaEndpointServiceProvider::Delegate::TransportProperties
190 properties_;
134 }; 191 };
135 192
136 TEST_F(BluetoothAudioSinkChromeOSTest, RegisterSucceeded) { 193 TEST_F(BluetoothAudioSinkChromeOSTest, RegisterSucceeded) {
137 // Sets up valid codec and capabilities. 194 GetAudioSink();
138 BluetoothAudioSink::Options options;
139 ASSERT_EQ(options.codec, 0x00);
140 ASSERT_EQ(options.capabilities,
141 std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35}));
142 adapter_->RegisterAudioSink(
143 options,
144 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
145 base::Unretained(this)),
146 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
147 base::Unretained(this)));
148 195
149 // Adds observer for the audio sink. 196 // Adds an observer for |audio_sink_|.
150 TestAudioSinkObserver observer(audio_sink_); 197 TestAudioSinkObserver observer(audio_sink_);
151 198 EXPECT_EQ(observer.state_changed_count_, 0);
152 ASSERT_EQ(callback_count_, 1); 199 EXPECT_EQ(observer.volume_changed_count_, 0);
153 ASSERT_EQ(error_callback_count_, 0);
154 ASSERT_EQ(observer.state_changed_count_, 0);
155 ASSERT_EQ(observer.volume_changed_count_, 0);
156 } 200 }
157 201
158 TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) { 202 TEST_F(BluetoothAudioSinkChromeOSTest, RegisterFailedWithInvalidOptions) {
159 // Sets options with an invalid codec and valid capabilities. 203 // Sets options with an invalid codec and valid capabilities.
160 BluetoothAudioSink::Options options; 204 BluetoothAudioSink::Options options;
161 options.codec = 0xff; 205 options.codec = 0xff;
162 options.capabilities = std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35}); 206 options.capabilities = std::vector<uint8_t>({0x3f, 0xff, 0x12, 0x35});
163 207
164 adapter_->RegisterAudioSink( 208 adapter_->RegisterAudioSink(
165 options, 209 options,
166 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback, 210 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
167 base::Unretained(this)), 211 base::Unretained(this)),
168 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback, 212 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
169 base::Unretained(this))); 213 base::Unretained(this)));
170 214
171 ASSERT_EQ(callback_count_, 0); 215 EXPECT_EQ(callback_count_, 0);
172 ASSERT_EQ(error_callback_count_, 1); 216 EXPECT_EQ(error_callback_count_, 1);
173 217
174 // Sets options with a valid codec and invalid capabilities. 218 // Sets options with a valid codec and invalid capabilities.
175 options.codec = 0x00; 219 options.codec = 0x00;
176 options.capabilities.clear(); 220 options.capabilities.clear();
177 adapter_->RegisterAudioSink( 221 adapter_->RegisterAudioSink(
178 options, 222 options,
179 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback, 223 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterCallback,
180 base::Unretained(this)), 224 base::Unretained(this)),
181 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback, 225 base::Bind(&BluetoothAudioSinkChromeOSTest::RegisterErrorCallback,
182 base::Unretained(this))); 226 base::Unretained(this)));
183 227
184 ASSERT_EQ(callback_count_, 0); 228 EXPECT_EQ(callback_count_, 0);
185 ASSERT_EQ(error_callback_count_, 2); 229 EXPECT_EQ(error_callback_count_, 2);
230 }
231
232 TEST_F(BluetoothAudioSinkChromeOSTest, SelectConfiguration) {
233 GetAudioSink();
234
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);
239
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);
248
249 media_endpoint->SelectConfiguration(
250 std::vector<uint8_t>({0x21, 0x15, 0x33, 0x2C}),
251 base::Bind(&BluetoothAudioSinkChromeOSTest::SelectConfigurationCallback,
252 base::Unretained(this)));
253
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);
259 }
260
261 TEST_F(BluetoothAudioSinkChromeOSTest, SetConfiguration) {
262 GetAudioSink();
263
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);
268
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);
278
279 media_endpoint->SetConfiguration(
280 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
281 properties_);
282
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);
288 }
289
290 TEST_F(BluetoothAudioSinkChromeOSTest, SetConfigurationWithUnexpectedState) {
291 GetAudioSink();
292
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);
297
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);
307
308 // Set state of Delegate::TransportProperties with an unexpected value.
309 properties_.state = "active";
310
311 media_endpoint->SetConfiguration(
312 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
313 properties_);
314
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);
320 }
321
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
324 // longer valid.
325 TEST_F(BluetoothAudioSinkChromeOSTest, ObserverNotifiedWhenMediaRemoved) {
326 GetAudioSink();
327
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);
332
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);
338
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());
344
345 EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_INVALID);
346 EXPECT_EQ(media_endpoint, nullptr);
347 }
348
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) {
353 GetAudioSink();
354
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);
359
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);
369
370 media_endpoint->SetConfiguration(
371 ObjectPath(FakeBluetoothMediaTransportClient::kTransportPath),
372 properties_);
373
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);
379
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());
385
386 transport->SetValid(media_endpoint->object_path(), false);
387 EXPECT_EQ(audio_sink_->GetState(), BluetoothAudioSink::STATE_DISCONNECTED);
388 EXPECT_NE(media_endpoint, nullptr);
186 } 389 }
187 390
188 } // namespace chromeos 391 } // namespace chromeos
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_audio_sink_chromeos.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698