Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host_unittest.cc
blob559ff129e00622b5a6e28183de4a0b6d0a8d4bd5
1 // Copyright (c) 2012 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.
5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/sync_socket.h"
10 #include "content/browser/media/capture/audio_mirroring_manager.h"
11 #include "content/browser/media/media_internals.h"
12 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
13 #include "content/browser/renderer_host/media/audio_renderer_host.h"
14 #include "content/browser/renderer_host/media/media_stream_manager.h"
15 #include "content/common/media/audio_messages.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "ipc/ipc_message_utils.h"
19 #include "media/audio/audio_manager.h"
20 #include "media/base/bind_to_current_loop.h"
21 #include "media/base/media_switches.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using ::testing::_;
26 using ::testing::Assign;
27 using ::testing::DoAll;
28 using ::testing::NotNull;
30 namespace {
31 const int kRenderProcessId = 1;
32 const int kRenderFrameId = 5;
33 const int kStreamId = 50;
34 const int kBadStreamId = 99;
35 const url::Origin kSecurityOrigin(GURL("http://localhost"));
36 const url::Origin kDefaultSecurityOrigin;
37 const std::string kDefaultDeviceID;
38 const std::string kBadDeviceID =
39 "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1";
40 const std::string kInvalidDeviceID = "invalid-device-id";
41 } // namespace
43 namespace content {
45 class MockAudioMirroringManager : public AudioMirroringManager {
46 public:
47 MockAudioMirroringManager() {}
48 virtual ~MockAudioMirroringManager() {}
50 MOCK_METHOD3(AddDiverter,
51 void(int render_process_id,
52 int render_frame_id,
53 Diverter* diverter));
54 MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter));
56 private:
57 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
60 class MockAudioRendererHost : public AudioRendererHost {
61 public:
62 MockAudioRendererHost(media::AudioManager* audio_manager,
63 AudioMirroringManager* mirroring_manager,
64 MediaInternals* media_internals,
65 MediaStreamManager* media_stream_manager,
66 const ResourceContext::SaltCallback& salt_callback)
67 : AudioRendererHost(kRenderProcessId,
68 audio_manager,
69 mirroring_manager,
70 media_internals,
71 media_stream_manager,
72 salt_callback),
73 shared_memory_length_(0) {}
75 // A list of mock methods.
76 MOCK_METHOD3(OnDeviceAuthorized,
77 void(int stream_id,
78 bool success,
79 const media::AudioParameters& output_params));
80 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length));
81 MOCK_METHOD1(OnStreamPlaying, void(int stream_id));
82 MOCK_METHOD1(OnStreamPaused, void(int stream_id));
83 MOCK_METHOD1(OnStreamError, void(int stream_id));
84 MOCK_METHOD2(OnOutputDeviceSwitched,
85 void(int stream_id, media::SwitchOutputDeviceResult result));
87 private:
88 virtual ~MockAudioRendererHost() {
89 // Make sure all audio streams have been deleted.
90 EXPECT_TRUE(audio_entries_.empty());
93 // This method is used to dispatch IPC messages to the renderer. We intercept
94 // these messages here and dispatch to our mock methods to verify the
95 // conversation between this object and the renderer.
96 virtual bool Send(IPC::Message* message) {
97 CHECK(message);
99 // In this method we dispatch the messages to the according handlers as if
100 // we are the renderer.
101 bool handled = true;
102 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message)
103 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceAuthorized,
104 OnNotifyDeviceAuthorized)
105 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated,
106 OnNotifyStreamCreated)
107 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged,
108 OnNotifyStreamStateChanged)
109 IPC_MESSAGE_HANDLER(AudioMsg_NotifyOutputDeviceSwitched,
110 OnNotifyOutputDeviceSwitched)
111 IPC_MESSAGE_UNHANDLED(handled = false)
112 IPC_END_MESSAGE_MAP()
113 EXPECT_TRUE(handled);
115 delete message;
116 return true;
119 void OnNotifyDeviceAuthorized(int stream_id,
120 bool success,
121 const media::AudioParameters& output_params) {
122 OnDeviceAuthorized(stream_id, success, output_params);
125 void OnNotifyStreamCreated(
126 int stream_id, base::SharedMemoryHandle handle,
127 base::SyncSocket::TransitDescriptor socket_descriptor, uint32 length) {
128 // Maps the shared memory.
129 shared_memory_.reset(new base::SharedMemory(handle, false));
130 CHECK(shared_memory_->Map(length));
131 CHECK(shared_memory_->memory());
132 shared_memory_length_ = length;
134 // Create the SyncSocket using the handle.
135 base::SyncSocket::Handle sync_socket_handle =
136 base::SyncSocket::UnwrapHandle(socket_descriptor);
137 sync_socket_.reset(new base::SyncSocket(sync_socket_handle));
139 // And then delegate the call to the mock method.
140 OnStreamCreated(stream_id, length);
143 void OnNotifyStreamStateChanged(int stream_id,
144 media::AudioOutputIPCDelegateState state) {
145 switch (state) {
146 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
147 OnStreamPlaying(stream_id);
148 break;
149 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
150 OnStreamPaused(stream_id);
151 break;
152 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
153 OnStreamError(stream_id);
154 break;
155 default:
156 FAIL() << "Unknown stream state";
157 break;
161 void OnNotifyOutputDeviceSwitched(int stream_id,
162 media::SwitchOutputDeviceResult result) {
163 switch (result) {
164 case media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS:
165 case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND:
166 case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED:
167 case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL:
168 OnOutputDeviceSwitched(stream_id, result);
169 break;
170 default:
171 FAIL() << "Unknown SwitchOutputDevice result";
172 break;
176 scoped_ptr<base::SharedMemory> shared_memory_;
177 scoped_ptr<base::SyncSocket> sync_socket_;
178 uint32 shared_memory_length_;
180 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost);
183 namespace {
184 std::string ReturnMockSalt() {
185 return std::string();
188 ResourceContext::SaltCallback GetMockSaltCallback() {
189 return base::Bind(&ReturnMockSalt);
192 void WaitForEnumeration(base::RunLoop* loop,
193 const AudioOutputDeviceEnumeration& e) {
194 loop->Quit();
196 } // namespace
198 class AudioRendererHostTest : public testing::Test {
199 public:
200 AudioRendererHostTest() {
201 audio_manager_.reset(media::AudioManager::CreateForTesting());
202 base::CommandLine::ForCurrentProcess()->AppendSwitch(
203 switches::kUseFakeDeviceForMediaStream);
204 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
206 // Enable caching to make enumerations run in a single thread
207 media_stream_manager_->audio_output_device_enumerator()->SetCachePolicy(
208 AudioOutputDeviceEnumerator::CACHE_POLICY_MANUAL_INVALIDATION);
209 base::RunLoop().RunUntilIdle();
210 base::RunLoop run_loop;
211 media_stream_manager_->audio_output_device_enumerator()->Enumerate(
212 base::Bind(&WaitForEnumeration, &run_loop));
213 run_loop.Run();
215 host_ = new MockAudioRendererHost(audio_manager_.get(), &mirroring_manager_,
216 MediaInternals::GetInstance(),
217 media_stream_manager_.get(),
218 GetMockSaltCallback());
220 // Simulate IPC channel connected.
221 host_->set_peer_process_for_testing(base::Process::Current());
224 ~AudioRendererHostTest() override {
225 // Simulate closing the IPC channel and give the audio thread time to close
226 // the underlying streams.
227 host_->OnChannelClosing();
228 SyncWithAudioThread();
230 // Release the reference to the mock object. The object will be destructed
231 // on message_loop_.
232 host_ = NULL;
235 protected:
236 void Create(bool unified_stream) {
237 EXPECT_CALL(*host_.get(), OnDeviceAuthorized(kStreamId, true, _));
238 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _));
240 EXPECT_CALL(mirroring_manager_,
241 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()))
242 .RetiresOnSaturation();
244 // Send a create stream message to the audio output stream and wait until
245 // we receive the created message.
246 media::AudioParameters params(
247 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO,
248 media::AudioParameters::kAudioCDSampleRate, 16,
249 media::AudioParameters::kAudioCDSampleRate / 10);
250 int session_id = 0;
251 if (unified_stream) {
252 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to
253 // pass the permission check.
254 session_id = AudioInputDeviceManager::kFakeOpenSessionId;
256 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id,
257 kDefaultDeviceID,
258 kDefaultSecurityOrigin);
259 host_->OnCreateStream(kStreamId, kRenderFrameId, params);
261 // At some point in the future, a corresponding RemoveDiverter() call must
262 // be made.
263 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()))
264 .RetiresOnSaturation();
265 SyncWithAudioThread();
268 void Close() {
269 // Send a message to AudioRendererHost to tell it we want to close the
270 // stream.
271 host_->OnCloseStream(kStreamId);
272 SyncWithAudioThread();
275 void Play() {
276 EXPECT_CALL(*host_.get(), OnStreamPlaying(kStreamId));
277 host_->OnPlayStream(kStreamId);
278 SyncWithAudioThread();
281 void Pause() {
282 EXPECT_CALL(*host_.get(), OnStreamPaused(kStreamId));
283 host_->OnPauseStream(kStreamId);
284 SyncWithAudioThread();
287 void SetVolume(double volume) {
288 host_->OnSetVolume(kStreamId, volume);
289 SyncWithAudioThread();
292 void SwitchOutputDevice(int stream_id,
293 const std::string& device_id,
294 const url::Origin& security_origin,
295 media::SwitchOutputDeviceResult expected_result) {
296 EXPECT_CALL(*host_.get(),
297 OnOutputDeviceSwitched(stream_id, expected_result));
298 host_->OnSwitchOutputDevice(stream_id, kRenderFrameId, device_id,
299 security_origin);
300 SyncWithAudioThread();
303 void SimulateError() {
304 EXPECT_EQ(1u, host_->audio_entries_.size())
305 << "Calls Create() before calling this method";
307 // Expect an error signal sent through IPC.
308 EXPECT_CALL(*host_.get(), OnStreamError(kStreamId));
310 // Simulate an error sent from the audio device.
311 host_->ReportErrorAndClose(kStreamId);
312 SyncWithAudioThread();
314 // Expect the audio stream record is removed.
315 EXPECT_EQ(0u, host_->audio_entries_.size());
318 // SyncWithAudioThread() waits until all pending tasks on the audio thread
319 // are executed while also processing pending task in message_loop_ on the
320 // current thread. It is used to synchronize with the audio thread when we are
321 // closing an audio stream.
322 void SyncWithAudioThread() {
323 base::RunLoop().RunUntilIdle();
325 base::RunLoop run_loop;
326 audio_manager_->GetTaskRunner()->PostTask(
327 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure()));
328 run_loop.Run();
331 private:
332 // MediaStreamManager uses a DestructionObserver, so it must outlive the
333 // TestBrowserThreadBundle.
334 scoped_ptr<MediaStreamManager> media_stream_manager_;
335 TestBrowserThreadBundle thread_bundle_;
336 scoped_ptr<media::AudioManager> audio_manager_;
337 MockAudioMirroringManager mirroring_manager_;
338 scoped_refptr<MockAudioRendererHost> host_;
340 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest);
343 TEST_F(AudioRendererHostTest, CreateAndClose) {
344 Create(false);
345 Close();
348 // Simulate the case where a stream is not properly closed.
349 TEST_F(AudioRendererHostTest, CreateAndShutdown) {
350 Create(false);
353 TEST_F(AudioRendererHostTest, CreatePlayAndClose) {
354 Create(false);
355 Play();
356 Close();
359 TEST_F(AudioRendererHostTest, CreatePlayPauseAndClose) {
360 Create(false);
361 Play();
362 Pause();
363 Close();
366 TEST_F(AudioRendererHostTest, SetVolume) {
367 Create(false);
368 SetVolume(0.5);
369 Play();
370 Pause();
371 Close();
374 TEST_F(AudioRendererHostTest, SwitchOutputDevice) {
375 Create(false);
376 SwitchOutputDevice(kStreamId, kDefaultDeviceID, kDefaultSecurityOrigin,
377 media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS);
378 Close();
381 TEST_F(AudioRendererHostTest, SwitchOutputDeviceNotAuthorized) {
382 Create(false);
383 SwitchOutputDevice(kStreamId, kBadDeviceID, kSecurityOrigin,
384 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED);
385 Close();
388 TEST_F(AudioRendererHostTest, SwitchOutputDeviceInvalidDeviceId) {
389 Create(false);
390 SwitchOutputDevice(kStreamId, kInvalidDeviceID, kSecurityOrigin,
391 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
392 Close();
395 TEST_F(AudioRendererHostTest, SwitchOutputDeviceNoStream) {
396 Create(false);
397 SwitchOutputDevice(kBadStreamId, kDefaultDeviceID, kDefaultSecurityOrigin,
398 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
399 Close();
402 // Simulate the case where a stream is not properly closed.
403 TEST_F(AudioRendererHostTest, CreatePlayAndShutdown) {
404 Create(false);
405 Play();
408 // Simulate the case where a stream is not properly closed.
409 TEST_F(AudioRendererHostTest, CreatePlayPauseAndShutdown) {
410 Create(false);
411 Play();
412 Pause();
415 TEST_F(AudioRendererHostTest, SimulateError) {
416 Create(false);
417 Play();
418 SimulateError();
421 // Simulate the case when an error is generated on the browser process,
422 // the audio device is closed but the render process try to close the
423 // audio stream again.
424 TEST_F(AudioRendererHostTest, SimulateErrorAndClose) {
425 Create(false);
426 Play();
427 SimulateError();
428 Close();
431 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) {
432 Create(true);
433 Close();
436 // TODO(hclam): Add tests for data conversation in low latency mode.
438 } // namespace content