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

Unified Diff: content/browser/media/audio_stream_monitor_unittest.cc

Issue 569713002: Revert of Gardening: Revert "Use AudioStreamMonitor to control power save blocking." (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/media/audio_stream_monitor_unittest.cc
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b8871af65636e896ebe4b84eba3787ca67961b6a
--- /dev/null
+++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/audio_stream_monitor.h"
+
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/invalidate_type.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/test_renderer_host.h"
+#include "media/audio/audio_power_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InvokeWithoutArgs;
+
+namespace content {
+
+namespace {
+
+const int kRenderProcessId = 1;
+const int kAnotherRenderProcessId = 2;
+const int kStreamId = 3;
+const int kAnotherStreamId = 6;
+
+// Used to confirm audio indicator state changes occur at the correct times.
+class MockWebContentsDelegate : public WebContentsDelegate {
+ public:
+ MOCK_METHOD2(NavigationStateChanged,
+ void(const WebContents* source, InvalidateTypes changed_flags));
+};
+
+} // namespace
+
+class AudioStreamMonitorTest : public RenderViewHostTestHarness {
+ public:
+ AudioStreamMonitorTest() {
+ // Start |clock_| at non-zero.
+ clock_.Advance(base::TimeDelta::FromSeconds(1000000));
+ }
+
+ virtual void SetUp() OVERRIDE {
+ RenderViewHostTestHarness::SetUp();
+
+ WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
+ RenderViewHostTestHarness::web_contents());
+ web_contents->SetDelegate(&mock_web_contents_delegate_);
+ monitor_ = web_contents->audio_stream_monitor();
+ const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
+ }
+
+ base::TimeTicks GetTestClockTime() { return clock_.NowTicks(); }
+
+ void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
+
+ AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
+ int stream_id) {
+ return base::Bind(
+ &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
+ }
+
+ void SetStreamPower(int stream_id, float power) {
+ current_power_[stream_id] = power;
+ }
+
+ void SimulatePollTimerFired() { monitor_->Poll(); }
+
+ void SimulateOffTimerFired() { monitor_->MaybeToggle(); }
+
+ void ExpectIsPolling(int render_process_id, int stream_id, bool is_polling) {
+ const AudioStreamMonitor::StreamID key(render_process_id, stream_id);
+ EXPECT_EQ(
+ is_polling,
+ monitor_->poll_callbacks_.find(key) != monitor_->poll_callbacks_.end());
+ EXPECT_EQ(!monitor_->poll_callbacks_.empty(),
+ monitor_->poll_timer_.IsRunning());
+ }
+
+ void ExpectTabWasRecentlyAudible(bool was_audible,
+ const base::TimeTicks& last_blurt_time) {
+ EXPECT_EQ(was_audible, monitor_->was_recently_audible_);
+ EXPECT_EQ(last_blurt_time, monitor_->last_blurt_time_);
+ EXPECT_EQ(monitor_->was_recently_audible_,
+ monitor_->off_timer_.IsRunning());
+ }
+
+ void ExpectWebContentsWillBeNotifiedOnce(bool should_be_audible) {
+ EXPECT_CALL(
+ mock_web_contents_delegate_,
+ NavigationStateChanged(RenderViewHostTestHarness::web_contents(),
+ INVALIDATE_TYPE_TAB))
+ .WillOnce(InvokeWithoutArgs(
+ this,
+ should_be_audible
+ ? &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOn
+ : &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOff))
+ .RetiresOnSaturation();
+ }
+
+ static base::TimeDelta one_polling_interval() {
+ return base::TimeDelta::FromSeconds(1) /
+ AudioStreamMonitor::kPowerMeasurementsPerSecond;
+ }
+
+ static base::TimeDelta holding_period() {
+ return base::TimeDelta::FromMilliseconds(
+ AudioStreamMonitor::kHoldOnMilliseconds);
+ }
+
+ void StartMonitoring(
+ int render_process_id,
+ int stream_id,
+ const AudioStreamMonitor::ReadPowerAndClipCallback& callback) {
+ monitor_->StartMonitoringStreamOnUIThread(
+ render_process_id, stream_id, callback);
+ }
+
+ void StopMonitoring(int render_process_id, int stream_id) {
+ monitor_->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
+ }
+
+ protected:
+ AudioStreamMonitor* monitor_;
+
+ private:
+ std::pair<float, bool> ReadPower(int stream_id) {
+ return std::make_pair(current_power_[stream_id], false);
+ }
+
+ void ExpectIsNotifyingForToggleOn() {
+ EXPECT_TRUE(monitor_->WasRecentlyAudible());
+ }
+
+ void ExpectIsNotifyingForToggleOff() {
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ }
+
+ MockWebContentsDelegate mock_web_contents_delegate_;
+ base::SimpleTestTickClock clock_;
+ std::map<int, float> current_power_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
+};
+
+// Tests that AudioStreamMonitor is polling while it has a
+// ReadPowerAndClipCallback, and is not polling at other times.
+TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, false);
+
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+
+ StopMonitoring(kRenderProcessId, kStreamId);
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, false);
+}
+
+// Tests that AudioStreamMonitor debounces the power level readings it's taking,
+// which could be fluctuating rapidly between the audible versus silence
+// threshold. See comments in audio_stream_monitor.h for expected behavior.
+TEST_F(AudioStreamMonitorTest,
+ ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+
+ // Expect WebContents will get one call form AudioStreamMonitor to toggle the
+ // indicator on upon the very first poll.
+ ExpectWebContentsWillBeNotifiedOnce(true);
+
+ // Loop, each time testing a slightly longer period of polled silence. The
+ // indicator should remain on throughout.
+ int num_silence_polls = 0;
+ base::TimeTicks last_blurt_time;
+ do {
+ // Poll an audible signal, and expect tab indicator state is on.
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+
+ // Poll a silent signal repeatedly, ensuring that the indicator is being
+ // held on during the holding period.
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
+ for (int i = 0; i < num_silence_polls; ++i) {
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ // Note: Redundant off timer firings should not have any effect.
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+ }
+
+ ++num_silence_polls;
+ } while (GetTestClockTime() < last_blurt_time + holding_period());
+
+ // At this point, the clock has just advanced to beyond the holding period, so
+ // the next firing of the off timer should turn off the tab indicator. Also,
+ // make sure it stays off for several cycles thereafter.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ for (int i = 0; i < 10; ++i) {
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+ }
+}
+
+// Tests that the AudioStreamMonitor correctly processes the blurts from two
+// different streams in the same tab.
+TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ StartMonitoring(
+ kRenderProcessId, kAnotherStreamId, CreatePollCallback(kAnotherStreamId));
+
+ base::TimeTicks last_blurt_time;
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Measure audible sound from the first stream and silence from the second.
+ // The indicator turns on (i.e., tab was recently audible).
+ ExpectWebContentsWillBeNotifiedOnce(true);
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Halfway through the holding period, the second stream joins in. The
+ // indicator stays on.
+ AdvanceClock(holding_period() / 2);
+ SimulateOffTimerFired();
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired(); // Restarts holding period.
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Now, measure silence from both streams. After an entire holding period
+ // has passed (since the second stream joined in), the indicator should turn
+ // off.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ AdvanceClock(holding_period());
+ SimulateOffTimerFired();
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Now, measure silence from the first stream and audible sound from the
+ // second. The indicator turns back on.
+ ExpectWebContentsWillBeNotifiedOnce(true);
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // From here onwards, both streams are silent. Halfway through the holding
+ // period, the indicator should not have changed.
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ AdvanceClock(holding_period() / 2);
+ SimulatePollTimerFired();
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Just past the holding period, the indicator should be turned off.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Polling should not turn the indicator back while both streams are remaining
+ // silent.
+ for (int i = 0; i < 100; ++i) {
+ AdvanceClock(one_polling_interval());
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+ }
+}
+
+TEST_F(AudioStreamMonitorTest, MultipleRendererProcesses) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ StartMonitoring(
+ kAnotherRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+ ExpectIsPolling(kAnotherRenderProcessId, kStreamId, true);
+ StopMonitoring(kAnotherRenderProcessId, kStreamId);
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+ ExpectIsPolling(kAnotherRenderProcessId, kStreamId, false);
+}
+
+} // namespace content
« no previous file with comments | « content/browser/media/audio_stream_monitor.cc ('k') | content/browser/renderer_host/media/audio_renderer_host.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698