[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / content / renderer / media / webrtc_audio_device_impl.cc
blob5b87c186e68d7964acbfe5db0ad513ed59cff2f6
1 // Copyright 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/renderer/media/webrtc_audio_device_impl.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "base/win/windows_version.h"
11 #include "content/renderer/media/media_stream_audio_processor.h"
12 #include "content/renderer/media/webrtc_audio_capturer.h"
13 #include "content/renderer/media/webrtc_audio_renderer.h"
14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_parameters.h"
16 #include "media/audio/sample_rates.h"
18 using media::AudioParameters;
19 using media::ChannelLayout;
21 namespace content {
23 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
24 : ref_count_(0),
25 audio_transport_callback_(NULL),
26 output_delay_ms_(0),
27 initialized_(false),
28 playing_(false),
29 recording_(false),
30 microphone_volume_(0) {
31 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
32 // This object can be constructed on either the signaling thread or the main
33 // thread, so we need to detach these thread checkers here and have them
34 // initialize automatically when the first methods are called.
35 signaling_thread_checker_.DetachFromThread();
36 main_thread_checker_.DetachFromThread();
38 worker_thread_checker_.DetachFromThread();
41 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
42 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
43 DCHECK(main_thread_checker_.CalledOnValidThread());
44 Terminate();
47 int32_t WebRtcAudioDeviceImpl::AddRef() {
48 // We can be AddRefed and released on both the UI thread as well as
49 // libjingle's signaling thread.
50 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
53 int32_t WebRtcAudioDeviceImpl::Release() {
54 // We can be AddRefed and released on both the UI thread as well as
55 // libjingle's signaling thread.
56 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
57 if (ret == 0) {
58 delete this;
60 return ret;
63 void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
64 int sample_rate,
65 int audio_delay_milliseconds,
66 base::TimeDelta* current_time) {
67 render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
70 base::AutoLock auto_lock(lock_);
71 DCHECK(audio_transport_callback_);
72 // Store the reported audio delay locally.
73 output_delay_ms_ = audio_delay_milliseconds;
76 int frames_per_10_ms = (sample_rate / 100);
77 int bytes_per_sample = sizeof(render_buffer_[0]);
78 const int bytes_per_10_ms =
79 audio_bus->channels() * frames_per_10_ms * bytes_per_sample;
80 DCHECK_EQ(audio_bus->frames() % frames_per_10_ms, 0);
82 // Get audio frames in blocks of 10 milliseconds from the registered
83 // webrtc::AudioTransport source. Keep reading until our internal buffer
84 // is full.
85 int accumulated_audio_frames = 0;
86 int16* audio_data = &render_buffer_[0];
87 while (accumulated_audio_frames < audio_bus->frames()) {
88 // Get 10ms and append output to temporary byte buffer.
89 int64_t elapsed_time_ms = -1;
90 int64_t ntp_time_ms = -1;
91 static const int kBitsPerByte = 8;
92 audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
93 sample_rate,
94 audio_bus->channels(),
95 frames_per_10_ms,
96 audio_data,
97 &elapsed_time_ms,
98 &ntp_time_ms);
99 accumulated_audio_frames += frames_per_10_ms;
100 if (elapsed_time_ms >= 0) {
101 *current_time = base::TimeDelta::FromMilliseconds(elapsed_time_ms);
103 audio_data += bytes_per_10_ms;
106 // De-interleave each channel and convert to 32-bit floating-point
107 // with nominal range -1.0 -> +1.0 to match the callback format.
108 audio_bus->FromInterleaved(&render_buffer_[0],
109 audio_bus->frames(),
110 bytes_per_sample);
112 // Pass the render data to the playout sinks.
113 base::AutoLock auto_lock(lock_);
114 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
115 it != playout_sinks_.end(); ++it) {
116 (*it)->OnPlayoutData(audio_bus, sample_rate, audio_delay_milliseconds);
120 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
121 DCHECK(main_thread_checker_.CalledOnValidThread());
122 base::AutoLock auto_lock(lock_);
123 DCHECK_EQ(renderer, renderer_.get());
124 // Notify the playout sink of the change.
125 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
126 it != playout_sinks_.end(); ++it) {
127 (*it)->OnPlayoutDataSourceChanged();
130 renderer_ = NULL;
131 playing_ = false;
134 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
135 webrtc::AudioTransport* audio_callback) {
136 DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
137 DCHECK(signaling_thread_checker_.CalledOnValidThread());
138 base::AutoLock lock(lock_);
139 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL);
140 audio_transport_callback_ = audio_callback;
141 return 0;
144 int32_t WebRtcAudioDeviceImpl::Init() {
145 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
146 DCHECK(signaling_thread_checker_.CalledOnValidThread());
148 // We need to return a success to continue the initialization of WebRtc VoE
149 // because failure on the capturer_ initialization should not prevent WebRTC
150 // from working. See issue http://crbug.com/144421 for details.
151 initialized_ = true;
153 return 0;
156 int32_t WebRtcAudioDeviceImpl::Terminate() {
157 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
158 DCHECK(signaling_thread_checker_.CalledOnValidThread());
160 // Calling Terminate() multiple times in a row is OK.
161 if (!initialized_)
162 return 0;
164 StopRecording();
165 StopPlayout();
167 DCHECK(!renderer_.get() || !renderer_->IsStarted())
168 << "The shared audio renderer shouldn't be running";
170 // Stop all the capturers to ensure no further OnData() and
171 // RemoveAudioCapturer() callback.
172 // Cache the capturers in a local list since WebRtcAudioCapturer::Stop()
173 // will trigger RemoveAudioCapturer() callback.
174 CapturerList capturers;
175 capturers.swap(capturers_);
176 for (CapturerList::const_iterator iter = capturers.begin();
177 iter != capturers.end(); ++iter) {
178 (*iter)->Stop();
181 initialized_ = false;
182 return 0;
185 bool WebRtcAudioDeviceImpl::Initialized() const {
186 DCHECK(signaling_thread_checker_.CalledOnValidThread());
187 return initialized_;
190 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
191 DCHECK(signaling_thread_checker_.CalledOnValidThread());
192 *available = initialized_;
193 return 0;
196 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
197 DCHECK(signaling_thread_checker_.CalledOnValidThread());
198 return initialized_;
201 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
202 DCHECK(signaling_thread_checker_.CalledOnValidThread());
203 base::AutoLock auto_lock(lock_);
204 *available = (!capturers_.empty());
205 return 0;
208 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
209 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
210 DCHECK(signaling_thread_checker_.CalledOnValidThread());
211 base::AutoLock auto_lock(lock_);
212 return (!capturers_.empty());
215 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
216 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
217 DCHECK(worker_thread_checker_.CalledOnValidThread());
218 base::AutoLock auto_lock(lock_);
219 if (!audio_transport_callback_) {
220 LOG(ERROR) << "Audio transport is missing";
221 return 0;
224 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
225 // that the call is ignored the second time.
226 playing_ = true;
227 return 0;
230 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
231 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
232 DCHECK(initialized_);
233 // Can be called both from the worker thread (e.g. when called from webrtc)
234 // or the signaling thread (e.g. when we call it ourselves internally).
235 // The order in this check is important so that we won't incorrectly
236 // initialize worker_thread_checker_ on the signaling thread.
237 DCHECK(signaling_thread_checker_.CalledOnValidThread() ||
238 worker_thread_checker_.CalledOnValidThread());
239 base::AutoLock auto_lock(lock_);
240 // webrtc::VoiceEngine assumes that it is OK to call Stop() multiple times.
241 playing_ = false;
242 return 0;
245 bool WebRtcAudioDeviceImpl::Playing() const {
246 DCHECK(worker_thread_checker_.CalledOnValidThread());
247 base::AutoLock auto_lock(lock_);
248 return playing_;
251 int32_t WebRtcAudioDeviceImpl::StartRecording() {
252 DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
253 DCHECK(worker_thread_checker_.CalledOnValidThread());
254 DCHECK(initialized_);
255 base::AutoLock auto_lock(lock_);
256 if (!audio_transport_callback_) {
257 LOG(ERROR) << "Audio transport is missing";
258 return -1;
261 recording_ = true;
263 return 0;
266 int32_t WebRtcAudioDeviceImpl::StopRecording() {
267 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
268 DCHECK(initialized_);
269 // Can be called both from the worker thread (e.g. when called from webrtc)
270 // or the signaling thread (e.g. when we call it ourselves internally).
271 // The order in this check is important so that we won't incorrectly
272 // initialize worker_thread_checker_ on the signaling thread.
273 DCHECK(signaling_thread_checker_.CalledOnValidThread() ||
274 worker_thread_checker_.CalledOnValidThread());
276 base::AutoLock auto_lock(lock_);
277 recording_ = false;
278 return 0;
281 bool WebRtcAudioDeviceImpl::Recording() const {
282 DCHECK(worker_thread_checker_.CalledOnValidThread());
283 base::AutoLock auto_lock(lock_);
284 return recording_;
287 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
288 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
289 DCHECK(signaling_thread_checker_.CalledOnValidThread());
290 DCHECK(initialized_);
292 // Only one microphone is supported at the moment, which is represented by
293 // the default capturer.
294 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
295 if (!capturer.get())
296 return -1;
298 capturer->SetVolume(volume);
299 return 0;
302 // TODO(henrika): sort out calling thread once we start using this API.
303 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
304 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
305 DCHECK(signaling_thread_checker_.CalledOnValidThread());
306 // We only support one microphone now, which is accessed via the default
307 // capturer.
308 DCHECK(initialized_);
309 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
310 if (!capturer.get())
311 return -1;
313 *volume = static_cast<uint32_t>(capturer->Volume());
315 return 0;
318 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
319 DCHECK(initialized_);
320 DCHECK(signaling_thread_checker_.CalledOnValidThread());
321 *max_volume = kMaxVolumeLevel;
322 return 0;
325 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
326 DCHECK(signaling_thread_checker_.CalledOnValidThread());
327 *min_volume = 0;
328 return 0;
331 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
332 DCHECK(initialized_);
333 // This method is called during initialization on the signaling thread and
334 // then later on the worker thread. Due to this we cannot DCHECK on what
335 // thread we're on since it might incorrectly initialize the
336 // worker_thread_checker_.
337 base::AutoLock auto_lock(lock_);
338 *available = renderer_.get() && renderer_->channels() == 2;
339 return 0;
342 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
343 bool* available) const {
344 DCHECK(initialized_);
345 // This method is called during initialization on the signaling thread and
346 // then later on the worker thread. Due to this we cannot DCHECK on what
347 // thread we're on since it might incorrectly initialize the
348 // worker_thread_checker_.
350 // TODO(xians): These kind of hardware methods do not make much sense since we
351 // support multiple sources. Remove or figure out new APIs for such methods.
352 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
353 if (!capturer.get())
354 return -1;
356 *available = (capturer->source_audio_parameters().channels() == 2);
357 return 0;
360 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
361 DCHECK(worker_thread_checker_.CalledOnValidThread());
362 base::AutoLock auto_lock(lock_);
363 *delay_ms = static_cast<uint16_t>(output_delay_ms_);
364 return 0;
367 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
368 DCHECK(signaling_thread_checker_.CalledOnValidThread());
370 // There is no way to report a correct delay value to WebRTC since there
371 // might be multiple WebRtcAudioCapturer instances.
372 NOTREACHED();
373 return -1;
376 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
377 uint32_t* sample_rate) const {
378 DCHECK(signaling_thread_checker_.CalledOnValidThread());
379 // We use the default capturer as the recording sample rate.
380 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
381 if (!capturer.get())
382 return -1;
384 *sample_rate = static_cast<uint32_t>(
385 capturer->source_audio_parameters().sample_rate());
386 return 0;
389 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
390 uint32_t* sample_rate) const {
391 DCHECK(signaling_thread_checker_.CalledOnValidThread());
392 *sample_rate = renderer_.get() ? renderer_->sample_rate() : 0;
393 return 0;
396 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
397 DCHECK(main_thread_checker_.CalledOnValidThread());
398 DCHECK(renderer);
400 base::AutoLock auto_lock(lock_);
401 if (renderer_.get())
402 return false;
404 if (!renderer->Initialize(this))
405 return false;
407 renderer_ = renderer;
408 return true;
411 void WebRtcAudioDeviceImpl::AddAudioCapturer(
412 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
413 DCHECK(main_thread_checker_.CalledOnValidThread());
414 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
415 DCHECK(capturer.get());
416 DCHECK(!capturer->device_id().empty());
418 base::AutoLock auto_lock(lock_);
419 DCHECK(std::find(capturers_.begin(), capturers_.end(), capturer) ==
420 capturers_.end());
421 capturers_.push_back(capturer);
424 void WebRtcAudioDeviceImpl::RemoveAudioCapturer(
425 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
426 DCHECK(main_thread_checker_.CalledOnValidThread());
427 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
428 DCHECK(capturer.get());
429 base::AutoLock auto_lock(lock_);
430 capturers_.remove(capturer);
433 scoped_refptr<WebRtcAudioCapturer>
434 WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
435 // Called on the signaling thread (during initialization), worker
436 // thread during capture or main thread for a WebAudio source.
437 // We can't DCHECK on those three checks here since GetDefaultCapturer
438 // may be the first call and therefore could incorrectly initialize the
439 // thread checkers.
440 DCHECK(initialized_);
441 base::AutoLock auto_lock(lock_);
442 // Use the last |capturer| which is from the latest getUserMedia call as
443 // the default capture device.
444 return capturers_.empty() ? NULL : capturers_.back();
447 void WebRtcAudioDeviceImpl::AddPlayoutSink(
448 WebRtcPlayoutDataSource::Sink* sink) {
449 DCHECK(main_thread_checker_.CalledOnValidThread());
450 DCHECK(sink);
451 base::AutoLock auto_lock(lock_);
452 DCHECK(std::find(playout_sinks_.begin(), playout_sinks_.end(), sink) ==
453 playout_sinks_.end());
454 playout_sinks_.push_back(sink);
457 void WebRtcAudioDeviceImpl::RemovePlayoutSink(
458 WebRtcPlayoutDataSource::Sink* sink) {
459 DCHECK(main_thread_checker_.CalledOnValidThread());
460 DCHECK(sink);
461 base::AutoLock auto_lock(lock_);
462 playout_sinks_.remove(sink);
465 bool WebRtcAudioDeviceImpl::GetAuthorizedDeviceInfoForAudioRenderer(
466 int* session_id,
467 int* output_sample_rate,
468 int* output_frames_per_buffer) {
469 DCHECK(main_thread_checker_.CalledOnValidThread());
470 base::AutoLock lock(lock_);
471 // If there is no capturer or there are more than one open capture devices,
472 // return false.
473 if (capturers_.size() != 1)
474 return false;
476 return capturers_.back()->GetPairedOutputParameters(
477 session_id, output_sample_rate, output_frames_per_buffer);
480 } // namespace content