Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host_unittest.cc
blob9dc99f20d0e0fa794ed8dddea7a7600d71683eaf
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 kRenderViewId = 4;
33 const int kRenderFrameId = 5;
34 const int kStreamId = 50;
35 } // namespace
37 namespace content {
39 class MockAudioMirroringManager : public AudioMirroringManager {
40 public:
41 MockAudioMirroringManager() {}
42 virtual ~MockAudioMirroringManager() {}
44 MOCK_METHOD3(AddDiverter,
45 void(int render_process_id,
46 int render_view_id,
47 Diverter* diverter));
48 MOCK_METHOD3(RemoveDiverter,
49 void(int render_process_id,
50 int render_view_id,
51 Diverter* diverter));
53 private:
54 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
57 class MockAudioRendererHost : public AudioRendererHost {
58 public:
59 MockAudioRendererHost(media::AudioManager* audio_manager,
60 AudioMirroringManager* mirroring_manager,
61 MediaInternals* media_internals,
62 MediaStreamManager* media_stream_manager)
63 : AudioRendererHost(kRenderProcessId,
64 audio_manager,
65 mirroring_manager,
66 media_internals,
67 media_stream_manager),
68 shared_memory_length_(0) {}
70 // A list of mock methods.
71 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length));
72 MOCK_METHOD1(OnStreamPlaying, void(int stream_id));
73 MOCK_METHOD1(OnStreamPaused, void(int stream_id));
74 MOCK_METHOD1(OnStreamError, void(int stream_id));
76 private:
77 virtual ~MockAudioRendererHost() {
78 // Make sure all audio streams have been deleted.
79 EXPECT_TRUE(audio_entries_.empty());
82 // This method is used to dispatch IPC messages to the renderer. We intercept
83 // these messages here and dispatch to our mock methods to verify the
84 // conversation between this object and the renderer.
85 virtual bool Send(IPC::Message* message) {
86 CHECK(message);
88 // In this method we dispatch the messages to the according handlers as if
89 // we are the renderer.
90 bool handled = true;
91 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message)
92 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated,
93 OnNotifyStreamCreated)
94 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged,
95 OnNotifyStreamStateChanged)
96 IPC_MESSAGE_UNHANDLED(handled = false)
97 IPC_END_MESSAGE_MAP()
98 EXPECT_TRUE(handled);
100 delete message;
101 return true;
104 void OnNotifyStreamCreated(int stream_id,
105 base::SharedMemoryHandle handle,
106 #if defined(OS_WIN)
107 base::SyncSocket::Handle socket_handle,
108 #else
109 base::FileDescriptor socket_descriptor,
110 #endif
111 uint32 length) {
112 // Maps the shared memory.
113 shared_memory_.reset(new base::SharedMemory(handle, false));
114 CHECK(shared_memory_->Map(length));
115 CHECK(shared_memory_->memory());
116 shared_memory_length_ = length;
118 // Create the SyncSocket using the handle.
119 base::SyncSocket::Handle sync_socket_handle;
120 #if defined(OS_WIN)
121 sync_socket_handle = socket_handle;
122 #else
123 sync_socket_handle = socket_descriptor.fd;
124 #endif
125 sync_socket_.reset(new base::SyncSocket(sync_socket_handle));
127 // And then delegate the call to the mock method.
128 OnStreamCreated(stream_id, length);
131 void OnNotifyStreamStateChanged(int stream_id,
132 media::AudioOutputIPCDelegate::State state) {
133 switch (state) {
134 case media::AudioOutputIPCDelegate::kPlaying:
135 OnStreamPlaying(stream_id);
136 break;
137 case media::AudioOutputIPCDelegate::kPaused:
138 OnStreamPaused(stream_id);
139 break;
140 case media::AudioOutputIPCDelegate::kError:
141 OnStreamError(stream_id);
142 break;
143 default:
144 FAIL() << "Unknown stream state";
145 break;
149 scoped_ptr<base::SharedMemory> shared_memory_;
150 scoped_ptr<base::SyncSocket> sync_socket_;
151 uint32 shared_memory_length_;
153 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost);
156 class AudioRendererHostTest : public testing::Test {
157 public:
158 AudioRendererHostTest() {
159 audio_manager_.reset(media::AudioManager::CreateForTesting());
160 base::CommandLine::ForCurrentProcess()->AppendSwitch(
161 switches::kUseFakeDeviceForMediaStream);
162 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
163 host_ = new MockAudioRendererHost(audio_manager_.get(),
164 &mirroring_manager_,
165 MediaInternals::GetInstance(),
166 media_stream_manager_.get());
168 // Simulate IPC channel connected.
169 host_->set_peer_pid_for_testing(base::GetCurrentProcId());
172 virtual ~AudioRendererHostTest() {
173 // Simulate closing the IPC channel and give the audio thread time to close
174 // the underlying streams.
175 host_->OnChannelClosing();
176 SyncWithAudioThread();
178 // Release the reference to the mock object. The object will be destructed
179 // on message_loop_.
180 host_ = NULL;
183 protected:
184 void Create(bool unified_stream) {
185 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _));
187 EXPECT_CALL(mirroring_manager_,
188 AddDiverter(kRenderProcessId, kRenderViewId, NotNull()))
189 .RetiresOnSaturation();
191 // Send a create stream message to the audio output stream and wait until
192 // we receive the created message.
193 int session_id;
194 media::AudioParameters params;
195 if (unified_stream) {
196 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to
197 // pass the permission check.
198 session_id = AudioInputDeviceManager::kFakeOpenSessionId;
199 params = media::AudioParameters(
200 media::AudioParameters::AUDIO_FAKE,
201 media::CHANNEL_LAYOUT_STEREO,
203 media::AudioParameters::kAudioCDSampleRate, 16,
204 media::AudioParameters::kAudioCDSampleRate / 10,
205 media::AudioParameters::NO_EFFECTS);
206 } else {
207 session_id = 0;
208 params = media::AudioParameters(
209 media::AudioParameters::AUDIO_FAKE,
210 media::CHANNEL_LAYOUT_STEREO,
211 media::AudioParameters::kAudioCDSampleRate, 16,
212 media::AudioParameters::kAudioCDSampleRate / 10);
214 host_->OnCreateStream(kStreamId, kRenderViewId, kRenderFrameId, session_id,
215 params);
217 // At some point in the future, a corresponding RemoveDiverter() call must
218 // be made.
219 EXPECT_CALL(mirroring_manager_,
220 RemoveDiverter(kRenderProcessId, kRenderViewId, NotNull()))
221 .RetiresOnSaturation();
222 SyncWithAudioThread();
225 void Close() {
226 // Send a message to AudioRendererHost to tell it we want to close the
227 // stream.
228 host_->OnCloseStream(kStreamId);
229 SyncWithAudioThread();
232 void Play() {
233 EXPECT_CALL(*host_.get(), OnStreamPlaying(kStreamId));
234 host_->OnPlayStream(kStreamId);
235 SyncWithAudioThread();
238 void Pause() {
239 EXPECT_CALL(*host_.get(), OnStreamPaused(kStreamId));
240 host_->OnPauseStream(kStreamId);
241 SyncWithAudioThread();
244 void SetVolume(double volume) {
245 host_->OnSetVolume(kStreamId, volume);
246 SyncWithAudioThread();
249 void SimulateError() {
250 EXPECT_EQ(1u, host_->audio_entries_.size())
251 << "Calls Create() before calling this method";
253 // Expect an error signal sent through IPC.
254 EXPECT_CALL(*host_.get(), OnStreamError(kStreamId));
256 // Simulate an error sent from the audio device.
257 host_->ReportErrorAndClose(kStreamId);
258 SyncWithAudioThread();
260 // Expect the audio stream record is removed.
261 EXPECT_EQ(0u, host_->audio_entries_.size());
264 // SyncWithAudioThread() waits until all pending tasks on the audio thread
265 // are executed while also processing pending task in message_loop_ on the
266 // current thread. It is used to synchronize with the audio thread when we are
267 // closing an audio stream.
268 void SyncWithAudioThread() {
269 base::RunLoop().RunUntilIdle();
271 base::RunLoop run_loop;
272 audio_manager_->GetTaskRunner()->PostTask(
273 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure()));
274 run_loop.Run();
277 private:
278 // MediaStreamManager uses a DestructionObserver, so it must outlive the
279 // TestBrowserThreadBundle.
280 scoped_ptr<MediaStreamManager> media_stream_manager_;
281 TestBrowserThreadBundle thread_bundle_;
282 scoped_ptr<media::AudioManager> audio_manager_;
283 MockAudioMirroringManager mirroring_manager_;
284 scoped_refptr<MockAudioRendererHost> host_;
286 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest);
289 TEST_F(AudioRendererHostTest, CreateAndClose) {
290 Create(false);
291 Close();
294 // Simulate the case where a stream is not properly closed.
295 TEST_F(AudioRendererHostTest, CreateAndShutdown) {
296 Create(false);
299 TEST_F(AudioRendererHostTest, CreatePlayAndClose) {
300 Create(false);
301 Play();
302 Close();
305 TEST_F(AudioRendererHostTest, CreatePlayPauseAndClose) {
306 Create(false);
307 Play();
308 Pause();
309 Close();
312 TEST_F(AudioRendererHostTest, SetVolume) {
313 Create(false);
314 SetVolume(0.5);
315 Play();
316 Pause();
317 Close();
320 // Simulate the case where a stream is not properly closed.
321 TEST_F(AudioRendererHostTest, CreatePlayAndShutdown) {
322 Create(false);
323 Play();
326 // Simulate the case where a stream is not properly closed.
327 TEST_F(AudioRendererHostTest, CreatePlayPauseAndShutdown) {
328 Create(false);
329 Play();
330 Pause();
333 TEST_F(AudioRendererHostTest, SimulateError) {
334 Create(false);
335 Play();
336 SimulateError();
339 // Simulate the case when an error is generated on the browser process,
340 // the audio device is closed but the render process try to close the
341 // audio stream again.
342 TEST_F(AudioRendererHostTest, SimulateErrorAndClose) {
343 Create(false);
344 Play();
345 SimulateError();
346 Close();
349 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) {
350 Create(true);
351 Close();
354 // TODO(hclam): Add tests for data conversation in low latency mode.
356 } // namespace content