Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / media / capture / web_contents_audio_input_stream.cc
blob9d42c2d61999d6b4a0215f124d7fab90d56a5197
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 "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 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.
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 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_;
95 State state_;
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),
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());
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())
144 return false;
146 state_ = OPENED;
148 tracker_->Start(
149 initial_render_process_id_, initial_main_render_frame_id_,
150 base::Bind(&Impl::OnTargetChanged, this));
152 return true;
155 void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
156 DCHECK(thread_checker_.CalledOnValidThread());
157 DCHECK(callback);
159 if (state_ != OPENED)
160 return;
162 callback_ = callback;
163 if (IsTargetLost()) {
164 ReportError();
165 callback_ = NULL;
166 return;
169 state_ = MIRRORING;
170 mixer_stream_->Start(callback);
172 StartMirroring();
175 void WebContentsAudioInputStream::Impl::Stop() {
176 DCHECK(thread_checker_.CalledOnValidThread());
178 if (state_ != MIRRORING)
179 return;
181 state_ = OPENED;
183 mixer_stream_->Stop();
184 callback_ = NULL;
186 if (!IsTargetLost())
187 StopMirroring();
190 void WebContentsAudioInputStream::Impl::Close() {
191 DCHECK(thread_checker_.CalledOnValidThread());
193 Stop();
195 if (state_ == OPENED) {
196 state_ = CONSTRUCTED;
197 tracker_->Stop();
198 mixer_stream_->Close();
201 DCHECK_EQ(CONSTRUCTED, state_);
202 state_ = CLOSED;
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;
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(
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)));
232 void WebContentsAudioInputStream::Impl::StopMirroring() {
233 DCHECK(thread_checker_.CalledOnValidThread());
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)));
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));
255 void WebContentsAudioInputStream::Impl::ReleaseInput(
256 media::VirtualAudioOutputStream* stream) {
257 delete 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) {
267 return;
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)
275 StopMirroring();
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()) {
283 ReportError();
284 Stop();
285 } else {
286 StartMirroring();
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;
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() {
332 impl_->Stop();
335 void WebContentsAudioInputStream::Close() {
336 impl_->Close();
337 delete this;
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