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

Side by Side Diff: content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc

Issue 2788173002: Revert of Add mojo interface+impl creation of audio streams. (Closed)
Patch Set: Created 3 years, 8 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/browser/renderer_host/media/render_frame_audio_output_stream_f actory.h"
6
7 #include <limits>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/memory/shared_memory_handle.h"
13 #include "base/run_loop.h"
14 #include "base/sync_socket.h"
15 #include "content/browser/renderer_host/media/media_stream_manager.h"
16 #include "content/browser/renderer_host/media/renderer_audio_output_stream_facto ry_context.h"
17 #include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/test/test_browser_context.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "media/audio/audio_output_controller.h"
22 #include "media/base/audio_parameters.h"
23 #include "mojo/edk/embedder/embedder.h"
24 #include "mojo/public/cpp/bindings/binding.h"
25 #include "mojo/public/cpp/system/platform_handle.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace content {
30
31 namespace {
32
33 using testing::Test;
34 using AudioOutputStreamFactory = mojom::RendererAudioOutputStreamFactory;
35 using AudioOutputStreamFactoryPtr =
36 mojo::InterfacePtr<AudioOutputStreamFactory>;
37 using AudioOutputStreamFactoryRequest =
38 mojo::InterfaceRequest<AudioOutputStreamFactory>;
39 using AudioOutputStream = media::mojom::AudioOutputStream;
40 using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>;
41 using AudioOutputStreamRequest = mojo::InterfaceRequest<AudioOutputStream>;
42 using AudioOutputStreamProvider = media::mojom::AudioOutputStreamProvider;
43 using AudioOutputStreamProviderPtr =
44 mojo::InterfacePtr<AudioOutputStreamProvider>;
45 using AudioOutputStreamProviderRequest =
46 mojo::InterfaceRequest<AudioOutputStreamProvider>;
47
48 const int kStreamId = 0;
49 const int kNoSessionId = 0;
50 const int kRenderProcessId = 42;
51 const int kRenderFrameId = 24;
52 const int kSampleFrequency = 44100;
53 const int kBitsPerSample = 16;
54 const int kSamplesPerBuffer = kSampleFrequency / 100;
55 const char kSalt[] = "salt";
56
57 media::AudioParameters GetTestAudioParameters() {
58 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
59 media::CHANNEL_LAYOUT_MONO, kSampleFrequency,
60 kBitsPerSample, kSamplesPerBuffer);
61 }
62
63 class MockAudioOutputDelegate : public media::AudioOutputDelegate {
64 public:
65 // |on_destruction| can be used to observe the destruction of the delegate.
66 explicit MockAudioOutputDelegate(
67 base::OnceClosure on_destruction = base::OnceClosure())
68 : on_destruction_(std::move(on_destruction)) {}
69
70 ~MockAudioOutputDelegate() {
71 if (on_destruction_)
72 std::move(on_destruction_).Run();
73 }
74
75 MOCK_CONST_METHOD0(GetController,
76 scoped_refptr<media::AudioOutputController>());
77 MOCK_CONST_METHOD0(GetStreamId, int());
78 MOCK_METHOD0(OnPlayStream, void());
79 MOCK_METHOD0(OnPauseStream, void());
80 MOCK_METHOD1(OnSetVolume, void(double));
81
82 private:
83 base::OnceClosure on_destruction_;
84
85 DISALLOW_COPY_AND_ASSIGN(MockAudioOutputDelegate);
86 };
87
88 class MockContext : public RendererAudioOutputStreamFactoryContext {
89 public:
90 explicit MockContext(bool auth_ok) : salt_(kSalt), auth_ok_(auth_ok) {}
91
92 ~MockContext() override { EXPECT_EQ(nullptr, delegate_); }
93
94 int GetRenderProcessId() const override { return kRenderProcessId; }
95
96 std::string GetHMACForDeviceId(
97 const url::Origin& origin,
98 const std::string& raw_device_id) const override {
99 return MediaStreamManager::GetHMACForMediaDeviceID(salt_, origin,
100 raw_device_id);
101 }
102
103 void RequestDeviceAuthorization(
104 int render_frame_id,
105 int session_id,
106 const std::string& device_id,
107 const url::Origin& security_origin,
108 AuthorizationCompletedCallback cb) const override {
109 EXPECT_EQ(render_frame_id, kRenderFrameId);
110 EXPECT_EQ(session_id, 0);
111 if (auth_ok_) {
112 base::ThreadTaskRunnerHandle::Get()->PostTask(
113 FROM_HERE,
114 base::Bind(cb, media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
115 false, GetTestAudioParameters(), "default"));
116 return;
117 }
118 base::ThreadTaskRunnerHandle::Get()->PostTask(
119 FROM_HERE,
120 base::Bind(cb,
121 media::OutputDeviceStatus::
122 OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
123 false, media::AudioParameters::UnavailableDeviceParams(),
124 ""));
125 }
126
127 // The event handler for the delegate will be stored at
128 // |*event_handler_location| when the delegate is created.
129 void PrepareDelegateForCreation(
130 std::unique_ptr<media::AudioOutputDelegate> delegate,
131 media::AudioOutputDelegate::EventHandler** event_handler_location) {
132 EXPECT_EQ(nullptr, delegate_);
133 EXPECT_EQ(nullptr, delegate_event_handler_location_);
134 delegate_ = std::move(delegate);
135 delegate_event_handler_location_ = event_handler_location;
136 }
137
138 std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
139 const std::string& unique_device_id,
140 int render_frame_id,
141 const media::AudioParameters& params,
142 media::AudioOutputDelegate::EventHandler* handler) override {
143 EXPECT_NE(nullptr, delegate_);
144 EXPECT_NE(nullptr, delegate_event_handler_location_);
145 *delegate_event_handler_location_ = handler;
146 delegate_event_handler_location_ = nullptr;
147 return std::move(delegate_);
148 }
149
150 AudioOutputStreamFactoryPtr CreateFactory() {
151 DCHECK(!factory_);
152 AudioOutputStreamFactoryPtr ret;
153 factory_ = base::MakeUnique<RenderFrameAudioOutputStreamFactory>(
154 kRenderFrameId, this);
155 factory_binding_ = base::MakeUnique<
156 mojo::Binding<mojom::RendererAudioOutputStreamFactory>>(factory_.get(),
157 &ret);
158 return ret;
159 }
160
161 private:
162 const std::string salt_;
163 const bool auth_ok_;
164 std::unique_ptr<RenderFrameAudioOutputStreamFactory> factory_;
165 std::unique_ptr<mojo::Binding<mojom::RendererAudioOutputStreamFactory>>
166 factory_binding_;
167 std::unique_ptr<media::AudioOutputDelegate> delegate_;
168 media::AudioOutputDelegate::EventHandler** delegate_event_handler_location_ =
169 nullptr;
170
171 DISALLOW_COPY_AND_ASSIGN(MockContext);
172 };
173
174 class MockClient {
175 public:
176 MockClient() {}
177 ~MockClient() {}
178
179 void StreamCreated(mojo::ScopedSharedBufferHandle handle1,
180 mojo::ScopedHandle handle2) {
181 was_called_ = true;
182 }
183
184 bool was_called() { return was_called_; }
185
186 private:
187 bool was_called_ = false;
188
189 DISALLOW_COPY_AND_ASSIGN(MockClient);
190 };
191
192 void AuthCallback(media::OutputDeviceStatus* status_out,
193 media::AudioParameters* params_out,
194 std::string* id_out,
195 media::OutputDeviceStatus status,
196 const media::AudioParameters& params,
197 const std::string& id) {
198 *status_out = status;
199 *params_out = params;
200 *id_out = id;
201 }
202
203 } // namespace
204
205 // This test authorizes and creates a stream, and checks that
206 // 1. the authorization callback is called with appropriate parameters.
207 // 2. the AudioOutputDelegate is created.
208 // 3. when the delegate calls OnStreamCreated, this is propagated to the client.
209 TEST(RenderFrameAudioOutputStreamFactoryTest, CreateStream) {
210 content::TestBrowserThreadBundle thread_bundle;
211 AudioOutputStreamProviderPtr provider;
212 AudioOutputStreamPtr output_stream;
213 MockClient client;
214 media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
215 auto factory_context = base::MakeUnique<MockContext>(true);
216 factory_context->PrepareDelegateForCreation(
217 base::MakeUnique<MockAudioOutputDelegate>(), &event_handler);
218 AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
219
220 media::OutputDeviceStatus status;
221 media::AudioParameters params;
222 std::string id;
223 factory_ptr->RequestDeviceAuthorization(
224 mojo::MakeRequest(&provider), kNoSessionId, "default",
225 base::Bind(&AuthCallback, base::Unretained(&status),
226 base::Unretained(&params), base::Unretained(&id)));
227 base::RunLoop().RunUntilIdle();
228 EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_OK);
229 EXPECT_EQ(params.AsHumanReadableString(),
230 GetTestAudioParameters().AsHumanReadableString());
231 EXPECT_TRUE(id.empty());
232
233 provider->Acquire(
234 mojo::MakeRequest<AudioOutputStream>(&output_stream), params,
235 base::Bind(&MockClient::StreamCreated, base::Unretained(&client)));
236 base::RunLoop().RunUntilIdle();
237 ASSERT_NE(event_handler, nullptr);
238
239 base::SharedMemory shared_memory;
240 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(100));
241
242 base::CancelableSyncSocket local, remote;
243 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&local, &remote));
244 event_handler->OnStreamCreated(kStreamId, &shared_memory, &remote);
245
246 base::RunLoop().RunUntilIdle();
247 // Make sure we got the callback from creating stream.
248 EXPECT_TRUE(client.was_called());
249 }
250
251 TEST(RenderFrameAudioOutputStreamFactoryTest, NotAuthorized_Denied) {
252 content::TestBrowserThreadBundle thread_bundle;
253 AudioOutputStreamProviderPtr output_provider;
254 auto factory_context = base::MakeUnique<MockContext>(false);
255 AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
256
257 media::OutputDeviceStatus status;
258 media::AudioParameters params;
259 std::string id;
260 factory_ptr->RequestDeviceAuthorization(
261 mojo::MakeRequest(&output_provider), kNoSessionId, "default",
262 base::Bind(&AuthCallback, base::Unretained(&status),
263 base::Unretained(&params), base::Unretained(&id)));
264 base::RunLoop().RunUntilIdle();
265 EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED);
266 EXPECT_TRUE(id.empty());
267 }
268
269 TEST(RenderFrameAudioOutputStreamFactoryTest, ConnectionError_DeletesStream) {
270 content::TestBrowserThreadBundle thread_bundle;
271 AudioOutputStreamProviderPtr provider;
272 AudioOutputStreamPtr output_stream;
273 MockClient client;
274 bool delegate_is_destructed = false;
275 media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
276 auto factory_context = base::MakeUnique<MockContext>(true);
277 factory_context->PrepareDelegateForCreation(
278 base::MakeUnique<MockAudioOutputDelegate>(
279 base::BindOnce([](bool* destructed) { *destructed = true; },
280 &delegate_is_destructed)),
281 &event_handler);
282 AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
283
284 factory_ptr->RequestDeviceAuthorization(
285 mojo::MakeRequest(&provider), kNoSessionId, "default",
286 base::Bind([](media::OutputDeviceStatus status,
287 const media::AudioParameters& params,
288 const std::string& id) {}));
289 base::RunLoop().RunUntilIdle();
290
291 provider->Acquire(
292 mojo::MakeRequest<AudioOutputStream>(&output_stream),
293 GetTestAudioParameters(),
294 base::Bind(&MockClient::StreamCreated, base::Unretained(&client)));
295 base::RunLoop().RunUntilIdle();
296 ASSERT_NE(event_handler, nullptr);
297 EXPECT_FALSE(delegate_is_destructed);
298 output_stream.reset();
299 base::RunLoop().RunUntilIdle();
300 EXPECT_TRUE(delegate_is_destructed);
301 }
302
303 TEST(RenderFrameAudioOutputStreamFactoryTest, DelegateError_DeletesStream) {
304 content::TestBrowserThreadBundle thread_bundle;
305 AudioOutputStreamProviderPtr provider;
306 AudioOutputStreamPtr output_stream;
307 MockClient client;
308 bool delegate_is_destructed = false;
309 media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
310 auto factory_context = base::MakeUnique<MockContext>(true);
311 factory_context->PrepareDelegateForCreation(
312 base::MakeUnique<MockAudioOutputDelegate>(
313 base::BindOnce([](bool* destructed) { *destructed = true; },
314 &delegate_is_destructed)),
315 &event_handler);
316 AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
317
318 factory_ptr->RequestDeviceAuthorization(
319 mojo::MakeRequest(&provider), kNoSessionId, "default",
320 base::Bind([](media::OutputDeviceStatus status,
321 const media::AudioParameters& params,
322 const std::string& id) {}));
323 base::RunLoop().RunUntilIdle();
324
325 provider->Acquire(
326 mojo::MakeRequest<AudioOutputStream>(&output_stream),
327 GetTestAudioParameters(),
328 base::Bind(&MockClient::StreamCreated, base::Unretained(&client)));
329 base::RunLoop().RunUntilIdle();
330 ASSERT_NE(event_handler, nullptr);
331 EXPECT_FALSE(delegate_is_destructed);
332 event_handler->OnStreamError(kStreamId);
333 base::RunLoop().RunUntilIdle();
334 EXPECT_TRUE(delegate_is_destructed);
335 }
336
337 TEST(RenderFrameAudioOutputStreamFactoryTest, OutOfRangeSessionId_BadMessage) {
338 // This test checks that we get a bad message if session_id is too large
339 // to fit in an integer. This ensures that we don't overflow when casting the
340 // int64_t to an int
341 if (sizeof(int) >= sizeof(int64_t)) {
342 // In this case, any int64_t would fit in an int, and the case we are
343 // checking for is impossible.
344 return;
345 }
346
347 bool got_bad_message = false;
348 mojo::edk::SetDefaultProcessErrorCallback(
349 base::Bind([](bool* got_bad_message,
350 const std::string& s) { *got_bad_message = true; },
351 &got_bad_message));
352
353 TestBrowserThreadBundle thread_bundle;
354
355 AudioOutputStreamProviderPtr output_provider;
356 auto factory_context = base::MakeUnique<MockContext>(true);
357 auto factory_ptr = factory_context->CreateFactory();
358
359 int64_t session_id = std::numeric_limits<int>::max();
360 ++session_id;
361
362 EXPECT_FALSE(got_bad_message);
363 factory_ptr->RequestDeviceAuthorization(
364 mojo::MakeRequest(&output_provider), session_id, "default",
365 base::Bind([](media::OutputDeviceStatus, const media::AudioParameters&,
366 const std::string&) {}));
367 base::RunLoop().RunUntilIdle();
368 EXPECT_TRUE(got_bad_message);
369 }
370
371 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698