1 // Copyright (c) 2012 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_indicator.h"
10 #include "chrome/browser/tab_contents/tab_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/invalidate_type.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/web_contents.h"
17 using content::BrowserThread
;
18 using content::WebContents
;
20 AudioStreamIndicator::AudioStreamIndicator() {}
21 AudioStreamIndicator::~AudioStreamIndicator() {}
23 void AudioStreamIndicator::UpdateWebContentsStatus(
24 int render_process_id
, int render_view_id
, int stream_id
,
25 bool is_playing
, float power_dbfs
, bool clipped
) {
26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
28 BrowserThread::PostTask(
29 BrowserThread::UI
, FROM_HERE
,
30 base::Bind(&AudioStreamIndicator::UpdateWebContentsStatusOnUIThread
, this,
31 render_process_id
, render_view_id
, stream_id
,
32 is_playing
, power_dbfs
, clipped
));
35 bool AudioStreamIndicator::IsPlayingAudio(const WebContents
* contents
) {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
38 // TODO(miu): In order to prevent breaking existing uses of this method, the
39 // old semantics of "playing AND not silent" have been retained here. Once
40 // the tab audio indicator UI switches over to using the new
41 // GetAudioSignalPower(), this method should really be just "playing."
44 CurrentAudibleLevel(contents
, &level
, &ignored
);
48 void AudioStreamIndicator::CurrentAudibleLevel(
49 const content::WebContents
* contents
, float* level
, bool* clipped
) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
52 float max_power_dbfs
= -std::numeric_limits
<float>::infinity();
53 bool has_clipped
= false;
55 // Since a RenderView can have more than one stream playing back, return the
56 // maximum of the last-reported power levels. For more information about how
57 // the power level is measured, see media/audio/audio_power_monitor.h.
58 const RenderViewId
id(contents
->GetRenderProcessHost()->GetID(),
59 contents
->GetRenderViewHost()->GetRoutingID());
60 RenderViewStreamMap::const_iterator view_it
= audio_streams_
.find(id
);
61 if (view_it
!= audio_streams_
.end()) {
62 const StreamPowerLevels
& stream_levels
= view_it
->second
;
63 for (StreamPowerLevels::const_iterator stream_it
= stream_levels
.begin();
64 stream_it
!= stream_levels
.end(); ++stream_it
) {
65 if (stream_it
->power_dbfs
> max_power_dbfs
)
66 max_power_dbfs
= stream_it
->power_dbfs
;
67 has_clipped
|= stream_it
->clipped
;
71 // Map the power into an "audible level" in the range [0.0,1.0]. dBFS values
72 // are in the range -inf (minimum power) to 0.0 (maximum power).
73 static const float kSilenceThresholdDBFS
= -72.24719896f
;
74 if (max_power_dbfs
< kSilenceThresholdDBFS
)
76 else if (max_power_dbfs
> 0.0f
)
79 *level
= 1.0f
- max_power_dbfs
/ kSilenceThresholdDBFS
;
80 *clipped
= has_clipped
;
83 void AudioStreamIndicator::UpdateWebContentsStatusOnUIThread(
84 int render_process_id
, int render_view_id
, int stream_id
,
85 bool is_playing
, float power_dbfs
, bool clipped
) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
88 const RenderViewId
id(render_process_id
, render_view_id
);
90 // Find the StreamPowerLevel instance associated with |stream_id|, or
91 // auto-create a new one.
92 StreamPowerLevels
& stream_levels
= audio_streams_
[id
];
93 StreamPowerLevels::iterator stream_it
;
94 for (stream_it
= stream_levels
.begin(); stream_it
!= stream_levels
.end();
96 if (stream_it
->stream_id
== stream_id
)
99 if (stream_it
== stream_levels
.end()) {
100 stream_it
= stream_levels
.insert(stream_levels
.end(), StreamPowerLevel());
101 stream_it
->stream_id
= stream_id
;
104 // Update power and clip values.
105 stream_it
->power_dbfs
= power_dbfs
;
106 stream_it
->clipped
= clipped
;
108 // Find and erase the StreamPowerLevel instance associated with |stream_id|.
109 RenderViewStreamMap::iterator view_it
= audio_streams_
.find(id
);
110 if (view_it
!= audio_streams_
.end()) {
111 StreamPowerLevels
& stream_levels
= view_it
->second
;
112 for (StreamPowerLevels::iterator stream_it
= stream_levels
.begin();
113 stream_it
!= stream_levels
.end(); ++stream_it
) {
114 if (stream_it
->stream_id
== stream_id
) {
115 stream_levels
.erase(stream_it
);
116 if (stream_levels
.empty())
117 audio_streams_
.erase(view_it
);
124 // Trigger UI update.
125 WebContents
* web_contents
= tab_util::GetWebContentsByID(render_process_id
,
128 web_contents
->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB
);