Process Alt-Svc headers.
[chromium-blink-merge.git] / content / browser / media / capture / web_contents_audio_input_stream.cc
blob8fd1f976d59998ad91ecd67dc71de3b9f30a7193
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"
7 #include <string>
9 #include "base/bind.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"
24 namespace content {
26 class WebContentsAudioInputStream::Impl
27 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>,
28 public AudioMirroringManager::MirroringDestination {
29 public:
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.
37 bool Open();
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.
45 void Stop();
47 // Close the underlying VirtualAudioInputStream and stop the tracker.
48 void Close();
50 // Accessor to underlying VirtualAudioInputStream.
51 media::VirtualAudioInputStream* mixer_stream() const {
52 return mixer_stream_.get();
55 private:
56 friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
58 typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
60 enum State {
61 CONSTRUCTED,
62 OPENED,
63 MIRRORING,
64 CLOSED
67 ~Impl() override;
69 // Notifies the consumer callback that the stream is now dead.
70 void ReportError();
72 // (Re-)Start/Stop mirroring by posting a call to AudioMirroringManager on the
73 // IO BrowserThread.
74 void StartMirroring();
75 void StopMirroring();
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 void QueryForMatches(const std::set<SourceFrameRef>& candidates,
83 const MatchesCallback& results_callback) override;
84 void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
85 const MatchesCallback& results_callback);
86 media::AudioOutputStream* AddInput(
87 const media::AudioParameters& params) override;
89 // Callback which is run when |stream| is closed. Deletes |stream|.
90 void ReleaseInput(media::VirtualAudioOutputStream* stream);
92 // Called by WebContentsTracker when the target of the audio mirroring has
93 // changed.
94 void OnTargetChanged(bool had_target);
96 // Injected dependencies.
97 const int initial_render_process_id_;
98 const int initial_main_render_frame_id_;
99 AudioMirroringManager* const mirroring_manager_;
100 const scoped_refptr<WebContentsTracker> tracker_;
101 // The AudioInputStream implementation that handles the audio conversion and
102 // mixing details.
103 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
105 State state_;
107 // Set to true if |tracker_| reports a NULL target, which indicates the target
108 // is permanently lost.
109 bool is_target_lost_;
111 // Current callback used to consume the resulting mixed audio data.
112 AudioInputCallback* callback_;
114 base::ThreadChecker thread_checker_;
116 DISALLOW_COPY_AND_ASSIGN(Impl);
119 WebContentsAudioInputStream::Impl::Impl(
120 int render_process_id, int main_render_frame_id,
121 AudioMirroringManager* mirroring_manager,
122 const scoped_refptr<WebContentsTracker>& tracker,
123 media::VirtualAudioInputStream* mixer_stream)
124 : initial_render_process_id_(render_process_id),
125 initial_main_render_frame_id_(main_render_frame_id),
126 mirroring_manager_(mirroring_manager),
127 tracker_(tracker),
128 mixer_stream_(mixer_stream),
129 state_(CONSTRUCTED),
130 is_target_lost_(false),
131 callback_(NULL) {
132 DCHECK(mirroring_manager_);
133 DCHECK(tracker_.get());
134 DCHECK(mixer_stream_.get());
136 // WAIS::Impl can be constructed on any thread, but will DCHECK that all
137 // its methods from here on are called from the same thread.
138 thread_checker_.DetachFromThread();
141 WebContentsAudioInputStream::Impl::~Impl() {
142 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED);
145 bool WebContentsAudioInputStream::Impl::Open() {
146 DCHECK(thread_checker_.CalledOnValidThread());
148 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once.";
150 if (!mixer_stream_->Open())
151 return false;
153 state_ = OPENED;
155 tracker_->Start(
156 initial_render_process_id_, initial_main_render_frame_id_,
157 base::Bind(&Impl::OnTargetChanged, this));
159 return true;
162 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK(callback);
166 if (state_ != OPENED)
167 return;
169 callback_ = callback;
170 if (is_target_lost_) {
171 ReportError();
172 callback_ = NULL;
173 return;
176 state_ = MIRRORING;
177 mixer_stream_->Start(callback);
179 StartMirroring();
181 // WebContents audio muting is implemented as audio capture to nowhere.
182 // Unmuting will stop that audio capture, allowing AudioMirroringManager to
183 // divert audio capture to here.
184 BrowserThread::PostTask(
185 BrowserThread::UI,
186 FROM_HERE,
187 base::Bind(&Impl::UnmuteWebContentsAudio, this));
190 void WebContentsAudioInputStream::Impl::Stop() {
191 DCHECK(thread_checker_.CalledOnValidThread());
193 if (state_ != MIRRORING)
194 return;
196 state_ = OPENED;
198 mixer_stream_->Stop();
199 callback_ = NULL;
201 StopMirroring();
204 void WebContentsAudioInputStream::Impl::Close() {
205 DCHECK(thread_checker_.CalledOnValidThread());
207 Stop();
209 if (state_ == OPENED) {
210 state_ = CONSTRUCTED;
211 tracker_->Stop();
212 mixer_stream_->Close();
215 DCHECK_EQ(CONSTRUCTED, state_);
216 state_ = CLOSED;
219 void WebContentsAudioInputStream::Impl::ReportError() {
220 DCHECK(thread_checker_.CalledOnValidThread());
222 // TODO(miu): Need clean-up of AudioInputCallback interface in a future
223 // change, since its only implementation ignores the first argument entirely
224 callback_->OnError(NULL);
227 void WebContentsAudioInputStream::Impl::StartMirroring() {
228 DCHECK(thread_checker_.CalledOnValidThread());
230 BrowserThread::PostTask(
231 BrowserThread::IO,
232 FROM_HERE,
233 base::Bind(&AudioMirroringManager::StartMirroring,
234 base::Unretained(mirroring_manager_),
235 make_scoped_refptr(this)));
238 void WebContentsAudioInputStream::Impl::StopMirroring() {
239 DCHECK(thread_checker_.CalledOnValidThread());
241 BrowserThread::PostTask(
242 BrowserThread::IO,
243 FROM_HERE,
244 base::Bind(&AudioMirroringManager::StopMirroring,
245 base::Unretained(mirroring_manager_),
246 make_scoped_refptr(this)));
249 void WebContentsAudioInputStream::Impl::UnmuteWebContentsAudio() {
250 DCHECK_CURRENTLY_ON(BrowserThread::UI);
252 WebContents* const contents = tracker_->web_contents();
253 if (contents)
254 contents->SetAudioMuted(false);
257 void WebContentsAudioInputStream::Impl::QueryForMatches(
258 const std::set<SourceFrameRef>& candidates,
259 const MatchesCallback& results_callback) {
260 BrowserThread::PostTask(
261 BrowserThread::UI,
262 FROM_HERE,
263 base::Bind(&Impl::QueryForMatchesOnUIThread,
264 this,
265 candidates,
266 media::BindToCurrentLoop(results_callback)));
269 void WebContentsAudioInputStream::Impl::QueryForMatchesOnUIThread(
270 const std::set<SourceFrameRef>& candidates,
271 const MatchesCallback& results_callback) {
272 DCHECK_CURRENTLY_ON(BrowserThread::UI);
274 std::set<SourceFrameRef> matches;
275 WebContents* const contents = tracker_->web_contents();
276 if (contents) {
277 // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
278 // currently-tracked WebContents.
279 for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
280 i != candidates.end(); ++i) {
281 WebContents* const contents_containing_frame =
282 WebContents::FromRenderFrameHost(
283 RenderFrameHost::FromID(i->first, i->second));
284 if (contents_containing_frame == contents)
285 matches.insert(*i);
289 results_callback.Run(matches);
292 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
293 const media::AudioParameters& params) {
294 // Note: The closure created here holds a reference to "this," which will
295 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the
296 // VirtualAudioOutputStream.
297 return new media::VirtualAudioOutputStream(
298 params,
299 mixer_stream_.get(),
300 base::Bind(&Impl::ReleaseInput, this));
303 void WebContentsAudioInputStream::Impl::ReleaseInput(
304 media::VirtualAudioOutputStream* stream) {
305 delete stream;
308 void WebContentsAudioInputStream::Impl::OnTargetChanged(bool had_target) {
309 DCHECK(thread_checker_.CalledOnValidThread());
311 is_target_lost_ = !had_target;
313 if (state_ == MIRRORING) {
314 if (is_target_lost_) {
315 ReportError();
316 Stop();
317 } else {
318 StartMirroring();
323 // static
324 WebContentsAudioInputStream* WebContentsAudioInputStream::Create(
325 const std::string& device_id,
326 const media::AudioParameters& params,
327 const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
328 AudioMirroringManager* audio_mirroring_manager) {
329 int render_process_id;
330 int main_render_frame_id;
331 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
332 device_id, &render_process_id, &main_render_frame_id)) {
333 return NULL;
336 return new WebContentsAudioInputStream(
337 render_process_id, main_render_frame_id,
338 audio_mirroring_manager,
339 new WebContentsTracker(false),
340 new media::VirtualAudioInputStream(
341 params, worker_task_runner,
342 media::VirtualAudioInputStream::AfterCloseCallback()));
345 WebContentsAudioInputStream::WebContentsAudioInputStream(
346 int render_process_id, int main_render_frame_id,
347 AudioMirroringManager* mirroring_manager,
348 const scoped_refptr<WebContentsTracker>& tracker,
349 media::VirtualAudioInputStream* mixer_stream)
350 : impl_(new Impl(render_process_id, main_render_frame_id,
351 mirroring_manager, tracker, mixer_stream)) {}
353 WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
355 bool WebContentsAudioInputStream::Open() {
356 return impl_->Open();
359 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) {
360 impl_->Start(callback);
363 void WebContentsAudioInputStream::Stop() {
364 impl_->Stop();
367 void WebContentsAudioInputStream::Close() {
368 impl_->Close();
369 delete this;
372 double WebContentsAudioInputStream::GetMaxVolume() {
373 return impl_->mixer_stream()->GetMaxVolume();
376 void WebContentsAudioInputStream::SetVolume(double volume) {
377 impl_->mixer_stream()->SetVolume(volume);
380 double WebContentsAudioInputStream::GetVolume() {
381 return impl_->mixer_stream()->GetVolume();
384 bool WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
385 return impl_->mixer_stream()->SetAutomaticGainControl(enabled);
388 bool WebContentsAudioInputStream::GetAutomaticGainControl() {
389 return impl_->mixer_stream()->GetAutomaticGainControl();
392 bool WebContentsAudioInputStream::IsMuted() {
393 return false;
396 } // namespace content