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"
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;
23 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
25 audio_transport_callback_(NULL),
31 microphone_volume_(0),
32 is_audio_track_processing_enabled_(
33 MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled()) {
34 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
37 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
38 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
39 DCHECK(thread_checker_.CalledOnValidThread());
43 int32_t WebRtcAudioDeviceImpl::AddRef() {
44 DCHECK(thread_checker_.CalledOnValidThread());
45 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
48 int32_t WebRtcAudioDeviceImpl::Release() {
49 DCHECK(thread_checker_.CalledOnValidThread());
50 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
56 int WebRtcAudioDeviceImpl::OnData(const int16* audio_data,
58 int number_of_channels,
60 const std::vector<int>& channels,
61 int audio_delay_milliseconds,
63 bool need_audio_processing,
65 int total_delay_ms = 0;
67 base::AutoLock auto_lock(lock_);
68 // Return immediately when not recording or |channels| is empty.
69 // See crbug.com/274017: renderer crash dereferencing invalid channels[0].
70 if (!recording_ || channels.empty())
73 // Store the reported audio delay locally.
74 input_delay_ms_ = audio_delay_milliseconds;
75 total_delay_ms = input_delay_ms_ + output_delay_ms_;
76 DVLOG(2) << "total delay: " << input_delay_ms_ + output_delay_ms_;
79 // Write audio frames in blocks of 10 milliseconds to the registered
80 // webrtc::AudioTransport sink. Keep writing until our internal byte
82 const int16* audio_buffer = audio_data;
83 const int frames_per_10_ms = (sample_rate / 100);
84 CHECK_EQ(number_of_frames % frames_per_10_ms, 0);
85 int accumulated_audio_frames = 0;
86 uint32_t new_volume = 0;
88 // The lock here is to protect a race in the resampler inside webrtc when
89 // there are more than one input stream calling OnData(), which can happen
90 // when the users setup two getUserMedia, one for the microphone, another
91 // for WebAudio. Currently we don't have a better way to fix it except for
92 // adding a lock here to sequence the call.
93 // TODO(xians): Remove this workaround after we move the
94 // webrtc::AudioProcessing module to Chrome. See http://crbug/264611 for
96 base::AutoLock auto_lock(capture_callback_lock_);
97 while (accumulated_audio_frames < number_of_frames) {
98 // Deliver 10ms of recorded 16-bit linear PCM audio.
99 int new_mic_level = audio_transport_callback_->OnDataAvailable(
109 need_audio_processing);
111 accumulated_audio_frames += frames_per_10_ms;
112 audio_buffer += frames_per_10_ms * number_of_channels;
114 // The latest non-zero new microphone level will be returned.
116 new_volume = new_mic_level;
122 void WebRtcAudioDeviceImpl::OnSetFormat(
123 const media::AudioParameters& params) {
124 DVLOG(1) << "WebRtcAudioDeviceImpl::OnSetFormat()";
127 void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
129 int audio_delay_milliseconds) {
130 render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
133 base::AutoLock auto_lock(lock_);
134 DCHECK(audio_transport_callback_);
135 // Store the reported audio delay locally.
136 output_delay_ms_ = audio_delay_milliseconds;
139 int frames_per_10_ms = (sample_rate / 100);
140 int bytes_per_sample = sizeof(render_buffer_[0]);
141 const int bytes_per_10_ms =
142 audio_bus->channels() * frames_per_10_ms * bytes_per_sample;
143 DCHECK_EQ(audio_bus->frames() % frames_per_10_ms, 0);
145 // Get audio frames in blocks of 10 milliseconds from the registered
146 // webrtc::AudioTransport source. Keep reading until our internal buffer
148 uint32_t num_audio_frames = 0;
149 int accumulated_audio_frames = 0;
150 int16* audio_data = &render_buffer_[0];
151 while (accumulated_audio_frames < audio_bus->frames()) {
152 // Get 10ms and append output to temporary byte buffer.
153 if (is_audio_track_processing_enabled_) {
154 // When audio processing is enabled in the audio track, we use
155 // PullRenderData() instead of NeedMorePlayData() to avoid passing the
156 // render data to the APM in WebRTC as reference signal for echo
158 static const int kBitsPerByte = 8;
159 audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
161 audio_bus->channels(),
164 accumulated_audio_frames += frames_per_10_ms;
166 // TODO(xians): Remove the following code after the APM in WebRTC is
168 audio_transport_callback_->NeedMorePlayData(frames_per_10_ms,
170 audio_bus->channels(),
174 accumulated_audio_frames += num_audio_frames;
177 audio_data += bytes_per_10_ms;
180 // De-interleave each channel and convert to 32-bit floating-point
181 // with nominal range -1.0 -> +1.0 to match the callback format.
182 audio_bus->FromInterleaved(&render_buffer_[0],
186 // Pass the render data to the playout sinks.
187 base::AutoLock auto_lock(lock_);
188 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
189 it != playout_sinks_.end(); ++it) {
190 (*it)->OnPlayoutData(audio_bus, sample_rate, audio_delay_milliseconds);
194 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
195 DCHECK(thread_checker_.CalledOnValidThread());
196 DCHECK_EQ(renderer, renderer_);
197 base::AutoLock auto_lock(lock_);
198 // Notify the playout sink of the change.
199 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
200 it != playout_sinks_.end(); ++it) {
201 (*it)->OnPlayoutDataSourceChanged();
208 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
209 webrtc::AudioTransport* audio_callback) {
210 DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
211 DCHECK(thread_checker_.CalledOnValidThread());
212 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL);
213 audio_transport_callback_ = audio_callback;
217 int32_t WebRtcAudioDeviceImpl::Init() {
218 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
219 DCHECK(thread_checker_.CalledOnValidThread());
221 // We need to return a success to continue the initialization of WebRtc VoE
222 // because failure on the capturer_ initialization should not prevent WebRTC
223 // from working. See issue http://crbug.com/144421 for details.
229 int32_t WebRtcAudioDeviceImpl::Terminate() {
230 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
231 DCHECK(thread_checker_.CalledOnValidThread());
233 // Calling Terminate() multiple times in a row is OK.
240 DCHECK(!renderer_.get() || !renderer_->IsStarted())
241 << "The shared audio renderer shouldn't be running";
247 initialized_ = false;
251 bool WebRtcAudioDeviceImpl::Initialized() const {
255 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
256 *available = initialized_;
260 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
264 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
265 *available = (!capturers_.empty());
269 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
270 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
271 DCHECK(thread_checker_.CalledOnValidThread());
272 return (!capturers_.empty());
275 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
276 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
277 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
279 base::AutoLock auto_lock(lock_);
280 if (!audio_transport_callback_)
285 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
286 // that the call is ignored the second time.
294 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
295 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
297 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
305 bool WebRtcAudioDeviceImpl::Playing() const {
309 int32_t WebRtcAudioDeviceImpl::StartRecording() {
310 DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
311 DCHECK(initialized_);
312 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
313 if (!audio_transport_callback_) {
318 base::AutoLock auto_lock(lock_);
328 int32_t WebRtcAudioDeviceImpl::StopRecording() {
329 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
331 base::AutoLock auto_lock(lock_);
341 bool WebRtcAudioDeviceImpl::Recording() const {
342 base::AutoLock auto_lock(lock_);
346 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
347 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
348 DCHECK(initialized_);
350 // Only one microphone is supported at the moment, which is represented by
351 // the default capturer.
352 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
356 capturer->SetVolume(volume);
360 // TODO(henrika): sort out calling thread once we start using this API.
361 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
362 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
363 // We only support one microphone now, which is accessed via the default
365 DCHECK(initialized_);
366 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
370 *volume = static_cast<uint32_t>(capturer->Volume());
375 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
376 DCHECK(initialized_);
377 *max_volume = kMaxVolumeLevel;
381 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
386 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
387 DCHECK(initialized_);
388 *available = renderer_ && renderer_->channels() == 2;
392 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
393 bool* available) const {
394 DCHECK(initialized_);
395 // TODO(xians): These kind of hardware methods do not make much sense since we
396 // support multiple sources. Remove or figure out new APIs for such methods.
397 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
401 *available = (capturer->source_audio_parameters().channels() == 2);
405 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
406 base::AutoLock auto_lock(lock_);
407 *delay_ms = static_cast<uint16_t>(output_delay_ms_);
411 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
412 base::AutoLock auto_lock(lock_);
413 *delay_ms = static_cast<uint16_t>(input_delay_ms_);
417 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
418 uint32_t* sample_rate) const {
419 // We use the default capturer as the recording sample rate.
420 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
424 *sample_rate = static_cast<uint32_t>(
425 capturer->source_audio_parameters().sample_rate());
429 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
430 uint32_t* sample_rate) const {
431 *sample_rate = renderer_ ? renderer_->sample_rate() : 0;
435 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
436 DCHECK(thread_checker_.CalledOnValidThread());
439 base::AutoLock auto_lock(lock_);
443 if (!renderer->Initialize(this))
446 renderer_ = renderer;
450 void WebRtcAudioDeviceImpl::AddAudioCapturer(
451 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
452 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
453 DCHECK(thread_checker_.CalledOnValidThread());
454 DCHECK(capturer.get());
455 DCHECK(!capturer->device_id().empty());
457 base::AutoLock auto_lock(lock_);
458 DCHECK(std::find(capturers_.begin(), capturers_.end(), capturer) ==
460 capturers_.push_back(capturer);
463 // Start the Aec dump if the Aec dump has been enabled and has not been
465 if (aec_dump_file_.IsValid())
469 void WebRtcAudioDeviceImpl::RemoveAudioCapturer(
470 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
471 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
472 DCHECK(thread_checker_.CalledOnValidThread());
473 DCHECK(capturer.get());
474 base::AutoLock auto_lock(lock_);
475 capturers_.remove(capturer);
478 scoped_refptr<WebRtcAudioCapturer>
479 WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
480 base::AutoLock auto_lock(lock_);
481 // Use the last |capturer| which is from the latest getUserMedia call as
482 // the default capture device.
483 return capturers_.empty() ? NULL : capturers_.back();
486 void WebRtcAudioDeviceImpl::AddPlayoutSink(
487 WebRtcPlayoutDataSource::Sink* sink) {
488 DCHECK(thread_checker_.CalledOnValidThread());
490 base::AutoLock auto_lock(lock_);
491 DCHECK(std::find(playout_sinks_.begin(), playout_sinks_.end(), sink) ==
492 playout_sinks_.end());
493 playout_sinks_.push_back(sink);
496 void WebRtcAudioDeviceImpl::RemovePlayoutSink(
497 WebRtcPlayoutDataSource::Sink* sink) {
498 DCHECK(thread_checker_.CalledOnValidThread());
500 base::AutoLock auto_lock(lock_);
501 playout_sinks_.remove(sink);
504 bool WebRtcAudioDeviceImpl::GetAuthorizedDeviceInfoForAudioRenderer(
506 int* output_sample_rate,
507 int* output_frames_per_buffer) {
508 DCHECK(thread_checker_.CalledOnValidThread());
509 // If there is no capturer or there are more than one open capture devices,
511 if (capturers_.empty() || capturers_.size() > 1)
514 return GetDefaultCapturer()->GetPairedOutputParameters(
515 session_id, output_sample_rate, output_frames_per_buffer);
518 void WebRtcAudioDeviceImpl::EnableAecDump(base::File aec_dump_file) {
519 DCHECK(thread_checker_.CalledOnValidThread());
520 DCHECK(aec_dump_file.IsValid());
521 DCHECK(!aec_dump_file_.IsValid());
522 aec_dump_file_ = aec_dump_file.Pass();
526 void WebRtcAudioDeviceImpl::DisableAecDump() {
527 DCHECK(thread_checker_.CalledOnValidThread());
528 // Simply invalidate the |aec_dump_file_| if we have not pass the ownership
530 if (aec_dump_file_.IsValid()) {
531 aec_dump_file_.Close();
535 // We might have call StartAecDump() on one of the capturer. Loop
536 // through all the capturers and call StopAecDump() on each of them.
537 for (CapturerList::const_iterator iter = capturers_.begin();
538 iter != capturers_.end(); ++iter) {
539 (*iter)->StopAecDump();
543 void WebRtcAudioDeviceImpl::MaybeStartAecDump() {
544 DCHECK(thread_checker_.CalledOnValidThread());
545 DCHECK(aec_dump_file_.IsValid());
547 // Start the Aec dump on the current default capturer.
548 scoped_refptr<WebRtcAudioCapturer> default_capturer(GetDefaultCapturer());
549 if (!default_capturer)
552 default_capturer->StartAecDump(aec_dump_file_.Pass());
555 } // namespace content