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
3 // found in the LICENSE file.
5 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
10 #include "base/bind_helpers.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/threading/thread_checker.h"
14 #include "content/browser/media/capture/audio_mirroring_manager.h"
15 #include "content/browser/media/capture/web_contents_capture_util.h"
16 #include "content/browser/media/capture/web_contents_tracker.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "media/audio/virtual_audio_input_stream.h"
21 #include "media/audio/virtual_audio_output_stream.h"
22 #include "media/base/bind_to_current_loop.h"
26 class WebContentsAudioInputStream::Impl
27 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>,
28 public AudioMirroringManager::MirroringDestination {
30 // Takes ownership of |mixer_stream|. The rest outlive this instance.
31 Impl(int render_process_id, int main_render_frame_id,
32 AudioMirroringManager* mirroring_manager,
33 const scoped_refptr<WebContentsTracker>& tracker,
34 media::VirtualAudioInputStream* mixer_stream);
36 // Open underlying VirtualAudioInputStream and start tracker.
39 // Start the underlying VirtualAudioInputStream and instruct
40 // AudioMirroringManager to begin a mirroring session.
41 void Start(AudioInputCallback* callback);
43 // Stop the underlying VirtualAudioInputStream and instruct
44 // AudioMirroringManager to shutdown a mirroring session.
47 // Close the underlying VirtualAudioInputStream and stop the tracker.
50 // Accessor to underlying VirtualAudioInputStream.
51 media::VirtualAudioInputStream* mixer_stream() const {
52 return mixer_stream_.get();
56 friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
58 typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
69 // Notifies the consumer callback that the stream is now dead.
72 // (Re-)Start/Stop mirroring by posting a call to AudioMirroringManager on the
74 void StartMirroring();
77 // Invoked on the UI thread to make sure WebContents muting is turned off for
78 // successful audio capture.
79 void UnmuteWebContentsAudio();
81 // AudioMirroringManager::MirroringDestination implementation
82 virtual void QueryForMatches(
83 const std::set<SourceFrameRef>& candidates,
84 const MatchesCallback& results_callback) OVERRIDE;
85 void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
86 const MatchesCallback& results_callback);
87 virtual media::AudioOutputStream* AddInput(
88 const media::AudioParameters& params) OVERRIDE;
90 // Callback which is run when |stream| is closed. Deletes |stream|.
91 void ReleaseInput(media::VirtualAudioOutputStream* stream);
93 // Called by WebContentsTracker when the target of the audio mirroring has
95 void OnTargetChanged(RenderWidgetHost* target);
97 // Injected dependencies.
98 const int initial_render_process_id_;
99 const int initial_main_render_frame_id_;
100 AudioMirroringManager* const mirroring_manager_;
101 const scoped_refptr<WebContentsTracker> tracker_;
102 // The AudioInputStream implementation that handles the audio conversion and
104 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
108 // Set to true if |tracker_| reports a NULL target, which indicates the target
109 // is permanently lost.
110 bool is_target_lost_;
112 // Current callback used to consume the resulting mixed audio data.
113 AudioInputCallback* callback_;
115 base::ThreadChecker thread_checker_;
117 DISALLOW_COPY_AND_ASSIGN(Impl);
120 WebContentsAudioInputStream::Impl::Impl(
121 int render_process_id, int main_render_frame_id,
122 AudioMirroringManager* mirroring_manager,
123 const scoped_refptr<WebContentsTracker>& tracker,
124 media::VirtualAudioInputStream* mixer_stream)
125 : initial_render_process_id_(render_process_id),
126 initial_main_render_frame_id_(main_render_frame_id),
127 mirroring_manager_(mirroring_manager),
129 mixer_stream_(mixer_stream),
131 is_target_lost_(false),
133 DCHECK(mirroring_manager_);
134 DCHECK(tracker_.get());
135 DCHECK(mixer_stream_.get());
137 // WAIS::Impl can be constructed on any thread, but will DCHECK that all
138 // its methods from here on are called from the same thread.
139 thread_checker_.DetachFromThread();
142 WebContentsAudioInputStream::Impl::~Impl() {
143 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED);
146 bool WebContentsAudioInputStream::Impl::Open() {
147 DCHECK(thread_checker_.CalledOnValidThread());
149 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once.";
151 if (!mixer_stream_->Open())
157 initial_render_process_id_, initial_main_render_frame_id_,
158 base::Bind(&Impl::OnTargetChanged, this));
163 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
164 DCHECK(thread_checker_.CalledOnValidThread());
167 if (state_ != OPENED)
170 callback_ = callback;
171 if (is_target_lost_) {
178 mixer_stream_->Start(callback);
182 // WebContents audio muting is implemented as audio capture to nowhere.
183 // Unmuting will stop that audio capture, allowing AudioMirroringManager to
184 // divert audio capture to here.
185 BrowserThread::PostTask(
188 base::Bind(&Impl::UnmuteWebContentsAudio, this));
191 void WebContentsAudioInputStream::Impl::Stop() {
192 DCHECK(thread_checker_.CalledOnValidThread());
194 if (state_ != MIRRORING)
199 mixer_stream_->Stop();
205 void WebContentsAudioInputStream::Impl::Close() {
206 DCHECK(thread_checker_.CalledOnValidThread());
210 if (state_ == OPENED) {
211 state_ = CONSTRUCTED;
213 mixer_stream_->Close();
216 DCHECK_EQ(CONSTRUCTED, state_);
220 void WebContentsAudioInputStream::Impl::ReportError() {
221 DCHECK(thread_checker_.CalledOnValidThread());
223 // TODO(miu): Need clean-up of AudioInputCallback interface in a future
224 // change, since its only implementation ignores the first argument entirely
225 callback_->OnError(NULL);
228 void WebContentsAudioInputStream::Impl::StartMirroring() {
229 DCHECK(thread_checker_.CalledOnValidThread());
231 BrowserThread::PostTask(
234 base::Bind(&AudioMirroringManager::StartMirroring,
235 base::Unretained(mirroring_manager_),
236 make_scoped_refptr(this)));
239 void WebContentsAudioInputStream::Impl::StopMirroring() {
240 DCHECK(thread_checker_.CalledOnValidThread());
242 BrowserThread::PostTask(
245 base::Bind(&AudioMirroringManager::StopMirroring,
246 base::Unretained(mirroring_manager_),
247 make_scoped_refptr(this)));
250 void WebContentsAudioInputStream::Impl::UnmuteWebContentsAudio() {
251 DCHECK_CURRENTLY_ON(BrowserThread::UI);
253 WebContents* const contents = tracker_->web_contents();
255 contents->SetAudioMuted(false);
258 void WebContentsAudioInputStream::Impl::QueryForMatches(
259 const std::set<SourceFrameRef>& candidates,
260 const MatchesCallback& results_callback) {
261 BrowserThread::PostTask(
264 base::Bind(&Impl::QueryForMatchesOnUIThread,
267 media::BindToCurrentLoop(results_callback)));
270 void WebContentsAudioInputStream::Impl::QueryForMatchesOnUIThread(
271 const std::set<SourceFrameRef>& candidates,
272 const MatchesCallback& results_callback) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
275 std::set<SourceFrameRef> matches;
276 WebContents* const contents = tracker_->web_contents();
278 // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
279 // currently-tracked WebContents.
280 for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
281 i != candidates.end(); ++i) {
282 WebContents* const contents_containing_frame =
283 WebContents::FromRenderFrameHost(
284 RenderFrameHost::FromID(i->first, i->second));
285 if (contents_containing_frame == contents)
290 results_callback.Run(matches);
293 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
294 const media::AudioParameters& params) {
295 // Note: The closure created here holds a reference to "this," which will
296 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the
297 // VirtualAudioOutputStream.
298 return new media::VirtualAudioOutputStream(
301 base::Bind(&Impl::ReleaseInput, this));
304 void WebContentsAudioInputStream::Impl::ReleaseInput(
305 media::VirtualAudioOutputStream* stream) {
309 void WebContentsAudioInputStream::Impl::OnTargetChanged(
310 RenderWidgetHost* target) {
311 DCHECK(thread_checker_.CalledOnValidThread());
313 is_target_lost_ = !target;
315 if (state_ == MIRRORING) {
316 if (is_target_lost_) {
326 WebContentsAudioInputStream* WebContentsAudioInputStream::Create(
327 const std::string& device_id,
328 const media::AudioParameters& params,
329 const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
330 AudioMirroringManager* audio_mirroring_manager) {
331 int render_process_id;
332 int main_render_frame_id;
333 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
334 device_id, &render_process_id, &main_render_frame_id)) {
338 return new WebContentsAudioInputStream(
339 render_process_id, main_render_frame_id,
340 audio_mirroring_manager,
341 new WebContentsTracker(false),
342 new media::VirtualAudioInputStream(
343 params, worker_task_runner,
344 media::VirtualAudioInputStream::AfterCloseCallback()));
347 WebContentsAudioInputStream::WebContentsAudioInputStream(
348 int render_process_id, int main_render_frame_id,
349 AudioMirroringManager* mirroring_manager,
350 const scoped_refptr<WebContentsTracker>& tracker,
351 media::VirtualAudioInputStream* mixer_stream)
352 : impl_(new Impl(render_process_id, main_render_frame_id,
353 mirroring_manager, tracker, mixer_stream)) {}
355 WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
357 bool WebContentsAudioInputStream::Open() {
358 return impl_->Open();
361 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) {
362 impl_->Start(callback);
365 void WebContentsAudioInputStream::Stop() {
369 void WebContentsAudioInputStream::Close() {
374 double WebContentsAudioInputStream::GetMaxVolume() {
375 return impl_->mixer_stream()->GetMaxVolume();
378 void WebContentsAudioInputStream::SetVolume(double volume) {
379 impl_->mixer_stream()->SetVolume(volume);
382 double WebContentsAudioInputStream::GetVolume() {
383 return impl_->mixer_stream()->GetVolume();
386 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
387 impl_->mixer_stream()->SetAutomaticGainControl(enabled);
390 bool WebContentsAudioInputStream::GetAutomaticGainControl() {
391 return impl_->mixer_stream()->GetAutomaticGainControl();
394 bool WebContentsAudioInputStream::IsMuted() {
398 } // namespace content