OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "base/bind.h" | |
6 #include "base/bind_helpers.h" | |
7 #include "base/message_loop.h" | |
8 #include "base/process_util.h" | |
9 #include "base/synchronization/waitable_event.h" | |
10 #include "base/test/test_timeouts.h" | |
11 #include "base/time.h" | |
12 #include "content/common/child_process.h" | |
13 #include "content/common/child_thread.h" | |
14 #include "content/renderer/media/audio_renderer_impl.h" | |
15 #include "content/renderer/mock_content_renderer_client.h" | |
16 #include "content/renderer/render_process.h" | |
17 #include "content/renderer/render_thread_impl.h" | |
18 #include "ipc/ipc_channel.h" | |
19 #include "media/base/data_buffer.h" | |
20 #include "media/base/mock_callback.h" | |
21 #include "media/base/mock_filter_host.h" | |
22 #include "media/base/mock_filters.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 using ::testing::Return; | |
26 | |
27 namespace { | |
28 // This class is a mock of the child process singleton which is needed | |
29 // to be able to create a RenderThread object. | |
30 class MockRenderProcess : public RenderProcess { | |
31 public: | |
32 MockRenderProcess() {} | |
33 virtual ~MockRenderProcess() {} | |
34 | |
35 // RenderProcess implementation. | |
36 virtual skia::PlatformCanvas* GetDrawingCanvas(TransportDIB** memory, | |
37 const gfx::Rect& rect) { return NULL; } | |
38 virtual void ReleaseTransportDIB(TransportDIB* memory) {} | |
39 virtual bool UseInProcessPlugins() const { return false; } | |
40 virtual void AddBindings(int bindings) {} | |
41 virtual int GetEnabledBindings() const { return 0; } | |
42 virtual bool HasInitializedMediaLibrary() const { return false; } | |
43 | |
44 private: | |
45 DISALLOW_COPY_AND_ASSIGN(MockRenderProcess); | |
46 }; | |
47 } | |
48 | |
49 // This callback can be posted on the IO thread and will signal an event when | |
50 // done. The caller can then wait for this signal to ensure that no | |
51 // additional tasks remain in the task queue. | |
52 void WaitCallback(base::WaitableEvent* event) { | |
53 event->Signal(); | |
54 } | |
55 | |
56 // Class we would be testing. | |
57 class TestAudioRendererImpl : public AudioRendererImpl { | |
58 public: | |
59 explicit TestAudioRendererImpl(media::AudioRendererSink* sink) | |
60 : AudioRendererImpl(sink) { | |
61 } | |
62 }; | |
63 | |
64 class AudioRendererImplTest | |
65 : public ::testing::Test, | |
66 public IPC::Channel::Listener { | |
67 public: | |
68 // IPC::Channel::Listener implementation. | |
69 virtual bool OnMessageReceived(const IPC::Message& message) { | |
70 NOTIMPLEMENTED(); | |
71 return true; | |
72 } | |
73 | |
74 static const int kSize; | |
75 | |
76 AudioRendererImplTest() {} | |
77 virtual ~AudioRendererImplTest() {} | |
78 | |
79 virtual void SetUp() { | |
80 // This part sets up a RenderThread environment to ensure that | |
81 // RenderThread::current() (<=> TLS pointer) is valid. | |
82 // Main parts are inspired by the RenderViewFakeResourcesTest. | |
83 // Note that, the IPC part is not utilized in this test. | |
84 content::GetContentClient()->set_renderer(&mock_content_renderer_client_); | |
85 | |
86 static const char kThreadName[] = "RenderThread"; | |
87 channel_.reset(new IPC::Channel(kThreadName, | |
88 IPC::Channel::MODE_SERVER, this)); | |
89 ASSERT_TRUE(channel_->Connect()); | |
90 | |
91 mock_process_.reset(new MockRenderProcess); | |
92 render_thread_ = new RenderThreadImpl(kThreadName); | |
93 | |
94 // Setup expectations for initialization. | |
95 decoder_ = new media::MockAudioDecoder(); | |
96 | |
97 EXPECT_CALL(*decoder_, bits_per_channel()) | |
98 .WillRepeatedly(Return(16)); | |
99 EXPECT_CALL(*decoder_, channel_layout()) | |
100 .WillRepeatedly(Return(CHANNEL_LAYOUT_MONO)); | |
101 EXPECT_CALL(*decoder_, samples_per_second()) | |
102 .WillRepeatedly(Return(44100)); | |
103 | |
104 // Create a sink for the audio renderer. | |
105 scoped_refptr<media::AudioRendererSink> default_sink = | |
106 new AudioDevice(); | |
107 | |
108 // Create and initialize the audio renderer. | |
109 renderer_ = new TestAudioRendererImpl(default_sink.get()); | |
110 renderer_->Initialize(decoder_, | |
111 media::NewExpectedStatusCB(media::PIPELINE_OK), | |
112 NewUnderflowClosure(), NewTimeClosure()); | |
113 | |
114 // We need an event to verify that all tasks are done before leaving | |
115 // our tests. | |
116 event_.reset(new base::WaitableEvent(false, false)); | |
117 } | |
118 | |
119 virtual void TearDown() { | |
120 mock_process_.reset(); | |
121 } | |
122 | |
123 MOCK_METHOD0(OnUnderflow, void()); | |
124 | |
125 base::Closure NewUnderflowClosure() { | |
126 return base::Bind(&AudioRendererImplTest::OnUnderflow, | |
127 base::Unretained(this)); | |
128 } | |
129 | |
130 void OnTimeCallback( | |
131 base::TimeDelta current_time, base::TimeDelta max_time) { | |
132 CHECK(current_time <= max_time); | |
133 } | |
134 | |
135 media::AudioRenderer::TimeCB NewTimeClosure() { | |
136 return base::Bind(&AudioRendererImplTest::OnTimeCallback, | |
137 base::Unretained(this)); | |
138 } | |
139 | |
140 protected: | |
141 // Posts a final task to the IO message loop and waits for completion. | |
142 void WaitForIOThreadCompletion() { | |
143 ChildProcess::current()->io_message_loop()->PostTask( | |
144 FROM_HERE, base::Bind(&WaitCallback, base::Unretained(event_.get()))); | |
145 EXPECT_TRUE(event_->TimedWait( | |
146 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()))); | |
147 } | |
148 | |
149 MessageLoopForIO message_loop_; | |
150 content::MockContentRendererClient mock_content_renderer_client_; | |
151 scoped_ptr<IPC::Channel> channel_; | |
152 RenderThreadImpl* render_thread_; // owned by mock_process_ | |
153 scoped_ptr<MockRenderProcess> mock_process_; | |
154 scoped_refptr<media::MockAudioDecoder> decoder_; | |
155 scoped_refptr<AudioRendererImpl> renderer_; | |
156 scoped_ptr<base::WaitableEvent> event_; | |
157 | |
158 private: | |
159 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); | |
160 }; | |
161 | |
162 const int AudioRendererImplTest::kSize = 1024; | |
163 | |
164 TEST_F(AudioRendererImplTest, SetPlaybackRate) { | |
165 // Execute SetPlaybackRate() codepath by toggling play/pause. | |
166 // These methods will be called on the pipeline thread but calling from | |
167 // here is fine for this test. Tasks will be posted internally on | |
168 // the IO thread. | |
169 renderer_->SetPlaybackRate(0.0f); | |
170 renderer_->SetPlaybackRate(1.0f); | |
171 renderer_->SetPlaybackRate(0.0f); | |
172 | |
173 renderer_->Stop(media::NewExpectedClosure()); | |
174 WaitForIOThreadCompletion(); | |
175 } | |
176 | |
177 TEST_F(AudioRendererImplTest, SetVolume) { | |
178 // Execute SetVolume() codepath. | |
179 // This method will be called on the pipeline thread IRL. | |
180 // Tasks will be posted internally on the IO thread. | |
181 renderer_->SetVolume(0.5f); | |
182 | |
183 renderer_->Stop(media::NewExpectedClosure()); | |
184 WaitForIOThreadCompletion(); | |
185 } | |
186 | |
187 TEST_F(AudioRendererImplTest, UpdateEarliestEndTime) { | |
188 renderer_->SetPlaybackRate(1.0f); | |
189 WaitForIOThreadCompletion(); | |
190 base::Time time_now = base::Time(); // Null time by default. | |
191 renderer_->set_earliest_end_time(time_now); | |
192 renderer_->UpdateEarliestEndTime(renderer_->bytes_per_second(), | |
193 base::TimeDelta::FromMilliseconds(100), | |
194 time_now); | |
195 int time_delta = (renderer_->earliest_end_time() - time_now).InMilliseconds(); | |
196 EXPECT_EQ(1100, time_delta); | |
197 renderer_->Stop(media::NewExpectedClosure()); | |
198 WaitForIOThreadCompletion(); | |
199 } | |
OLD | NEW |