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 "chrome/browser/media/audio_stream_monitor.h"
8 #include "base/bind_helpers.h"
9 #include "content/public/browser/invalidate_type.h"
10 #include "content/public/browser/web_contents.h"
12 DEFINE_WEB_CONTENTS_USER_DATA_KEY(AudioStreamMonitor
);
14 AudioStreamMonitor::AudioStreamMonitor(content::WebContents
* contents
)
15 : web_contents_(contents
),
16 clock_(&default_tick_clock_
),
17 was_recently_audible_(false) {
18 DCHECK(web_contents_
);
21 AudioStreamMonitor::~AudioStreamMonitor() {}
23 bool AudioStreamMonitor::WasRecentlyAudible() const {
24 DCHECK(thread_checker_
.CalledOnValidThread());
25 return was_recently_audible_
;
28 void AudioStreamMonitor::StartMonitoringStream(
30 const ReadPowerAndClipCallback
& read_power_callback
) {
31 DCHECK(thread_checker_
.CalledOnValidThread());
32 DCHECK(!read_power_callback
.is_null());
33 poll_callbacks_
[stream_id
] = read_power_callback
;
34 if (!poll_timer_
.IsRunning()) {
37 base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond
,
38 base::Bind(&AudioStreamMonitor::Poll
, base::Unretained(this)));
42 void AudioStreamMonitor::StopMonitoringStream(int stream_id
) {
43 DCHECK(thread_checker_
.CalledOnValidThread());
44 poll_callbacks_
.erase(stream_id
);
45 if (poll_callbacks_
.empty())
49 void AudioStreamMonitor::Poll() {
50 for (StreamPollCallbackMap::const_iterator it
= poll_callbacks_
.begin();
51 it
!= poll_callbacks_
.end();
53 // TODO(miu): A new UI for delivering specific power level and clipping
54 // information is still in the works. For now, we throw away all
55 // information except for "is it audible?"
56 const float power_dbfs
= it
->second
.Run().first
;
57 const float kSilenceThresholdDBFS
= -72.24719896f
;
58 if (power_dbfs
>= kSilenceThresholdDBFS
) {
59 last_blurt_time_
= clock_
->NowTicks();
61 break; // No need to poll remaining streams.
66 void AudioStreamMonitor::MaybeToggle() {
67 const bool indicator_was_on
= was_recently_audible_
;
68 const base::TimeTicks off_time
=
69 last_blurt_time_
+ base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds
);
70 const base::TimeTicks now
= clock_
->NowTicks();
71 const bool should_indicator_be_on
= now
< off_time
;
73 if (should_indicator_be_on
!= indicator_was_on
) {
74 was_recently_audible_
= should_indicator_be_on
;
75 web_contents_
->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB
);
78 if (!should_indicator_be_on
) {
80 } else if (!off_timer_
.IsRunning()) {
84 base::Bind(&AudioStreamMonitor::MaybeToggle
, base::Unretained(this)));