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

Side by Side Diff: chrome/browser/media/audio_stream_indicator.cc

Issue 14600025: Replace AudioSilenceDetector with an AudioPowerMonitor. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Replace RMS scheme with 1st-order low-pass filter, per crogers@. Simpler, single-threaded unit tes… Created 7 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/audio_stream_indicator.h" 5 #include "chrome/browser/media/audio_stream_indicator.h"
6 6
7 #include <limits>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "chrome/browser/tab_contents/tab_util.h" 10 #include "chrome/browser/tab_contents/tab_util.h"
9 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/invalidate_type.h" 12 #include "content/public/browser/invalidate_type.h"
11 #include "content/public/browser/render_process_host.h" 13 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/render_view_host.h" 14 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
14 16
15 using content::BrowserThread; 17 using content::BrowserThread;
16 using content::WebContents; 18 using content::WebContents;
17 19
18 AudioStreamIndicator::AudioStreamIndicator() {} 20 AudioStreamIndicator::AudioStreamIndicator() {}
19 AudioStreamIndicator::~AudioStreamIndicator() {} 21 AudioStreamIndicator::~AudioStreamIndicator() {}
20 22
21 void AudioStreamIndicator::UpdateWebContentsStatus( 23 void AudioStreamIndicator::UpdateWebContentsStatus(
22 int render_process_id, int render_view_id, int stream_id, 24 int render_process_id, int render_view_id, int stream_id,
23 bool is_playing_and_audible) { 25 bool is_playing, float power_dBFS, bool clipped) {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
25 27
26 BrowserThread::PostTask( 28 BrowserThread::PostTask(
27 BrowserThread::UI, FROM_HERE, 29 BrowserThread::UI, FROM_HERE,
28 base::Bind(&AudioStreamIndicator::UpdateWebContentsStatusOnUIThread, this, 30 base::Bind(&AudioStreamIndicator::UpdateWebContentsStatusOnUIThread, this,
29 render_process_id, render_view_id, stream_id, 31 render_process_id, render_view_id, stream_id,
30 is_playing_and_audible)); 32 is_playing, power_dBFS, clipped));
31 } 33 }
32 34
33 bool AudioStreamIndicator::IsPlayingAudio(WebContents* contents) { 35 bool AudioStreamIndicator::IsPlayingAudio(const WebContents* contents) {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
37 // TODO(miu): In order to prevent breaking existing uses of this method, the
38 // old semantics of "playing AND not silent" have been retained here. Once
39 // the tab audio indicator UI switches over to using the new
40 // GetAudioSignalPower(), this method should really be just "playing."
41 float level;
42 bool ignored;
43 CurrentAudibleLevel(contents, &level, &ignored);
44 return level > 0.0f;
45 }
46
47 void AudioStreamIndicator::CurrentAudibleLevel(
48 const content::WebContents* contents, float* level, bool* clipped) {
34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
35 50
36 RenderViewId id(contents->GetRenderProcessHost()->GetID(), 51 float max_power_dBFS = -std::numeric_limits<float>::infinity();
37 contents->GetRenderViewHost()->GetRoutingID()); 52 bool has_clipped = false;
38 return audio_streams_.find(id) != audio_streams_.end(); 53
54 // Since a RenderView can have more than one stream playing back, return the
55 // maximum of the last-reported power levels. For more information about how
56 // the power level is measured, see media/audio/audio_power_monitor.h.
57 const RenderViewId id(contents->GetRenderProcessHost()->GetID(),
58 contents->GetRenderViewHost()->GetRoutingID());
59 RenderViewStreamMap::iterator stream_it = audio_streams_.find(id);
60 if (stream_it != audio_streams_.end()) {
61 StreamPowerLevelMap& power_levels = stream_it->second;
62 for (StreamPowerLevelMap::iterator power_it = power_levels.begin();
63 power_it != power_levels.end(); ++power_it) {
64 SignalPower& stream_power = power_it->second;
65 if (stream_power.power_dBFS > max_power_dBFS)
66 max_power_dBFS = stream_power.power_dBFS;
67 if (stream_power.clipped) {
68 has_clipped = true;
69 // Clear the flag now that we'll be reporting the clipping.
70 stream_power.clipped = false;
71 }
72 }
73 }
74
75 // Map the power into an "audible level" in the range [0.0,1.0]. dBFS values
76 // are in the range -inf (minimum power) to 0.0 (maximum power).
77 static const float kSilenceThresholdDBFS = -72.24719896f;
78 if (max_power_dBFS < kSilenceThresholdDBFS)
79 *level = 0.0f;
80 else if (max_power_dBFS > 0.0f)
81 *level = 1.0f;
82 else
83 *level = 1.0f - max_power_dBFS / kSilenceThresholdDBFS;
84 *clipped = has_clipped;
39 } 85 }
40 86
41 AudioStreamIndicator::RenderViewId::RenderViewId(int render_process_id, 87 AudioStreamIndicator::RenderViewId::RenderViewId(int render_process_id,
42 int render_view_id) 88 int render_view_id)
43 : render_process_id(render_process_id), 89 : render_process_id(render_process_id),
44 render_view_id(render_view_id) { 90 render_view_id(render_view_id) {
45 } 91 }
46 92
47 bool AudioStreamIndicator::RenderViewId::operator<( 93 bool AudioStreamIndicator::RenderViewId::operator<(
48 const RenderViewId& other) const { 94 const RenderViewId& other) const {
49 if (render_process_id != other.render_process_id) 95 if (render_process_id != other.render_process_id)
50 return render_process_id < other.render_process_id; 96 return render_process_id < other.render_process_id;
51 97
52 return render_view_id < other.render_view_id; 98 return render_view_id < other.render_view_id;
53 } 99 }
54 100
55 void AudioStreamIndicator::UpdateWebContentsStatusOnUIThread( 101 void AudioStreamIndicator::UpdateWebContentsStatusOnUIThread(
56 int render_process_id, 102 int render_process_id, int render_view_id, int stream_id,
57 int render_view_id, 103 bool is_playing, float power_dBFS, bool clipped) {
58 int stream_id,
59 bool is_playing_and_audible) {
60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61 RenderViewId id(render_process_id, render_view_id); 105 const RenderViewId id(render_process_id, render_view_id);
62 if (is_playing_and_audible) { 106 if (is_playing) {
63 audio_streams_[id].insert(stream_id); 107 SignalPower& stream_power = audio_streams_[id][stream_id];
108 stream_power.power_dBFS = power_dBFS;
109 stream_power.clipped |= clipped;
64 } else { 110 } else {
65 std::map<RenderViewId, std::set<int> >::iterator it = 111 RenderViewStreamMap::iterator stream_it = audio_streams_.find(id);
66 audio_streams_.find(id); 112 if (stream_it == audio_streams_.end())
67 if (it == audio_streams_.end())
68 return; 113 return;
69 114 StreamPowerLevelMap& power_levels = stream_it->second;
70 it->second.erase(stream_id); 115 StreamPowerLevelMap::iterator power_it = power_levels.find(stream_id);
71 if (it->second.empty()) 116 if (power_it == power_levels.end())
72 audio_streams_.erase(it); 117 return;
118 power_levels.erase(power_it);
119 if (power_levels.empty())
120 audio_streams_.erase(stream_it);
73 } 121 }
74 122
75 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id, 123 WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id,
76 render_view_id); 124 render_view_id);
77 if (web_contents) 125 if (web_contents)
78 web_contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 126 web_contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
79 } 127 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698