Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / capture / web_contents_audio_input_stream.cc
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.
4
5 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
6
7 #include <string>
8
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 "media/audio/virtual_audio_input_stream.h"
19 #include "media/audio/virtual_audio_output_stream.h"
20
21 namespace content {
22
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 main_render_frame_id,
29        AudioMirroringManager* mirroring_manager,
30        const scoped_refptr<WebContentsTracker>& tracker,
31        media::VirtualAudioInputStream* mixer_stream);
32
33   // Open underlying VirtualAudioInputStream and start tracker.
34   bool Open();
35
36   // Start the underlying VirtualAudioInputStream and instruct
37   // AudioMirroringManager to begin a mirroring session.
38   void Start(AudioInputCallback* callback);
39
40   // Stop the underlying VirtualAudioInputStream and instruct
41   // AudioMirroringManager to shutdown a mirroring session.
42   void Stop();
43
44   // Close the underlying VirtualAudioInputStream and stop the tracker.
45   void Close();
46
47   // Accessor to underlying VirtualAudioInputStream.
48   media::VirtualAudioInputStream* mixer_stream() const {
49     return mixer_stream_.get();
50   }
51
52  private:
53   friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
54
55   enum State {
56     CONSTRUCTED,
57     OPENED,
58     MIRRORING,
59     CLOSED
60   };
61
62   virtual ~Impl();
63
64   // Returns true if the mirroring target has been permanently lost.
65   bool IsTargetLost() const;
66
67   // Notifies the consumer callback that the stream is now dead.
68   void ReportError();
69
70   // Start/Stop mirroring by posting a call to AudioMirroringManager on the IO
71   // BrowserThread.
72   void StartMirroring();
73   void StopMirroring();
74
75   // AudioMirroringManager::MirroringDestination implementation
76   virtual media::AudioOutputStream* AddInput(
77       const media::AudioParameters& params) OVERRIDE;
78
79   // Callback which is run when |stream| is closed.  Deletes |stream|.
80   void ReleaseInput(media::VirtualAudioOutputStream* stream);
81
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);
85
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
92   // mixing details.
93   const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
94
95   State state_;
96
97   // Current audio mirroring target.
98   bool target_identified_;
99   int target_render_process_id_;
100   int target_render_view_id_;
101
102   // Current callback used to consume the resulting mixed audio data.
103   AudioInputCallback* callback_;
104
105   base::ThreadChecker thread_checker_;
106
107   DISALLOW_COPY_AND_ASSIGN(Impl);
108 };
109
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),
118       tracker_(tracker),
119       mixer_stream_(mixer_stream),
120       state_(CONSTRUCTED),
121       target_identified_(false),
122       target_render_process_id_(-1),
123       target_render_view_id_(-1),
124       callback_(NULL) {
125   DCHECK(mirroring_manager_);
126   DCHECK(tracker_.get());
127   DCHECK(mixer_stream_.get());
128
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();
132 }
133
134 WebContentsAudioInputStream::Impl::~Impl() {
135   DCHECK(state_ == CONSTRUCTED || state_ == CLOSED);
136 }
137
138 bool WebContentsAudioInputStream::Impl::Open() {
139   DCHECK(thread_checker_.CalledOnValidThread());
140
141   DCHECK_EQ(CONSTRUCTED, state_) << "Illegal to Open more than once.";
142
143   if (!mixer_stream_->Open())
144     return false;
145
146   state_ = OPENED;
147
148   tracker_->Start(
149       initial_render_process_id_, initial_main_render_frame_id_,
150       base::Bind(&Impl::OnTargetChanged, this));
151
152   return true;
153 }
154
155 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
156   DCHECK(thread_checker_.CalledOnValidThread());
157   DCHECK(callback);
158
159   if (state_ != OPENED)
160     return;
161
162   callback_ = callback;
163   if (IsTargetLost()) {
164     ReportError();
165     callback_ = NULL;
166     return;
167   }
168
169   state_ = MIRRORING;
170   mixer_stream_->Start(callback);
171
172   StartMirroring();
173 }
174
175 void WebContentsAudioInputStream::Impl::Stop() {
176   DCHECK(thread_checker_.CalledOnValidThread());
177
178   if (state_ != MIRRORING)
179     return;
180
181   state_ = OPENED;
182
183   mixer_stream_->Stop();
184   callback_ = NULL;
185
186   if (!IsTargetLost())
187     StopMirroring();
188 }
189
190 void WebContentsAudioInputStream::Impl::Close() {
191   DCHECK(thread_checker_.CalledOnValidThread());
192
193   Stop();
194
195   if (state_ == OPENED) {
196     state_ = CONSTRUCTED;
197     tracker_->Stop();
198     mixer_stream_->Close();
199   }
200
201   DCHECK_EQ(CONSTRUCTED, state_);
202   state_ = CLOSED;
203 }
204
205 bool WebContentsAudioInputStream::Impl::IsTargetLost() const {
206   DCHECK(thread_checker_.CalledOnValidThread());
207   if (!target_identified_)
208     return false;
209   return target_render_process_id_ <= 0 || target_render_view_id_ <= 0;
210 }
211
212 void WebContentsAudioInputStream::Impl::ReportError() {
213   DCHECK(thread_checker_.CalledOnValidThread());
214
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);
218 }
219
220 void WebContentsAudioInputStream::Impl::StartMirroring() {
221   DCHECK(thread_checker_.CalledOnValidThread());
222
223   BrowserThread::PostTask(
224       BrowserThread::IO,
225       FROM_HERE,
226       base::Bind(&AudioMirroringManager::StartMirroring,
227                  base::Unretained(mirroring_manager_),
228                  target_render_process_id_, target_render_view_id_,
229                  make_scoped_refptr(this)));
230 }
231
232 void WebContentsAudioInputStream::Impl::StopMirroring() {
233   DCHECK(thread_checker_.CalledOnValidThread());
234
235   BrowserThread::PostTask(
236       BrowserThread::IO,
237       FROM_HERE,
238       base::Bind(&AudioMirroringManager::StopMirroring,
239                  base::Unretained(mirroring_manager_),
240                  target_render_process_id_, target_render_view_id_,
241                  make_scoped_refptr(this)));
242 }
243
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(
250       params,
251       mixer_stream_.get(),
252       base::Bind(&Impl::ReleaseInput, this));
253 }
254
255 void WebContentsAudioInputStream::Impl::ReleaseInput(
256     media::VirtualAudioOutputStream* stream) {
257   delete stream;
258 }
259
260 void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id,
261                                                         int render_view_id) {
262   DCHECK(thread_checker_.CalledOnValidThread());
263
264   if (target_identified_ &&
265       target_render_process_id_ == render_process_id &&
266       target_render_view_id_ == render_view_id) {
267     return;
268   }
269
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;
273
274   if (state_ == MIRRORING)
275     StopMirroring();
276
277   target_identified_ = true;
278   target_render_process_id_ = render_process_id;
279   target_render_view_id_ = render_view_id;
280
281   if (state_ == MIRRORING) {
282     if (IsTargetLost()) {
283       ReportError();
284       Stop();
285     } else {
286       StartMirroring();
287     }
288   }
289 }
290
291 // static
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)) {
301     return NULL;
302   }
303
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()));
311 }
312
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)) {}
320
321 WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
322
323 bool WebContentsAudioInputStream::Open() {
324   return impl_->Open();
325 }
326
327 void WebContentsAudioInputStream::Start(AudioInputCallback* callback) {
328   impl_->Start(callback);
329 }
330
331 void WebContentsAudioInputStream::Stop() {
332   impl_->Stop();
333 }
334
335 void WebContentsAudioInputStream::Close() {
336   impl_->Close();
337   delete this;
338 }
339
340 double WebContentsAudioInputStream::GetMaxVolume() {
341   return impl_->mixer_stream()->GetMaxVolume();
342 }
343
344 void WebContentsAudioInputStream::SetVolume(double volume) {
345   impl_->mixer_stream()->SetVolume(volume);
346 }
347
348 double WebContentsAudioInputStream::GetVolume() {
349   return impl_->mixer_stream()->GetVolume();
350 }
351
352 void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) {
353   impl_->mixer_stream()->SetAutomaticGainControl(enabled);
354 }
355
356 bool WebContentsAudioInputStream::GetAutomaticGainControl() {
357   return impl_->mixer_stream()->GetAutomaticGainControl();
358 }
359
360 }  // namespace content