OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/renderer_host/media/web_contents_audio_input_stream.h" | 5 #include "content/browser/renderer_host/media/web_contents_audio_input_stream.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/message_loop/message_loop_proxy.h" | 13 #include "base/threading/thread_checker.h" |
14 #include "content/browser/renderer_host/media/audio_mirroring_manager.h" | 14 #include "content/browser/renderer_host/media/audio_mirroring_manager.h" |
15 #include "content/browser/renderer_host/media/web_contents_capture_util.h" | 15 #include "content/browser/renderer_host/media/web_contents_capture_util.h" |
16 #include "content/browser/renderer_host/media/web_contents_tracker.h" | 16 #include "content/browser/renderer_host/media/web_contents_tracker.h" |
17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
18 #include "media/audio/virtual_audio_input_stream.h" | 18 #include "media/audio/virtual_audio_input_stream.h" |
19 #include "media/audio/virtual_audio_output_stream.h" | 19 #include "media/audio/virtual_audio_output_stream.h" |
20 | 20 |
21 namespace content { | 21 namespace content { |
22 | 22 |
23 class WebContentsAudioInputStream::Impl | 23 class WebContentsAudioInputStream::Impl |
24 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>, | 24 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>, |
25 public AudioMirroringManager::MirroringDestination { | 25 public AudioMirroringManager::MirroringDestination { |
26 public: | 26 public: |
27 // Takes ownership of |mixer_stream|. The rest outlive this instance. | 27 // Takes ownership of |mixer_stream|. The rest outlive this instance. |
28 Impl(int render_process_id, int render_view_id, | 28 Impl(int render_process_id, int render_view_id, |
29 const scoped_refptr<base::MessageLoopProxy>& message_loop, | |
30 AudioMirroringManager* mirroring_manager, | 29 AudioMirroringManager* mirroring_manager, |
31 const scoped_refptr<WebContentsTracker>& tracker, | 30 const scoped_refptr<WebContentsTracker>& tracker, |
32 media::VirtualAudioInputStream* mixer_stream); | 31 media::VirtualAudioInputStream* mixer_stream); |
33 | 32 |
34 // Open underlying VirtualAudioInputStream and start tracker. | 33 // Open underlying VirtualAudioInputStream and start tracker. |
35 bool Open(); | 34 bool Open(); |
36 | 35 |
37 // Start the underlying VirtualAudioInputStream and instruct | 36 // Start the underlying VirtualAudioInputStream and instruct |
38 // AudioMirroringManager to begin a mirroring session. | 37 // AudioMirroringManager to begin a mirroring session. |
39 void Start(AudioInputCallback* callback); | 38 void Start(AudioInputCallback* callback); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 const media::AudioParameters& params) OVERRIDE; | 77 const media::AudioParameters& params) OVERRIDE; |
79 | 78 |
80 // Callback which is run when |stream| is closed. Deletes |stream|. | 79 // Callback which is run when |stream| is closed. Deletes |stream|. |
81 void ReleaseInput(media::VirtualAudioOutputStream* stream); | 80 void ReleaseInput(media::VirtualAudioOutputStream* stream); |
82 | 81 |
83 // Called by WebContentsTracker when the target of the audio mirroring has | 82 // Called by WebContentsTracker when the target of the audio mirroring has |
84 // changed. | 83 // changed. |
85 void OnTargetChanged(int render_process_id, int render_view_id); | 84 void OnTargetChanged(int render_process_id, int render_view_id); |
86 | 85 |
87 // Injected dependencies. | 86 // Injected dependencies. |
88 const scoped_refptr<base::MessageLoopProxy> message_loop_; | |
89 AudioMirroringManager* const mirroring_manager_; | 87 AudioMirroringManager* const mirroring_manager_; |
90 const scoped_refptr<WebContentsTracker> tracker_; | 88 const scoped_refptr<WebContentsTracker> tracker_; |
91 // The AudioInputStream implementation that handles the audio conversion and | 89 // The AudioInputStream implementation that handles the audio conversion and |
92 // mixing details. | 90 // mixing details. |
93 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_; | 91 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_; |
94 | 92 |
95 State state_; | 93 State state_; |
96 | 94 |
97 // Current audio mirroring target. | 95 // Current audio mirroring target. |
98 int target_render_process_id_; | 96 int target_render_process_id_; |
99 int target_render_view_id_; | 97 int target_render_view_id_; |
100 | 98 |
101 // Current callback used to consume the resulting mixed audio data. | 99 // Current callback used to consume the resulting mixed audio data. |
102 AudioInputCallback* callback_; | 100 AudioInputCallback* callback_; |
103 | 101 |
| 102 base::ThreadChecker thread_checker_; |
| 103 |
104 DISALLOW_COPY_AND_ASSIGN(Impl); | 104 DISALLOW_COPY_AND_ASSIGN(Impl); |
105 }; | 105 }; |
106 | 106 |
107 WebContentsAudioInputStream::Impl::Impl( | 107 WebContentsAudioInputStream::Impl::Impl( |
108 int render_process_id, int render_view_id, | 108 int render_process_id, int render_view_id, |
109 const scoped_refptr<base::MessageLoopProxy>& message_loop, | |
110 AudioMirroringManager* mirroring_manager, | 109 AudioMirroringManager* mirroring_manager, |
111 const scoped_refptr<WebContentsTracker>& tracker, | 110 const scoped_refptr<WebContentsTracker>& tracker, |
112 media::VirtualAudioInputStream* mixer_stream) | 111 media::VirtualAudioInputStream* mixer_stream) |
113 : message_loop_(message_loop), mirroring_manager_(mirroring_manager), | 112 : mirroring_manager_(mirroring_manager), |
114 tracker_(tracker), mixer_stream_(mixer_stream), state_(CONSTRUCTED), | 113 tracker_(tracker), mixer_stream_(mixer_stream), state_(CONSTRUCTED), |
115 target_render_process_id_(render_process_id), | 114 target_render_process_id_(render_process_id), |
116 target_render_view_id_(render_view_id), | 115 target_render_view_id_(render_view_id), |
117 callback_(NULL) { | 116 callback_(NULL) { |
118 DCHECK(message_loop_.get()); | |
119 DCHECK(mirroring_manager_); | 117 DCHECK(mirroring_manager_); |
120 DCHECK(tracker_.get()); | 118 DCHECK(tracker_.get()); |
121 DCHECK(mixer_stream_.get()); | 119 DCHECK(mixer_stream_.get()); |
| 120 |
| 121 // WAIS::Impl can be constructed on any thread, but will DCHECK that all |
| 122 // its methods from here on are called from the same thread. |
| 123 thread_checker_.DetachFromThread(); |
122 } | 124 } |
123 | 125 |
124 WebContentsAudioInputStream::Impl::~Impl() { | 126 WebContentsAudioInputStream::Impl::~Impl() { |
125 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED); | 127 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED); |
126 } | 128 } |
127 | 129 |
128 bool WebContentsAudioInputStream::Impl::Open() { | 130 bool WebContentsAudioInputStream::Impl::Open() { |
129 DCHECK(message_loop_->BelongsToCurrentThread()); | 131 DCHECK(thread_checker_.CalledOnValidThread()); |
130 | 132 |
131 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once."; | 133 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once."; |
132 | 134 |
133 if (!mixer_stream_->Open()) | 135 if (!mixer_stream_->Open()) |
134 return false; | 136 return false; |
135 | 137 |
136 state_ = OPENED; | 138 state_ = OPENED; |
137 | 139 |
138 tracker_->Start( | 140 tracker_->Start( |
139 target_render_process_id_, target_render_view_id_, | 141 target_render_process_id_, target_render_view_id_, |
140 base::Bind(&Impl::OnTargetChanged, this)); | 142 base::Bind(&Impl::OnTargetChanged, this)); |
141 | 143 |
142 return true; | 144 return true; |
143 } | 145 } |
144 | 146 |
145 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) { | 147 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) { |
146 DCHECK(message_loop_->BelongsToCurrentThread()); | 148 DCHECK(thread_checker_.CalledOnValidThread()); |
147 DCHECK(callback); | 149 DCHECK(callback); |
148 | 150 |
149 if (state_ != OPENED) | 151 if (state_ != OPENED) |
150 return; | 152 return; |
151 | 153 |
152 callback_ = callback; | 154 callback_ = callback; |
153 if (IsTargetLost()) { | 155 if (IsTargetLost()) { |
154 ReportError(); | 156 ReportError(); |
155 callback_ = NULL; | 157 callback_ = NULL; |
156 return; | 158 return; |
157 } | 159 } |
158 | 160 |
159 state_ = MIRRORING; | 161 state_ = MIRRORING; |
160 mixer_stream_->Start(callback); | 162 mixer_stream_->Start(callback); |
161 | 163 |
162 StartMirroring(); | 164 StartMirroring(); |
163 } | 165 } |
164 | 166 |
165 void WebContentsAudioInputStream::Impl::Stop() { | 167 void WebContentsAudioInputStream::Impl::Stop() { |
166 DCHECK(message_loop_->BelongsToCurrentThread()); | 168 DCHECK(thread_checker_.CalledOnValidThread()); |
167 | 169 |
168 if (state_ != MIRRORING) | 170 if (state_ != MIRRORING) |
169 return; | 171 return; |
170 | 172 |
171 state_ = OPENED; | 173 state_ = OPENED; |
172 | 174 |
173 mixer_stream_->Stop(); | 175 mixer_stream_->Stop(); |
174 callback_ = NULL; | 176 callback_ = NULL; |
175 | 177 |
176 if (!IsTargetLost()) | 178 if (!IsTargetLost()) |
177 StopMirroring(); | 179 StopMirroring(); |
178 } | 180 } |
179 | 181 |
180 void WebContentsAudioInputStream::Impl::Close() { | 182 void WebContentsAudioInputStream::Impl::Close() { |
181 DCHECK(message_loop_->BelongsToCurrentThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
182 | 184 |
183 Stop(); | 185 Stop(); |
184 | 186 |
185 if (state_ == OPENED) { | 187 if (state_ == OPENED) { |
186 state_ = CONSTRUCTED; | 188 state_ = CONSTRUCTED; |
187 tracker_->Stop(); | 189 tracker_->Stop(); |
188 mixer_stream_->Close(); | 190 mixer_stream_->Close(); |
189 } | 191 } |
190 | 192 |
191 DCHECK_EQ(CONSTRUCTED, state_); | 193 DCHECK_EQ(CONSTRUCTED, state_); |
192 state_ = CLOSED; | 194 state_ = CLOSED; |
193 } | 195 } |
194 | 196 |
195 bool WebContentsAudioInputStream::Impl::IsTargetLost() const { | 197 bool WebContentsAudioInputStream::Impl::IsTargetLost() const { |
196 DCHECK(message_loop_->BelongsToCurrentThread()); | 198 DCHECK(thread_checker_.CalledOnValidThread()); |
197 | 199 |
198 return target_render_process_id_ <= 0 || target_render_view_id_ <= 0; | 200 return target_render_process_id_ <= 0 || target_render_view_id_ <= 0; |
199 } | 201 } |
200 | 202 |
201 void WebContentsAudioInputStream::Impl::ReportError() { | 203 void WebContentsAudioInputStream::Impl::ReportError() { |
202 DCHECK(message_loop_->BelongsToCurrentThread()); | 204 DCHECK(thread_checker_.CalledOnValidThread()); |
203 | 205 |
204 // TODO(miu): Need clean-up of AudioInputCallback interface in a future | 206 // TODO(miu): Need clean-up of AudioInputCallback interface in a future |
205 // change, since its only implementation ignores the first argument entirely | 207 // change, since its only implementation ignores the first argument entirely |
206 callback_->OnError(NULL); | 208 callback_->OnError(NULL); |
207 } | 209 } |
208 | 210 |
209 void WebContentsAudioInputStream::Impl::StartMirroring() { | 211 void WebContentsAudioInputStream::Impl::StartMirroring() { |
210 DCHECK(message_loop_->BelongsToCurrentThread()); | 212 DCHECK(thread_checker_.CalledOnValidThread()); |
211 | 213 |
212 BrowserThread::PostTask( | 214 BrowserThread::PostTask( |
213 BrowserThread::IO, | 215 BrowserThread::IO, |
214 FROM_HERE, | 216 FROM_HERE, |
215 base::Bind(&AudioMirroringManager::StartMirroring, | 217 base::Bind(&AudioMirroringManager::StartMirroring, |
216 base::Unretained(mirroring_manager_), | 218 base::Unretained(mirroring_manager_), |
217 target_render_process_id_, target_render_view_id_, | 219 target_render_process_id_, target_render_view_id_, |
218 make_scoped_refptr(this))); | 220 make_scoped_refptr(this))); |
219 } | 221 } |
220 | 222 |
221 void WebContentsAudioInputStream::Impl::StopMirroring() { | 223 void WebContentsAudioInputStream::Impl::StopMirroring() { |
222 DCHECK(message_loop_->BelongsToCurrentThread()); | 224 DCHECK(thread_checker_.CalledOnValidThread()); |
223 | 225 |
224 BrowserThread::PostTask( | 226 BrowserThread::PostTask( |
225 BrowserThread::IO, | 227 BrowserThread::IO, |
226 FROM_HERE, | 228 FROM_HERE, |
227 base::Bind(&AudioMirroringManager::StopMirroring, | 229 base::Bind(&AudioMirroringManager::StopMirroring, |
228 base::Unretained(mirroring_manager_), | 230 base::Unretained(mirroring_manager_), |
229 target_render_process_id_, target_render_view_id_, | 231 target_render_process_id_, target_render_view_id_, |
230 make_scoped_refptr(this))); | 232 make_scoped_refptr(this))); |
231 } | 233 } |
232 | 234 |
233 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput( | 235 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput( |
234 const media::AudioParameters& params) { | 236 const media::AudioParameters& params) { |
235 // Note: The closure created here holds a reference to "this," which will | 237 // Note: The closure created here holds a reference to "this," which will |
236 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the | 238 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the |
237 // VirtualAudioOutputStream. | 239 // VirtualAudioOutputStream. |
238 return new media::VirtualAudioOutputStream( | 240 return new media::VirtualAudioOutputStream( |
239 params, | 241 params, |
240 message_loop_.get(), | |
241 mixer_stream_.get(), | 242 mixer_stream_.get(), |
242 base::Bind(&Impl::ReleaseInput, this)); | 243 base::Bind(&Impl::ReleaseInput, this)); |
243 } | 244 } |
244 | 245 |
245 void WebContentsAudioInputStream::Impl::ReleaseInput( | 246 void WebContentsAudioInputStream::Impl::ReleaseInput( |
246 media::VirtualAudioOutputStream* stream) { | 247 media::VirtualAudioOutputStream* stream) { |
247 delete stream; | 248 delete stream; |
248 } | 249 } |
249 | 250 |
250 void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id, | 251 void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id, |
251 int render_view_id) { | 252 int render_view_id) { |
252 DCHECK(message_loop_->BelongsToCurrentThread()); | 253 DCHECK(thread_checker_.CalledOnValidThread()); |
253 | 254 |
254 if (target_render_process_id_ == render_process_id && | 255 if (target_render_process_id_ == render_process_id && |
255 target_render_view_id_ == render_view_id) { | 256 target_render_view_id_ == render_view_id) { |
256 return; | 257 return; |
257 } | 258 } |
258 | 259 |
259 DVLOG(1) << "Target RenderView has changed from " | 260 DVLOG(1) << "Target RenderView has changed from " |
260 << target_render_process_id_ << ':' << target_render_view_id_ | 261 << target_render_process_id_ << ':' << target_render_view_id_ |
261 << " to " << render_process_id << ':' << render_view_id; | 262 << " to " << render_process_id << ':' << render_view_id; |
262 | 263 |
(...skipping 10 matching lines...) Expand all Loading... |
273 } else { | 274 } else { |
274 StartMirroring(); | 275 StartMirroring(); |
275 } | 276 } |
276 } | 277 } |
277 } | 278 } |
278 | 279 |
279 // static | 280 // static |
280 WebContentsAudioInputStream* WebContentsAudioInputStream::Create( | 281 WebContentsAudioInputStream* WebContentsAudioInputStream::Create( |
281 const std::string& device_id, | 282 const std::string& device_id, |
282 const media::AudioParameters& params, | 283 const media::AudioParameters& params, |
283 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 284 const scoped_refptr<base::MessageLoopProxy>& worker_loop, |
284 AudioMirroringManager* audio_mirroring_manager) { | 285 AudioMirroringManager* audio_mirroring_manager) { |
285 int render_process_id; | 286 int render_process_id; |
286 int render_view_id; | 287 int render_view_id; |
287 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( | 288 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( |
288 device_id, &render_process_id, &render_view_id)) { | 289 device_id, &render_process_id, &render_view_id)) { |
289 return NULL; | 290 return NULL; |
290 } | 291 } |
291 | 292 |
292 return new WebContentsAudioInputStream( | 293 return new WebContentsAudioInputStream( |
293 render_process_id, render_view_id, message_loop, | 294 render_process_id, render_view_id, |
294 audio_mirroring_manager, | 295 audio_mirroring_manager, |
295 new WebContentsTracker(), | 296 new WebContentsTracker(), |
296 new media::VirtualAudioInputStream( | 297 new media::VirtualAudioInputStream( |
297 params, message_loop, | 298 params, worker_loop, |
298 media::VirtualAudioInputStream::AfterCloseCallback())); | 299 media::VirtualAudioInputStream::AfterCloseCallback())); |
299 } | 300 } |
300 | 301 |
301 WebContentsAudioInputStream::WebContentsAudioInputStream( | 302 WebContentsAudioInputStream::WebContentsAudioInputStream( |
302 int render_process_id, int render_view_id, | 303 int render_process_id, int render_view_id, |
303 const scoped_refptr<base::MessageLoopProxy>& message_loop, | |
304 AudioMirroringManager* mirroring_manager, | 304 AudioMirroringManager* mirroring_manager, |
305 const scoped_refptr<WebContentsTracker>& tracker, | 305 const scoped_refptr<WebContentsTracker>& tracker, |
306 media::VirtualAudioInputStream* mixer_stream) | 306 media::VirtualAudioInputStream* mixer_stream) |
307 : impl_(new Impl(render_process_id, render_view_id, message_loop, | 307 : impl_(new Impl(render_process_id, render_view_id, |
308 mirroring_manager, tracker, mixer_stream)) {} | 308 mirroring_manager, tracker, mixer_stream)) {} |
309 | 309 |
310 WebContentsAudioInputStream::~WebContentsAudioInputStream() {} | 310 WebContentsAudioInputStream::~WebContentsAudioInputStream() {} |
311 | 311 |
312 bool WebContentsAudioInputStream::Open() { | 312 bool WebContentsAudioInputStream::Open() { |
313 return impl_->Open(); | 313 return impl_->Open(); |
314 } | 314 } |
315 | 315 |
316 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) { | 316 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) { |
317 impl_->Start(callback); | 317 impl_->Start(callback); |
(...skipping 22 matching lines...) Expand all Loading... |
340 | 340 |
341 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) { | 341 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) { |
342 impl_->mixer_stream()->SetAutomaticGainControl(enabled); | 342 impl_->mixer_stream()->SetAutomaticGainControl(enabled); |
343 } | 343 } |
344 | 344 |
345 bool WebContentsAudioInputStream::GetAutomaticGainControl() { | 345 bool WebContentsAudioInputStream::GetAutomaticGainControl() { |
346 return impl_->mixer_stream()->GetAutomaticGainControl(); | 346 return impl_->mixer_stream()->GetAutomaticGainControl(); |
347 } | 347 } |
348 | 348 |
349 } // namespace content | 349 } // namespace content |
OLD | NEW |