Chromium Code Reviews| 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(); |
| 156 { | |
| 157 // It is necessary to stop the |renderer_| before going away. | |
| 158 base::AutoLock auto_lock(lock_); | |
| 159 if (renderer_) | |
| 160 renderer_->Stop(); | |
| 161 } | |
| 160 if (recording_) | 162 if (recording_) |
| 161 StopRecording(); | 163 StopRecording(); |
| 162 if (initialized_) | 164 if (initialized_) |
| 163 Terminate(); | 165 Terminate(); |
| 164 } | 166 } |
| 165 | 167 |
| 166 int32_t WebRtcAudioDeviceImpl::AddRef() { | 168 int32_t WebRtcAudioDeviceImpl::AddRef() { |
| 167 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1); | 169 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1); |
| 168 } | 170 } |
| 169 | 171 |
| 170 int32_t WebRtcAudioDeviceImpl::Release() { | 172 int32_t WebRtcAudioDeviceImpl::Release() { |
| 171 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1); | 173 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1); |
| 172 if (ret == 0) { | 174 if (ret == 0) { |
| 173 delete this; | 175 delete this; |
| 174 } | 176 } |
| 175 return ret; | 177 return ret; |
| 176 } | 178 } |
| 177 | 179 |
| 178 int WebRtcAudioDeviceImpl::Render( | 180 void WebRtcAudioDeviceImpl::RenderData(uint8* audio_data, |
| 179 media::AudioBus* audio_bus, | 181 int number_of_channels, |
| 180 int audio_delay_milliseconds) { | 182 int number_of_frames, |
| 181 DCHECK_LE(audio_bus->frames(), output_buffer_size()); | 183 int audio_delay_milliseconds) { |
| 184 DCHECK_LE(number_of_frames, output_buffer_size()); | |
| 182 | 185 |
| 183 { | 186 { |
| 184 base::AutoLock auto_lock(lock_); | 187 base::AutoLock auto_lock(lock_); |
| 185 // Store the reported audio delay locally. | 188 // Store the reported audio delay locally. |
| 186 output_delay_ms_ = audio_delay_milliseconds; | 189 output_delay_ms_ = audio_delay_milliseconds; |
| 187 } | 190 } |
| 188 | 191 |
| 189 const int channels = audio_bus->channels(); | 192 const int channels = number_of_channels; |
| 190 DCHECK_LE(channels, output_channels()); | 193 DCHECK_LE(channels, output_channels()); |
| 191 | 194 |
| 192 int samples_per_sec = output_sample_rate(); | 195 int samples_per_sec = output_sample_rate(); |
| 193 if (samples_per_sec == 44100) { | 196 if (samples_per_sec == 44100) { |
| 194 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. | 197 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. |
| 195 samples_per_sec = 44000; | 198 samples_per_sec = 44000; |
| 196 } | 199 } |
| 197 int samples_per_10_msec = (samples_per_sec / 100); | 200 int samples_per_10_msec = (samples_per_sec / 100); |
| 198 const int bytes_per_10_msec = | 201 const int bytes_per_10_msec = |
| 199 channels * samples_per_10_msec * bytes_per_sample_; | 202 channels * samples_per_10_msec * bytes_per_sample_; |
| 200 | 203 |
| 201 uint32_t num_audio_samples = 0; | 204 uint32_t num_audio_samples = 0; |
| 202 int accumulated_audio_samples = 0; | 205 int accumulated_audio_samples = 0; |
| 203 | 206 |
| 204 char* audio_byte_buffer = reinterpret_cast<char*>(output_buffer_.get()); | |
| 205 | |
| 206 // Get audio samples in blocks of 10 milliseconds from the registered | 207 // Get audio samples in blocks of 10 milliseconds from the registered |
| 207 // webrtc::AudioTransport source. Keep reading until our internal buffer | 208 // webrtc::AudioTransport source. Keep reading until our internal buffer |
| 208 // is full. | 209 // is full. |
| 209 while (accumulated_audio_samples < audio_bus->frames()) { | 210 while (accumulated_audio_samples < number_of_frames) { |
| 210 // Get 10ms and append output to temporary byte buffer. | 211 // Get 10ms and append output to temporary byte buffer. |
| 211 audio_transport_callback_->NeedMorePlayData(samples_per_10_msec, | 212 audio_transport_callback_->NeedMorePlayData(samples_per_10_msec, |
| 212 bytes_per_sample_, | 213 bytes_per_sample_, |
| 213 channels, | 214 channels, |
| 214 samples_per_sec, | 215 samples_per_sec, |
| 215 audio_byte_buffer, | 216 audio_data, |
| 216 num_audio_samples); | 217 num_audio_samples); |
| 217 accumulated_audio_samples += num_audio_samples; | 218 accumulated_audio_samples += num_audio_samples; |
| 218 audio_byte_buffer += bytes_per_10_msec; | 219 audio_data += bytes_per_10_msec; |
| 219 } | 220 } |
| 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 } | 221 } |
| 227 | 222 |
| 228 void WebRtcAudioDeviceImpl::OnRenderError() { | 223 void WebRtcAudioDeviceImpl::SetRenderFormat(const AudioParameters& params) { |
| 229 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | 224 output_audio_parameters_ = params; |
| 230 // TODO(henrika): Implement error handling. | |
| 231 LOG(ERROR) << "OnRenderError()"; | |
| 232 } | 225 } |
| 233 | 226 |
| 234 void WebRtcAudioDeviceImpl::Capture(media::AudioBus* audio_bus, | 227 void WebRtcAudioDeviceImpl::Capture(media::AudioBus* audio_bus, |
| 235 int audio_delay_milliseconds, | 228 int audio_delay_milliseconds, |
| 236 double volume) { | 229 double volume) { |
| 237 DCHECK_LE(audio_bus->frames(), input_buffer_size()); | 230 DCHECK_LE(audio_bus->frames(), input_buffer_size()); |
| 238 #if defined(OS_WIN) || defined(OS_MACOSX) | 231 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 239 DCHECK_LE(volume, 1.0); | 232 DCHECK_LE(volume, 1.0); |
| 240 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 233 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 241 // We have a special situation on Linux where the microphone volume can be | 234 // 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(); | 397 event.Wait(); |
| 405 return error; | 398 return error; |
| 406 } | 399 } |
| 407 | 400 |
| 408 // Calling Init() multiple times in a row is OK. | 401 // Calling Init() multiple times in a row is OK. |
| 409 if (initialized_) | 402 if (initialized_) |
| 410 return 0; | 403 return 0; |
| 411 | 404 |
| 412 DCHECK(!audio_input_device_); | 405 DCHECK(!audio_input_device_); |
| 413 DCHECK(!input_buffer_.get()); | 406 DCHECK(!input_buffer_.get()); |
| 414 DCHECK(!output_buffer_.get()); | |
| 415 | 407 |
| 416 // TODO(henrika): it could be possible to allow one of the directions (input | 408 // 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 | 409 // 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 | 410 // output rate is OK, we could finalize Init() and only set up an |
| 419 // AudioOutputDevice. | 411 // AudioOutputDevice. |
| 420 | 412 |
| 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. | 413 // Ask the browser for the default audio input hardware sample-rate. |
| 438 // This request is based on a synchronous IPC message. | 414 // This request is based on a synchronous IPC message. |
| 439 int in_sample_rate = GetAudioInputSampleRate(); | 415 int in_sample_rate = GetAudioInputSampleRate(); |
| 440 DVLOG(1) << "Audio input hardware sample rate: " << in_sample_rate; | 416 DVLOG(1) << "Audio input hardware sample rate: " << in_sample_rate; |
| 441 AddHistogramSampleRate(kAudioInput, in_sample_rate); | 417 AddHistogramSampleRate(kAudioInput, in_sample_rate); |
| 442 | 418 |
| 443 // Verify that the reported input hardware sample rate is supported | 419 // Verify that the reported input hardware sample rate is supported |
| 444 // on the current platform. | 420 // on the current platform. |
| 445 if (std::find(&kValidInputRates[0], | 421 if (std::find(&kValidInputRates[0], |
| 446 &kValidInputRates[0] + arraysize(kValidInputRates), | 422 &kValidInputRates[0] + arraysize(kValidInputRates), |
| 447 in_sample_rate) == | 423 in_sample_rate) == |
| 448 &kValidInputRates[arraysize(kValidInputRates)]) { | 424 &kValidInputRates[arraysize(kValidInputRates)]) { |
| 449 DLOG(ERROR) << in_sample_rate << " is not a supported input rate."; | 425 DLOG(ERROR) << in_sample_rate << " is not a supported input rate."; |
| 450 return -1; | 426 return -1; |
| 451 } | 427 } |
| 452 | 428 |
| 453 // Ask the browser for the default number of audio input channels. | 429 // Ask the browser for the default number of audio input channels. |
| 454 // This request is based on a synchronous IPC message. | 430 // This request is based on a synchronous IPC message. |
| 455 ChannelLayout in_channel_layout = GetAudioInputChannelLayout(); | 431 ChannelLayout in_channel_layout = GetAudioInputChannelLayout(); |
| 456 DVLOG(1) << "Audio input hardware channels: " << in_channel_layout; | 432 DVLOG(1) << "Audio input hardware channels: " << in_channel_layout; |
| 457 ChannelLayout out_channel_layout = media::CHANNEL_LAYOUT_MONO; | |
| 458 | 433 |
| 459 AudioParameters::Format in_format = AudioParameters::AUDIO_PCM_LINEAR; | 434 AudioParameters::Format in_format = AudioParameters::AUDIO_PCM_LINEAR; |
| 460 int in_buffer_size = 0; | 435 int in_buffer_size = 0; |
| 461 int out_buffer_size = 0; | |
| 462 | 436 |
| 463 // TODO(henrika): factor out all platform specific parts in separate | 437 // TODO(henrika): factor out all platform specific parts in separate |
| 464 // functions. Code is a bit messy right now. | 438 // functions. Code is a bit messy right now. |
| 465 | 439 |
| 466 // Windows | 440 // Windows |
| 467 #if defined(OS_WIN) | 441 #if defined(OS_WIN) |
| 468 // Always use stereo rendering on Windows. | |
| 469 out_channel_layout = media::CHANNEL_LAYOUT_STEREO; | |
| 470 | |
| 471 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; | 442 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; |
| 472 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 443 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 473 | 444 |
| 474 // Capture side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) | 445 // 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, | 446 // API which was introduced in Windows Vista. For lower Windows versions, |
| 476 // a callback-driven Wave implementation is used instead. An input buffer | 447 // a callback-driven Wave implementation is used instead. An input buffer |
| 477 // size of 10ms works well for both these implementations. | 448 // size of 10ms works well for both these implementations. |
| 478 | 449 |
| 479 // Use different buffer sizes depending on the current hardware sample rate. | 450 // Use different buffer sizes depending on the current hardware sample rate. |
| 480 if (in_sample_rate == 44100) { | 451 if (in_sample_rate == 44100) { |
| 481 // We do run at 44.1kHz at the actual audio layer, but ask for frames | 452 // 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. | 453 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. |
| 483 in_buffer_size = 440; | 454 in_buffer_size = 440; |
| 484 } else { | 455 } else { |
| 485 in_buffer_size = (in_sample_rate / 100); | 456 in_buffer_size = (in_sample_rate / 100); |
| 486 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << | 457 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << |
| 487 "Sample rate not supported. Should have been caught in Init()."; | 458 "Sample rate not supported. Should have been caught in Init()."; |
| 488 } | 459 } |
| 489 | 460 |
| 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 | 461 // Mac OS X |
| 515 #elif defined(OS_MACOSX) | 462 #elif defined(OS_MACOSX) |
| 516 out_channel_layout = media::CHANNEL_LAYOUT_MONO; | |
| 517 | |
| 518 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; | 463 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; |
| 519 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 464 in_format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 520 | 465 |
| 521 // Capture side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- | 466 // 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 | 467 // driven Core Audio implementation. Tests have shown that 10ms is a suitable |
| 523 // frame size to use, both for 48kHz and 44.1kHz. | 468 // frame size to use, both for 48kHz and 44.1kHz. |
| 524 | 469 |
| 525 // Use different buffer sizes depending on the current hardware sample rate. | 470 // Use different buffer sizes depending on the current hardware sample rate. |
| 526 if (in_sample_rate == 44100) { | 471 if (in_sample_rate == 44100) { |
| 527 // We do run at 44.1kHz at the actual audio layer, but ask for frames | 472 // 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. | 473 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. |
| 529 in_buffer_size = 440; | 474 in_buffer_size = 440; |
| 530 } else { | 475 } else { |
| 531 in_buffer_size = (in_sample_rate / 100); | 476 in_buffer_size = (in_sample_rate / 100); |
| 532 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << | 477 DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << |
| 533 "Sample rate not supported. Should have been caught in Init()."; | 478 "Sample rate not supported. Should have been caught in Init()."; |
| 534 } | 479 } |
| 535 | 480 |
| 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 | 481 // Linux |
| 549 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 482 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 550 in_channel_layout = media::CHANNEL_LAYOUT_STEREO; | 483 in_channel_layout = media::CHANNEL_LAYOUT_STEREO; |
| 551 out_channel_layout = media::CHANNEL_LAYOUT_MONO; | |
| 552 | 484 |
| 553 // Based on tests using the current ALSA implementation in Chrome, we have | 485 // 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 | 486 // found that the best combination is 20ms on the input side and 10ms on the |
| 555 // output side. | 487 // output side. |
| 556 // TODO(henrika): It might be possible to reduce the input buffer | 488 // TODO(henrika): It might be possible to reduce the input buffer |
| 557 // size and reduce the delay even more. | 489 // size and reduce the delay even more. |
| 558 in_buffer_size = 2 * 480; | 490 in_buffer_size = 2 * 480; |
| 559 out_buffer_size = 480; | |
| 560 #else | 491 #else |
| 561 DLOG(ERROR) << "Unsupported platform"; | 492 DLOG(ERROR) << "Unsupported platform"; |
| 562 return -1; | 493 return -1; |
| 563 #endif | 494 #endif |
| 564 | 495 |
| 565 // Store utilized parameters to ensure that we can check them | 496 // Store utilized parameters to ensure that we can check them |
| 566 // after a successful initialization. | 497 // 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( | 498 input_audio_parameters_.Reset( |
| 572 in_format, in_channel_layout, in_sample_rate, | 499 in_format, in_channel_layout, in_sample_rate, |
| 573 16, in_buffer_size); | 500 16, in_buffer_size); |
| 574 | 501 |
| 575 // Create and configure the audio capturing client. | 502 // Create and configure the audio capturing client. |
| 576 audio_input_device_ = AudioDeviceFactory::NewInputDevice(); | 503 audio_input_device_ = AudioDeviceFactory::NewInputDevice(); |
| 577 audio_input_device_->Initialize(input_audio_parameters_, this, this); | 504 audio_input_device_->Initialize(input_audio_parameters_, this, this); |
| 578 | 505 |
| 579 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout", | |
| 580 out_channel_layout, media::CHANNEL_LAYOUT_MAX); | |
| 581 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | 506 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
| 582 in_channel_layout, media::CHANNEL_LAYOUT_MAX); | 507 in_channel_layout, media::CHANNEL_LAYOUT_MAX); |
| 583 AddHistogramFramesPerBuffer(kAudioOutput, out_buffer_size); | |
| 584 AddHistogramFramesPerBuffer(kAudioInput, in_buffer_size); | 508 AddHistogramFramesPerBuffer(kAudioInput, in_buffer_size); |
| 585 | 509 |
| 586 // Configure the audio rendering client. | |
| 587 audio_output_device_->Initialize(output_audio_parameters_, this); | |
| 588 | |
| 589 DCHECK(audio_input_device_); | 510 DCHECK(audio_input_device_); |
| 590 | 511 |
| 591 // Allocate local audio buffers based on the parameters above. | 512 // Allocate local audio buffers based on the parameters above. |
| 592 // It is assumed that each audio sample contains 16 bits and each | 513 // It is assumed that each audio sample contains 16 bits and each |
| 593 // audio frame contains one or two audio samples depending on the | 514 // audio frame contains one or two audio samples depending on the |
| 594 // number of channels. | 515 // number of channels. |
| 595 input_buffer_.reset(new int16[input_buffer_size() * input_channels()]); | 516 input_buffer_.reset(new int16[input_buffer_size() * input_channels()]); |
| 596 output_buffer_.reset(new int16[output_buffer_size() * output_channels()]); | |
| 597 | 517 |
| 598 DCHECK(input_buffer_.get()); | 518 DCHECK(input_buffer_.get()); |
| 599 DCHECK(output_buffer_.get()); | |
| 600 | 519 |
| 601 bytes_per_sample_ = sizeof(*input_buffer_.get()); | 520 bytes_per_sample_ = sizeof(*input_buffer_.get()); |
| 602 | 521 |
| 603 initialized_ = true; | 522 initialized_ = true; |
| 604 | 523 |
| 605 DVLOG(1) << "Capture parameters (size/channels/rate): (" | 524 DVLOG(1) << "Capture parameters (size/channels/rate): (" |
| 606 << input_buffer_size() << "/" << input_channels() << "/" | 525 << input_buffer_size() << "/" << input_channels() << "/" |
| 607 << input_sample_rate() << ")"; | 526 << input_sample_rate() << ")"; |
| 608 DVLOG(1) << "Render parameters (size/channels/rate): (" | 527 DVLOG(1) << "Render parameters (size/channels/rate): (" |
| 609 << output_buffer_size() << "/" << output_channels() << "/" | 528 << output_buffer_size() << "/" << output_channels() << "/" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 620 | 539 |
| 621 int32_t WebRtcAudioDeviceImpl::Terminate() { | 540 int32_t WebRtcAudioDeviceImpl::Terminate() { |
| 622 DVLOG(1) << "Terminate()"; | 541 DVLOG(1) << "Terminate()"; |
| 623 | 542 |
| 624 // Calling Terminate() multiple times in a row is OK. | 543 // Calling Terminate() multiple times in a row is OK. |
| 625 if (!initialized_) | 544 if (!initialized_) |
| 626 return 0; | 545 return 0; |
| 627 | 546 |
| 628 DCHECK(audio_input_device_); | 547 DCHECK(audio_input_device_); |
| 629 DCHECK(input_buffer_.get()); | 548 DCHECK(input_buffer_.get()); |
| 630 DCHECK(output_buffer_.get()); | |
| 631 | 549 |
| 632 // Release all resources allocated in Init(). | 550 // Release all resources allocated in Init(). |
| 633 audio_input_device_ = NULL; | 551 audio_input_device_ = NULL; |
| 634 input_buffer_.reset(); | 552 input_buffer_.reset(); |
| 635 output_buffer_.reset(); | |
| 636 | 553 |
| 637 initialized_ = false; | 554 initialized_ = false; |
| 638 return 0; | 555 return 0; |
| 639 } | 556 } |
| 640 | 557 |
| 641 bool WebRtcAudioDeviceImpl::Initialized() const { | 558 bool WebRtcAudioDeviceImpl::Initialized() const { |
| 642 return initialized_; | 559 return initialized_; |
| 643 } | 560 } |
| 644 | 561 |
| 645 int16_t WebRtcAudioDeviceImpl::PlayoutDevices() { | 562 int16_t WebRtcAudioDeviceImpl::PlayoutDevices() { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 732 if (!audio_transport_callback_) { | 649 if (!audio_transport_callback_) { |
| 733 return -1; | 650 return -1; |
| 734 } | 651 } |
| 735 | 652 |
| 736 if (playing_) { | 653 if (playing_) { |
| 737 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and | 654 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and |
| 738 // that the call is ignored the second time. | 655 // that the call is ignored the second time. |
| 739 return 0; | 656 return 0; |
| 740 } | 657 } |
| 741 | 658 |
| 659 { | |
| 660 base::AutoLock auto_lock(lock_); | |
| 661 if (!renderer_) | |
| 662 return -1; | |
| 663 | |
| 664 renderer_->Play(); | |
| 665 } | |
| 666 | |
| 667 playing_ = true; | |
| 668 | |
| 742 start_render_time_ = base::Time::Now(); | 669 start_render_time_ = base::Time::Now(); |
| 743 | 670 |
| 744 audio_output_device_->Start(); | |
| 745 playing_ = true; | |
| 746 return 0; | 671 return 0; |
| 747 } | 672 } |
| 748 | 673 |
| 749 int32_t WebRtcAudioDeviceImpl::StopPlayout() { | 674 int32_t WebRtcAudioDeviceImpl::StopPlayout() { |
| 750 DVLOG(1) << "StopPlayout()"; | 675 DVLOG(1) << "StopPlayout()"; |
| 751 if (!playing_) { | 676 if (!playing_) { |
| 752 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case. | 677 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case. |
| 753 return 0; | 678 return 0; |
| 754 } | 679 } |
| 755 | 680 |
| 756 // Add histogram data to be uploaded as part of an UMA logging event. | 681 // Add histogram data to be uploaded as part of an UMA logging event. |
| 757 // This histogram keeps track of total playout times. | 682 // This histogram keeps track of total playout times. |
| 758 if (!start_render_time_.is_null()) { | 683 if (!start_render_time_.is_null()) { |
| 759 base::TimeDelta render_time = base::Time::Now() - start_render_time_; | 684 base::TimeDelta render_time = base::Time::Now() - start_render_time_; |
| 760 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time); | 685 UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time); |
| 761 } | 686 } |
| 762 | 687 |
| 763 audio_output_device_->Stop(); | 688 { |
| 689 base::AutoLock auto_lock(lock_); | |
| 690 if (!renderer_) | |
| 691 return -1; | |
| 692 | |
| 693 renderer_->Pause(); | |
|
scherkus (not reviewing)
2012/10/26 17:28:22
which thread is this being called on?
is seems a
no longer working on chromium
2012/10/29 15:01:36
It is called on libjingle thread.
| |
| 694 } | |
| 695 | |
| 764 playing_ = false; | 696 playing_ = false; |
| 765 return 0; | 697 return 0; |
| 766 } | 698 } |
| 767 | 699 |
| 768 bool WebRtcAudioDeviceImpl::Playing() const { | 700 bool WebRtcAudioDeviceImpl::Playing() const { |
| 769 return playing_; | 701 return playing_; |
| 770 } | 702 } |
| 771 | 703 |
| 772 int32_t WebRtcAudioDeviceImpl::StartRecording() { | 704 int32_t WebRtcAudioDeviceImpl::StartRecording() { |
| 773 DVLOG(1) << "StartRecording()"; | 705 DVLOG(1) << "StartRecording()"; |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1159 | 1091 |
| 1160 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { | 1092 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { |
| 1161 NOTIMPLEMENTED(); | 1093 NOTIMPLEMENTED(); |
| 1162 return -1; | 1094 return -1; |
| 1163 } | 1095 } |
| 1164 | 1096 |
| 1165 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { | 1097 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { |
| 1166 session_id_ = session_id; | 1098 session_id_ = session_id; |
| 1167 } | 1099 } |
| 1168 | 1100 |
| 1101 bool WebRtcAudioDeviceImpl::SetRenderer(WebRtcAudioRenderer* renderer) { | |
| 1102 DCHECK(renderer); | |
| 1103 | |
| 1104 base::AutoLock auto_lock(lock_); | |
| 1105 if (renderer_) | |
| 1106 return false; | |
| 1107 | |
| 1108 if (!renderer->Initialize(this)) | |
| 1109 return false; | |
| 1110 | |
| 1111 renderer_ = renderer; | |
| 1112 return true; | |
| 1113 } | |
| 1114 | |
| 1169 } // namespace content | 1115 } // namespace content |
| OLD | NEW |