Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / content / browser / media / audio_stream_monitor_unittest.cc
blobf3189af9ed03d31ee9e9d248e5eb58b0b9bef741
1 // Copyright 2014 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 "content/browser/media/audio_stream_monitor.h"
7 #include <map>
8 #include <utility>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/test/simple_test_tick_clock.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/browser/invalidate_type.h"
16 #include "content/public/browser/web_contents_delegate.h"
17 #include "content/public/test/test_renderer_host.h"
18 #include "media/audio/audio_power_monitor.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using ::testing::InvokeWithoutArgs;
24 namespace content {
26 namespace {
28 const int kRenderProcessId = 1;
29 const int kAnotherRenderProcessId = 2;
30 const int kStreamId = 3;
31 const int kAnotherStreamId = 6;
33 // Used to confirm audio indicator state changes occur at the correct times.
34 class MockWebContentsDelegate : public WebContentsDelegate {
35 public:
36 MOCK_METHOD2(NavigationStateChanged,
37 void(WebContents* source, InvalidateTypes changed_flags));
40 } // namespace
42 class AudioStreamMonitorTest : public RenderViewHostTestHarness {
43 public:
44 AudioStreamMonitorTest() {
45 // Start |clock_| at non-zero.
46 clock_.Advance(base::TimeDelta::FromSeconds(1000000));
49 void SetUp() override {
50 RenderViewHostTestHarness::SetUp();
52 WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
53 RenderViewHostTestHarness::web_contents());
54 web_contents->SetDelegate(&mock_web_contents_delegate_);
56 monitor_ = web_contents->audio_stream_monitor();
57 const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
60 base::TimeTicks GetTestClockTime() { return clock_.NowTicks(); }
62 void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
64 AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
65 int stream_id) {
66 return base::Bind(
67 &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
70 void SetStreamPower(int stream_id, float power) {
71 current_power_[stream_id] = power;
74 void SimulatePollTimerFired() { monitor_->Poll(); }
76 void SimulateOffTimerFired() { monitor_->MaybeToggle(); }
78 void ExpectIsPolling(int render_process_id, int stream_id, bool is_polling) {
79 const AudioStreamMonitor::StreamID key(render_process_id, stream_id);
80 EXPECT_EQ(
81 is_polling,
82 monitor_->poll_callbacks_.find(key) != monitor_->poll_callbacks_.end());
83 EXPECT_EQ(!monitor_->poll_callbacks_.empty(),
84 monitor_->poll_timer_.IsRunning());
87 void ExpectTabWasRecentlyAudible(bool was_audible,
88 const base::TimeTicks& last_blurt_time) {
89 EXPECT_EQ(was_audible, monitor_->was_recently_audible_);
90 EXPECT_EQ(last_blurt_time, monitor_->last_blurt_time_);
91 EXPECT_EQ(monitor_->was_recently_audible_,
92 monitor_->off_timer_.IsRunning());
95 void ExpectWebContentsWillBeNotifiedOnce(bool should_be_audible) {
96 EXPECT_CALL(
97 mock_web_contents_delegate_,
98 NavigationStateChanged(RenderViewHostTestHarness::web_contents(),
99 INVALIDATE_TYPE_TAB))
100 .WillOnce(InvokeWithoutArgs(
101 this,
102 should_be_audible
103 ? &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOn
104 : &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOff))
105 .RetiresOnSaturation();
108 static base::TimeDelta one_polling_interval() {
109 return base::TimeDelta::FromSeconds(1) /
110 static_cast<int>(AudioStreamMonitor::kPowerMeasurementsPerSecond);
113 static base::TimeDelta holding_period() {
114 return base::TimeDelta::FromMilliseconds(
115 AudioStreamMonitor::kHoldOnMilliseconds);
118 void StartMonitoring(
119 int render_process_id,
120 int stream_id,
121 const AudioStreamMonitor::ReadPowerAndClipCallback& callback) {
122 monitor_->StartMonitoringStreamOnUIThread(
123 render_process_id, stream_id, callback);
126 void StopMonitoring(int render_process_id, int stream_id) {
127 monitor_->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
130 protected:
131 AudioStreamMonitor* monitor_;
133 private:
134 std::pair<float, bool> ReadPower(int stream_id) {
135 return std::make_pair(current_power_[stream_id], false);
138 void ExpectIsNotifyingForToggleOn() {
139 EXPECT_TRUE(monitor_->WasRecentlyAudible());
142 void ExpectIsNotifyingForToggleOff() {
143 EXPECT_FALSE(monitor_->WasRecentlyAudible());
146 MockWebContentsDelegate mock_web_contents_delegate_;
147 base::SimpleTestTickClock clock_;
148 std::map<int, float> current_power_;
150 DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
153 // Tests that AudioStreamMonitor is polling while it has a
154 // ReadPowerAndClipCallback, and is not polling at other times.
155 TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
156 EXPECT_FALSE(monitor_->WasRecentlyAudible());
157 ExpectIsPolling(kRenderProcessId, kStreamId, false);
159 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
160 EXPECT_FALSE(monitor_->WasRecentlyAudible());
161 ExpectIsPolling(kRenderProcessId, kStreamId, true);
163 StopMonitoring(kRenderProcessId, kStreamId);
164 EXPECT_FALSE(monitor_->WasRecentlyAudible());
165 ExpectIsPolling(kRenderProcessId, kStreamId, false);
168 // Tests that AudioStreamMonitor debounces the power level readings it's taking,
169 // which could be fluctuating rapidly between the audible versus silence
170 // threshold. See comments in audio_stream_monitor.h for expected behavior.
171 TEST_F(AudioStreamMonitorTest,
172 ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
173 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
175 // Expect WebContents will get one call form AudioStreamMonitor to toggle the
176 // indicator on upon the very first poll.
177 ExpectWebContentsWillBeNotifiedOnce(true);
179 // Loop, each time testing a slightly longer period of polled silence. The
180 // indicator should remain on throughout.
181 int num_silence_polls = 0;
182 base::TimeTicks last_blurt_time;
183 do {
184 // Poll an audible signal, and expect tab indicator state is on.
185 SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
186 last_blurt_time = GetTestClockTime();
187 SimulatePollTimerFired();
188 ExpectTabWasRecentlyAudible(true, last_blurt_time);
189 AdvanceClock(one_polling_interval());
191 // Poll a silent signal repeatedly, ensuring that the indicator is being
192 // held on during the holding period.
193 SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
194 for (int i = 0; i < num_silence_polls; ++i) {
195 SimulatePollTimerFired();
196 ExpectTabWasRecentlyAudible(true, last_blurt_time);
197 // Note: Redundant off timer firings should not have any effect.
198 SimulateOffTimerFired();
199 ExpectTabWasRecentlyAudible(true, last_blurt_time);
200 AdvanceClock(one_polling_interval());
203 ++num_silence_polls;
204 } while (GetTestClockTime() < last_blurt_time + holding_period());
206 // At this point, the clock has just advanced to beyond the holding period, so
207 // the next firing of the off timer should turn off the tab indicator. Also,
208 // make sure it stays off for several cycles thereafter.
209 ExpectWebContentsWillBeNotifiedOnce(false);
210 for (int i = 0; i < 10; ++i) {
211 SimulateOffTimerFired();
212 ExpectTabWasRecentlyAudible(false, last_blurt_time);
213 AdvanceClock(one_polling_interval());
217 // Tests that the AudioStreamMonitor correctly processes the blurts from two
218 // different streams in the same tab.
219 TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
220 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
221 StartMonitoring(
222 kRenderProcessId, kAnotherStreamId, CreatePollCallback(kAnotherStreamId));
224 base::TimeTicks last_blurt_time;
225 ExpectTabWasRecentlyAudible(false, last_blurt_time);
227 // Measure audible sound from the first stream and silence from the second.
228 // The indicator turns on (i.e., tab was recently audible).
229 ExpectWebContentsWillBeNotifiedOnce(true);
230 SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
231 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
232 last_blurt_time = GetTestClockTime();
233 SimulatePollTimerFired();
234 ExpectTabWasRecentlyAudible(true, last_blurt_time);
236 // Halfway through the holding period, the second stream joins in. The
237 // indicator stays on.
238 AdvanceClock(holding_period() / 2);
239 SimulateOffTimerFired();
240 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
241 last_blurt_time = GetTestClockTime();
242 SimulatePollTimerFired(); // Restarts holding period.
243 ExpectTabWasRecentlyAudible(true, last_blurt_time);
245 // Now, measure silence from both streams. After an entire holding period
246 // has passed (since the second stream joined in), the indicator should turn
247 // off.
248 ExpectWebContentsWillBeNotifiedOnce(false);
249 AdvanceClock(holding_period());
250 SimulateOffTimerFired();
251 SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
252 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
253 SimulatePollTimerFired();
254 ExpectTabWasRecentlyAudible(false, last_blurt_time);
256 // Now, measure silence from the first stream and audible sound from the
257 // second. The indicator turns back on.
258 ExpectWebContentsWillBeNotifiedOnce(true);
259 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
260 last_blurt_time = GetTestClockTime();
261 SimulatePollTimerFired();
262 ExpectTabWasRecentlyAudible(true, last_blurt_time);
264 // From here onwards, both streams are silent. Halfway through the holding
265 // period, the indicator should not have changed.
266 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
267 AdvanceClock(holding_period() / 2);
268 SimulatePollTimerFired();
269 SimulateOffTimerFired();
270 ExpectTabWasRecentlyAudible(true, last_blurt_time);
272 // Just past the holding period, the indicator should be turned off.
273 ExpectWebContentsWillBeNotifiedOnce(false);
274 AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
275 SimulateOffTimerFired();
276 ExpectTabWasRecentlyAudible(false, last_blurt_time);
278 // Polling should not turn the indicator back while both streams are remaining
279 // silent.
280 for (int i = 0; i < 100; ++i) {
281 AdvanceClock(one_polling_interval());
282 SimulatePollTimerFired();
283 ExpectTabWasRecentlyAudible(false, last_blurt_time);
287 TEST_F(AudioStreamMonitorTest, MultipleRendererProcesses) {
288 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
289 StartMonitoring(
290 kAnotherRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
291 ExpectIsPolling(kRenderProcessId, kStreamId, true);
292 ExpectIsPolling(kAnotherRenderProcessId, kStreamId, true);
293 StopMonitoring(kAnotherRenderProcessId, kStreamId);
294 ExpectIsPolling(kRenderProcessId, kStreamId, true);
295 ExpectIsPolling(kAnotherRenderProcessId, kStreamId, false);
298 } // namespace content