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

Side by Side Diff: content/renderer/media/mojo_audio_output_ipc_unittest.cc

Issue 2821203005: Add a mojo implementation of AudioOutputIPC. (Closed)
Patch Set: rebase Created 3 years, 7 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
OLDNEW
(Empty)
1 // Copyright 2017 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.
4
5 #include "content/renderer/media/mojo_audio_output_ipc.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "base/message_loop/message_loop.h"
13 #include "base/optional.h"
14 #include "base/run_loop.h"
15 #include "media/audio/audio_device_description.h"
16 #include "media/base/audio_parameters.h"
17 #include "mojo/public/cpp/bindings/binding.h"
18 #include "mojo/public/cpp/system/platform_handle.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/origin.h"
22
23 using testing::_;
24 using testing::AtLeast;
25 using testing::Mock;
26 using testing::StrictMock;
27
28 namespace content {
29
30 namespace {
31
32 const int kSessionId = 1234;
33 const size_t kMemoryLength = 4321;
34 const char kDeviceId[] = "device_id";
35 const char kReturnedDeviceId[] = "returned_device_id";
36 const double kNewVolume = 0.271828;
37
38 url::Origin Origin() {
39 return {};
40 }
41
42 media::AudioParameters Params() {
43 return media::AudioParameters::UnavailableDeviceParams();
44 }
45
46 MojoAudioOutputIPC::FactoryAccessor NullAccessor() {
47 return base::BindRepeating(
48 []() -> mojom::RendererAudioOutputStreamFactory* { return nullptr; });
49 }
50
51 class TestRemoteFactory : public mojom::RendererAudioOutputStreamFactory {
52 public:
53 TestRemoteFactory()
54 : expect_request_(false),
55 binding_(this, mojo::MakeRequest(&this_proxy_)) {}
56
57 ~TestRemoteFactory() override {}
58
59 void RequestDeviceAuthorization(
60 media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
61 int64_t session_id,
62 const std::string& device_id,
63 RequestDeviceAuthorizationCallback callback) override {
64 EXPECT_EQ(session_id, expected_session_id_);
65 EXPECT_EQ(device_id, expected_device_id_);
66 EXPECT_TRUE(expect_request_);
67 if (provider_) {
68 std::move(callback).Run(
69 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, Params(),
70 std::string(kReturnedDeviceId));
71 provider_binding_.emplace(provider_.get(),
72 std::move(stream_provider_request));
73 } else {
74 std::move(callback).Run(
75 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
76 Params(), std::string(""));
77 }
78 expect_request_ = false;
79 }
80
81 void PrepareProviderForAuthorization(
82 int64_t session_id,
83 const std::string& device_id,
84 std::unique_ptr<media::mojom::AudioOutputStreamProvider> provider) {
85 DCHECK(!expect_request_);
o1ka 2017/05/18 09:16:50 EXPECTation?
Max Morin 2017/05/18 12:30:18 Done.
86 expect_request_ = true;
87 expected_session_id_ = session_id;
88 expected_device_id_ = device_id;
89 provider_binding_.reset();
90 std::swap(provider_, provider);
91 }
92
93 void RefuseNextRequest(int64_t session_id, const std::string& device_id) {
94 DCHECK(!expect_request_);
o1ka 2017/05/18 09:16:50 same?
Max Morin 2017/05/18 12:30:18 Done.
95 expect_request_ = true;
96 expected_session_id_ = session_id;
97 expected_device_id_ = device_id;
98 }
99
100 void Disconnect() {
101 binding_.Close();
102 this_proxy_.reset();
103 binding_.Bind(mojo::MakeRequest(&this_proxy_));
104 provider_binding_.reset();
105 provider_.reset();
106 expect_request_ = false;
107 }
108
109 MojoAudioOutputIPC::FactoryAccessor GetAccessor() {
110 return base::BindRepeating(&TestRemoteFactory::get, base::Unretained(this));
111 }
112
113 private:
114 mojom::RendererAudioOutputStreamFactory* get() { return this_proxy_.get(); }
115
116 bool expect_request_;
117 int64_t expected_session_id_;
118 std::string expected_device_id_;
119
120 mojom::RendererAudioOutputStreamFactoryPtr this_proxy_;
121 mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;
122 std::unique_ptr<media::mojom::AudioOutputStreamProvider> provider_;
123 base::Optional<mojo::Binding<media::mojom::AudioOutputStreamProvider>>
124 provider_binding_;
125 };
126
127 class TestStreamProvider : public media::mojom::AudioOutputStreamProvider {
128 public:
129 explicit TestStreamProvider(media::mojom::AudioOutputStream* stream)
130 : stream_(stream) {}
131
132 ~TestStreamProvider() override {
133 // If we expected a stream to be acquired, make sure it is so.
134 if (stream_)
135 EXPECT_TRUE(binding_);
136 }
137
138 void Acquire(media::mojom::AudioOutputStreamRequest stream_request,
139 const media::AudioParameters& params,
140 const AcquireCallback& callback) override {
141 DCHECK(!binding_);
o1ka 2017/05/18 09:16:50 EXPECT_TRUE?
Max Morin 2017/05/18 12:30:18 Done.
142 EXPECT_TRUE(stream_);
o1ka 2017/05/18 09:16:50 EXPECT_NE(nullptr, stream_)
Max Morin 2017/05/18 12:30:18 Done.
143 binding_.emplace(stream_, std::move(stream_request));
144 base::CancelableSyncSocket foreign_socket;
145 EXPECT_TRUE(
146 base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
147 std::move(callback).Run(mojo::SharedBufferHandle::Create(kMemoryLength),
148 mojo::WrapPlatformFile(foreign_socket.Release()));
149 }
150
151 private:
152 media::mojom::AudioOutputStream* stream_;
153 base::Optional<mojo::Binding<media::mojom::AudioOutputStream>> binding_;
154 base::CancelableSyncSocket socket_;
155 };
156
157 class MockStream : public media::mojom::AudioOutputStream {
158 public:
159 MOCK_METHOD0(Play, void());
160 MOCK_METHOD0(Pause, void());
161 MOCK_METHOD1(SetVolume, void(double));
162 };
163
164 class MockDelegate : public media::AudioOutputIPCDelegate {
165 public:
166 MockDelegate() {}
167 ~MockDelegate() override {}
168
169 void OnStreamCreated(base::SharedMemoryHandle mem_handle,
170 base::SyncSocket::Handle socket_handle,
171 int length) {
172 base::SharedMemory sh_mem(
173 mem_handle, /*read_only*/ false); // Releases the shared memory handle.
174 base::SyncSocket socket(socket_handle); // Releases the socket descriptor.
175 GotOnStreamCreated(length);
176 }
177
178 MOCK_METHOD0(OnError, void());
179 MOCK_METHOD3(OnDeviceAuthorized,
180 void(media::OutputDeviceStatus device_status,
181 const media::AudioParameters& output_params,
182 const std::string& matched_device_id));
183 MOCK_METHOD1(GotOnStreamCreated, void(int length));
184 MOCK_METHOD0(OnIPCClosed, void());
185 };
186
187 } // namespace
188
189 TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsOnIPCClosed) {
190 base::MessageLoopForIO message_loop;
191 StrictMock<MockDelegate> delegate;
192
193 const std::unique_ptr<media::AudioOutputIPC> ipc =
194 base::MakeUnique<MojoAudioOutputIPC>(NullAccessor());
195
196 EXPECT_CALL(delegate, OnIPCClosed());
197 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
198 base::RunLoop().RunUntilIdle();
199 }
200
201 TEST(MojoAudioOutputIPC, CreateWithoutFactoryOrAuthorization_CallsOnIPCClosed) {
202 base::MessageLoopForIO message_loop;
203 StrictMock<MockDelegate> delegate;
204
205 const std::unique_ptr<media::AudioOutputIPC> ipc =
206 base::MakeUnique<MojoAudioOutputIPC>(NullAccessor());
207
208 EXPECT_CALL(delegate, OnIPCClosed());
209 ipc->CreateStream(&delegate, Params());
210 base::RunLoop().RunUntilIdle();
211 }
212
213 TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) {
214 base::MessageLoopForIO message_loop;
215 TestRemoteFactory stream_factory;
216 StrictMock<MockDelegate> delegate;
217
218 const std::unique_ptr<media::AudioOutputIPC> ipc =
219 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
220 stream_factory.PrepareProviderForAuthorization(
221 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
222
223 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
224
225 EXPECT_CALL(delegate, OnDeviceAuthorized(
226 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
227 _, std::string(kReturnedDeviceId)));
228 base::RunLoop().RunUntilIdle();
229
230 ipc->CloseStream();
231 base::RunLoop().RunUntilIdle();
232 }
233
234 TEST(MojoAudioOutputIPC, OnDeviceCreated_Propagates) {
235 base::MessageLoopForIO message_loop;
236 TestRemoteFactory stream_factory;
237 StrictMock<MockStream> stream;
238 StrictMock<MockDelegate> delegate;
239
240 const std::unique_ptr<media::AudioOutputIPC> ipc =
241 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
242 stream_factory.PrepareProviderForAuthorization(
243 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
244
245 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
246 ipc->CreateStream(&delegate, Params());
247
248 EXPECT_CALL(delegate, OnDeviceAuthorized(
249 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
250 _, std::string(kReturnedDeviceId)));
251 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
252 base::RunLoop().RunUntilIdle();
253
254 ipc->CloseStream();
255 base::RunLoop().RunUntilIdle();
256 }
257
258 TEST(MojoAudioOutputIPC,
259 CreateWithoutAuthorization_RequestsAuthorizationFirst) {
260 base::MessageLoopForIO message_loop;
261 TestRemoteFactory stream_factory;
262 StrictMock<MockStream> stream;
263 StrictMock<MockDelegate> delegate;
264 const std::unique_ptr<media::AudioOutputIPC> ipc =
265 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
266
267 // Note: This call implicitly EXPECTs that authorization is requested,
268 // an constructing the TestStreamProvider with a |&stream| EXPECTs that the
o1ka 2017/05/18 09:16:50 nit: and
Max Morin 2017/05/18 12:30:18 Done.
269 // stream is created. This implicit request should always be for the default
270 // device and no session id.
271 stream_factory.PrepareProviderForAuthorization(
272 0, std::string(media::AudioDeviceDescription::kDefaultDeviceId),
273 base::MakeUnique<TestStreamProvider>(&stream));
274
275 ipc->CreateStream(&delegate, Params());
276
277 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
278 base::RunLoop().RunUntilIdle();
279
280 ipc->CloseStream();
281 base::RunLoop().RunUntilIdle();
282 }
283
284 TEST(MojoAudioOutputIPC, IsReusable) {
285 base::MessageLoopForIO message_loop;
286 TestRemoteFactory stream_factory;
287 StrictMock<MockStream> stream;
288 StrictMock<MockDelegate> delegate;
289
290 const std::unique_ptr<media::AudioOutputIPC> ipc =
291 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
292
293 for (int i = 0; i < 5; ++i) {
294 stream_factory.PrepareProviderForAuthorization(
295 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
296
297 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
298 ipc->CreateStream(&delegate, Params());
299
300 EXPECT_CALL(
301 delegate,
302 OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
303 _, std::string(kReturnedDeviceId)));
304 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
305 base::RunLoop().RunUntilIdle();
306 Mock::VerifyAndClearExpectations(&delegate);
307
308 ipc->CloseStream();
309 base::RunLoop().RunUntilIdle();
310 }
311 }
312
313 TEST(MojoAudioOutputIPC, IsReusableAfterError) {
314 base::MessageLoopForIO message_loop;
315 TestRemoteFactory stream_factory;
316 StrictMock<MockStream> stream;
317 StrictMock<MockDelegate> delegate;
318
319 const std::unique_ptr<media::AudioOutputIPC> ipc =
320 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
321
322 stream_factory.PrepareProviderForAuthorization(
323 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
324 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
325
326 EXPECT_CALL(delegate, OnDeviceAuthorized(
327 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
328 _, std::string(kReturnedDeviceId)));
329 base::RunLoop().RunUntilIdle();
330 Mock::VerifyAndClearExpectations(&delegate);
331
332 EXPECT_CALL(delegate, OnError()).Times(AtLeast(1));
333 stream_factory.Disconnect();
334 base::RunLoop().RunUntilIdle();
335 Mock::VerifyAndClearExpectations(&delegate);
336
337 ipc->CloseStream();
338 base::RunLoop().RunUntilIdle();
339
340 for (int i = 0; i < 5; ++i) {
341 stream_factory.PrepareProviderForAuthorization(
342 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
343
344 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
345 ipc->CreateStream(&delegate, Params());
346
347 EXPECT_CALL(
348 delegate,
349 OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
350 _, std::string(kReturnedDeviceId)));
351 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
352 base::RunLoop().RunUntilIdle();
353 Mock::VerifyAndClearExpectations(&delegate);
354
355 ipc->CloseStream();
356 base::RunLoop().RunUntilIdle();
357 }
358 }
359
360 TEST(MojoAudioOutputIPC, DeviceNotAuthorized_Propagates) {
361 base::MessageLoopForIO message_loop;
362 TestRemoteFactory stream_factory;
363 StrictMock<MockDelegate> delegate;
364
365 const std::unique_ptr<media::AudioOutputIPC> ipc =
366 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
367 stream_factory.RefuseNextRequest(kSessionId, kDeviceId);
368
369 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
370
371 EXPECT_CALL(
372 delegate,
373 OnDeviceAuthorized(
374 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
375 _, std::string()));
376 EXPECT_CALL(delegate, OnError()).Times(AtLeast(0));
377 base::RunLoop().RunUntilIdle();
378
379 ipc->CloseStream();
380 base::RunLoop().RunUntilIdle();
381 }
382
383 TEST(MojoAudioOutputIPC,
384 FactoryDisconnectedBeforeAuthorizationReply_CallsAuthorizedAnyways) {
o1ka 2017/05/18 09:16:50 Please add a comment explaining what is tested
Max Morin 2017/05/18 12:30:18 Done.
385 base::MessageLoopForIO message_loop;
386 TestRemoteFactory stream_factory;
387 StrictMock<MockDelegate> delegate;
388
389 const std::unique_ptr<media::AudioOutputIPC> ipc =
390 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
391
392 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
393
394 EXPECT_CALL(
395 delegate,
396 OnDeviceAuthorized(
397 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _,
398 std::string()));
399 stream_factory.Disconnect();
400 EXPECT_CALL(delegate, OnError());
401 base::RunLoop().RunUntilIdle();
402
403 ipc->CloseStream();
404 base::RunLoop().RunUntilIdle();
405 }
406
407 TEST(MojoAudioOutputIPC,
408 FactoryDisconnectedAfterAuthorizationReply_CallsAuthorizedOnlyOnce) {
o1ka 2017/05/18 09:16:50 ditto
Max Morin 2017/05/18 12:30:18 Done.
409 base::MessageLoopForIO message_loop;
410 TestRemoteFactory stream_factory;
411 stream_factory.PrepareProviderForAuthorization(
412 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
413 StrictMock<MockDelegate> delegate;
414
415 const std::unique_ptr<media::AudioOutputIPC> ipc =
416 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
417
418 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
419
420 EXPECT_CALL(delegate, OnDeviceAuthorized(
421 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
422 _, std::string(kReturnedDeviceId)));
423 base::RunLoop().RunUntilIdle();
424
425 stream_factory.Disconnect();
426 EXPECT_CALL(delegate, OnError());
427 base::RunLoop().RunUntilIdle();
428
429 ipc->CloseStream();
430 base::RunLoop().RunUntilIdle();
431 }
432
433 TEST(MojoAudioOutputIPC, Play_Plays) {
434 base::MessageLoopForIO message_loop;
435 TestRemoteFactory stream_factory;
436 StrictMock<MockStream> stream;
437 StrictMock<MockDelegate> delegate;
438
439 const std::unique_ptr<media::AudioOutputIPC> ipc =
440 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
441 stream_factory.PrepareProviderForAuthorization(
442 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
443
444 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
445 ipc->CreateStream(&delegate, Params());
446 ipc->PlayStream();
447
448 EXPECT_CALL(delegate, OnDeviceAuthorized(
449 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
450 _, std::string(kReturnedDeviceId)));
451 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
452 EXPECT_CALL(stream, Play());
453 base::RunLoop().RunUntilIdle();
454
455 ipc->CloseStream();
456 base::RunLoop().RunUntilIdle();
457 }
458
459 TEST(MojoAudioOutputIPC, Pause_Pauses) {
460 base::MessageLoopForIO message_loop;
461 TestRemoteFactory stream_factory;
462 StrictMock<MockStream> stream;
463 StrictMock<MockDelegate> delegate;
464
465 const std::unique_ptr<media::AudioOutputIPC> ipc =
466 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
467 stream_factory.PrepareProviderForAuthorization(
468 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
469
470 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
471 ipc->CreateStream(&delegate, Params());
472 ipc->PauseStream();
473
474 EXPECT_CALL(delegate, OnDeviceAuthorized(
475 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
476 _, std::string(kReturnedDeviceId)));
477 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
478 EXPECT_CALL(stream, Pause());
479 base::RunLoop().RunUntilIdle();
480
481 ipc->CloseStream();
482 base::RunLoop().RunUntilIdle();
483 }
484
485 TEST(MojoAudioOutputIPC, SetVolume_SetsVolume) {
486 base::MessageLoopForIO message_loop;
487 TestRemoteFactory stream_factory;
488 StrictMock<MockStream> stream;
489 StrictMock<MockDelegate> delegate;
490
491 const std::unique_ptr<media::AudioOutputIPC> ipc =
492 base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
493 stream_factory.PrepareProviderForAuthorization(
494 kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
495
496 ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
497 ipc->CreateStream(&delegate, Params());
498 ipc->SetVolume(kNewVolume);
499
500 EXPECT_CALL(delegate, OnDeviceAuthorized(
501 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
502 _, std::string(kReturnedDeviceId)));
503 EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
504 EXPECT_CALL(stream, SetVolume(kNewVolume));
505 base::RunLoop().RunUntilIdle();
506
507 ipc->CloseStream();
508 base::RunLoop().RunUntilIdle();
509 }
510
o1ka 2017/05/18 09:16:50 WDYT of testing that we crash with DCHECK if Close
Max Morin 2017/05/18 12:30:18 Added a couple of death tests.
511 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698