| 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/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/win/windows_version.h" | 9 #include "base/win/windows_version.h" |
| 10 #include "content/renderer/media/audio_hardware.h" | 10 #include "content/renderer/media/audio_hardware.h" |
| 11 #include "content/renderer/render_thread_impl.h" | 11 #include "content/renderer/render_thread_impl.h" |
| 12 #include "media/audio/audio_util.h" | 12 #include "media/audio/audio_util.h" |
| 13 | 13 |
| 14 static const int64 kMillisecondsBetweenProcessCalls = 5000; | 14 static const int64 kMillisecondsBetweenProcessCalls = 5000; |
| 15 static const double kMaxVolumeLevel = 255.0; |
| 15 | 16 |
| 16 // Supported hardware sample rates for input and output sides. | 17 // Supported hardware sample rates for input and output sides. |
| 17 #if defined(OS_WIN) || defined(OS_MACOSX) | 18 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 18 // media::GetAudioInput[Output]HardwareSampleRate() asks the audio layer | 19 // media::GetAudioInput[Output]HardwareSampleRate() asks the audio layer |
| 19 // for its current sample rate (set by the user) on Windows and Mac OS X. | 20 // for its current sample rate (set by the user) on Windows and Mac OS X. |
| 20 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init() | 21 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init() |
| 21 // will fail if the user selects any rate outside these ranges. | 22 // will fail if the user selects any rate outside these ranges. |
| 22 static int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000}; | 23 static int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000}; |
| 23 static int kValidOutputRates[] = {96000, 48000, 44100}; | 24 static int kValidOutputRates[] = {96000, 48000, 44100}; |
| 24 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 25 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 39 input_sample_rate_(0), | 40 input_sample_rate_(0), |
| 40 output_sample_rate_(0), | 41 output_sample_rate_(0), |
| 41 input_delay_ms_(0), | 42 input_delay_ms_(0), |
| 42 output_delay_ms_(0), | 43 output_delay_ms_(0), |
| 43 last_error_(AudioDeviceModule::kAdmErrNone), | 44 last_error_(AudioDeviceModule::kAdmErrNone), |
| 44 last_process_time_(base::TimeTicks::Now()), | 45 last_process_time_(base::TimeTicks::Now()), |
| 45 session_id_(0), | 46 session_id_(0), |
| 46 bytes_per_sample_(0), | 47 bytes_per_sample_(0), |
| 47 initialized_(false), | 48 initialized_(false), |
| 48 playing_(false), | 49 playing_(false), |
| 49 recording_(false) { | 50 recording_(false), |
| 51 agc_is_enabled_(false) { |
| 50 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; | 52 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; |
| 51 DCHECK(RenderThreadImpl::current()) << | 53 DCHECK(RenderThreadImpl::current()) << |
| 52 "WebRtcAudioDeviceImpl must be constructed on the render thread"; | 54 "WebRtcAudioDeviceImpl must be constructed on the render thread"; |
| 53 } | 55 } |
| 54 | 56 |
| 55 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { | 57 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { |
| 56 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; | 58 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; |
| 57 if (playing_) | 59 if (playing_) |
| 58 StopPlayout(); | 60 StopPlayout(); |
| 59 if (recording_) | 61 if (recording_) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 } | 133 } |
| 132 return number_of_frames; | 134 return number_of_frames; |
| 133 } | 135 } |
| 134 | 136 |
| 135 void WebRtcAudioDeviceImpl::OnRenderError() { | 137 void WebRtcAudioDeviceImpl::OnRenderError() { |
| 136 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | 138 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
| 137 // TODO(henrika): Implement error handling. | 139 // TODO(henrika): Implement error handling. |
| 138 LOG(ERROR) << "OnRenderError()"; | 140 LOG(ERROR) << "OnRenderError()"; |
| 139 } | 141 } |
| 140 | 142 |
| 141 void WebRtcAudioDeviceImpl::Capture( | 143 void WebRtcAudioDeviceImpl::Capture(const std::vector<float*>& audio_data, |
| 142 const std::vector<float*>& audio_data, | 144 size_t number_of_frames, |
| 143 size_t number_of_frames, | 145 size_t audio_delay_milliseconds, |
| 144 size_t audio_delay_milliseconds) { | 146 double volume) { |
| 145 DCHECK_LE(number_of_frames, input_buffer_size_); | 147 DCHECK_LE(number_of_frames, input_buffer_size_); |
| 146 | 148 DCHECK_LE(volume, 1.0); |
| 147 int output_delay_ms = 0; | 149 int output_delay_ms = 0; |
| 148 { | 150 { |
| 149 base::AutoLock auto_lock(lock_); | 151 base::AutoLock auto_lock(lock_); |
| 150 // Store the reported audio delay locally. | 152 // Store the reported audio delay locally. |
| 151 input_delay_ms_ = audio_delay_milliseconds; | 153 input_delay_ms_ = audio_delay_milliseconds; |
| 152 output_delay_ms = output_delay_ms_; | 154 output_delay_ms = output_delay_ms_; |
| 153 } | 155 } |
| 154 | 156 |
| 155 const int channels = audio_data.size(); | 157 const int channels = audio_data.size(); |
| 156 DCHECK_LE(channels, input_channels_); | 158 DCHECK_LE(channels, input_channels_); |
| 157 uint32_t new_mic_level = 0; | 159 uint32_t new_mic_level = 0; |
| 158 | 160 |
| 159 // Interleave, scale, and clip input to int16 and store result in | 161 // Interleave, scale, and clip input to int16 and store result in |
| 160 // a local byte buffer. | 162 // a local byte buffer. |
| 161 media::InterleaveFloatToInt16(audio_data, | 163 media::InterleaveFloatToInt16(audio_data, |
| 162 input_buffer_.get(), | 164 input_buffer_.get(), |
| 163 number_of_frames); | 165 number_of_frames); |
| 164 | 166 |
| 165 int samples_per_sec = static_cast<int>(input_sample_rate_); | 167 int samples_per_sec = static_cast<int>(input_sample_rate_); |
| 166 if (samples_per_sec == 44100) { | 168 if (samples_per_sec == 44100) { |
| 167 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. | 169 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. |
| 168 samples_per_sec = 44000; | 170 samples_per_sec = 44000; |
| 169 } | 171 } |
| 170 const int samples_per_10_msec = (samples_per_sec / 100); | 172 const int samples_per_10_msec = (samples_per_sec / 100); |
| 171 const int bytes_per_10_msec = | 173 const int bytes_per_10_msec = |
| 172 channels * samples_per_10_msec * bytes_per_sample_; | 174 channels * samples_per_10_msec * bytes_per_sample_; |
| 173 size_t accumulated_audio_samples = 0; | 175 size_t accumulated_audio_samples = 0; |
| 176 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get()); |
| 174 | 177 |
| 175 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get()); | 178 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the |
| 179 // webrtc::VoiceEngine. |
| 180 uint32_t current_mic_level = static_cast<uint32_t>(volume * kMaxVolumeLevel); |
| 176 | 181 |
| 177 // Write audio samples in blocks of 10 milliseconds to the registered | 182 // Write audio samples in blocks of 10 milliseconds to the registered |
| 178 // webrtc::AudioTransport sink. Keep writing until our internal byte | 183 // webrtc::AudioTransport sink. Keep writing until our internal byte |
| 179 // buffer is empty. | 184 // buffer is empty. |
| 180 while (accumulated_audio_samples < number_of_frames) { | 185 while (accumulated_audio_samples < number_of_frames) { |
| 181 // Deliver 10ms of recorded PCM audio. | 186 // Deliver 10ms of recorded 16-bit linear PCM audio. |
| 182 // TODO(henrika): add support for analog AGC? | |
| 183 audio_transport_callback_->RecordedDataIsAvailable( | 187 audio_transport_callback_->RecordedDataIsAvailable( |
| 184 audio_byte_buffer, | 188 audio_byte_buffer, |
| 185 samples_per_10_msec, | 189 samples_per_10_msec, |
| 186 bytes_per_sample_, | 190 bytes_per_sample_, |
| 187 channels, | 191 channels, |
| 188 samples_per_sec, | 192 samples_per_sec, |
| 189 input_delay_ms_ + output_delay_ms, | 193 input_delay_ms_ + output_delay_ms, |
| 190 0, // clock_drift | 194 0, // TODO(henrika): |clock_drift| parameter is not utilized today. |
| 191 0, // current_mic_level | 195 current_mic_level, |
| 192 new_mic_level); // not used | 196 new_mic_level); |
| 197 |
| 193 accumulated_audio_samples += samples_per_10_msec; | 198 accumulated_audio_samples += samples_per_10_msec; |
| 194 audio_byte_buffer += bytes_per_10_msec; | 199 audio_byte_buffer += bytes_per_10_msec; |
| 195 } | 200 } |
| 201 |
| 202 // The AGC returns a non-zero microphone level if it has been decided |
| 203 // that a new level should be set. |
| 204 if (new_mic_level != 0) { |
| 205 // Use IPC and set the new level. Note that, it will take some time |
| 206 // before the new level is effective due to the IPC scheme. |
| 207 // During this time, |current_mic_level| will contain "non-valid" values |
| 208 // and it might reduce the AGC performance. Measurements on Windows 7 have |
| 209 // shown that we might receive old volume levels for one or two callbacks. |
| 210 SetMicrophoneVolume(new_mic_level); |
| 211 } |
| 196 } | 212 } |
| 197 | 213 |
| 198 void WebRtcAudioDeviceImpl::OnCaptureError() { | 214 void WebRtcAudioDeviceImpl::OnCaptureError() { |
| 199 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | 215 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
| 200 // TODO(henrika): Implement error handling. | 216 // TODO(henrika): Implement error handling. |
| 201 LOG(ERROR) << "OnCaptureError()"; | 217 LOG(ERROR) << "OnCaptureError()"; |
| 202 } | 218 } |
| 203 | 219 |
| 204 void WebRtcAudioDeviceImpl::OnDeviceStarted(const std::string& device_id) { | 220 void WebRtcAudioDeviceImpl::OnDeviceStarted(const std::string& device_id) { |
| 205 DVLOG(1) << "OnDeviceStarted (device_id=" << device_id << ")"; | 221 DVLOG(1) << "OnDeviceStarted (device_id=" << device_id << ")"; |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 base::AutoLock auto_lock(lock_); | 686 base::AutoLock auto_lock(lock_); |
| 671 recording_ = false; | 687 recording_ = false; |
| 672 return 0; | 688 return 0; |
| 673 } | 689 } |
| 674 | 690 |
| 675 bool WebRtcAudioDeviceImpl::Recording() const { | 691 bool WebRtcAudioDeviceImpl::Recording() const { |
| 676 return recording_; | 692 return recording_; |
| 677 } | 693 } |
| 678 | 694 |
| 679 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { | 695 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { |
| 680 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::SetAGC() " << "NOT IMPLEMENTED"; | 696 // The current implementation does not support changing the AGC state while |
| 681 return -1; | 697 // recording. Using this approach simplifies the design and it is also |
| 698 // inline with the latest WebRTC standard. |
| 699 DCHECK(!recording_); |
| 700 if (recording_) { |
| 701 DLOG(ERROR) << "Failed to modify the AGC state since recording is active."; |
| 702 return -1; |
| 703 } |
| 704 |
| 705 audio_input_device_->SetAutomaticGainControl(enable); |
| 706 agc_is_enabled_ = enable; |
| 707 return 0; |
| 682 } | 708 } |
| 683 | 709 |
| 684 bool WebRtcAudioDeviceImpl::AGC() const { | 710 bool WebRtcAudioDeviceImpl::AGC() const { |
| 685 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::AGC() " << "NOT IMPLEMENTED"; | 711 // To reduce the usage of IPC messages, an internal AGC state is used. |
| 686 return false; | 712 // TODO(henrika): investigate if there is a need for a "deeper" getter. |
| 713 return agc_is_enabled_; |
| 687 } | 714 } |
| 688 | 715 |
| 689 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left, | 716 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left, |
| 690 uint16_t volume_right) { | 717 uint16_t volume_right) { |
| 691 NOTIMPLEMENTED(); | 718 NOTIMPLEMENTED(); |
| 692 return -1; | 719 return -1; |
| 693 } | 720 } |
| 694 int32_t WebRtcAudioDeviceImpl::WaveOutVolume( | 721 int32_t WebRtcAudioDeviceImpl::WaveOutVolume( |
| 695 uint16_t* volume_left, | 722 uint16_t* volume_left, |
| 696 uint16_t* volume_right) const { | 723 uint16_t* volume_right) const { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const { | 776 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const { |
| 750 NOTIMPLEMENTED(); | 777 NOTIMPLEMENTED(); |
| 751 return -1; | 778 return -1; |
| 752 } | 779 } |
| 753 | 780 |
| 754 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const { | 781 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const { |
| 755 NOTIMPLEMENTED(); | 782 NOTIMPLEMENTED(); |
| 756 return -1; | 783 return -1; |
| 757 } | 784 } |
| 758 | 785 |
| 759 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume( | 786 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume(uint32_t* min_volume) const { |
| 760 uint32_t* min_volume) const { | |
| 761 NOTIMPLEMENTED(); | 787 NOTIMPLEMENTED(); |
| 762 return -1; | 788 return -1; |
| 763 } | 789 } |
| 764 | 790 |
| 765 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize( | 791 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize( |
| 766 uint16_t* step_size) const { | 792 uint16_t* step_size) const { |
| 767 NOTIMPLEMENTED(); | 793 NOTIMPLEMENTED(); |
| 768 return -1; | 794 return -1; |
| 769 } | 795 } |
| 770 | 796 |
| 771 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) { | 797 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) { |
| 772 NOTIMPLEMENTED(); | 798 NOTIMPLEMENTED(); |
| 773 return -1; | 799 return -1; |
| 774 } | 800 } |
| 775 | 801 |
| 776 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { | 802 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { |
| 777 NOTIMPLEMENTED(); | 803 DVLOG(1) << "SetMicrophoneVolume(" << volume << ")"; |
| 804 if (volume > kMaxVolumeLevel) |
| 805 return -1; |
| 806 |
| 807 // WebRTC uses a range of [0, 255] to represent the level of the microphone |
| 808 // volume. The IPC channel between the renderer and browser process works |
| 809 // with doubles in the [0.0, 1.0] range and we have to compensate for that. |
| 810 double normalized_volume = static_cast<double>(volume / kMaxVolumeLevel); |
| 811 audio_input_device_->SetVolume(normalized_volume); |
| 812 return 0; |
| 813 } |
| 814 |
| 815 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { |
| 816 // The microphone level is fed to this class using the Capture() callback |
| 817 // and this external API should not be used. Additional IPC messages are |
| 818 // required if support for this API is ever needed. |
| 819 NOTREACHED(); |
| 778 return -1; | 820 return -1; |
| 779 } | 821 } |
| 780 | 822 |
| 781 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { | 823 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const { |
| 782 NOTIMPLEMENTED(); | 824 *max_volume = kMaxVolumeLevel; |
| 783 return -1; | 825 return 0; |
| 784 } | 826 } |
| 785 | 827 |
| 786 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume( | 828 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const { |
| 787 uint32_t* max_volume) const { | 829 *min_volume = 0; |
| 788 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MaxMicrophoneVolume() " | 830 return 0; |
| 789 << "NOT IMPLEMENTED"; | |
| 790 return -1; | |
| 791 } | |
| 792 | |
| 793 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume( | |
| 794 uint32_t* min_volume) const { | |
| 795 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MinMicrophoneVolume() " | |
| 796 << "NOT IMPLEMENTED"; | |
| 797 return -1; | |
| 798 } | 831 } |
| 799 | 832 |
| 800 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize( | 833 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize( |
| 801 uint16_t* step_size) const { | 834 uint16_t* step_size) const { |
| 802 NOTIMPLEMENTED(); | 835 NOTREACHED(); |
| 803 return -1; | 836 return -1; |
| 804 } | 837 } |
| 805 | 838 |
| 806 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) { | 839 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) { |
| 807 NOTIMPLEMENTED(); | 840 NOTIMPLEMENTED(); |
| 808 return -1; | 841 return -1; |
| 809 } | 842 } |
| 810 | 843 |
| 811 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) { | 844 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) { |
| 812 NOTIMPLEMENTED(); | 845 NOTIMPLEMENTED(); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 } | 1023 } |
| 991 | 1024 |
| 992 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { | 1025 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { |
| 993 NOTIMPLEMENTED(); | 1026 NOTIMPLEMENTED(); |
| 994 return -1; | 1027 return -1; |
| 995 } | 1028 } |
| 996 | 1029 |
| 997 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { | 1030 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { |
| 998 session_id_ = session_id; | 1031 session_id_ = session_id; |
| 999 } | 1032 } |
| OLD | NEW |