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 "media/audio/virtual_audio_input_stream.h"
19 #include "media/audio/virtual_audio_output_stream.h"
23 class WebContentsAudioInputStream::Impl
24 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>,
25 public AudioMirroringManager::MirroringDestination {
27 // Takes ownership of |mixer_stream|. The rest outlive this instance.
28 Impl(int render_process_id, int main_render_frame_id,
29 AudioMirroringManager* mirroring_manager,
30 const scoped_refptr<WebContentsTracker>& tracker,
31 media::VirtualAudioInputStream* mixer_stream);
33 // Open underlying VirtualAudioInputStream and start tracker.
36 // Start the underlying VirtualAudioInputStream and instruct
37 // AudioMirroringManager to begin a mirroring session.
38 void Start(AudioInputCallback* callback);
40 // Stop the underlying VirtualAudioInputStream and instruct
41 // AudioMirroringManager to shutdown a mirroring session.
44 // Close the underlying VirtualAudioInputStream and stop the tracker.
47 // Accessor to underlying VirtualAudioInputStream.
48 media::VirtualAudioInputStream* mixer_stream() const {
49 return mixer_stream_.get();
53 friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
64 // Returns true if the mirroring target has been permanently lost.
65 bool IsTargetLost() const;
67 // Notifies the consumer callback that the stream is now dead.
70 // Start/Stop mirroring by posting a call to AudioMirroringManager on the IO
72 void StartMirroring();
75 // AudioMirroringManager::MirroringDestination implementation
76 virtual media::AudioOutputStream* AddInput(
77 const media::AudioParameters& params) OVERRIDE;
79 // Callback which is run when |stream| is closed. Deletes |stream|.
80 void ReleaseInput(media::VirtualAudioOutputStream* stream);
82 // Called by WebContentsTracker when the target of the audio mirroring has
84 void OnTargetChanged(int render_process_id, int render_view_id);
86 // Injected dependencies.
87 const int initial_render_process_id_;
88 const int initial_main_render_frame_id_;
89 AudioMirroringManager* const mirroring_manager_;
90 const scoped_refptr<WebContentsTracker> tracker_;
91 // The AudioInputStream implementation that handles the audio conversion and
93 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
97 // Current audio mirroring target.
98 bool target_identified_;
99 int target_render_process_id_;
100 int target_render_view_id_;
102 // Current callback used to consume the resulting mixed audio data.
103 AudioInputCallback* callback_;
105 base::ThreadChecker thread_checker_;
107 DISALLOW_COPY_AND_ASSIGN(Impl);
110 WebContentsAudioInputStream::Impl::Impl(
111 int render_process_id, int main_render_frame_id,
112 AudioMirroringManager* mirroring_manager,
113 const scoped_refptr<WebContentsTracker>& tracker,
114 media::VirtualAudioInputStream* mixer_stream)
115 : initial_render_process_id_(render_process_id),
116 initial_main_render_frame_id_(main_render_frame_id),
117 mirroring_manager_(mirroring_manager),
119 mixer_stream_(mixer_stream),
121 target_identified_(false),
122 target_render_process_id_(-1),
123 target_render_view_id_(-1),
125 DCHECK(mirroring_manager_);
126 DCHECK(tracker_.get());
127 DCHECK(mixer_stream_.get());
129 // WAIS::Impl can be constructed on any thread, but will DCHECK that all
130 // its methods from here on are called from the same thread.
131 thread_checker_.DetachFromThread();
134 WebContentsAudioInputStream::Impl::~Impl() {
135 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED);
138 bool WebContentsAudioInputStream::Impl::Open() {
139 DCHECK(thread_checker_.CalledOnValidThread());
141 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once.";
143 if (!mixer_stream_->Open())
149 initial_render_process_id_, initial_main_render_frame_id_,
150 base::Bind(&Impl::OnTargetChanged, this));
155 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
156 DCHECK(thread_checker_.CalledOnValidThread());
159 if (state_ != OPENED)
162 callback_ = callback;
163 if (IsTargetLost()) {
170 mixer_stream_->Start(callback);
175 void WebContentsAudioInputStream::Impl::Stop() {
176 DCHECK(thread_checker_.CalledOnValidThread());
178 if (state_ != MIRRORING)
183 mixer_stream_->Stop();
190 void WebContentsAudioInputStream::Impl::Close() {
191 DCHECK(thread_checker_.CalledOnValidThread());
195 if (state_ == OPENED) {
196 state_ = CONSTRUCTED;
198 mixer_stream_->Close();
201 DCHECK_EQ(CONSTRUCTED, state_);
205 bool WebContentsAudioInputStream::Impl::IsTargetLost() const {
206 DCHECK(thread_checker_.CalledOnValidThread());
207 if (!target_identified_)
209 return target_render_process_id_ <= 0 || target_render_view_id_ <= 0;
212 void WebContentsAudioInputStream::Impl::ReportError() {
213 DCHECK(thread_checker_.CalledOnValidThread());
215 // TODO(miu): Need clean-up of AudioInputCallback interface in a future
216 // change, since its only implementation ignores the first argument entirely
217 callback_->OnError(NULL);
220 void WebContentsAudioInputStream::Impl::StartMirroring() {
221 DCHECK(thread_checker_.CalledOnValidThread());
223 BrowserThread::PostTask(
226 base::Bind(&AudioMirroringManager::StartMirroring,
227 base::Unretained(mirroring_manager_),
228 target_render_process_id_, target_render_view_id_,
229 make_scoped_refptr(this)));
232 void WebContentsAudioInputStream::Impl::StopMirroring() {
233 DCHECK(thread_checker_.CalledOnValidThread());
235 BrowserThread::PostTask(
238 base::Bind(&AudioMirroringManager::StopMirroring,
239 base::Unretained(mirroring_manager_),
240 target_render_process_id_, target_render_view_id_,
241 make_scoped_refptr(this)));
244 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
245 const media::AudioParameters& params) {
246 // Note: The closure created here holds a reference to "this," which will
247 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the
248 // VirtualAudioOutputStream.
249 return new media::VirtualAudioOutputStream(
252 base::Bind(&Impl::ReleaseInput, this));
255 void WebContentsAudioInputStream::Impl::ReleaseInput(
256 media::VirtualAudioOutputStream* stream) {
260 void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id,
261 int render_view_id) {
262 DCHECK(thread_checker_.CalledOnValidThread());
264 if (target_identified_ &&
265 target_render_process_id_ == render_process_id &&
266 target_render_view_id_ == render_view_id) {
270 DVLOG(1) << "Target RenderView has changed from "
271 << target_render_process_id_ << ':' << target_render_view_id_
272 << " to " << render_process_id << ':' << render_view_id;
274 if (state_ == MIRRORING)
277 target_identified_ = true;
278 target_render_process_id_ = render_process_id;
279 target_render_view_id_ = render_view_id;
281 if (state_ == MIRRORING) {
282 if (IsTargetLost()) {
292 WebContentsAudioInputStream* WebContentsAudioInputStream::Create(
293 const std::string& device_id,
294 const media::AudioParameters& params,
295 const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
296 AudioMirroringManager* audio_mirroring_manager) {
297 int render_process_id;
298 int main_render_frame_id;
299 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
300 device_id, &render_process_id, &main_render_frame_id)) {
304 return new WebContentsAudioInputStream(
305 render_process_id, main_render_frame_id,
306 audio_mirroring_manager,
307 new WebContentsTracker(),
308 new media::VirtualAudioInputStream(
309 params, worker_task_runner,
310 media::VirtualAudioInputStream::AfterCloseCallback()));
313 WebContentsAudioInputStream::WebContentsAudioInputStream(
314 int render_process_id, int main_render_frame_id,
315 AudioMirroringManager* mirroring_manager,
316 const scoped_refptr<WebContentsTracker>& tracker,
317 media::VirtualAudioInputStream* mixer_stream)
318 : impl_(new Impl(render_process_id, main_render_frame_id,
319 mirroring_manager, tracker, mixer_stream)) {}
321 WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
323 bool WebContentsAudioInputStream::Open() {
324 return impl_->Open();
327 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) {
328 impl_->Start(callback);
331 void WebContentsAudioInputStream::Stop() {
335 void WebContentsAudioInputStream::Close() {
340 double WebContentsAudioInputStream::GetMaxVolume() {
341 return impl_->mixer_stream()->GetMaxVolume();
344 void WebContentsAudioInputStream::SetVolume(double volume) {
345 impl_->mixer_stream()->SetVolume(volume);
348 double WebContentsAudioInputStream::GetVolume() {
349 return impl_->mixer_stream()->GetVolume();
352 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
353 impl_->mixer_stream()->SetAutomaticGainControl(enabled);
356 bool WebContentsAudioInputStream::GetAutomaticGainControl() {
357 return impl_->mixer_stream()->GetAutomaticGainControl();
360 } // namespace content