Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host_unittest.cc
blob537b73bd36a7e6c98b79e28ad16e8804aad26192
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/environment.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop.h"
9 #include "base/process_util.h"
10 #include "base/sync_socket.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
13 #include "content/browser/renderer_host/media/audio_mirroring_manager.h"
14 #include "content/browser/renderer_host/media/audio_renderer_host.h"
15 #include "content/browser/renderer_host/media/media_stream_manager.h"
16 #include "content/browser/renderer_host/media/mock_media_observer.h"
17 #include "content/common/media/audio_messages.h"
18 #include "content/common/media/media_stream_options.h"
19 #include "ipc/ipc_message_utils.h"
20 #include "media/audio/audio_manager.h"
21 #include "media/audio/audio_manager_base.h"
22 #include "media/audio/fake_audio_output_stream.h"
23 #include "net/url_request/url_request_context.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::_;
28 using ::testing::AtLeast;
29 using ::testing::DoAll;
30 using ::testing::InSequence;
31 using ::testing::NotNull;
32 using ::testing::Return;
33 using ::testing::SaveArg;
34 using ::testing::SetArgumentPointee;
36 namespace content {
38 static const int kRenderProcessId = 1;
39 static const int kRenderViewId = 4;
40 static const int kStreamId = 50;
42 class MockAudioMirroringManager : public AudioMirroringManager {
43 public:
44 MockAudioMirroringManager() {}
45 virtual ~MockAudioMirroringManager() {}
47 MOCK_METHOD3(AddDiverter,
48 void(int render_process_id, int render_view_id,
49 Diverter* diverter));
50 MOCK_METHOD3(RemoveDiverter,
51 void(int render_process_id, int render_view_id,
52 Diverter* diverter));
54 private:
55 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
58 class MockAudioRendererHost : public AudioRendererHost {
59 public:
60 explicit MockAudioRendererHost(
61 media::AudioManager* audio_manager,
62 AudioMirroringManager* mirroring_manager,
63 MediaInternals* media_internals,
64 MediaStreamManager* media_stream_manager)
65 : AudioRendererHost(kRenderProcessId,
66 audio_manager,
67 mirroring_manager,
68 media_internals,
69 media_stream_manager),
70 shared_memory_length_(0) {
73 // A list of mock methods.
74 MOCK_METHOD2(OnStreamCreated,
75 void(int stream_id, int length));
76 MOCK_METHOD1(OnStreamPlaying, void(int stream_id));
77 MOCK_METHOD1(OnStreamPaused, void(int stream_id));
78 MOCK_METHOD1(OnStreamError, void(int stream_id));
80 private:
81 virtual ~MockAudioRendererHost() {
82 // Make sure all audio streams have been deleted.
83 EXPECT_TRUE(audio_entries_.empty());
86 // This method is used to dispatch IPC messages to the renderer. We intercept
87 // these messages here and dispatch to our mock methods to verify the
88 // conversation between this object and the renderer.
89 virtual bool Send(IPC::Message* message) {
90 CHECK(message);
92 // In this method we dispatch the messages to the according handlers as if
93 // we are the renderer.
94 bool handled = true;
95 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message)
96 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated,
97 OnStreamCreated)
98 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged,
99 OnStreamStateChanged)
100 IPC_MESSAGE_UNHANDLED(handled = false)
101 IPC_END_MESSAGE_MAP()
102 EXPECT_TRUE(handled);
104 delete message;
105 return true;
108 void OnStreamCreated(const IPC::Message& msg, int stream_id,
109 base::SharedMemoryHandle handle,
110 #if defined(OS_WIN)
111 base::SyncSocket::Handle socket_handle,
112 #else
113 base::FileDescriptor socket_descriptor,
114 #endif
115 uint32 length) {
116 // Maps the shared memory.
117 shared_memory_.reset(new base::SharedMemory(handle, false));
118 CHECK(shared_memory_->Map(length));
119 CHECK(shared_memory_->memory());
120 shared_memory_length_ = length;
122 // Create the SyncSocket using the handle.
123 base::SyncSocket::Handle sync_socket_handle;
124 #if defined(OS_WIN)
125 sync_socket_handle = socket_handle;
126 #else
127 sync_socket_handle = socket_descriptor.fd;
128 #endif
129 sync_socket_.reset(new base::SyncSocket(sync_socket_handle));
131 // And then delegate the call to the mock method.
132 OnStreamCreated(stream_id, length);
135 void OnStreamStateChanged(const IPC::Message& msg, int stream_id,
136 media::AudioOutputIPCDelegate::State state) {
137 switch (state) {
138 case media::AudioOutputIPCDelegate::kPlaying:
139 OnStreamPlaying(stream_id);
140 break;
141 case media::AudioOutputIPCDelegate::kPaused:
142 OnStreamPaused(stream_id);
143 break;
144 case media::AudioOutputIPCDelegate::kError:
145 OnStreamError(stream_id);
146 break;
147 default:
148 FAIL() << "Unknown stream state";
149 break;
153 scoped_ptr<base::SharedMemory> shared_memory_;
154 scoped_ptr<base::SyncSocket> sync_socket_;
155 uint32 shared_memory_length_;
157 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost);
160 ACTION_P(QuitMessageLoop, message_loop) {
161 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
164 class AudioRendererHostTest : public testing::Test {
165 public:
166 AudioRendererHostTest() {}
168 protected:
169 virtual void SetUp() {
170 // Create a message loop so AudioRendererHost can use it.
171 message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
173 // Claim to be on both the UI and IO threads to pass all the DCHECKS.
174 io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
175 message_loop_.get()));
176 ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI,
177 message_loop_.get()));
178 audio_manager_.reset(media::AudioManager::Create());
179 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
180 media_stream_manager_->UseFakeDevice();
181 observer_.reset(new MockMediaInternals());
182 host_ = new MockAudioRendererHost(
183 audio_manager_.get(), &mirroring_manager_, observer_.get(),
184 media_stream_manager_.get());
186 // Simulate IPC channel connected.
187 host_->OnChannelConnected(base::GetCurrentProcId());
190 virtual void TearDown() {
191 // Simulate closing the IPC channel.
192 host_->OnChannelClosing();
194 // Release the reference to the mock object. The object will be destructed
195 // on message_loop_.
196 host_ = NULL;
198 // We need to continue running message_loop_ to complete all destructions.
199 SyncWithAudioThread();
200 audio_manager_.reset();
202 io_thread_.reset();
203 ui_thread_.reset();
205 // Delete the IO message loop. This will cause the MediaStreamManager to be
206 // notified so it will stop its device thread and device managers.
207 message_loop_.reset();
210 void Create() {
211 EXPECT_CALL(*observer_,
212 OnSetAudioStreamStatus(_, kStreamId, "created"));
213 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _))
214 .WillOnce(QuitMessageLoop(message_loop_.get()));
215 EXPECT_CALL(mirroring_manager_,
216 AddDiverter(kRenderProcessId, kRenderViewId, NotNull()))
217 .RetiresOnSaturation();
219 // Send a create stream message to the audio output stream and wait until
220 // we receive the created message.
221 host_->OnCreateStream(kStreamId,
222 kRenderViewId,
224 media::AudioParameters(
225 media::AudioParameters::AUDIO_FAKE,
226 media::CHANNEL_LAYOUT_STEREO,
227 media::AudioParameters::kAudioCDSampleRate, 16,
228 media::AudioParameters::kAudioCDSampleRate / 10));
229 message_loop_->Run();
231 // At some point in the future, a corresponding RemoveDiverter() call must
232 // be made.
233 EXPECT_CALL(mirroring_manager_,
234 RemoveDiverter(kRenderProcessId, kRenderViewId, NotNull()))
235 .RetiresOnSaturation();
237 // All created streams should ultimately be closed.
238 EXPECT_CALL(*observer_,
239 OnSetAudioStreamStatus(_, kStreamId, "closed"));
241 // Expect the audio stream will be deleted at some later point.
242 EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId));
245 void CreateUnifiedStream() {
246 EXPECT_CALL(*observer_,
247 OnSetAudioStreamStatus(_, kStreamId, "created"));
248 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _))
249 .WillOnce(QuitMessageLoop(message_loop_.get()));
250 EXPECT_CALL(mirroring_manager_,
251 AddDiverter(kRenderProcessId, kRenderViewId, NotNull()))
252 .RetiresOnSaturation();
253 // Send a create stream message to the audio output stream and wait until
254 // we receive the created message.
255 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to
256 // pass the permission check.
257 host_->OnCreateStream(kStreamId,
258 kRenderViewId,
259 AudioInputDeviceManager::kFakeOpenSessionId,
260 media::AudioParameters(
261 media::AudioParameters::AUDIO_FAKE,
262 media::CHANNEL_LAYOUT_STEREO,
264 media::AudioParameters::kAudioCDSampleRate, 16,
265 media::AudioParameters::kAudioCDSampleRate / 10));
266 message_loop_->Run();
268 // At some point in the future, a corresponding RemoveDiverter() call must
269 // be made.
270 EXPECT_CALL(mirroring_manager_,
271 RemoveDiverter(kRenderProcessId, kRenderViewId, NotNull()))
272 .RetiresOnSaturation();
274 // All created streams should ultimately be closed.
275 EXPECT_CALL(*observer_,
276 OnSetAudioStreamStatus(_, kStreamId, "closed"));
278 // Expect the audio stream will be deleted at some later point.
279 EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId));
282 void Close() {
283 // Send a message to AudioRendererHost to tell it we want to close the
284 // stream.
285 host_->OnCloseStream(kStreamId);
286 message_loop_->RunUntilIdle();
289 void Play() {
290 EXPECT_CALL(*observer_,
291 OnSetAudioStreamPlaying(_, kStreamId, true));
292 EXPECT_CALL(*host_.get(), OnStreamPlaying(kStreamId))
293 .WillOnce(QuitMessageLoop(message_loop_.get()));
295 host_->OnPlayStream(kStreamId);
296 message_loop_->Run();
299 void Pause() {
300 EXPECT_CALL(*observer_,
301 OnSetAudioStreamPlaying(_, kStreamId, false));
302 EXPECT_CALL(*host_.get(), OnStreamPaused(kStreamId))
303 .WillOnce(QuitMessageLoop(message_loop_.get()));
305 host_->OnPauseStream(kStreamId);
306 message_loop_->Run();
309 void SetVolume(double volume) {
310 EXPECT_CALL(*observer_,
311 OnSetAudioStreamVolume(_, kStreamId, volume));
313 host_->OnSetVolume(kStreamId, volume);
314 message_loop_->RunUntilIdle();
317 void SimulateError() {
318 EXPECT_CALL(*observer_,
319 OnSetAudioStreamStatus(_, kStreamId, "error"));
320 EXPECT_EQ(1u, host_->audio_entries_.size())
321 << "Calls Create() before calling this method";
323 // Expect an error signal sent through IPC.
324 EXPECT_CALL(*host_.get(), OnStreamError(kStreamId));
326 // Simulate an error sent from the audio device.
327 host_->ReportErrorAndClose(kStreamId);
328 SyncWithAudioThread();
330 // Expect the audio stream record is removed.
331 EXPECT_EQ(0u, host_->audio_entries_.size());
334 // Called on the audio thread.
335 static void PostQuitMessageLoop(base::MessageLoop* message_loop) {
336 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
339 // Called on the main thread.
340 static void PostQuitOnAudioThread(media::AudioManager* audio_manager,
341 base::MessageLoop* message_loop) {
342 audio_manager->GetMessageLoop()->PostTask(FROM_HERE,
343 base::Bind(&PostQuitMessageLoop, message_loop));
346 // SyncWithAudioThread() waits until all pending tasks on the audio thread
347 // are executed while also processing pending task in message_loop_ on the
348 // current thread. It is used to synchronize with the audio thread when we are
349 // closing an audio stream.
350 void SyncWithAudioThread() {
351 // Don't use scoped_refptr to addref the media::AudioManager when posting
352 // to the thread that itself owns.
353 message_loop_->PostTask(
354 FROM_HERE, base::Bind(&PostQuitOnAudioThread,
355 base::Unretained(audio_manager_.get()),
356 message_loop_.get()));
357 message_loop_->Run();
360 private:
361 scoped_ptr<MockMediaInternals> observer_;
362 MockAudioMirroringManager mirroring_manager_;
363 scoped_refptr<MockAudioRendererHost> host_;
364 scoped_ptr<base::MessageLoop> message_loop_;
365 scoped_ptr<BrowserThreadImpl> io_thread_;
366 scoped_ptr<BrowserThreadImpl> ui_thread_;
367 scoped_ptr<media::AudioManager> audio_manager_;
368 scoped_ptr<MediaStreamManager> media_stream_manager_;
370 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest);
373 TEST_F(AudioRendererHostTest, CreateAndClose) {
374 Create();
375 Close();
378 // Simulate the case where a stream is not properly closed.
379 TEST_F(AudioRendererHostTest, CreateAndShutdown) {
380 Create();
383 TEST_F(AudioRendererHostTest, CreatePlayAndClose) {
384 Create();
385 Play();
386 Close();
389 TEST_F(AudioRendererHostTest, CreatePlayPauseAndClose) {
390 Create();
391 Play();
392 Pause();
393 Close();
396 TEST_F(AudioRendererHostTest, SetVolume) {
397 Create();
398 SetVolume(0.5);
399 Play();
400 Pause();
401 Close();
404 // Simulate the case where a stream is not properly closed.
405 TEST_F(AudioRendererHostTest, CreatePlayAndShutdown) {
406 Create();
407 Play();
410 // Simulate the case where a stream is not properly closed.
411 TEST_F(AudioRendererHostTest, CreatePlayPauseAndShutdown) {
412 Create();
413 Play();
414 Pause();
417 TEST_F(AudioRendererHostTest, SimulateError) {
418 Create();
419 Play();
420 SimulateError();
423 // Simulate the case when an error is generated on the browser process,
424 // the audio device is closed but the render process try to close the
425 // audio stream again.
426 TEST_F(AudioRendererHostTest, SimulateErrorAndClose) {
427 Create();
428 Play();
429 SimulateError();
430 Close();
433 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) {
434 CreateUnifiedStream();
435 Close();
438 // TODO(hclam): Add tests for data conversation in low latency mode.
440 } // namespace content