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 base::TimeDelta
* current_time
) {
131 render_buffer_
.resize(audio_bus
->frames() * audio_bus
->channels());
134 base::AutoLock
auto_lock(lock_
);
135 DCHECK(audio_transport_callback_
);
136 // Store the reported audio delay locally.
137 output_delay_ms_
= audio_delay_milliseconds
;
140 int frames_per_10_ms
= (sample_rate
/ 100);
141 int bytes_per_sample
= sizeof(render_buffer_
[0]);
142 const int bytes_per_10_ms
=
143 audio_bus
->channels() * frames_per_10_ms
* bytes_per_sample
;
144 DCHECK_EQ(audio_bus
->frames() % frames_per_10_ms
, 0);
146 // Get audio frames in blocks of 10 milliseconds from the registered
147 // webrtc::AudioTransport source. Keep reading until our internal buffer
149 uint32_t num_audio_frames
= 0;
150 int accumulated_audio_frames
= 0;
151 int16
* audio_data
= &render_buffer_
[0];
152 while (accumulated_audio_frames
< audio_bus
->frames()) {
153 // Get 10ms and append output to temporary byte buffer.
154 int64_t elapsed_time_ms
= -1;
155 int64_t ntp_time_ms
= -1;
156 if (is_audio_track_processing_enabled_
) {
157 // When audio processing is enabled in the audio track, we use
158 // PullRenderData() instead of NeedMorePlayData() to avoid passing the
159 // render data to the APM in WebRTC as reference signal for echo
161 static const int kBitsPerByte
= 8;
162 audio_transport_callback_
->PullRenderData(bytes_per_sample
* kBitsPerByte
,
164 audio_bus
->channels(),
169 accumulated_audio_frames
+= frames_per_10_ms
;
171 // TODO(xians): Remove the following code after the APM in WebRTC is
173 audio_transport_callback_
->NeedMorePlayData(frames_per_10_ms
,
175 audio_bus
->channels(),
181 accumulated_audio_frames
+= num_audio_frames
;
183 if (elapsed_time_ms
>= 0) {
184 *current_time
= base::TimeDelta::FromMilliseconds(elapsed_time_ms
);
186 audio_data
+= bytes_per_10_ms
;
189 // De-interleave each channel and convert to 32-bit floating-point
190 // with nominal range -1.0 -> +1.0 to match the callback format.
191 audio_bus
->FromInterleaved(&render_buffer_
[0],
195 // Pass the render data to the playout sinks.
196 base::AutoLock
auto_lock(lock_
);
197 for (PlayoutDataSinkList::const_iterator it
= playout_sinks_
.begin();
198 it
!= playout_sinks_
.end(); ++it
) {
199 (*it
)->OnPlayoutData(audio_bus
, sample_rate
, audio_delay_milliseconds
);
203 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer
* renderer
) {
204 DCHECK(thread_checker_
.CalledOnValidThread());
205 DCHECK_EQ(renderer
, renderer_
.get());
206 base::AutoLock
auto_lock(lock_
);
207 // Notify the playout sink of the change.
208 for (PlayoutDataSinkList::const_iterator it
= playout_sinks_
.begin();
209 it
!= playout_sinks_
.end(); ++it
) {
210 (*it
)->OnPlayoutDataSourceChanged();
217 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
218 webrtc::AudioTransport
* audio_callback
) {
219 DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
220 DCHECK(thread_checker_
.CalledOnValidThread());
221 DCHECK_EQ(audio_transport_callback_
== NULL
, audio_callback
!= NULL
);
222 audio_transport_callback_
= audio_callback
;
226 int32_t WebRtcAudioDeviceImpl::Init() {
227 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
228 DCHECK(thread_checker_
.CalledOnValidThread());
230 // We need to return a success to continue the initialization of WebRtc VoE
231 // because failure on the capturer_ initialization should not prevent WebRTC
232 // from working. See issue http://crbug.com/144421 for details.
238 int32_t WebRtcAudioDeviceImpl::Terminate() {
239 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
240 DCHECK(thread_checker_
.CalledOnValidThread());
242 // Calling Terminate() multiple times in a row is OK.
249 DCHECK(!renderer_
.get() || !renderer_
->IsStarted())
250 << "The shared audio renderer shouldn't be running";
252 // Stop all the capturers to ensure no further OnData() and
253 // RemoveAudioCapturer() callback.
254 // Cache the capturers in a local list since WebRtcAudioCapturer::Stop()
255 // will trigger RemoveAudioCapturer() callback.
256 CapturerList capturers
;
257 capturers
.swap(capturers_
);
258 for (CapturerList::const_iterator iter
= capturers
.begin();
259 iter
!= capturers
.end(); ++iter
) {
263 initialized_
= false;
267 bool WebRtcAudioDeviceImpl::Initialized() const {
271 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available
) {
272 *available
= initialized_
;
276 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
280 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available
) {
281 *available
= (!capturers_
.empty());
285 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
286 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
287 DCHECK(thread_checker_
.CalledOnValidThread());
288 return (!capturers_
.empty());
291 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
292 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
293 LOG_IF(ERROR
, !audio_transport_callback_
) << "Audio transport is missing";
295 base::AutoLock
auto_lock(lock_
);
296 if (!audio_transport_callback_
)
301 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
302 // that the call is ignored the second time.
310 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
311 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
313 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
321 bool WebRtcAudioDeviceImpl::Playing() const {
325 int32_t WebRtcAudioDeviceImpl::StartRecording() {
326 DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
327 DCHECK(initialized_
);
328 LOG_IF(ERROR
, !audio_transport_callback_
) << "Audio transport is missing";
329 if (!audio_transport_callback_
) {
334 base::AutoLock
auto_lock(lock_
);
344 int32_t WebRtcAudioDeviceImpl::StopRecording() {
345 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
347 base::AutoLock
auto_lock(lock_
);
357 bool WebRtcAudioDeviceImpl::Recording() const {
358 base::AutoLock
auto_lock(lock_
);
362 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume
) {
363 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume
<< ")";
364 DCHECK(initialized_
);
366 // Only one microphone is supported at the moment, which is represented by
367 // the default capturer.
368 scoped_refptr
<WebRtcAudioCapturer
> capturer(GetDefaultCapturer());
372 capturer
->SetVolume(volume
);
376 // TODO(henrika): sort out calling thread once we start using this API.
377 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume
) const {
378 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
379 // We only support one microphone now, which is accessed via the default
381 DCHECK(initialized_
);
382 scoped_refptr
<WebRtcAudioCapturer
> capturer(GetDefaultCapturer());
386 *volume
= static_cast<uint32_t>(capturer
->Volume());
391 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume
) const {
392 DCHECK(initialized_
);
393 *max_volume
= kMaxVolumeLevel
;
397 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume
) const {
402 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available
) const {
403 DCHECK(initialized_
);
404 *available
= renderer_
.get() && renderer_
->channels() == 2;
408 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
409 bool* available
) const {
410 DCHECK(initialized_
);
411 // TODO(xians): These kind of hardware methods do not make much sense since we
412 // support multiple sources. Remove or figure out new APIs for such methods.
413 scoped_refptr
<WebRtcAudioCapturer
> capturer(GetDefaultCapturer());
417 *available
= (capturer
->source_audio_parameters().channels() == 2);
421 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms
) const {
422 base::AutoLock
auto_lock(lock_
);
423 *delay_ms
= static_cast<uint16_t>(output_delay_ms_
);
427 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms
) const {
428 base::AutoLock
auto_lock(lock_
);
429 *delay_ms
= static_cast<uint16_t>(input_delay_ms_
);
433 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
434 uint32_t* sample_rate
) const {
435 // We use the default capturer as the recording sample rate.
436 scoped_refptr
<WebRtcAudioCapturer
> capturer(GetDefaultCapturer());
440 *sample_rate
= static_cast<uint32_t>(
441 capturer
->source_audio_parameters().sample_rate());
445 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
446 uint32_t* sample_rate
) const {
447 *sample_rate
= renderer_
.get() ? renderer_
->sample_rate() : 0;
451 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer
* renderer
) {
452 DCHECK(thread_checker_
.CalledOnValidThread());
455 base::AutoLock
auto_lock(lock_
);
459 if (!renderer
->Initialize(this))
462 renderer_
= renderer
;
466 void WebRtcAudioDeviceImpl::AddAudioCapturer(
467 const scoped_refptr
<WebRtcAudioCapturer
>& capturer
) {
468 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
469 DCHECK(thread_checker_
.CalledOnValidThread());
470 DCHECK(capturer
.get());
471 DCHECK(!capturer
->device_id().empty());
473 base::AutoLock
auto_lock(lock_
);
474 DCHECK(std::find(capturers_
.begin(), capturers_
.end(), capturer
) ==
476 capturers_
.push_back(capturer
);
480 void WebRtcAudioDeviceImpl::RemoveAudioCapturer(
481 const scoped_refptr
<WebRtcAudioCapturer
>& capturer
) {
482 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
483 DCHECK(thread_checker_
.CalledOnValidThread());
484 DCHECK(capturer
.get());
485 base::AutoLock
auto_lock(lock_
);
486 capturers_
.remove(capturer
);
489 scoped_refptr
<WebRtcAudioCapturer
>
490 WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
491 base::AutoLock
auto_lock(lock_
);
492 // Use the last |capturer| which is from the latest getUserMedia call as
493 // the default capture device.
494 return capturers_
.empty() ? NULL
: capturers_
.back();
497 void WebRtcAudioDeviceImpl::AddPlayoutSink(
498 WebRtcPlayoutDataSource::Sink
* sink
) {
499 DCHECK(thread_checker_
.CalledOnValidThread());
501 base::AutoLock
auto_lock(lock_
);
502 DCHECK(std::find(playout_sinks_
.begin(), playout_sinks_
.end(), sink
) ==
503 playout_sinks_
.end());
504 playout_sinks_
.push_back(sink
);
507 void WebRtcAudioDeviceImpl::RemovePlayoutSink(
508 WebRtcPlayoutDataSource::Sink
* sink
) {
509 DCHECK(thread_checker_
.CalledOnValidThread());
511 base::AutoLock
auto_lock(lock_
);
512 playout_sinks_
.remove(sink
);
515 bool WebRtcAudioDeviceImpl::GetAuthorizedDeviceInfoForAudioRenderer(
517 int* output_sample_rate
,
518 int* output_frames_per_buffer
) {
519 DCHECK(thread_checker_
.CalledOnValidThread());
520 // If there is no capturer or there are more than one open capture devices,
522 if (capturers_
.empty() || capturers_
.size() > 1)
525 return GetDefaultCapturer()->GetPairedOutputParameters(
526 session_id
, output_sample_rate
, output_frames_per_buffer
);
529 } // namespace content