| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/media/webrtc_audio_device_impl.h" | 5 #include "content/renderer/media/webrtc_audio_device_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/win/windows_version.h" | 10 #include "base/win/windows_version.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 static const int64 kMillisecondsBetweenProcessCalls = 5000; | 23 static const int64 kMillisecondsBetweenProcessCalls = 5000; |
| 24 static const double kMaxVolumeLevel = 255.0; | 24 static const double kMaxVolumeLevel = 255.0; |
| 25 | 25 |
| 26 // Supported hardware sample rates for input and output sides. | 26 // Supported hardware sample rates for input and output sides. |
| 27 #if defined(OS_WIN) || defined(OS_MACOSX) | 27 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 28 // media::GetAudioInput[Output]HardwareSampleRate() asks the audio layer | 28 // media::GetAudioInput[Output]HardwareSampleRate() asks the audio layer |
| 29 // for its current sample rate (set by the user) on Windows and Mac OS X. | 29 // for its current sample rate (set by the user) on Windows and Mac OS X. |
| 30 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init() | 30 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init() |
| 31 // will fail if the user selects any rate outside these ranges. | 31 // will fail if the user selects any rate outside these ranges. |
| 32 static int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000}; | 32 static int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000}; |
| 33 static int kValidOutputRates[] = {96000, 48000, 44100}; | |
| 34 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 33 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 35 // media::GetAudioInput[Output]HardwareSampleRate() is hardcoded to return | 34 // media::GetAudioInput[Output]HardwareSampleRate() is hardcoded to return |
| 36 // 48000 in both directions on Linux. | 35 // 48000 in both directions on Linux. |
| 37 static int kValidInputRates[] = {48000}; | 36 static int kValidInputRates[] = {48000}; |
| 38 static int kValidOutputRates[] = {48000}; | |
| 39 #endif | 37 #endif |
| 40 | 38 |
| 41 namespace { | 39 namespace { |
| 42 | 40 |
| 43 // Helper enum used for histogramming buffer sizes expressed in number of | 41 // Helper enum used for histogramming buffer sizes expressed in number of |
| 44 // audio frames. This enumerator covers all supported sizes for all platforms. | 42 // audio frames. This enumerator covers all supported sizes for all platforms. |
| 45 // Example: k480 <=> 480 audio frames <=> 10ms@48kHz. | 43 // Example: k480 <=> 480 audio frames <=> 10ms@48kHz. |
| 46 // TODO(henrika): can be moved to the media namespace if more clients need it. | 44 // TODO(henrika): can be moved to the media namespace if more clients need it. |
| 47 // TODO(henrika): add support for k80 as well. Will be listed as unexpected for | 45 // TODO(henrika): add support for k80 as well. Will be listed as unexpected for |
| 48 // now. Very rare case though and most likeley only on Mac OS X. | 46 // now. Very rare case though and most likeley only on Mac OS X. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 bytes_per_sample_(0), | 140 bytes_per_sample_(0), |
| 143 initialized_(false), | 141 initialized_(false), |
| 144 playing_(false), | 142 playing_(false), |
| 145 recording_(false), | 143 recording_(false), |
| 146 agc_is_enabled_(false) { | 144 agc_is_enabled_(false) { |
| 147 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; | 145 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; |
| 148 // TODO(henrika): remove this restriction when factory is used for the | 146 // TODO(henrika): remove this restriction when factory is used for the |
| 149 // input side as well. | 147 // input side as well. |
| 150 DCHECK(RenderThreadImpl::current()) << | 148 DCHECK(RenderThreadImpl::current()) << |
| 151 "WebRtcAudioDeviceImpl must be constructed on the render thread"; | 149 "WebRtcAudioDeviceImpl must be constructed on the render thread"; |
| 152 audio_output_device_ = AudioDeviceFactory::NewOutputDevice(); | |
| 153 DCHECK(audio_output_device_); | |
| 154 } | 150 } |
| 155 | 151 |
| 156 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { | 152 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { |
| 157 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; | 153 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; |
| 158 if (playing_) | 154 if (playing_) |
| 159 StopPlayout(); | 155 StopPlayout(); |
| 160 if (recording_) | 156 if (recording_) |
| 161 StopRecording(); | 157 StopRecording(); |
| 162 if (initialized_) | 158 if (initialized_) |
| 163 Terminate(); | 159 Terminate(); |
| 164 } | 160 } |
| 165 | 161 |
| 166 int32_t WebRtcAudioDeviceImpl::AddRef() { | 162 int32_t WebRtcAudioDeviceImpl::AddRef() { |
| 167 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1); | 163 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1); |
| 168 } | 164 } |
| 169 | 165 |
| 170 int32_t WebRtcAudioDeviceImpl::Release() { | 166 int32_t WebRtcAudioDeviceImpl::Release() { |
| 171 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1); | 167 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1); |
| 172 if (ret == 0) { | 168 if (ret == 0) { |
| 173 delete this; | 169 delete this; |
| 174 } | 170 } |
| 175 return ret; | 171 return ret; |
| 176 } | 172 } |
| 177 | 173 |
| 178 int WebRtcAudioDeviceImpl::Render( | 174 void WebRtcAudioDeviceImpl::RenderData(uint8* audio_data, |
| 179 media::AudioBus* audio_bus, | 175 int number_of_channels, |
| 180 int audio_delay_milliseconds) { | 176 int number_of_frames, |
| 181 DCHECK_LE(audio_bus->frames(), output_buffer_size()); | 177 int audio_delay_milliseconds) { |
| 178 DCHECK_LE(number_of_frames, output_buffer_size()); |
| 182 | 179 |
| 183 { | 180 { |
| 184 base::AutoLock auto_lock(lock_); | 181 base::AutoLock auto_lock(lock_); |
| 185 // Store the reported audio delay locally. | 182 // Store the reported audio delay locally. |
| 186 output_delay_ms_ = audio_delay_milliseconds; | 183 output_delay_ms_ = audio_delay_milliseconds; |
| 187 } | 184 } |
| 188 | 185 |
| 189 const int channels = audio_bus->channels(); | 186 const int channels = number_of_channels; |
| 190 DCHECK_LE(channels, output_channels()); | 187 DCHECK_LE(channels, output_channels()); |
| 191 | 188 |
| 192 int samples_per_sec = output_sample_rate(); | 189 int samples_per_sec = output_sample_rate(); |
| 193 if (samples_per_sec == 44100) { | 190 if (samples_per_sec == 44100) { |
| 194 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. | 191 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. |
| 195 samples_per_sec = 44000; | 192 samples_per_sec = 44000; |
| 196 } | 193 } |
| 197 int samples_per_10_msec = (samples_per_sec / 100); | 194 int samples_per_10_msec = (samples_per_sec / 100); |
| 198 const int bytes_per_10_msec = | 195 const int bytes_per_10_msec = |
| 199 channels * samples_per_10_msec * bytes_per_sample_; | 196 channels * samples_per_10_msec * bytes_per_sample_; |
| 200 | 197 |
| 201 uint32_t num_audio_samples = 0; | 198 uint32_t num_audio_samples = 0; |
| 202 int accumulated_audio_samples = 0; | 199 int accumulated_audio_samples = 0; |
| 203 | 200 |
| 204 char* audio_byte_buffer = reinterpret_cast<char*>(output_buffer_.get()); | |
| 205 | |
| 206 // Get audio samples in blocks of 10 milliseconds from the registered | 201 // Get audio samples in blocks of 10 milliseconds from the registered |
| 207 // webrtc::AudioTransport source. Keep reading until our internal buffer | 202 // webrtc::AudioTransport source. Keep reading until our internal buffer |
| 208 // is full. | 203 // is full. |
| 209 while (accumulated_audio_samples < audio_bus->frames()) { | 204 while (accumulated_audio_samples < number_of_frames) { |
| 210 // Get 10ms and append output to temporary byte buffer. | 205 // Get 10ms and append output to temporary byte buffer. |
| 211 audio_transport_callback_->NeedMorePlayData(samples_per_10_msec, | 206 audio_transport_callback_->NeedMorePlayData(samples_per_10_msec, |
| 212 bytes_per_sample_, | 207 bytes_per_sample_, |
| 213 channels, | 208 channels, |
| 214 samples_per_sec, | 209 samples_per_sec, |
| 215 audio_byte_buffer, | 210 audio_data, |
| 216 num_audio_samples); | 211 num_audio_samples); |
| 217 accumulated_audio_samples += num_audio_samples; | 212 accumulated_audio_samples += num_audio_samples; |
| 218 audio_byte_buffer += bytes_per_10_msec; | 213 audio_data += bytes_per_10_msec; |
| 219 } | 214 } |
| 220 | |
| 221 // Deinterleave each channel and convert to 32-bit floating-point | |
| 222 // with nominal range -1.0 -> +1.0 to match the callback format. | |
| 223 audio_bus->FromInterleaved(output_buffer_.get(), audio_bus->frames(), | |
| 224 bytes_per_sample_); | |
| 225 return audio_bus->frames(); | |
| 226 } | 215 } |
| 227 | 216 |
| 228 void WebRtcAudioDeviceImpl::OnRenderError() { | 217 void WebRtcAudioDeviceImpl::SetRenderFormat(media::AudioParameters params) { |
| 229 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | 218 output_audio_parameters_ = params; |
| 230 // TODO(henrika): Implement error handling. | |
| 231 LOG(ERROR) << "OnRenderError()"; | |
| 232 } | 219 } |
| 233 | 220 |
| 234 void WebRtcAudioDeviceImpl::Capture(media::AudioBus* audio_bus, | 221 void WebRtcAudioDeviceImpl::Capture(media::AudioBus* audio_bus, |
| 235 int audio_delay_milliseconds, | 222 int audio_delay_milliseconds, |
| 236 double volume) { | 223 double volume) { |
| 237 DCHECK_LE(audio_bus->frames(), input_buffer_size()); | 224 DCHECK_LE(audio_bus->frames(), input_buffer_size()); |
| 238 #if defined(OS_WIN) || defined(OS_MACOSX) | 225 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 239 DCHECK_LE(volume, 1.0); | 226 DCHECK_LE(volume, 1.0); |
| 240 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 227 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 241 // We have a special situation on Linux where the microphone volume can be | 228 // We have a special situation on Linux where the microphone volume can be |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 event.Wait(); | 391 event.Wait(); |
| 405 return error; | 392 return error; |
| 406 } | 393 } |
| 407 | 394 |
| 408 // Calling Init() multiple times in a row is OK. | 395 // Calling Init() multiple times in a row is OK. |
| 409 if (initialized_) | 396 if (initialized_) |
| 410 return 0; | 397 return 0; |
| 411 | 398 |
| 412 DCHECK(!audio_input_device_); | 399 DCHECK(!audio_input_device_); |
| 413 DCHECK(!input_buffer_.get()); | 400 DCHECK(!input_buffer_.get()); |
| 414 DCHECK(!output_buffer_.get()); | |
| 415 | 401 |
| 416 // TODO(henrika): it could be possible to allow one of the directions (input | 402 // TODO(henrika): it could be possible to allow one of the directions (input |
| 417 // or output) to use a non-supported rate. As an example: if only the | 403 // or output) to use a non-supported rate. As an example: if only the |
| 418 // output rate is OK, we could finalize Init() and only set up an | 404 // output rate is OK, we could finalize Init() and only set up an |
| 419 // AudioOutputDevice. | 405 // AudioOutputDevice. |
| 420 | 406 |
| 421 // Ask the browser for the default audio output hardware sample-rate. | |
| 422 // This request is based on a synchronous IPC message. | |
| 423 int out_sample_rate = GetAudioOutputSampleRate(); | |
| 424 DVLOG(1) << "Audio output hardware sample rate: " << out_sample_rate; | |
| 425 AddHistogramSampleRate(kAudioOutput, out_sample_rate); | |
| 426 | |
| 427 // Verify that the reported output hardware sample rate is supported | |
| 428 // on the current platform. | |
| 429 if (std::find(&kValidOutputRates[0], | |
| 430 &kValidOutputRates[0] + arraysize(kValidOutputRates), | |
| 431 out_sample_rate) == | |
| 432 &kValidOutputRates[arraysize(kValidOutputRates)]) { | |
| 433 DLOG(ERROR) << out_sample_rate << " is not a supported output rate."; | |
| 434 return -1; | |
| 435 } | |
| 436 | |
| 437 // Ask the browser for the default audio input hardware sample-rate. | 407 // Ask the browser for the default audio input hardware sample-rate. |
| 438 // This request is based on a synchronous IPC message. | 408 // This request is based on a synchronous IPC message. |
| 439 int in_sample_rate = GetAudioInputSampleRate(); | 409 int in_sample_rate = GetAudioInputSampleRate(); |
| 440 DVLOG(1) << "Audio input hardware sample rate: " << in_sample_rate; | 410 DVLOG(1) << "Audio input hardware sample rate: " << in_sample_rate; |
| 441 AddHistogramSampleRate(kAudioInput, in_sample_rate); | 411 AddHistogramSampleRate(kAudioInput, in_sample_rate); |
| 442 | 412 |
| 443 // Verify that the reported input hardware sample rate is supported | 413 // Verify that the reported input hardware sample rate is supported |
| 444 // on the current platform. | 414 // on the current platform. |
| 445 if (std::find(&kValidInputRates[0], | 415 if (std::find(&kValidInputRates[0], |
| 446 &kValidInputRates[0] + arraysize(kValidInputRates), | 416 &kValidInputRates[0] + arraysize(kValidInputRates), |
| 447 in_sample_rate) == | 417 in_sample_rate) == |
| 448 &kValidInputRates[arraysize(kValidInputRates)]) { | 418 &kValidInputRates[arraysize(kValidInputRates)]) { |
| 449 DLOG(ERROR) << in_sample_rate << " is not a supported input rate."; | 419 DLOG(ERROR) << in_sample_rate << " is not a supported input rate."; |
| 450 return -1; | 420 return -1; |
| 451 } | 421 } |
| 452 | 422 |
| 453 // Ask the browser for the default number of audio input channels. | 423 // Ask the browser for the default number of audio input channels. |
| 454 // This request is based on a synchronous IPC message. | 424 // This request is based on a synchronous IPC message. |
| 455 ChannelLayout in_channel_layout = GetAudioInputChannelLayout(); | 425 ChannelLayout in_channel_layout = GetAudioInputChannelLayout(); |
| 456 DVLOG(1) << "Audio input hardware channels: " << in_channel_layout; | 426 DVLOG(1) << "Audio input hardware channels: " << in_channel_layout; |
| 457 ChannelLayout out_channel_layout = media::CHANNEL_LAYOUT_MONO; | |
| 458 | 427 |
| 459 AudioParameters::Format in_format = AudioParameters::AUDIO_PCM_LINEAR; | 428 AudioParameters::Format in_format = AudioParameters::AUDIO_PCM_LINEAR; |
| 460 int in_buffer_size = 0; | 429 int in_buffer_size = 0; |
| 461 int out_buffer_size = 0; | |
| 462 | 430 |
| 463 // TODO(henrika): factor out all platform specific parts in separate | 431 // TODO(henrika): factor out all platform specific parts in separate |
| 464 // functions. Code is a bit messy right now. | 432 // functions. Code is a bit messy right now. |
| 465 | 433 |
| 466 // Windows | 434 // Windows |
| 467 #if defined(OS_WIN) | 435 #if defined(OS_WIN) |
| 468 // Always use stereo rendering on Windows. | |
| 469 out_channel_layout = media::CHANNEL_LAYOUT_STEREO; | |
| 470 | 436 |
| 471 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; | 437 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; |
| 472 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 438 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 473 | 439 |
| 474 // Capture side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) | 440 // Capture side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) |
| 475 // API which was introduced in Windows Vista. For lower Windows versions, | 441 // API which was introduced in Windows Vista. For lower Windows versions, |
| 476 // a callback-driven Wave implementation is used instead. An input buffer | 442 // a callback-driven Wave implementation is used instead. An input buffer |
| 477 // size of 10ms works well for both these implementations. | 443 // size of 10ms works well for both these implementations. |
| 478 | 444 |
| 479 // Use different buffer sizes depending on the current hardware sample rate. | 445 // Use different buffer sizes depending on the current hardware sample rate. |
| 480 if (in_sample_rate == 44100) { | 446 if (in_sample_rate == 44100) { |
| 481 // We do run at 44.1kHz at the actual audio layer, but ask for frames | 447 // We do run at 44.1kHz at the actual audio layer, but ask for frames |
| 482 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. | 448 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. |
| 483 in_buffer_size = 440; | 449 in_buffer_size = 440; |
| 484 } else { | 450 } else { |
| 485 in_buffer_size = (in_sample_rate / 100); | 451 in_buffer_size = (in_sample_rate / 100); |
| 486 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << | 452 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << |
| 487 "Sample rate not supported. Should have been caught in Init()."; | 453 "Sample rate not supported. Should have been caught in Init()."; |
| 488 } | 454 } |
| 489 | 455 |
| 490 // Render side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) | |
| 491 // API which was introduced in Windows Vista. For lower Windows versions, | |
| 492 // a callback-driven Wave implementation is used instead. An output buffer | |
| 493 // size of 10ms works well for WASAPI but 30ms is needed for Wave. | |
| 494 | |
| 495 // Use different buffer sizes depending on the current hardware sample rate. | |
| 496 if (out_sample_rate == 96000 || out_sample_rate == 48000) { | |
| 497 out_buffer_size = (out_sample_rate / 100); | |
| 498 } else { | |
| 499 // We do run at 44.1kHz at the actual audio layer, but ask for frames | |
| 500 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. | |
| 501 // TODO(henrika): figure out why we seem to need 20ms here for glitch- | |
| 502 // free audio. | |
| 503 out_buffer_size = 2 * 440; | |
| 504 } | |
| 505 | |
| 506 // Windows XP and lower can't cope with 10 ms output buffer size. | |
| 507 // It must be extended to 30 ms (60 ms will be used internally by WaveOut). | |
| 508 if (!media::IsWASAPISupported()) { | |
| 509 out_buffer_size = 3 * out_buffer_size; | |
| 510 DLOG(WARNING) << "Extending the output buffer size by a factor of three " | |
| 511 << "since Windows XP has been detected."; | |
| 512 } | |
| 513 | |
| 514 // Mac OS X | 456 // Mac OS X |
| 515 #elif defined(OS_MACOSX) | 457 #elif defined(OS_MACOSX) |
| 516 out_channel_layout = media::CHANNEL_LAYOUT_MONO; | 458 out_channel_layout = media::CHANNEL_LAYOUT_MONO; |
| 517 | 459 |
| 518 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; | 460 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; |
| 519 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 461 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 520 | 462 |
| 521 // Capture side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- | 463 // Capture side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- |
| 522 // driven Core Audio implementation. Tests have shown that 10ms is a suitable | 464 // driven Core Audio implementation. Tests have shown that 10ms is a suitable |
| 523 // frame size to use, both for 48kHz and 44.1kHz. | 465 // frame size to use, both for 48kHz and 44.1kHz. |
| 524 | 466 |
| 525 // Use different buffer sizes depending on the current hardware sample rate. | 467 // Use different buffer sizes depending on the current hardware sample rate. |
| 526 if (in_sample_rate == 44100) { | 468 if (in_sample_rate == 44100) { |
| 527 // We do run at 44.1kHz at the actual audio layer, but ask for frames | 469 // We do run at 44.1kHz at the actual audio layer, but ask for frames |
| 528 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. | 470 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. |
| 529 in_buffer_size = 440; | 471 in_buffer_size = 440; |
| 530 } else { | 472 } else { |
| 531 in_buffer_size = (in_sample_rate / 100); | 473 in_buffer_size = (in_sample_rate / 100); |
| 532 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << | 474 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << |
| 533 "Sample rate not supported. Should have been caught in Init()."; | 475 "Sample rate not supported. Should have been caught in Init()."; |
| 534 } | 476 } |
| 535 | 477 |
| 536 // Render side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- | |
| 537 // driven Core Audio implementation. Tests have shown that 10ms is a suitable | |
| 538 // frame size to use, both for 48kHz and 44.1kHz. | |
| 539 | |
| 540 // Use different buffer sizes depending on the current hardware sample rate. | |
| 541 if (out_sample_rate == 48000) { | |
| 542 out_buffer_size = 480; | |
| 543 } else { | |
| 544 // We do run at 44.1kHz at the actual audio layer, but ask for frames | |
| 545 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. | |
| 546 out_buffer_size = 440; | |
| 547 } | |
| 548 // Linux | 478 // Linux |
| 549 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 479 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 550 in_channel_layout = media::CHANNEL_LAYOUT_STEREO; | 480 in_channel_layout = media::CHANNEL_LAYOUT_STEREO; |
| 551 out_channel_layout = media::CHANNEL_LAYOUT_MONO; | |
| 552 | 481 |
| 553 // Based on tests using the current ALSA implementation in Chrome, we have | 482 // Based on tests using the current ALSA implementation in Chrome, we have |
| 554 // found that the best combination is 20ms on the input side and 10ms on the | 483 // found that the best combination is 20ms on the input side and 10ms on the |
| 555 // output side. | 484 // output side. |
| 556 // TODO(henrika): It might be possible to reduce the input buffer | 485 // TODO(henrika): It might be possible to reduce the input buffer |
| 557 // size and reduce the delay even more. | 486 // size and reduce the delay even more. |
| 558 in_buffer_size = 2 * 480; | 487 in_buffer_size = 2 * 480; |
| 559 out_buffer_size = 480; | 488 #else |
| 560 #else | |
| 561 DLOG(ERROR) << "Unsupported platform"; | 489 DLOG(ERROR) << "Unsupported platform"; |
| 562 return -1; | 490 return -1; |
| 563 #endif | 491 #endif |
| 564 | 492 |
| 565 // Store utilized parameters to ensure that we can check them | 493 // Store utilized parameters to ensure that we can check them |
| 566 // after a successful initialization. | 494 // after a successful initialization. |
| 567 output_audio_parameters_.Reset( | |
| 568 AudioParameters::AUDIO_PCM_LOW_LATENCY, out_channel_layout, | |
| 569 out_sample_rate, 16, out_buffer_size); | |
| 570 | |
| 571 input_audio_parameters_.Reset( | 495 input_audio_parameters_.Reset( |
| 572 in_format, in_channel_layout, in_sample_rate, | 496 in_format, in_channel_layout, in_sample_rate, |
| 573 16, in_buffer_size); | 497 16, in_buffer_size); |
| 574 | 498 |
| 575 // Create and configure the audio capturing client. | 499 // Create and configure the audio capturing client. |
| 576 audio_input_device_ = AudioDeviceFactory::NewInputDevice(); | 500 audio_input_device_ = AudioDeviceFactory::NewInputDevice(); |
| 577 audio_input_device_->Initialize(input_audio_parameters_, this, this); | 501 audio_input_device_->Initialize(input_audio_parameters_, this, this); |
| 578 | 502 |
| 579 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout", | |
| 580 out_channel_layout, media::CHANNEL_LAYOUT_MAX); | |
| 581 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | 503 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
| 582 in_channel_layout, media::CHANNEL_LAYOUT_MAX); | 504 in_channel_layout, media::CHANNEL_LAYOUT_MAX); |
| 583 AddHistogramFramesPerBuffer(kAudioOutput, out_buffer_size); | |
| 584 AddHistogramFramesPerBuffer(kAudioInput, in_buffer_size); | 505 AddHistogramFramesPerBuffer(kAudioInput, in_buffer_size); |
| 585 | 506 |
| 586 // Configure the audio rendering client. | |
| 587 audio_output_device_->Initialize(output_audio_parameters_, this); | |
| 588 | |
| 589 DCHECK(audio_input_device_); | 507 DCHECK(audio_input_device_); |
| 590 | 508 |
| 591 // Allocate local audio buffers based on the parameters above. | 509 // Allocate local audio buffers based on the parameters above. |
| 592 // It is assumed that each audio sample contains 16 bits and each | 510 // It is assumed that each audio sample contains 16 bits and each |
| 593 // audio frame contains one or two audio samples depending on the | 511 // audio frame contains one or two audio samples depending on the |
| 594 // number of channels. | 512 // number of channels. |
| 595 input_buffer_.reset(new int16[input_buffer_size() * input_channels()]); | 513 input_buffer_.reset(new int16[input_buffer_size() * input_channels()]); |
| 596 output_buffer_.reset(new int16[output_buffer_size() * output_channels()]); | |
| 597 | 514 |
| 598 DCHECK(input_buffer_.get()); | 515 DCHECK(input_buffer_.get()); |
| 599 DCHECK(output_buffer_.get()); | |
| 600 | 516 |
| 601 bytes_per_sample_ = sizeof(*input_buffer_.get()); | 517 bytes_per_sample_ = sizeof(*input_buffer_.get()); |
| 602 | 518 |
| 603 initialized_ = true; | 519 initialized_ = true; |
| 604 | 520 |
| 605 DVLOG(1) << "Capture parameters (size/channels/rate): (" | 521 DVLOG(1) << "Capture parameters (size/channels/rate): (" |
| 606 << input_buffer_size() << "/" << input_channels() << "/" | 522 << input_buffer_size() << "/" << input_channels() << "/" |
| 607 << input_sample_rate() << ")"; | 523 << input_sample_rate() << ")"; |
| 608 DVLOG(1) << "Render parameters (size/channels/rate): (" | 524 DVLOG(1) << "Render parameters (size/channels/rate): (" |
| 609 << output_buffer_size() << "/" << output_channels() << "/" | 525 << output_buffer_size() << "/" << output_channels() << "/" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 620 | 536 |
| 621 int32_t WebRtcAudioDeviceImpl::Terminate() { | 537 int32_t WebRtcAudioDeviceImpl::Terminate() { |
| 622 DVLOG(1) << "Terminate()"; | 538 DVLOG(1) << "Terminate()"; |
| 623 | 539 |
| 624 // Calling Terminate() multiple times in a row is OK. | 540 // Calling Terminate() multiple times in a row is OK. |
| 625 if (!initialized_) | 541 if (!initialized_) |
| 626 return 0; | 542 return 0; |
| 627 | 543 |
| 628 DCHECK(audio_input_device_); | 544 DCHECK(audio_input_device_); |
| 629 DCHECK(input_buffer_.get()); | 545 DCHECK(input_buffer_.get()); |
| 630 DCHECK(output_buffer_.get()); | |
| 631 | 546 |
| 632 // Release all resources allocated in Init(). | 547 // Release all resources allocated in Init(). |
| 633 audio_input_device_ = NULL; | 548 audio_input_device_ = NULL; |
| 634 input_buffer_.reset(); | 549 input_buffer_.reset(); |
| 635 output_buffer_.reset(); | |
| 636 | 550 |
| 637 initialized_ = false; | 551 initialized_ = false; |
| 638 return 0; | 552 return 0; |
| 639 } | 553 } |
| 640 | 554 |
| 641 bool WebRtcAudioDeviceImpl::Initialized() const { | 555 bool WebRtcAudioDeviceImpl::Initialized() const { |
| 642 return initialized_; | 556 return initialized_; |
| 643 } | 557 } |
| 644 | 558 |
| 645 int16_t WebRtcAudioDeviceImpl::PlayoutDevices() { | 559 int16_t WebRtcAudioDeviceImpl::PlayoutDevices() { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 if (!audio_transport_callback_) { | 646 if (!audio_transport_callback_) { |
| 733 return -1; | 647 return -1; |
| 734 } | 648 } |
| 735 | 649 |
| 736 if (playing_) { | 650 if (playing_) { |
| 737 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and | 651 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and |
| 738 // that the call is ignored the second time. | 652 // that the call is ignored the second time. |
| 739 return 0; | 653 return 0; |
| 740 } | 654 } |
| 741 | 655 |
| 656 { |
| 657 base::AutoLock auto_lock(lock_); |
| 658 if (!renderer_) |
| 659 return 0; |
| 660 |
| 661 renderer_->Play(); |
| 662 } |
| 663 |
| 664 playing_ = true; |
| 665 |
| 742 start_render_time_ = base::Time::Now(); | 666 start_render_time_ = base::Time::Now(); |
| 743 | 667 |
| 744 audio_output_device_->Start(); | |
| 745 playing_ = true; | |
| 746 return 0; | 668 return 0; |
| 747 } | 669 } |
| 748 | 670 |
| 749 int32_t WebRtcAudioDeviceImpl::StopPlayout() { | 671 int32_t WebRtcAudioDeviceImpl::StopPlayout() { |
| 750 DVLOG(1) << "StopPlayout()"; | 672 DVLOG(1) << "StopPlayout()"; |
| 751 if (!playing_) { | 673 if (!playing_) { |
| 752 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case. | 674 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case. |
| 753 return 0; | 675 return 0; |
| 754 } | 676 } |
| 755 | 677 |
| 756 // Add histogram data to be uploaded as part of an UMA logging event. | 678 // Add histogram data to be uploaded as part of an UMA logging event. |
| 757 // This histogram keeps track of total playout times. | 679 // This histogram keeps track of total playout times. |
| 758 if (!start_render_time_.is_null()) { | 680 if (!start_render_time_.is_null()) { |
| 759 base::TimeDelta render_time = base::Time::Now() - start_render_time_; | 681 base::TimeDelta render_time = base::Time::Now() - start_render_time_; |
| 760 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time); | 682 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time); |
| 761 } | 683 } |
| 762 | 684 |
| 763 audio_output_device_->Stop(); | 685 { |
| 686 base::AutoLock auto_lock(lock_); |
| 687 if (!renderer_) |
| 688 return 0; |
| 689 |
| 690 renderer_->Pause(); |
| 691 } |
| 692 |
| 764 playing_ = false; | 693 playing_ = false; |
| 765 return 0; | 694 return 0; |
| 766 } | 695 } |
| 767 | 696 |
| 768 bool WebRtcAudioDeviceImpl::Playing() const { | 697 bool WebRtcAudioDeviceImpl::Playing() const { |
| 769 return playing_; | 698 return playing_; |
| 770 } | 699 } |
| 771 | 700 |
| 772 int32_t WebRtcAudioDeviceImpl::StartRecording() { | 701 int32_t WebRtcAudioDeviceImpl::StartRecording() { |
| 773 DVLOG(1) << "StartRecording()"; | 702 DVLOG(1) << "StartRecording()"; |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1159 | 1088 |
| 1160 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { | 1089 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { |
| 1161 NOTIMPLEMENTED(); | 1090 NOTIMPLEMENTED(); |
| 1162 return -1; | 1091 return -1; |
| 1163 } | 1092 } |
| 1164 | 1093 |
| 1165 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { | 1094 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { |
| 1166 session_id_ = session_id; | 1095 session_id_ = session_id; |
| 1167 } | 1096 } |
| 1168 | 1097 |
| 1098 void WebRtcAudioDeviceImpl::SetRenderer(WebRtcAudioRenderer* renderer) { |
| 1099 DCHECK(!playing_); |
| 1100 |
| 1101 base::AutoLock auto_lock(lock_); |
| 1102 DCHECK(!renderer_); |
| 1103 renderer_ = renderer; |
| 1104 // Initialize the |renderer_| if it exists. |
| 1105 if (renderer_) { |
| 1106 renderer_->Initialize(this); |
| 1107 } |
| 1108 } |
| 1109 |
| 1169 } // namespace content | 1110 } // namespace content |
| OLD | NEW |