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