Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / media / webrtc_audio_device_impl.cc
blob2e6eed649d5b7c4054565870da03792248bd45c0
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 input_delay_ms_(0),
27 output_delay_ms_(0),
28 initialized_(false),
29 playing_(false),
30 recording_(false),
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());
40 Terminate();
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);
51 if (ret == 0) {
52 delete this;
54 return ret;
56 int WebRtcAudioDeviceImpl::OnData(const int16* audio_data,
57 int sample_rate,
58 int number_of_channels,
59 int number_of_frames,
60 const std::vector<int>& channels,
61 int audio_delay_milliseconds,
62 int current_volume,
63 bool need_audio_processing,
64 bool key_pressed) {
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())
71 return 0;
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
81 // buffer is empty.
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
95 // details.
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(
100 &channels[0],
101 channels.size(),
102 audio_buffer,
103 sample_rate,
104 number_of_channels,
105 frames_per_10_ms,
106 total_delay_ms,
107 current_volume,
108 key_pressed,
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.
115 if (new_mic_level)
116 new_volume = new_mic_level;
119 return new_volume;
122 void WebRtcAudioDeviceImpl::OnSetFormat(
123 const media::AudioParameters& params) {
124 DVLOG(1) << "WebRtcAudioDeviceImpl::OnSetFormat()";
127 void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
128 int sample_rate,
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
148 // is full.
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
160 // cancellation.
161 static const int kBitsPerByte = 8;
162 audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
163 sample_rate,
164 audio_bus->channels(),
165 frames_per_10_ms,
166 audio_data,
167 &elapsed_time_ms,
168 &ntp_time_ms);
169 accumulated_audio_frames += frames_per_10_ms;
170 } else {
171 // TODO(xians): Remove the following code after the APM in WebRTC is
172 // deprecated.
173 audio_transport_callback_->NeedMorePlayData(frames_per_10_ms,
174 bytes_per_sample,
175 audio_bus->channels(),
176 sample_rate,
177 audio_data,
178 num_audio_frames,
179 &elapsed_time_ms,
180 &ntp_time_ms);
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],
192 audio_bus->frames(),
193 bytes_per_sample);
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();
213 renderer_ = NULL;
214 playing_ = false;
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;
223 return 0;
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.
233 initialized_ = true;
235 return 0;
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.
243 if (!initialized_)
244 return 0;
246 StopRecording();
247 StopPlayout();
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) {
260 (*iter)->Stop();
263 initialized_ = false;
264 return 0;
267 bool WebRtcAudioDeviceImpl::Initialized() const {
268 return initialized_;
271 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
272 *available = initialized_;
273 return 0;
276 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
277 return initialized_;
280 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
281 *available = (!capturers_.empty());
282 return 0;
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_)
297 return 0;
300 if (playing_) {
301 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
302 // that the call is ignored the second time.
303 return 0;
306 playing_ = true;
307 return 0;
310 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
311 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
312 if (!playing_) {
313 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
314 return 0;
317 playing_ = false;
318 return 0;
321 bool WebRtcAudioDeviceImpl::Playing() const {
322 return playing_;
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_) {
330 return -1;
334 base::AutoLock auto_lock(lock_);
335 if (recording_)
336 return 0;
338 recording_ = true;
341 return 0;
344 int32_t WebRtcAudioDeviceImpl::StopRecording() {
345 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
347 base::AutoLock auto_lock(lock_);
348 if (!recording_)
349 return 0;
351 recording_ = false;
354 return 0;
357 bool WebRtcAudioDeviceImpl::Recording() const {
358 base::AutoLock auto_lock(lock_);
359 return recording_;
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());
369 if (!capturer.get())
370 return -1;
372 capturer->SetVolume(volume);
373 return 0;
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
380 // capturer.
381 DCHECK(initialized_);
382 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
383 if (!capturer.get())
384 return -1;
386 *volume = static_cast<uint32_t>(capturer->Volume());
388 return 0;
391 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
392 DCHECK(initialized_);
393 *max_volume = kMaxVolumeLevel;
394 return 0;
397 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
398 *min_volume = 0;
399 return 0;
402 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
403 DCHECK(initialized_);
404 *available = renderer_.get() && renderer_->channels() == 2;
405 return 0;
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());
414 if (!capturer.get())
415 return -1;
417 *available = (capturer->source_audio_parameters().channels() == 2);
418 return 0;
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_);
424 return 0;
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_);
430 return 0;
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());
437 if (!capturer.get())
438 return -1;
440 *sample_rate = static_cast<uint32_t>(
441 capturer->source_audio_parameters().sample_rate());
442 return 0;
445 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
446 uint32_t* sample_rate) const {
447 *sample_rate = renderer_.get() ? renderer_->sample_rate() : 0;
448 return 0;
451 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
452 DCHECK(thread_checker_.CalledOnValidThread());
453 DCHECK(renderer);
455 base::AutoLock auto_lock(lock_);
456 if (renderer_.get())
457 return false;
459 if (!renderer->Initialize(this))
460 return false;
462 renderer_ = renderer;
463 return true;
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) ==
475 capturers_.end());
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());
500 DCHECK(sink);
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());
510 DCHECK(sink);
511 base::AutoLock auto_lock(lock_);
512 playout_sinks_.remove(sink);
515 bool WebRtcAudioDeviceImpl::GetAuthorizedDeviceInfoForAudioRenderer(
516 int* session_id,
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,
521 // return false.
522 if (capturers_.empty() || capturers_.size() > 1)
523 return false;
525 return GetDefaultCapturer()->GetPairedOutputParameters(
526 session_id, output_sample_rate, output_frames_per_buffer);
529 } // namespace content