Add ICU message format support
[chromium-blink-merge.git] / content / browser / media / audio_stream_monitor_unittest.cc
blob786775dec67e3450cb69fde607124959411b5e6a
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 AudioStateProvider* provider = web_contents->audio_state_provider();
57 ASSERT_TRUE(provider);
59 monitor_ = provider->audio_stream_monitor();
60 ASSERT_TRUE(monitor_);
62 const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
65 base::TimeTicks GetTestClockTime() { return clock_.NowTicks(); }
67 void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
69 AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
70 int stream_id) {
71 return base::Bind(
72 &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
75 void SetStreamPower(int stream_id, float power) {
76 current_power_[stream_id] = power;
79 void SimulatePollTimerFired() { monitor_->Poll(); }
81 void SimulateOffTimerFired() { monitor_->MaybeToggle(); }
83 void ExpectIsPolling(int render_process_id, int stream_id, bool is_polling) {
84 const AudioStreamMonitor::StreamID key(render_process_id, stream_id);
85 EXPECT_EQ(
86 is_polling,
87 monitor_->poll_callbacks_.find(key) != monitor_->poll_callbacks_.end());
88 EXPECT_EQ(!monitor_->poll_callbacks_.empty(),
89 monitor_->poll_timer_.IsRunning());
92 void ExpectTabWasRecentlyAudible(bool was_audible,
93 const base::TimeTicks& last_blurt_time) {
94 EXPECT_EQ(was_audible, monitor_->was_recently_audible_);
95 EXPECT_EQ(last_blurt_time, monitor_->last_blurt_time_);
96 EXPECT_EQ(monitor_->was_recently_audible_,
97 monitor_->off_timer_.IsRunning());
100 void ExpectWebContentsWillBeNotifiedOnce(bool should_be_audible) {
101 EXPECT_CALL(
102 mock_web_contents_delegate_,
103 NavigationStateChanged(RenderViewHostTestHarness::web_contents(),
104 INVALIDATE_TYPE_TAB))
105 .WillOnce(InvokeWithoutArgs(
106 this,
107 should_be_audible
108 ? &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOn
109 : &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOff))
110 .RetiresOnSaturation();
113 static base::TimeDelta one_polling_interval() {
114 return base::TimeDelta::FromSeconds(1) /
115 static_cast<int>(AudioStreamMonitor::kPowerMeasurementsPerSecond);
118 static base::TimeDelta holding_period() {
119 return base::TimeDelta::FromMilliseconds(
120 AudioStreamMonitor::kHoldOnMilliseconds);
123 void StartMonitoring(
124 int render_process_id,
125 int stream_id,
126 const AudioStreamMonitor::ReadPowerAndClipCallback& callback) {
127 monitor_->StartMonitoringStreamOnUIThread(
128 render_process_id, stream_id, callback);
131 void StopMonitoring(int render_process_id, int stream_id) {
132 monitor_->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
135 protected:
136 AudioStreamMonitor* monitor_;
138 private:
139 std::pair<float, bool> ReadPower(int stream_id) {
140 return std::make_pair(current_power_[stream_id], false);
143 void ExpectIsNotifyingForToggleOn() {
144 EXPECT_TRUE(monitor_->WasRecentlyAudible());
147 void ExpectIsNotifyingForToggleOff() {
148 EXPECT_FALSE(monitor_->WasRecentlyAudible());
151 MockWebContentsDelegate mock_web_contents_delegate_;
152 base::SimpleTestTickClock clock_;
153 std::map<int, float> current_power_;
155 DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
158 // Tests that AudioStreamMonitor is polling while it has a
159 // ReadPowerAndClipCallback, and is not polling at other times.
160 TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
161 EXPECT_FALSE(monitor_->WasRecentlyAudible());
162 ExpectIsPolling(kRenderProcessId, kStreamId, false);
164 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
165 EXPECT_FALSE(monitor_->WasRecentlyAudible());
166 ExpectIsPolling(kRenderProcessId, kStreamId, true);
168 StopMonitoring(kRenderProcessId, kStreamId);
169 EXPECT_FALSE(monitor_->WasRecentlyAudible());
170 ExpectIsPolling(kRenderProcessId, kStreamId, false);
173 // Tests that AudioStreamMonitor debounces the power level readings it's taking,
174 // which could be fluctuating rapidly between the audible versus silence
175 // threshold. See comments in audio_stream_monitor.h for expected behavior.
176 TEST_F(AudioStreamMonitorTest,
177 ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
178 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
180 // Expect WebContents will get one call form AudioStreamMonitor to toggle the
181 // indicator on upon the very first poll.
182 ExpectWebContentsWillBeNotifiedOnce(true);
184 // Loop, each time testing a slightly longer period of polled silence. The
185 // indicator should remain on throughout.
186 int num_silence_polls = 0;
187 base::TimeTicks last_blurt_time;
188 do {
189 // Poll an audible signal, and expect tab indicator state is on.
190 SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
191 last_blurt_time = GetTestClockTime();
192 SimulatePollTimerFired();
193 ExpectTabWasRecentlyAudible(true, last_blurt_time);
194 AdvanceClock(one_polling_interval());
196 // Poll a silent signal repeatedly, ensuring that the indicator is being
197 // held on during the holding period.
198 SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
199 for (int i = 0; i < num_silence_polls; ++i) {
200 SimulatePollTimerFired();
201 ExpectTabWasRecentlyAudible(true, last_blurt_time);
202 // Note: Redundant off timer firings should not have any effect.
203 SimulateOffTimerFired();
204 ExpectTabWasRecentlyAudible(true, last_blurt_time);
205 AdvanceClock(one_polling_interval());
208 ++num_silence_polls;
209 } while (GetTestClockTime() < last_blurt_time + holding_period());
211 // At this point, the clock has just advanced to beyond the holding period, so
212 // the next firing of the off timer should turn off the tab indicator. Also,
213 // make sure it stays off for several cycles thereafter.
214 ExpectWebContentsWillBeNotifiedOnce(false);
215 for (int i = 0; i < 10; ++i) {
216 SimulateOffTimerFired();
217 ExpectTabWasRecentlyAudible(false, last_blurt_time);
218 AdvanceClock(one_polling_interval());
222 // Tests that the AudioStreamMonitor correctly processes the blurts from two
223 // different streams in the same tab.
224 TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
225 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
226 StartMonitoring(
227 kRenderProcessId, kAnotherStreamId, CreatePollCallback(kAnotherStreamId));
229 base::TimeTicks last_blurt_time;
230 ExpectTabWasRecentlyAudible(false, last_blurt_time);
232 // Measure audible sound from the first stream and silence from the second.
233 // The indicator turns on (i.e., tab was recently audible).
234 ExpectWebContentsWillBeNotifiedOnce(true);
235 SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
236 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
237 last_blurt_time = GetTestClockTime();
238 SimulatePollTimerFired();
239 ExpectTabWasRecentlyAudible(true, last_blurt_time);
241 // Halfway through the holding period, the second stream joins in. The
242 // indicator stays on.
243 AdvanceClock(holding_period() / 2);
244 SimulateOffTimerFired();
245 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
246 last_blurt_time = GetTestClockTime();
247 SimulatePollTimerFired(); // Restarts holding period.
248 ExpectTabWasRecentlyAudible(true, last_blurt_time);
250 // Now, measure silence from both streams. After an entire holding period
251 // has passed (since the second stream joined in), the indicator should turn
252 // off.
253 ExpectWebContentsWillBeNotifiedOnce(false);
254 AdvanceClock(holding_period());
255 SimulateOffTimerFired();
256 SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
257 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
258 SimulatePollTimerFired();
259 ExpectTabWasRecentlyAudible(false, last_blurt_time);
261 // Now, measure silence from the first stream and audible sound from the
262 // second. The indicator turns back on.
263 ExpectWebContentsWillBeNotifiedOnce(true);
264 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
265 last_blurt_time = GetTestClockTime();
266 SimulatePollTimerFired();
267 ExpectTabWasRecentlyAudible(true, last_blurt_time);
269 // From here onwards, both streams are silent. Halfway through the holding
270 // period, the indicator should not have changed.
271 SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
272 AdvanceClock(holding_period() / 2);
273 SimulatePollTimerFired();
274 SimulateOffTimerFired();
275 ExpectTabWasRecentlyAudible(true, last_blurt_time);
277 // Just past the holding period, the indicator should be turned off.
278 ExpectWebContentsWillBeNotifiedOnce(false);
279 AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
280 SimulateOffTimerFired();
281 ExpectTabWasRecentlyAudible(false, last_blurt_time);
283 // Polling should not turn the indicator back while both streams are remaining
284 // silent.
285 for (int i = 0; i < 100; ++i) {
286 AdvanceClock(one_polling_interval());
287 SimulatePollTimerFired();
288 ExpectTabWasRecentlyAudible(false, last_blurt_time);
292 TEST_F(AudioStreamMonitorTest, MultipleRendererProcesses) {
293 StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
294 StartMonitoring(
295 kAnotherRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
296 ExpectIsPolling(kRenderProcessId, kStreamId, true);
297 ExpectIsPolling(kAnotherRenderProcessId, kStreamId, true);
298 StopMonitoring(kAnotherRenderProcessId, kStreamId);
299 ExpectIsPolling(kRenderProcessId, kStreamId, true);
300 ExpectIsPolling(kAnotherRenderProcessId, kStreamId, false);
303 } // namespace content