Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / media / web_contents_audio_input_stream.cc
blob8336eb2c19594d63cacd283eb4c21cab6c83b831
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/renderer_host/media/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/renderer_host/media/audio_mirroring_manager.h"
15 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
16 #include "content/browser/renderer_host/media/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"
21 namespace content {
23 class WebContentsAudioInputStream::Impl
24 : public base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>,
25 public AudioMirroringManager::MirroringDestination {
26 public:
27 // Takes ownership of |mixer_stream|. The rest outlive this instance.
28 Impl(int render_process_id, int render_view_id,
29 AudioMirroringManager* mirroring_manager,
30 const scoped_refptr<WebContentsTracker>& tracker,
31 media::VirtualAudioInputStream* mixer_stream);
33 // Open underlying VirtualAudioInputStream and start tracker.
34 bool Open();
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.
42 void Stop();
44 // Close the underlying VirtualAudioInputStream and stop the tracker.
45 void Close();
47 // Accessor to underlying VirtualAudioInputStream.
48 media::VirtualAudioInputStream* mixer_stream() const {
49 return mixer_stream_.get();
52 private:
53 friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
55 enum State {
56 CONSTRUCTED,
57 OPENED,
58 MIRRORING,
59 CLOSED
62 virtual ~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.
68 void ReportError();
70 // Start/Stop mirroring by posting a call to AudioMirroringManager on the IO
71 // BrowserThread.
72 void StartMirroring();
73 void StopMirroring();
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
83 // changed.
84 void OnTargetChanged(int render_process_id, int render_view_id);
86 // Injected dependencies.
87 AudioMirroringManager* const mirroring_manager_;
88 const scoped_refptr<WebContentsTracker> tracker_;
89 // The AudioInputStream implementation that handles the audio conversion and
90 // mixing details.
91 const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
93 State state_;
95 // Current audio mirroring target.
96 int target_render_process_id_;
97 int target_render_view_id_;
99 // Current callback used to consume the resulting mixed audio data.
100 AudioInputCallback* callback_;
102 base::ThreadChecker thread_checker_;
104 DISALLOW_COPY_AND_ASSIGN(Impl);
107 WebContentsAudioInputStream::Impl::Impl(
108 int render_process_id, int render_view_id,
109 AudioMirroringManager* mirroring_manager,
110 const scoped_refptr<WebContentsTracker>& tracker,
111 media::VirtualAudioInputStream* mixer_stream)
112 : mirroring_manager_(mirroring_manager),
113 tracker_(tracker), mixer_stream_(mixer_stream), state_(CONSTRUCTED),
114 target_render_process_id_(render_process_id),
115 target_render_view_id_(render_view_id),
116 callback_(NULL) {
117 DCHECK(mirroring_manager_);
118 DCHECK(tracker_.get());
119 DCHECK(mixer_stream_.get());
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();
126 WebContentsAudioInputStream::Impl::~Impl() {
127 DCHECK(state_ == CONSTRUCTED || state_ == CLOSED);
130 bool WebContentsAudioInputStream::Impl::Open() {
131 DCHECK(thread_checker_.CalledOnValidThread());
133 DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once.";
135 if (!mixer_stream_->Open())
136 return false;
138 state_ = OPENED;
140 tracker_->Start(
141 target_render_process_id_, target_render_view_id_,
142 base::Bind(&Impl::OnTargetChanged, this));
144 return true;
147 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
148 DCHECK(thread_checker_.CalledOnValidThread());
149 DCHECK(callback);
151 if (state_ != OPENED)
152 return;
154 callback_ = callback;
155 if (IsTargetLost()) {
156 ReportError();
157 callback_ = NULL;
158 return;
161 state_ = MIRRORING;
162 mixer_stream_->Start(callback);
164 StartMirroring();
167 void WebContentsAudioInputStream::Impl::Stop() {
168 DCHECK(thread_checker_.CalledOnValidThread());
170 if (state_ != MIRRORING)
171 return;
173 state_ = OPENED;
175 mixer_stream_->Stop();
176 callback_ = NULL;
178 if (!IsTargetLost())
179 StopMirroring();
182 void WebContentsAudioInputStream::Impl::Close() {
183 DCHECK(thread_checker_.CalledOnValidThread());
185 Stop();
187 if (state_ == OPENED) {
188 state_ = CONSTRUCTED;
189 tracker_->Stop();
190 mixer_stream_->Close();
193 DCHECK_EQ(CONSTRUCTED, state_);
194 state_ = CLOSED;
197 bool WebContentsAudioInputStream::Impl::IsTargetLost() const {
198 DCHECK(thread_checker_.CalledOnValidThread());
200 return target_render_process_id_ <= 0 || target_render_view_id_ <= 0;
203 void WebContentsAudioInputStream::Impl::ReportError() {
204 DCHECK(thread_checker_.CalledOnValidThread());
206 // TODO(miu): Need clean-up of AudioInputCallback interface in a future
207 // change, since its only implementation ignores the first argument entirely
208 callback_->OnError(NULL);
211 void WebContentsAudioInputStream::Impl::StartMirroring() {
212 DCHECK(thread_checker_.CalledOnValidThread());
214 BrowserThread::PostTask(
215 BrowserThread::IO,
216 FROM_HERE,
217 base::Bind(&AudioMirroringManager::StartMirroring,
218 base::Unretained(mirroring_manager_),
219 target_render_process_id_, target_render_view_id_,
220 make_scoped_refptr(this)));
223 void WebContentsAudioInputStream::Impl::StopMirroring() {
224 DCHECK(thread_checker_.CalledOnValidThread());
226 BrowserThread::PostTask(
227 BrowserThread::IO,
228 FROM_HERE,
229 base::Bind(&AudioMirroringManager::StopMirroring,
230 base::Unretained(mirroring_manager_),
231 target_render_process_id_, target_render_view_id_,
232 make_scoped_refptr(this)));
235 media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
236 const media::AudioParameters& params) {
237 // Note: The closure created here holds a reference to "this," which will
238 // guarantee the VirtualAudioInputStream (mixer_stream_) outlives the
239 // VirtualAudioOutputStream.
240 return new media::VirtualAudioOutputStream(
241 params,
242 mixer_stream_.get(),
243 base::Bind(&Impl::ReleaseInput, this));
246 void WebContentsAudioInputStream::Impl::ReleaseInput(
247 media::VirtualAudioOutputStream* stream) {
248 delete stream;
251 void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id,
252 int render_view_id) {
253 DCHECK(thread_checker_.CalledOnValidThread());
255 if (target_render_process_id_ == render_process_id &&
256 target_render_view_id_ == render_view_id) {
257 return;
260 DVLOG(1) << "Target RenderView has changed from "
261 << target_render_process_id_ << ':' << target_render_view_id_
262 << " to " << render_process_id << ':' << render_view_id;
264 if (state_ == MIRRORING)
265 StopMirroring();
267 target_render_process_id_ = render_process_id;
268 target_render_view_id_ = render_view_id;
270 if (state_ == MIRRORING) {
271 if (IsTargetLost()) {
272 ReportError();
273 Stop();
274 } else {
275 StartMirroring();
280 // static
281 WebContentsAudioInputStream* WebContentsAudioInputStream::Create(
282 const std::string& device_id,
283 const media::AudioParameters& params,
284 const scoped_refptr<base::MessageLoopProxy>& worker_loop,
285 AudioMirroringManager* audio_mirroring_manager) {
286 int render_process_id;
287 int render_view_id;
288 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
289 device_id, &render_process_id, &render_view_id)) {
290 return NULL;
293 return new WebContentsAudioInputStream(
294 render_process_id, render_view_id,
295 audio_mirroring_manager,
296 new WebContentsTracker(),
297 new media::VirtualAudioInputStream(
298 params, worker_loop,
299 media::VirtualAudioInputStream::AfterCloseCallback()));
302 WebContentsAudioInputStream::WebContentsAudioInputStream(
303 int render_process_id, int render_view_id,
304 AudioMirroringManager* mirroring_manager,
305 const scoped_refptr<WebContentsTracker>& tracker,
306 media::VirtualAudioInputStream* mixer_stream)
307 : impl_(new Impl(render_process_id, render_view_id,
308 mirroring_manager, tracker, mixer_stream)) {}
310 WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
312 bool WebContentsAudioInputStream::Open() {
313 return impl_->Open();
316 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) {
317 impl_->Start(callback);
320 void WebContentsAudioInputStream::Stop() {
321 impl_->Stop();
324 void WebContentsAudioInputStream::Close() {
325 impl_->Close();
326 delete this;
329 double WebContentsAudioInputStream::GetMaxVolume() {
330 return impl_->mixer_stream()->GetMaxVolume();
333 void WebContentsAudioInputStream::SetVolume(double volume) {
334 impl_->mixer_stream()->SetVolume(volume);
337 double WebContentsAudioInputStream::GetVolume() {
338 return impl_->mixer_stream()->GetVolume();
341 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
342 impl_->mixer_stream()->SetAutomaticGainControl(enabled);
345 bool WebContentsAudioInputStream::GetAutomaticGainControl() {
346 return impl_->mixer_stream()->GetAutomaticGainControl();
349 } // namespace content