Add ICU message format support
[chromium-blink-merge.git] / content / browser / media / audio_stream_monitor.cc
blobbcc1e7649b955fbf4a9170a49582bcd5f480f622
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)));
25 if (!web_contents)
26 return nullptr;
28 AudioStateProvider* audio_provider = web_contents->audio_state_provider();
29 return audio_provider ? audio_provider->audio_stream_monitor() : nullptr;
32 } // namespace
34 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
35 : AudioStateProvider(contents),
36 clock_(&default_tick_clock_)
40 AudioStreamMonitor::~AudioStreamMonitor() {}
42 bool AudioStreamMonitor::IsAudioStateAvailable() const {
43 return media::AudioOutputController::will_monitor_audio_levels();
46 // This provider is the monitor.
47 AudioStreamMonitor* AudioStreamMonitor::audio_stream_monitor() {
48 return this;
51 bool AudioStreamMonitor::WasRecentlyAudible() const {
52 DCHECK(thread_checker_.CalledOnValidThread());
53 return AudioStateProvider::WasRecentlyAudible();
56 // static
57 void AudioStreamMonitor::StartMonitoringStream(
58 int render_process_id,
59 int render_frame_id,
60 int stream_id,
61 const ReadPowerAndClipCallback& read_power_callback) {
62 if (!media::AudioOutputController::will_monitor_audio_levels())
63 return;
64 BrowserThread::PostTask(BrowserThread::UI,
65 FROM_HERE,
66 base::Bind(&StartMonitoringHelper,
67 render_process_id,
68 render_frame_id,
69 stream_id,
70 read_power_callback));
73 // static
74 void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
75 int render_frame_id,
76 int stream_id) {
77 if (!media::AudioOutputController::will_monitor_audio_levels())
78 return;
79 BrowserThread::PostTask(BrowserThread::UI,
80 FROM_HERE,
81 base::Bind(&StopMonitoringHelper,
82 render_process_id,
83 render_frame_id,
84 stream_id));
87 // static
88 void AudioStreamMonitor::StartMonitoringHelper(
89 int render_process_id,
90 int render_frame_id,
91 int stream_id,
92 const ReadPowerAndClipCallback& read_power_callback) {
93 DCHECK_CURRENTLY_ON(BrowserThread::UI);
94 AudioStreamMonitor* const monitor =
95 AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
96 if (monitor) {
97 monitor->StartMonitoringStreamOnUIThread(
98 render_process_id, stream_id, read_power_callback);
102 // static
103 void AudioStreamMonitor::StopMonitoringHelper(int render_process_id,
104 int render_frame_id,
105 int stream_id) {
106 DCHECK_CURRENTLY_ON(BrowserThread::UI);
107 AudioStreamMonitor* const monitor =
108 AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
109 if (monitor)
110 monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
113 void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
114 int render_process_id,
115 int stream_id,
116 const ReadPowerAndClipCallback& read_power_callback) {
117 DCHECK(thread_checker_.CalledOnValidThread());
118 DCHECK(!read_power_callback.is_null());
119 poll_callbacks_[StreamID(render_process_id, stream_id)] = read_power_callback;
120 if (!poll_timer_.IsRunning()) {
121 poll_timer_.Start(
122 FROM_HERE,
123 base::TimeDelta::FromSeconds(1) /
124 static_cast<int>(kPowerMeasurementsPerSecond),
125 base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
129 void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id,
130 int stream_id) {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 poll_callbacks_.erase(StreamID(render_process_id, stream_id));
133 if (poll_callbacks_.empty())
134 poll_timer_.Stop();
137 void AudioStreamMonitor::Poll() {
138 for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin();
139 it != poll_callbacks_.end();
140 ++it) {
141 // TODO(miu): A new UI for delivering specific power level and clipping
142 // information is still in the works. For now, we throw away all
143 // information except for "is it audible?"
144 const float power_dbfs = it->second.Run().first;
145 const float kSilenceThresholdDBFS = -72.24719896f;
146 if (power_dbfs >= kSilenceThresholdDBFS) {
147 last_blurt_time_ = clock_->NowTicks();
148 MaybeToggle();
149 break; // No need to poll remaining streams.
154 void AudioStreamMonitor::MaybeToggle() {
155 const base::TimeTicks off_time =
156 last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
157 const base::TimeTicks now = clock_->NowTicks();
158 const bool should_indicator_be_on = now < off_time;
160 Notify(should_indicator_be_on);
162 if (!should_indicator_be_on) {
163 off_timer_.Stop();
164 } else if (!off_timer_.IsRunning()) {
165 off_timer_.Start(
166 FROM_HERE,
167 off_time - now,
168 base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
172 } // namespace content