Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / browser / media / audio_stream_monitor.cc
blob1d2f76f7f2c02f986f5b52122834363ff96be1e8
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 "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/invalidate_type.h"
12 #include "content/public/browser/render_frame_host.h"
14 namespace content {
16 namespace {
18 AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id,
19 int render_frame_id) {
20 DCHECK_CURRENTLY_ON(BrowserThread::UI);
21 WebContentsImpl* const web_contents =
22 static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(
23 RenderFrameHost::FromID(render_process_id, render_frame_id)));
24 return web_contents ? web_contents->audio_stream_monitor() : NULL;
27 } // namespace
29 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
30 : web_contents_(contents),
31 clock_(&default_tick_clock_),
32 was_recently_audible_(false) {
33 DCHECK(web_contents_);
36 AudioStreamMonitor::~AudioStreamMonitor() {}
38 bool AudioStreamMonitor::WasRecentlyAudible() const {
39 DCHECK(thread_checker_.CalledOnValidThread());
40 return was_recently_audible_;
43 // static
44 void AudioStreamMonitor::StartMonitoringStream(
45 int render_process_id,
46 int render_frame_id,
47 int stream_id,
48 const ReadPowerAndClipCallback& read_power_callback) {
49 if (!monitoring_available())
50 return;
51 BrowserThread::PostTask(BrowserThread::UI,
52 FROM_HERE,
53 base::Bind(&StartMonitoringHelper,
54 render_process_id,
55 render_frame_id,
56 stream_id,
57 read_power_callback));
60 // static
61 void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
62 int render_frame_id,
63 int stream_id) {
64 if (!monitoring_available())
65 return;
66 BrowserThread::PostTask(BrowserThread::UI,
67 FROM_HERE,
68 base::Bind(&StopMonitoringHelper,
69 render_process_id,
70 render_frame_id,
71 stream_id));
74 // static
75 void AudioStreamMonitor::StartMonitoringHelper(
76 int render_process_id,
77 int render_frame_id,
78 int stream_id,
79 const ReadPowerAndClipCallback& read_power_callback) {
80 DCHECK_CURRENTLY_ON(BrowserThread::UI);
81 AudioStreamMonitor* const monitor =
82 AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
83 if (monitor) {
84 monitor->StartMonitoringStreamOnUIThread(
85 render_process_id, stream_id, read_power_callback);
89 // static
90 void AudioStreamMonitor::StopMonitoringHelper(int render_process_id,
91 int render_frame_id,
92 int stream_id) {
93 DCHECK_CURRENTLY_ON(BrowserThread::UI);
94 AudioStreamMonitor* const monitor =
95 AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
96 if (monitor)
97 monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
100 void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
101 int render_process_id,
102 int stream_id,
103 const ReadPowerAndClipCallback& read_power_callback) {
104 DCHECK(thread_checker_.CalledOnValidThread());
105 DCHECK(!read_power_callback.is_null());
106 poll_callbacks_[StreamID(render_process_id, stream_id)] = read_power_callback;
107 if (!poll_timer_.IsRunning()) {
108 poll_timer_.Start(
109 FROM_HERE,
110 base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond,
111 base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
115 void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id,
116 int stream_id) {
117 DCHECK(thread_checker_.CalledOnValidThread());
118 poll_callbacks_.erase(StreamID(render_process_id, stream_id));
119 if (poll_callbacks_.empty())
120 poll_timer_.Stop();
123 void AudioStreamMonitor::Poll() {
124 for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin();
125 it != poll_callbacks_.end();
126 ++it) {
127 // TODO(miu): A new UI for delivering specific power level and clipping
128 // information is still in the works. For now, we throw away all
129 // information except for "is it audible?"
130 const float power_dbfs = it->second.Run().first;
131 const float kSilenceThresholdDBFS = -72.24719896f;
132 if (power_dbfs >= kSilenceThresholdDBFS) {
133 last_blurt_time_ = clock_->NowTicks();
134 MaybeToggle();
135 break; // No need to poll remaining streams.
140 void AudioStreamMonitor::MaybeToggle() {
141 const bool indicator_was_on = was_recently_audible_;
142 const base::TimeTicks off_time =
143 last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
144 const base::TimeTicks now = clock_->NowTicks();
145 const bool should_indicator_be_on = now < off_time;
147 if (should_indicator_be_on != indicator_was_on) {
148 was_recently_audible_ = should_indicator_be_on;
149 web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
152 if (!should_indicator_be_on) {
153 off_timer_.Stop();
154 } else if (!off_timer_.IsRunning()) {
155 off_timer_.Start(
156 FROM_HERE,
157 off_time - now,
158 base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
162 } // namespace content