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

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

Issue 7157001: Implements AudioMessageFilter as member in RenderThread (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Fixed nits in AudioRenderImpl unit test Created 9 years, 5 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/message_loop.h"
5 #include "base/process_util.h" 6 #include "base/process_util.h"
7 #include "base/synchronization/waitable_event.h"
8 #include "base/test/test_timeouts.h"
9 #include "base/time.h"
10 #include "content/common/child_process.h"
11 #include "content/common/child_thread.h"
6 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
7 #include "content/renderer/media/audio_renderer_impl.h" 13 #include "content/renderer/media/audio_renderer_impl.h"
14 #include "content/renderer/mock_content_renderer_client.h"
15 #include "content/renderer/render_process.h"
16 #include "content/renderer/render_thread.h"
17 #include "ipc/ipc_channel.h"
8 #include "media/base/data_buffer.h" 18 #include "media/base/data_buffer.h"
9 #include "media/base/mock_callback.h" 19 #include "media/base/mock_callback.h"
10 #include "media/base/mock_filter_host.h" 20 #include "media/base/mock_filter_host.h"
11 #include "media/base/mock_filters.h" 21 #include "media/base/mock_filters.h"
12 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
13 23
14 using ::testing::Return; 24 using ::testing::Return;
15 25
16 // Class we would be tesing. The only difference between it and "real" one 26 namespace {
27 // This class is a mock of the child process singleton which is needed
28 // to be able to create a RenderThread object.
29 class MockRenderProcess : public RenderProcess {
30 public:
31 MockRenderProcess() {}
32 virtual ~MockRenderProcess() {}
33
34 // RenderProcess implementation.
35 virtual skia::PlatformCanvas* GetDrawingCanvas(TransportDIB** memory,
36 const gfx::Rect& rect) { return NULL; }
37 virtual void ReleaseTransportDIB(TransportDIB* memory) {}
38 virtual bool UseInProcessPlugins() const { return false; }
39 virtual bool HasInitializedMediaLibrary() const { return false; }
40
41 private:
42 DISALLOW_COPY_AND_ASSIGN(MockRenderProcess);
43 };
44 }
45
46 // This class defines a set of methods which will be used in combination
47 // with NewRunnableMethod to form tasks which will be posted on the
48 // IO thread. All methods emulate AudioMessageFilter::Delegate calls.
49 class DelegateCaller : public base::RefCountedThreadSafe<DelegateCaller> {
50 public:
51 explicit DelegateCaller(AudioRendererImpl* renderer)
52 : renderer_(renderer) {}
53
54 void OnCreated(base::SharedMemoryHandle handle, uint32 length) {
55 if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) {
56 renderer_->OnCreated(handle, length);
57 } else {
58 renderer_->OnLowLatencyCreated(handle, 0, length);
59 }
60 }
61 void OnStateChanged(AudioStreamState state) {
62 renderer_->OnStateChanged(state);
63 }
64 void OnRequestPacket(AudioBuffersState buffers_state) {
65 renderer_->OnRequestPacket(buffers_state);
66 }
67 void OnVolume(double volume) {
68 renderer_->OnVolume(volume);
69 }
70 void DestroyCurrentMessageLoop() {
71 renderer_->WillDestroyCurrentMessageLoop();
72 }
73 private:
74 friend class base::RefCountedThreadSafe<DelegateCaller>;
75 virtual ~DelegateCaller() {}
76
77 scoped_refptr<AudioRendererImpl> renderer_;
78 DISALLOW_COPY_AND_ASSIGN(DelegateCaller);
79 };
80
81 // This task can be posted on the IO thread and will signal an event when
82 // done. The caller can then wait for this signal to ensure that no
83 // additional tasks remain in the task queue.
84 class WaitTask : public Task {
85 public:
86 explicit WaitTask(base::WaitableEvent* event)
87 : event_(event) {}
88 virtual ~WaitTask() {}
89 virtual void Run() {
90 event_->Signal();
91 }
92
93 private:
94 base::WaitableEvent* event_;
95 DISALLOW_COPY_AND_ASSIGN(WaitTask);
96 };
97
98 // Class we would be testing. The only difference between it and "real" one
17 // is that test class does not open sockets and launch audio thread. 99 // is that test class does not open sockets and launch audio thread.
18 class TestAudioRendererImpl : public AudioRendererImpl { 100 class TestAudioRendererImpl : public AudioRendererImpl {
19 public: 101 public:
20 explicit TestAudioRendererImpl(AudioMessageFilter* filter) 102 explicit TestAudioRendererImpl()
21 : AudioRendererImpl(filter) { 103 : AudioRendererImpl() {
22 } 104 }
23 private: 105 private:
24 virtual void CreateSocket(base::SyncSocket::Handle socket_handle) {} 106 virtual void CreateSocket(base::SyncSocket::Handle socket_handle) {}
25 virtual void CreateAudioThread() {} 107 virtual void CreateAudioThread() {}
26 }; 108 };
27 109
28 class AudioRendererImplTest : public ::testing::Test { 110 class AudioRendererImplTest
111 : public ::testing::Test,
112 public IPC::Channel::Listener {
29 public: 113 public:
30 static const int kRouteId = 0;
31 static const int kSize = 1024;
32
33 static void SetUpTestCase() { 114 static void SetUpTestCase() {
34 // Set low latency mode, as it soon would be on by default. 115 // Set low latency mode, as it soon would be on by default.
35 AudioRendererImpl::set_latency_type(AudioRendererImpl::kLowLatency); 116 AudioRendererImpl::set_latency_type(AudioRendererImpl::kLowLatency);
36 } 117 }
37 118
38 AudioRendererImplTest() { 119 // IPC::Channel::Listener implementation.
39 message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); 120 virtual bool OnMessageReceived(const IPC::Message& message) {
121 NOTIMPLEMENTED();
122 return true;
123 }
40 124
41 // TODO(scherkus): use gmock with AudioMessageFilter to verify 125 static const int kSize;
42 // AudioRendererImpl calls or doesn't call Send(). 126
43 filter_ = new AudioMessageFilter(kRouteId); 127 AudioRendererImplTest() {}
44 filter_->message_loop_ = message_loop_.get(); 128 virtual ~AudioRendererImplTest() {}
129
130 virtual void SetUp() {
131 // This part sets up a RenderThread environment to ensure that
132 // RenderThread::current() (<=> TLS pointer) is valid.
133 // Main parts are inspired by the RenderViewFakeResourcesTest.
134 // Note that, the IPC part is not utilized in this test.
135 content::GetContentClient()->set_renderer(&mock_content_renderer_client_);
136
137 static const char kThreadName[] = "RenderThread";
138 channel_.reset(new IPC::Channel(kThreadName,
139 IPC::Channel::MODE_SERVER, this));
140 ASSERT_TRUE(channel_->Connect());
141
142 mock_process_.reset(new MockRenderProcess);
143 render_thread_ = new RenderThread(kThreadName);
144 mock_process_->set_main_thread(render_thread_);
45 145
46 // Create temporary shared memory. 146 // Create temporary shared memory.
47 CHECK(shared_mem_.CreateAnonymous(kSize)); 147 CHECK(shared_mem_.CreateAnonymous(kSize));
48 148
49 // Setup expectations for initialization. 149 // Setup expectations for initialization.
50 decoder_ = new media::MockAudioDecoder(); 150 decoder_ = new media::MockAudioDecoder();
51 151
52 ON_CALL(*decoder_, config()) 152 ON_CALL(*decoder_, config())
53 .WillByDefault(Return(media::AudioDecoderConfig(16, 153 .WillByDefault(Return(media::AudioDecoderConfig(16,
54 CHANNEL_LAYOUT_MONO, 154 CHANNEL_LAYOUT_MONO,
55 44100))); 155 44100)));
56 156
57 // Create and initialize audio renderer. 157 // Create and initialize the audio renderer.
58 renderer_ = new TestAudioRendererImpl(filter_); 158 renderer_ = new TestAudioRendererImpl();
59 renderer_->set_host(&host_); 159 renderer_->set_host(&host_);
60 renderer_->Initialize(decoder_, media::NewExpectedCallback()); 160 renderer_->Initialize(decoder_, media::NewExpectedCallback());
61 161
62 // Run pending tasks and simulate responding with a created audio stream. 162 // Wraps delegate calls into tasks.
63 message_loop_->RunAllPending(); 163 delegate_caller_ = new DelegateCaller(renderer_);
164
165 // We need an event to verify that all tasks are done before leaving
166 // our tests.
167 event_.reset(new base::WaitableEvent(false, false));
64 168
65 // Duplicate the shared memory handle so both the test and the callee can 169 // Duplicate the shared memory handle so both the test and the callee can
66 // close their copy. 170 // close their copy.
67 base::SharedMemoryHandle duplicated_handle; 171 base::SharedMemoryHandle duplicated_handle;
68 EXPECT_TRUE(shared_mem_.ShareToProcess(base::GetCurrentProcessHandle(), 172 EXPECT_TRUE(shared_mem_.ShareToProcess(base::GetCurrentProcessHandle(),
69 &duplicated_handle)); 173 &duplicated_handle));
70 CallOnCreated(duplicated_handle); 174
175 // Set things up and ensure that the call comes from the IO thread
176 // as all AudioMessageFilter::Delegate methods.
177 ChildProcess::current()->io_message_loop()->PostTask(
178 FROM_HERE,
179 NewRunnableMethod(delegate_caller_.get(),
180 &DelegateCaller::OnCreated, duplicated_handle, kSize));
181 WaitForIOThreadCompletion();
71 } 182 }
72 183
73 virtual ~AudioRendererImplTest() { 184 virtual void TearDown() {
74 } 185 mock_process_.reset();
75
76 void CallOnCreated(base::SharedMemoryHandle handle) {
77 if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) {
78 renderer_->OnCreated(handle, kSize);
79 } else {
80 renderer_->OnLowLatencyCreated(handle, 0, kSize);
81 }
82 } 186 }
83 187
84 protected: 188 protected:
85 // Fixtures. 189 // Posts a final task to the IO message loop and waits for completion.
86 scoped_ptr<MessageLoop> message_loop_; 190 void WaitForIOThreadCompletion() {
87 scoped_refptr<AudioMessageFilter> filter_; 191 ChildProcess::current()->io_message_loop()->PostTask(
192 FROM_HERE, new WaitTask(event_.get()));
193 EXPECT_TRUE(event_->TimedWait(
194 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms())));
195 }
196
197 MessageLoopForIO message_loop_;
198 content::MockContentRendererClient mock_content_renderer_client_;
199 scoped_ptr<IPC::Channel> channel_;
200 RenderThread* render_thread_; // owned by mock_process_
201 scoped_ptr<MockRenderProcess> mock_process_;
88 base::SharedMemory shared_mem_; 202 base::SharedMemory shared_mem_;
89 media::MockFilterHost host_; 203 media::MockFilterHost host_;
90 scoped_refptr<media::MockAudioDecoder> decoder_; 204 scoped_refptr<media::MockAudioDecoder> decoder_;
91 scoped_refptr<AudioRendererImpl> renderer_; 205 scoped_refptr<AudioRendererImpl> renderer_;
206 scoped_ptr<base::WaitableEvent> event_;
207 scoped_refptr<DelegateCaller> delegate_caller_;
92 208
93 private: 209 private:
94 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); 210 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest);
95 }; 211 };
96 212
213 const int AudioRendererImplTest::kSize = 1024;
214
97 TEST_F(AudioRendererImplTest, SetPlaybackRate) { 215 TEST_F(AudioRendererImplTest, SetPlaybackRate) {
98 // Execute SetPlaybackRate() codepath to create an IPC message. 216 // Execute SetPlaybackRate() codepath by toggling play/pause.
99 217 // These methods will be called on the pipeline thread but calling from
100 // Toggle play/pause to generate some IPC messages. 218 // here is fine for this test. Tasks will be posted internally on
219 // the IO thread.
101 renderer_->SetPlaybackRate(0.0f); 220 renderer_->SetPlaybackRate(0.0f);
102 renderer_->SetPlaybackRate(1.0f); 221 renderer_->SetPlaybackRate(1.0f);
103 renderer_->SetPlaybackRate(0.0f); 222 renderer_->SetPlaybackRate(0.0f);
104 223
105 renderer_->Stop(media::NewExpectedCallback()); 224 renderer_->Stop(media::NewExpectedCallback());
106 message_loop_->RunAllPending(); 225 WaitForIOThreadCompletion();
107 } 226 }
108 227
109 TEST_F(AudioRendererImplTest, SetVolume) { 228 TEST_F(AudioRendererImplTest, SetVolume) {
110 // Execute SetVolume() codepath to create an IPC message. 229 // Execute SetVolume() codepath.
230 // This method will be called on the pipeline thread IRL.
231 // Tasks will be posted internally on the IO thread.
111 renderer_->SetVolume(0.5f); 232 renderer_->SetVolume(0.5f);
233
112 renderer_->Stop(media::NewExpectedCallback()); 234 renderer_->Stop(media::NewExpectedCallback());
113 message_loop_->RunAllPending(); 235 WaitForIOThreadCompletion();
114 } 236 }
115 237
116 TEST_F(AudioRendererImplTest, Stop) { 238 TEST_F(AudioRendererImplTest, Stop) {
117 // Execute Stop() codepath to create an IPC message. 239 // Execute Stop() codepath.
240 // Tasks will be posted internally on the IO thread.
118 renderer_->Stop(media::NewExpectedCallback()); 241 renderer_->Stop(media::NewExpectedCallback());
119 message_loop_->RunAllPending();
120 242
121 // Run AudioMessageFilter::Delegate methods, which can be executed after being 243 // Run AudioMessageFilter::Delegate methods, which can be executed after being
122 // stopped. AudioRendererImpl shouldn't create any messages. 244 // stopped. AudioRendererImpl shouldn't create any messages in this state.
245 // All delegate method calls are posted on the IO thread since it is
246 // a requirement.
123 if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) { 247 if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) {
124 renderer_->OnRequestPacket(AudioBuffersState(kSize, 0)); 248 ChildProcess::current()->io_message_loop()->PostTask(
249 FROM_HERE,
250 NewRunnableMethod(delegate_caller_.get(),
251 &DelegateCaller::OnRequestPacket, AudioBuffersState(kSize, 0)));
125 } 252 }
126 renderer_->OnStateChanged(kAudioStreamError); 253 ChildProcess::current()->io_message_loop()->PostTask(
127 renderer_->OnStateChanged(kAudioStreamPlaying); 254 FROM_HERE,
128 renderer_->OnStateChanged(kAudioStreamPaused); 255 NewRunnableMethod(delegate_caller_.get(),
129 CallOnCreated(shared_mem_.handle()); 256 &DelegateCaller::OnStateChanged, kAudioStreamError));
130 renderer_->OnVolume(0.5); 257 ChildProcess::current()->io_message_loop()->PostTask(
258 FROM_HERE,
259 NewRunnableMethod(delegate_caller_.get(),
260 &DelegateCaller::OnStateChanged, kAudioStreamPlaying));
261 ChildProcess::current()->io_message_loop()->PostTask(
262 FROM_HERE,
263 NewRunnableMethod(delegate_caller_.get(),
264 &DelegateCaller::OnStateChanged, kAudioStreamPaused));
265 ChildProcess::current()->io_message_loop()->PostTask(
266 FROM_HERE,
267 NewRunnableMethod(delegate_caller_.get(),
268 &DelegateCaller::OnCreated, shared_mem_.handle(), kSize));
269 ChildProcess::current()->io_message_loop()->PostTask(
270 FROM_HERE,
271 NewRunnableMethod(delegate_caller_.get(),
272 &DelegateCaller::OnVolume, 0.5));
273
274 WaitForIOThreadCompletion();
131 275
132 // It's possible that the upstream decoder replies right after being stopped. 276 // It's possible that the upstream decoder replies right after being stopped.
133 scoped_refptr<media::Buffer> buffer(new media::DataBuffer(kSize)); 277 scoped_refptr<media::Buffer> buffer(new media::DataBuffer(kSize));
134 renderer_->ConsumeAudioSamples(buffer); 278 renderer_->ConsumeAudioSamples(buffer);
135 } 279 }
136 280
137 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetPlaybackRate) { 281 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetPlaybackRate) {
138 // Kill the message loop and verify SetPlaybackRate() still works. 282 // Emulate "killing the message loop" and verify that SetPlaybackRate()
139 message_loop_.reset(); 283 // still works.
284 ChildProcess::current()->io_message_loop()->PostTask(
285 FROM_HERE,
286 NewRunnableMethod(delegate_caller_.get(),
287 &DelegateCaller::DestroyCurrentMessageLoop));
288 WaitForIOThreadCompletion();
289
290 // No tasks will be posted on the IO thread here since we are in
291 // a "stopped" state.
140 renderer_->SetPlaybackRate(0.0f); 292 renderer_->SetPlaybackRate(0.0f);
141 renderer_->SetPlaybackRate(1.0f); 293 renderer_->SetPlaybackRate(1.0f);
142 renderer_->SetPlaybackRate(0.0f); 294 renderer_->SetPlaybackRate(0.0f);
143 renderer_->Stop(media::NewExpectedCallback()); 295 renderer_->Stop(media::NewExpectedCallback());
144 } 296 }
145 297
146 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetVolume) { 298 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetVolume) {
147 // Kill the message loop and verify SetVolume() still works. 299 // Emulate "killing the message loop" and verify that SetVolume()
148 message_loop_.reset(); 300 // still works.
301 ChildProcess::current()->io_message_loop()->PostTask(
302 FROM_HERE,
303 NewRunnableMethod(delegate_caller_.get(),
304 &DelegateCaller::DestroyCurrentMessageLoop));
305 WaitForIOThreadCompletion();
306
307 // No tasks will be posted on the IO thread here since we are in
308 // a "stopped" state.
149 renderer_->SetVolume(0.5f); 309 renderer_->SetVolume(0.5f);
150 renderer_->Stop(media::NewExpectedCallback()); 310 renderer_->Stop(media::NewExpectedCallback());
151 } 311 }
152 312
153 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_ConsumeAudioSamples) { 313 TEST_F(AudioRendererImplTest, DestroyedMessageLoop_ConsumeAudioSamples) {
154 // Kill the message loop and verify OnReadComplete() still works. 314 // Emulate "killing the message loop" and verify that OnReadComplete()
155 message_loop_.reset(); 315 // still works.
316 ChildProcess::current()->io_message_loop()->PostTask(
317 FROM_HERE,
318 NewRunnableMethod(delegate_caller_.get(),
319 &DelegateCaller::DestroyCurrentMessageLoop));
320 WaitForIOThreadCompletion();
321
322 // No tasks will be posted on the IO thread here since we are in
323 // a "stopped" state.
156 scoped_refptr<media::Buffer> buffer(new media::DataBuffer(kSize)); 324 scoped_refptr<media::Buffer> buffer(new media::DataBuffer(kSize));
157 renderer_->ConsumeAudioSamples(buffer); 325 renderer_->ConsumeAudioSamples(buffer);
158 renderer_->Stop(media::NewExpectedCallback()); 326 renderer_->Stop(media::NewExpectedCallback());
159 } 327 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_renderer_impl.cc ('k') | content/renderer/pepper_plugin_delegate_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698