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

Side by Side Diff: content/browser/media/audio_stream_monitor.cc

Issue 2698813007: Fix teardown of stale AudioStreamMonitor poll callbacks. (Closed)
Patch Set: Always store callbacks, fix tests. Created 3 years, 10 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "content/browser/media/audio_stream_monitor.h" 5 #include "content/browser/media/audio_stream_monitor.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "content/browser/web_contents/web_contents_impl.h" 9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/browser_thread.h" 10 #include "content/public/browser/browser_thread.h"
(...skipping 30 matching lines...) Expand all
41 RenderFrameHost::FromID(render_process_id, render_frame_id))); 41 RenderFrameHost::FromID(render_process_id, render_frame_id)));
42 return web_contents ? web_contents->audio_stream_monitor() : nullptr; 42 return web_contents ? web_contents->audio_stream_monitor() : nullptr;
43 } 43 }
44 44
45 } // namespace 45 } // namespace
46 46
47 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents) 47 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
48 : web_contents_(contents), 48 : web_contents_(contents),
49 clock_(&default_tick_clock_), 49 clock_(&default_tick_clock_),
50 was_recently_audible_(false), 50 was_recently_audible_(false),
51 is_audible_(false), 51 is_audible_(false) {
52 active_streams_(0) {
53 DCHECK(web_contents_); 52 DCHECK(web_contents_);
54 } 53 }
55 54
56 AudioStreamMonitor::~AudioStreamMonitor() {} 55 AudioStreamMonitor::~AudioStreamMonitor() {}
57 56
58 bool AudioStreamMonitor::WasRecentlyAudible() const { 57 bool AudioStreamMonitor::WasRecentlyAudible() const {
59 DCHECK(thread_checker_.CalledOnValidThread()); 58 DCHECK(thread_checker_.CalledOnValidThread());
60 return was_recently_audible_; 59 return was_recently_audible_;
61 } 60 }
62 61
63 bool AudioStreamMonitor::IsCurrentlyAudible() const { 62 bool AudioStreamMonitor::IsCurrentlyAudible() const {
64 DCHECK(thread_checker_.CalledOnValidThread()); 63 DCHECK(thread_checker_.CalledOnValidThread());
65 return is_audible_; 64 return is_audible_;
66 } 65 }
67 66
67 void AudioStreamMonitor::RenderProcessGone(int render_process_id) {
68 DCHECK(thread_checker_.CalledOnValidThread());
69
70 // Note: It's possible for the RenderProcessHost and WebContents (and thus
71 // this class) to survive the death of the render process and subsequently be
72 // reused. During this period StartStopMonitoringHelper() will be unable to
73 // lookup the WebContents using the now-dead |render_frame_id|. We must thus
74 // have this secondary mechanism for clearing stale callbacks.
75
76 for (auto it = poll_callbacks_.begin(); it != poll_callbacks_.end();) {
77 if (it->first.first == render_process_id) {
78 it = poll_callbacks_.erase(it);
79 OnStreamRemoved();
80 } else {
81 ++it;
82 }
83 }
84
85 if (poll_callbacks_.empty())
86 poll_timer_.Stop();
87 }
88
68 // static 89 // static
69 void AudioStreamMonitor::StartMonitoringStream( 90 void AudioStreamMonitor::StartMonitoringStream(
70 int render_process_id, 91 int render_process_id,
71 int render_frame_id, 92 int render_frame_id,
72 int stream_id, 93 int stream_id,
73 const ReadPowerAndClipCallback& read_power_callback) { 94 const ReadPowerAndClipCallback& read_power_callback) {
74 BrowserThread::PostTask(BrowserThread::UI, 95 BrowserThread::PostTask(BrowserThread::UI,
75 FROM_HERE, 96 FROM_HERE,
76 base::Bind(&StartMonitoringHelper, 97 base::Bind(&StartMonitoringHelper,
77 render_process_id, 98 render_process_id,
(...skipping 16 matching lines...) Expand all
94 115
95 // static 116 // static
96 void AudioStreamMonitor::StartMonitoringHelper( 117 void AudioStreamMonitor::StartMonitoringHelper(
97 int render_process_id, 118 int render_process_id,
98 int render_frame_id, 119 int render_frame_id,
99 int stream_id, 120 int stream_id,
100 const ReadPowerAndClipCallback& read_power_callback) { 121 const ReadPowerAndClipCallback& read_power_callback) {
101 DCHECK_CURRENTLY_ON(BrowserThread::UI); 122 DCHECK_CURRENTLY_ON(BrowserThread::UI);
102 if (AudioStreamMonitor* monitor = StartStopMonitoringHelper( 123 if (AudioStreamMonitor* monitor = StartStopMonitoringHelper(
103 ActionType::STARTING, render_process_id, render_frame_id)) { 124 ActionType::STARTING, render_process_id, render_frame_id)) {
104 if (!power_level_monitoring_available()) { 125 monitor->StartMonitoringStreamOnUIThread(render_process_id, stream_id,
105 monitor->OnStreamAdded(); 126 read_power_callback);
106 } else {
107 monitor->StartMonitoringStreamOnUIThread(render_process_id, stream_id,
108 read_power_callback);
109 }
110 } 127 }
111 } 128 }
112 129
113 // static 130 // static
114 void AudioStreamMonitor::StopMonitoringHelper(int render_process_id, 131 void AudioStreamMonitor::StopMonitoringHelper(int render_process_id,
115 int render_frame_id, 132 int render_frame_id,
116 int stream_id) { 133 int stream_id) {
117 DCHECK_CURRENTLY_ON(BrowserThread::UI); 134 DCHECK_CURRENTLY_ON(BrowserThread::UI);
118 if (AudioStreamMonitor* monitor = StartStopMonitoringHelper( 135 if (AudioStreamMonitor* monitor = StartStopMonitoringHelper(
119 ActionType::STOPPING, render_process_id, render_frame_id)) { 136 ActionType::STOPPING, render_process_id, render_frame_id)) {
120 if (!power_level_monitoring_available()) 137 monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
121 monitor->OnStreamRemoved();
122 else
123 monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
124 } 138 }
125 } 139 }
126 140
127 void AudioStreamMonitor::StartMonitoringStreamOnUIThread( 141 void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
128 int render_process_id, 142 int render_process_id,
129 int stream_id, 143 int stream_id,
130 const ReadPowerAndClipCallback& read_power_callback) { 144 const ReadPowerAndClipCallback& read_power_callback) {
131 DCHECK(thread_checker_.CalledOnValidThread()); 145 DCHECK(thread_checker_.CalledOnValidThread());
132 DCHECK(!read_power_callback.is_null()); 146 DCHECK(!read_power_callback.is_null());
133 147
134 const StreamID qualified_id(render_process_id, stream_id); 148 const StreamID qualified_id(render_process_id, stream_id);
135 DCHECK(poll_callbacks_.find(qualified_id) == poll_callbacks_.end()); 149 DCHECK(poll_callbacks_.find(qualified_id) == poll_callbacks_.end());
150
136 poll_callbacks_[qualified_id] = read_power_callback; 151 poll_callbacks_[qualified_id] = read_power_callback;
137 152 OnStreamAdded();
138 if (!poll_timer_.IsRunning()) {
139 poll_timer_.Start(
140 FROM_HERE, base::TimeDelta::FromSeconds(1) /
141 static_cast<int>(kPowerMeasurementsPerSecond),
142 base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
143 }
144 } 153 }
145 154
146 void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id, 155 void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id,
147 int stream_id) { 156 int stream_id) {
148 DCHECK(thread_checker_.CalledOnValidThread()); 157 DCHECK(thread_checker_.CalledOnValidThread());
149 158
150 const StreamID qualified_id(render_process_id, stream_id); 159 // In the event of render process death, these may have already been cleared.
151 DCHECK(poll_callbacks_.find(qualified_id) != poll_callbacks_.end()); 160 auto it = poll_callbacks_.find(StreamID(render_process_id, stream_id));
152 poll_callbacks_.erase(qualified_id); 161 if (it == poll_callbacks_.end())
162 return;
153 163
154 if (poll_callbacks_.empty()) 164 poll_callbacks_.erase(it);
155 poll_timer_.Stop(); 165 OnStreamRemoved();
156 } 166 }
157 167
158 void AudioStreamMonitor::Poll() { 168 void AudioStreamMonitor::Poll() {
159 bool was_audible = is_audible_; 169 bool was_audible = is_audible_;
160 is_audible_ = false; 170 is_audible_ = false;
161 171
162 for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin(); 172 for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin();
163 it != poll_callbacks_.end(); 173 it != poll_callbacks_.end();
164 ++it) { 174 ++it) {
165 // TODO(miu): A new UI for delivering specific power level and clipping 175 // TODO(miu): A new UI for delivering specific power level and clipping
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 } else if (!off_timer_.IsRunning()) { 207 } else if (!off_timer_.IsRunning()) {
198 off_timer_.Start( 208 off_timer_.Start(
199 FROM_HERE, 209 FROM_HERE,
200 off_time - now, 210 off_time - now,
201 base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this))); 211 base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
202 } 212 }
203 } 213 }
204 214
205 void AudioStreamMonitor::OnStreamAdded() { 215 void AudioStreamMonitor::OnStreamAdded() {
206 DCHECK_CURRENTLY_ON(BrowserThread::UI); 216 DCHECK_CURRENTLY_ON(BrowserThread::UI);
207 DCHECK(!power_level_monitoring_available()); 217 if (poll_callbacks_.size() != 1u)
208 if (++active_streams_ == 1u) { 218 return;
219
220 if (!power_level_monitoring_available()) {
209 is_audible_ = true; 221 is_audible_ = true;
210 web_contents_->OnAudioStateChanged(true); 222 web_contents_->OnAudioStateChanged(true);
211 MaybeToggle(); 223 MaybeToggle();
224 } else if (!poll_timer_.IsRunning()) {
225 poll_timer_.Start(
226 FROM_HERE, base::TimeDelta::FromSeconds(1) /
227 static_cast<int>(kPowerMeasurementsPerSecond),
228 base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
212 } 229 }
213 } 230 }
214 231
215 void AudioStreamMonitor::OnStreamRemoved() { 232 void AudioStreamMonitor::OnStreamRemoved() {
216 DCHECK_CURRENTLY_ON(BrowserThread::UI); 233 DCHECK_CURRENTLY_ON(BrowserThread::UI);
217 DCHECK(!power_level_monitoring_available()); 234 if (!poll_callbacks_.empty())
218 DCHECK_GT(active_streams_, 0u); 235 return;
219 if (--active_streams_ == 0u) { 236
237 if (!power_level_monitoring_available()) {
220 is_audible_ = false; 238 is_audible_ = false;
221 web_contents_->OnAudioStateChanged(false); 239 web_contents_->OnAudioStateChanged(false);
222 MaybeToggle(); 240 MaybeToggle();
241 } else {
242 poll_timer_.Stop();
223 } 243 }
224 } 244 }
225 245
226 } // namespace content 246 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/audio_stream_monitor.h ('k') | content/browser/media/audio_stream_monitor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698