Fix build break
[chromium-blink-merge.git] / content / renderer / media / webrtc_audio_device_impl.cc
blob11091a62e0a0201cdc7a729a051394ef1efd0fd5
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/string_util.h"
10 #include "base/win/windows_version.h"
11 #include "content/renderer/media/webrtc_audio_capturer.h"
12 #include "content/renderer/media/webrtc_audio_renderer.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "media/audio/audio_parameters.h"
15 #include "media/audio/audio_util.h"
16 #include "media/audio/sample_rates.h"
18 using media::AudioParameters;
19 using media::ChannelLayout;
21 namespace content {
23 namespace {
25 const double kMaxVolumeLevel = 255.0;
27 } // namespace
29 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
30 : ref_count_(0),
31 audio_transport_callback_(NULL),
32 input_delay_ms_(0),
33 output_delay_ms_(0),
34 initialized_(false),
35 playing_(false),
36 recording_(false),
37 agc_is_enabled_(false),
38 microphone_volume_(0) {
39 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
42 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
43 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
44 DCHECK(thread_checker_.CalledOnValidThread());
45 Terminate();
48 int32_t WebRtcAudioDeviceImpl::AddRef() {
49 DCHECK(thread_checker_.CalledOnValidThread());
50 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
53 int32_t WebRtcAudioDeviceImpl::Release() {
54 DCHECK(thread_checker_.CalledOnValidThread());
55 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
56 if (ret == 0) {
57 delete this;
59 return ret;
62 void WebRtcAudioDeviceImpl::CaptureData(const int16* audio_data,
63 int number_of_channels,
64 int number_of_frames,
65 int audio_delay_milliseconds,
66 double volume) {
67 DCHECK_LE(number_of_frames, input_buffer_size());
68 #if defined(OS_WIN) || defined(OS_MACOSX)
69 DCHECK_LE(volume, 1.0);
70 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
71 // We have a special situation on Linux where the microphone volume can be
72 // "higher than maximum". The input volume slider in the sound preference
73 // allows the user to set a scaling that is higher than 100%. It means that
74 // even if the reported maximum levels is N, the actual microphone level can
75 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
76 DCHECK_LE(volume, 1.6);
77 #endif
79 media::AudioParameters input_audio_parameters;
80 int output_delay_ms = 0;
82 base::AutoLock auto_lock(lock_);
83 if (!recording_)
84 return;
86 // Take a copy of the input parameters while we are under a lock.
87 input_audio_parameters = input_audio_parameters_;
89 // Store the reported audio delay locally.
90 input_delay_ms_ = audio_delay_milliseconds;
91 output_delay_ms = output_delay_ms_;
93 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
94 // webrtc::VoiceEngine.
95 microphone_volume_ = static_cast<uint32_t>(volume * kMaxVolumeLevel);
98 const int channels = number_of_channels;
99 DCHECK_LE(channels, input_channels());
100 uint32_t new_mic_level = 0;
102 int samples_per_sec = input_sample_rate();
103 if (samples_per_sec == 44100) {
104 // Even if the hardware runs at 44.1kHz, we use 44.0 internally.
105 samples_per_sec = 44000;
107 const int samples_per_10_msec = (samples_per_sec / 100);
108 int bytes_per_sample = input_audio_parameters.bits_per_sample() / 8;
109 const int bytes_per_10_msec =
110 channels * samples_per_10_msec * bytes_per_sample;
111 int accumulated_audio_samples = 0;
113 const uint8* audio_byte_buffer = reinterpret_cast<const uint8*>(audio_data);
115 // Write audio samples in blocks of 10 milliseconds to the registered
116 // webrtc::AudioTransport sink. Keep writing until our internal byte
117 // buffer is empty.
118 while (accumulated_audio_samples < number_of_frames) {
119 // Deliver 10ms of recorded 16-bit linear PCM audio.
120 audio_transport_callback_->RecordedDataIsAvailable(
121 audio_byte_buffer,
122 samples_per_10_msec,
123 bytes_per_sample,
124 channels,
125 samples_per_sec,
126 input_delay_ms_ + output_delay_ms,
127 0, // TODO(henrika): |clock_drift| parameter is not utilized today.
128 microphone_volume_,
129 new_mic_level);
131 accumulated_audio_samples += samples_per_10_msec;
132 audio_byte_buffer += bytes_per_10_msec;
135 // The AGC returns a non-zero microphone level if it has been decided
136 // that a new level should be set.
137 if (new_mic_level != 0) {
138 // Use IPC and set the new level. Note that, it will take some time
139 // before the new level is effective due to the IPC scheme.
140 // During this time, |current_mic_level| will contain "non-valid" values
141 // and it might reduce the AGC performance. Measurements on Windows 7 have
142 // shown that we might receive old volume levels for one or two callbacks.
143 SetMicrophoneVolume(new_mic_level);
147 void WebRtcAudioDeviceImpl::SetCaptureFormat(
148 const media::AudioParameters& params) {
149 DVLOG(1) << "WebRtcAudioDeviceImpl::SetCaptureFormat()";
150 DCHECK(thread_checker_.CalledOnValidThread());
151 base::AutoLock auto_lock(lock_);
152 input_audio_parameters_ = params;
155 void WebRtcAudioDeviceImpl::RenderData(uint8* audio_data,
156 int number_of_channels,
157 int number_of_frames,
158 int audio_delay_milliseconds) {
159 DCHECK_LE(number_of_frames, output_buffer_size());
161 base::AutoLock auto_lock(lock_);
162 // Store the reported audio delay locally.
163 output_delay_ms_ = audio_delay_milliseconds;
166 const int channels = number_of_channels;
167 DCHECK_LE(channels, output_channels());
169 int samples_per_sec = output_sample_rate();
170 if (samples_per_sec == 44100) {
171 // Even if the hardware runs at 44.1kHz, we use 44.0 internally.
172 samples_per_sec = 44000;
174 int samples_per_10_msec = (samples_per_sec / 100);
175 int bytes_per_sample = output_audio_parameters_.bits_per_sample() / 8;
176 const int bytes_per_10_msec =
177 channels * samples_per_10_msec * bytes_per_sample;
179 uint32_t num_audio_samples = 0;
180 int accumulated_audio_samples = 0;
182 // Get audio samples in blocks of 10 milliseconds from the registered
183 // webrtc::AudioTransport source. Keep reading until our internal buffer
184 // is full.
185 while (accumulated_audio_samples < number_of_frames) {
186 // Get 10ms and append output to temporary byte buffer.
187 audio_transport_callback_->NeedMorePlayData(samples_per_10_msec,
188 bytes_per_sample,
189 channels,
190 samples_per_sec,
191 audio_data,
192 num_audio_samples);
193 accumulated_audio_samples += num_audio_samples;
194 audio_data += bytes_per_10_msec;
198 void WebRtcAudioDeviceImpl::SetRenderFormat(const AudioParameters& params) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 output_audio_parameters_ = params;
203 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
204 DCHECK(thread_checker_.CalledOnValidThread());
205 DCHECK_EQ(renderer, renderer_);
206 base::AutoLock auto_lock(lock_);
207 renderer_ = NULL;
208 playing_ = false;
211 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
212 webrtc::AudioTransport* audio_callback) {
213 DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
214 DCHECK(thread_checker_.CalledOnValidThread());
215 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL);
216 audio_transport_callback_ = audio_callback;
217 return 0;
220 int32_t WebRtcAudioDeviceImpl::Init() {
221 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
222 DCHECK(thread_checker_.CalledOnValidThread());
224 if (initialized_)
225 return 0;
227 DCHECK(!capturer_);
228 capturer_ = WebRtcAudioCapturer::CreateCapturer();
229 if (capturer_)
230 capturer_->AddCapturerSink(this);
232 // We need to return a success to continue the initialization of WebRtc VoE
233 // because failure on the capturer_ initialization should not prevent WebRTC
234 // from working. See issue http://crbug.com/144421 for details.
235 initialized_ = true;
237 return 0;
240 int32_t WebRtcAudioDeviceImpl::Terminate() {
241 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
242 DCHECK(thread_checker_.CalledOnValidThread());
244 // Calling Terminate() multiple times in a row is OK.
245 if (!initialized_)
246 return 0;
248 StopRecording();
249 StopPlayout();
251 // It is necessary to stop the |renderer_| before going away.
252 if (renderer_) {
253 renderer_->Stop();
254 renderer_ = NULL;
257 if (capturer_) {
258 // |capturer_| is stopped by the media stream, so do not need to
259 // call Stop() here.
260 capturer_->RemoveCapturerSink(this);
261 capturer_ = NULL;
264 initialized_ = false;
265 return 0;
268 bool WebRtcAudioDeviceImpl::Initialized() const {
269 return initialized_;
272 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
273 *available = initialized_;
274 return 0;
277 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
278 return initialized_;
281 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
282 *available = (capturer_ != NULL);
283 return 0;
286 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
287 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
288 DCHECK(thread_checker_.CalledOnValidThread());
289 return (capturer_ != NULL);
292 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
293 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
294 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
296 base::AutoLock auto_lock(lock_);
297 if (!audio_transport_callback_)
298 return 0;
301 if (playing_) {
302 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
303 // that the call is ignored the second time.
304 return 0;
307 playing_ = true;
308 start_render_time_ = base::Time::Now();
309 return 0;
312 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
313 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
314 if (!playing_) {
315 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
316 return 0;
319 // Add histogram data to be uploaded as part of an UMA logging event.
320 // This histogram keeps track of total playout times.
321 if (!start_render_time_.is_null()) {
322 base::TimeDelta render_time = base::Time::Now() - start_render_time_;
323 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time);
326 playing_ = false;
327 return 0;
330 bool WebRtcAudioDeviceImpl::Playing() const {
331 return playing_;
334 int32_t WebRtcAudioDeviceImpl::StartRecording() {
335 DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
336 DCHECK(initialized_);
337 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
338 if (!audio_transport_callback_) {
339 return -1;
342 start_capture_time_ = base::Time::Now();
344 base::AutoLock auto_lock(lock_);
345 recording_ = true;
347 return 0;
350 int32_t WebRtcAudioDeviceImpl::StopRecording() {
351 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
352 if (!recording_) {
353 return 0;
356 // Add histogram data to be uploaded as part of an UMA logging event.
357 // This histogram keeps track of total recording times.
358 if (!start_capture_time_.is_null()) {
359 base::TimeDelta capture_time = base::Time::Now() - start_capture_time_;
360 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioCaptureTime", capture_time);
363 base::AutoLock auto_lock(lock_);
364 recording_ = false;
366 return 0;
369 bool WebRtcAudioDeviceImpl::Recording() const {
370 base::AutoLock auto_lock(lock_);
371 return recording_;
374 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) {
375 DVLOG(1) << "WebRtcAudioDeviceImpl::SetAGC(enable=" << enable << ")";
376 DCHECK(initialized_);
378 // Return early if we are not changing the AGC state.
379 if (enable == agc_is_enabled_)
380 return 0;
382 // The current implementation does not support changing the AGC state while
383 // recording. Using this approach simplifies the design and it is also
384 // inline with the latest WebRTC standard.
385 if (!capturer_ || capturer_->is_recording())
386 return -1;
388 capturer_->SetAutomaticGainControl(enable);
389 agc_is_enabled_ = enable;
390 return 0;
393 bool WebRtcAudioDeviceImpl::AGC() const {
394 DVLOG(1) << "WebRtcAudioDeviceImpl::AGC()";
395 DCHECK(thread_checker_.CalledOnValidThread());
396 // To reduce the usage of IPC messages, an internal AGC state is used.
397 // TODO(henrika): investigate if there is a need for a "deeper" getter.
398 return agc_is_enabled_;
401 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
402 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
403 DCHECK(initialized_);
404 if (!capturer_)
405 return -1;
407 if (volume > kMaxVolumeLevel)
408 return -1;
410 // WebRTC uses a range of [0, 255] to represent the level of the microphone
411 // volume. The IPC channel between the renderer and browser process works
412 // with doubles in the [0.0, 1.0] range and we have to compensate for that.
413 double normalized_volume = static_cast<double>(volume) / kMaxVolumeLevel;
414 capturer_->SetVolume(normalized_volume);
415 return 0;
418 // TODO(henrika): sort out calling thread once we start using this API.
419 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
420 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
421 // The microphone level is fed to this class using the Capture() callback
422 // and cached in the same method, i.e. we don't ask the native audio layer
423 // for the actual micropone level here.
424 DCHECK(initialized_);
425 if (!capturer_)
426 return -1;
427 base::AutoLock auto_lock(lock_);
428 *volume = microphone_volume_;
429 return 0;
432 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
433 *max_volume = kMaxVolumeLevel;
434 return 0;
437 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
438 *min_volume = 0;
439 return 0;
442 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
443 DCHECK(initialized_);
444 *available = (output_channels() == 2);
445 return 0;
448 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
449 bool* available) const {
450 DCHECK(initialized_);
451 if (!capturer_)
452 return -1;
453 *available = (input_channels() == 2);
454 return 0;
457 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
458 base::AutoLock auto_lock(lock_);
459 *delay_ms = static_cast<uint16_t>(output_delay_ms_);
460 return 0;
463 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
464 base::AutoLock auto_lock(lock_);
465 *delay_ms = static_cast<uint16_t>(input_delay_ms_);
466 return 0;
469 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
470 uint32_t* samples_per_sec) const {
471 *samples_per_sec = static_cast<uint32_t>(input_sample_rate());
472 return 0;
475 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
476 uint32_t* samples_per_sec) const {
477 *samples_per_sec = static_cast<uint32_t>(output_sample_rate());
478 return 0;
481 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
482 DCHECK(thread_checker_.CalledOnValidThread());
483 DCHECK(renderer);
485 base::AutoLock auto_lock(lock_);
486 if (renderer_)
487 return false;
489 if (!renderer->Initialize(this))
490 return false;
492 renderer_ = renderer;
493 return true;
496 } // namespace content