Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media / audio_stream_monitor_unittest.cc
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.
4
5 #include "chrome/browser/media/audio_stream_monitor.h"
6
7 #include <map>
8 #include <utility>
9
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 "chrome/test/base/testing_profile.h"
15 #include "content/public/browser/invalidate_type.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_delegate.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "media/audio/audio_power_monitor.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using ::testing::InvokeWithoutArgs;
24
25 namespace {
26
27 const int kStreamId = 3;
28 const int kAnotherStreamId = 6;
29
30 // Used to confirm audio indicator state changes occur at the correct times.
31 class MockWebContentsDelegate : public content::WebContentsDelegate {
32  public:
33   MOCK_METHOD2(NavigationStateChanged,
34                void(const content::WebContents* source,
35                     content::InvalidateTypes changed_flags));
36 };
37
38 }  // namespace
39
40 class AudioStreamMonitorTest : public testing::Test {
41  public:
42   AudioStreamMonitorTest() {
43     // Start |clock_| at non-zero.
44     clock_.Advance(base::TimeDelta::FromSeconds(1000000));
45
46     // Create a WebContents instance and set it to use our mock delegate.
47     web_contents_.reset(content::WebContents::Create(
48         content::WebContents::CreateParams(&profile_, NULL)));
49     web_contents_->SetDelegate(&mock_web_contents_delegate_);
50
51     // Create an AudioStreamMonitor instance whose lifecycle is tied to that of
52     // |web_contents_|, and override its clock with the test clock.
53     AudioStreamMonitor::CreateForWebContents(web_contents_.get());
54     CHECK(audio_stream_monitor());
55     const_cast<base::TickClock*&>(audio_stream_monitor()->clock_) = &clock_;
56   }
57
58   AudioStreamMonitor* audio_stream_monitor() {
59     return AudioStreamMonitor::FromWebContents(web_contents_.get());
60   }
61
62   base::TimeTicks GetTestClockTime() { return clock_.NowTicks(); }
63
64   void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
65
66   AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
67       int stream_id) {
68     return base::Bind(
69         &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
70   }
71
72   void SetStreamPower(int stream_id, float power) {
73     current_power_[stream_id] = power;
74   }
75
76   void SimulatePollTimerFired() { audio_stream_monitor()->Poll(); }
77
78   void SimulateOffTimerFired() { audio_stream_monitor()->MaybeToggle(); }
79
80   void ExpectIsPolling(int stream_id, bool is_polling) {
81     AudioStreamMonitor* const monitor = audio_stream_monitor();
82     EXPECT_EQ(is_polling,
83               monitor->poll_callbacks_.find(stream_id) !=
84                   monitor->poll_callbacks_.end());
85     EXPECT_EQ(!monitor->poll_callbacks_.empty(),
86               monitor->poll_timer_.IsRunning());
87   }
88
89   void ExpectTabWasRecentlyAudible(bool was_audible,
90                                    const base::TimeTicks& last_blurt_time) {
91     AudioStreamMonitor* const monitor = audio_stream_monitor();
92     EXPECT_EQ(was_audible, monitor->was_recently_audible_);
93     EXPECT_EQ(last_blurt_time, monitor->last_blurt_time_);
94     EXPECT_EQ(monitor->was_recently_audible_, monitor->off_timer_.IsRunning());
95   }
96
97   void ExpectWebContentsWillBeNotifiedOnce(bool should_be_audible) {
98     EXPECT_CALL(mock_web_contents_delegate_,
99                 NavigationStateChanged(web_contents_.get(),
100                                        content::INVALIDATE_TYPE_TAB))
101         .WillOnce(InvokeWithoutArgs(
102             this,
103             should_be_audible
104                 ? &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOn
105                 : &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOff))
106         .RetiresOnSaturation();
107   }
108
109   static base::TimeDelta one_polling_interval() {
110     return base::TimeDelta::FromSeconds(1) /
111            AudioStreamMonitor::kPowerMeasurementsPerSecond;
112   }
113
114   static base::TimeDelta holding_period() {
115     return base::TimeDelta::FromMilliseconds(
116         AudioStreamMonitor::kHoldOnMilliseconds);
117   }
118
119  private:
120   std::pair<float, bool> ReadPower(int stream_id) {
121     return std::make_pair(current_power_[stream_id], false);
122   }
123
124   void ExpectIsNotifyingForToggleOn() {
125     EXPECT_TRUE(audio_stream_monitor()->WasRecentlyAudible());
126   }
127
128   void ExpectIsNotifyingForToggleOff() {
129     EXPECT_FALSE(audio_stream_monitor()->WasRecentlyAudible());
130   }
131
132   content::TestBrowserThreadBundle browser_thread_bundle_;
133   TestingProfile profile_;
134   MockWebContentsDelegate mock_web_contents_delegate_;
135   base::SimpleTestTickClock clock_;
136   std::map<int, float> current_power_;
137   scoped_ptr<content::WebContents> web_contents_;
138
139   DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
140 };
141
142 // Tests that AudioStreamMonitor is polling while it has a
143 // ReadPowerAndClipCallback, and is not polling at other times.
144 TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
145   EXPECT_FALSE(audio_stream_monitor()->WasRecentlyAudible());
146   ExpectIsPolling(kStreamId, false);
147
148   audio_stream_monitor()->StartMonitoringStream(kStreamId,
149                                                 CreatePollCallback(kStreamId));
150   EXPECT_FALSE(audio_stream_monitor()->WasRecentlyAudible());
151   ExpectIsPolling(kStreamId, true);
152
153   audio_stream_monitor()->StopMonitoringStream(kStreamId);
154   EXPECT_FALSE(audio_stream_monitor()->WasRecentlyAudible());
155   ExpectIsPolling(kStreamId, false);
156 }
157
158 // Tests that AudioStreamMonitor debounces the power level readings it's taking,
159 // which could be fluctuating rapidly between the audible versus silence
160 // threshold.  See comments in audio_stream_monitor.h for expected behavior.
161 TEST_F(AudioStreamMonitorTest,
162        ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
163   audio_stream_monitor()->StartMonitoringStream(kStreamId,
164                                                 CreatePollCallback(kStreamId));
165
166   // Expect WebContents will get one call form AudioStreamMonitor to toggle the
167   // indicator on upon the very first poll.
168   ExpectWebContentsWillBeNotifiedOnce(true);
169
170   // Loop, each time testing a slightly longer period of polled silence.  The
171   // indicator should remain on throughout.
172   int num_silence_polls = 0;
173   base::TimeTicks last_blurt_time;
174   do {
175     // Poll an audible signal, and expect tab indicator state is on.
176     SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
177     last_blurt_time = GetTestClockTime();
178     SimulatePollTimerFired();
179     ExpectTabWasRecentlyAudible(true, last_blurt_time);
180     AdvanceClock(one_polling_interval());
181
182     // Poll a silent signal repeatedly, ensuring that the indicator is being
183     // held on during the holding period.
184     SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
185     for (int i = 0; i < num_silence_polls; ++i) {
186       SimulatePollTimerFired();
187       ExpectTabWasRecentlyAudible(true, last_blurt_time);
188       // Note: Redundant off timer firings should not have any effect.
189       SimulateOffTimerFired();
190       ExpectTabWasRecentlyAudible(true, last_blurt_time);
191       AdvanceClock(one_polling_interval());
192     }
193
194     ++num_silence_polls;
195   } while (GetTestClockTime() < last_blurt_time + holding_period());
196
197   // At this point, the clock has just advanced to beyond the holding period, so
198   // the next firing of the off timer should turn off the tab indicator.  Also,
199   // make sure it stays off for several cycles thereafter.
200   ExpectWebContentsWillBeNotifiedOnce(false);
201   for (int i = 0; i < 10; ++i) {
202     SimulateOffTimerFired();
203     ExpectTabWasRecentlyAudible(false, last_blurt_time);
204     AdvanceClock(one_polling_interval());
205   }
206 }
207
208 // Tests that the AudioStreamMonitor correctly processes the blurts from two
209 // different streams in the same tab.
210 TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
211   audio_stream_monitor()->StartMonitoringStream(kStreamId,
212                                                 CreatePollCallback(kStreamId));
213   audio_stream_monitor()->StartMonitoringStream(
214       kAnotherStreamId,
215       CreatePollCallback(kAnotherStreamId));
216
217   base::TimeTicks last_blurt_time;
218   ExpectTabWasRecentlyAudible(false, last_blurt_time);
219
220   // Measure audible sound from the first stream and silence from the second.
221   // The indicator turns on (i.e., tab was recently audible).
222   ExpectWebContentsWillBeNotifiedOnce(true);
223   SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
224   SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
225   last_blurt_time = GetTestClockTime();
226   SimulatePollTimerFired();
227   ExpectTabWasRecentlyAudible(true, last_blurt_time);
228
229   // Halfway through the holding period, the second stream joins in.  The
230   // indicator stays on.
231   AdvanceClock(holding_period() / 2);
232   SimulateOffTimerFired();
233   SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
234   last_blurt_time = GetTestClockTime();
235   SimulatePollTimerFired();  // Restarts holding period.
236   ExpectTabWasRecentlyAudible(true, last_blurt_time);
237
238   // Now, measure silence from both streams.  After an entire holding period
239   // has passed (since the second stream joined in), the indicator should turn
240   // off.
241   ExpectWebContentsWillBeNotifiedOnce(false);
242   AdvanceClock(holding_period());
243   SimulateOffTimerFired();
244   SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
245   SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
246   SimulatePollTimerFired();
247   ExpectTabWasRecentlyAudible(false, last_blurt_time);
248
249   // Now, measure silence from the first stream and audible sound from the
250   // second.  The indicator turns back on.
251   ExpectWebContentsWillBeNotifiedOnce(true);
252   SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
253   last_blurt_time = GetTestClockTime();
254   SimulatePollTimerFired();
255   ExpectTabWasRecentlyAudible(true, last_blurt_time);
256
257   // From here onwards, both streams are silent.  Halfway through the holding
258   // period, the indicator should not have changed.
259   SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
260   AdvanceClock(holding_period() / 2);
261   SimulatePollTimerFired();
262   SimulateOffTimerFired();
263   ExpectTabWasRecentlyAudible(true, last_blurt_time);
264
265   // Just past the holding period, the indicator should be turned off.
266   ExpectWebContentsWillBeNotifiedOnce(false);
267   AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
268   SimulateOffTimerFired();
269   ExpectTabWasRecentlyAudible(false, last_blurt_time);
270
271   // Polling should not turn the indicator back while both streams are remaining
272   // silent.
273   for (int i = 0; i < 100; ++i) {
274     AdvanceClock(one_polling_interval());
275     SimulatePollTimerFired();
276     ExpectTabWasRecentlyAudible(false, last_blurt_time);
277   }
278 }