Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: content/renderer/media/webrtc_audio_device_impl.cc

Issue 9702019: Adds Analog Gain Control (AGC) to the WebRTC client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved AGC comments Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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)
25 // media::GetAudioInput[Output]HardwareSampleRate() is hardcoded to return 26 // media::GetAudioInput[Output]HardwareSampleRate() is hardcoded to return
26 // 48000 in both directions on Linux. 27 // 48000 in both directions on Linux.
27 static int kValidInputRates[] = {48000}; 28 static int kValidInputRates[] = {48000};
28 static int kValidOutputRates[] = {48000}; 29 static int kValidOutputRates[] = {48000};
29 #endif 30 #endif
30 31
31 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl() 32 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
32 : ref_count_(0), 33 : ref_count_(0),
33 render_loop_(base::MessageLoopProxy::current()), 34 render_loop_(base::MessageLoopProxy::current()),
34 audio_transport_callback_(NULL), 35 audio_transport_callback_(NULL),
35 input_delay_ms_(0), 36 input_delay_ms_(0),
36 output_delay_ms_(0), 37 output_delay_ms_(0),
37 last_error_(AudioDeviceModule::kAdmErrNone), 38 last_error_(AudioDeviceModule::kAdmErrNone),
38 last_process_time_(base::TimeTicks::Now()), 39 last_process_time_(base::TimeTicks::Now()),
39 session_id_(0), 40 session_id_(0),
40 bytes_per_sample_(0), 41 bytes_per_sample_(0),
41 initialized_(false), 42 initialized_(false),
42 playing_(false), 43 playing_(false),
43 recording_(false) { 44 recording_(false),
45 agc_is_enabled_(false) {
44 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; 46 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
45 DCHECK(RenderThreadImpl::current()) << 47 DCHECK(RenderThreadImpl::current()) <<
46 "WebRtcAudioDeviceImpl must be constructed on the render thread"; 48 "WebRtcAudioDeviceImpl must be constructed on the render thread";
47 } 49 }
48 50
49 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { 51 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
50 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; 52 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
51 if (playing_) 53 if (playing_)
52 StopPlayout(); 54 StopPlayout();
53 if (recording_) 55 if (recording_)
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 } 127 }
126 return number_of_frames; 128 return number_of_frames;
127 } 129 }
128 130
129 void WebRtcAudioDeviceImpl::OnRenderError() { 131 void WebRtcAudioDeviceImpl::OnRenderError() {
130 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 132 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop());
131 // TODO(henrika): Implement error handling. 133 // TODO(henrika): Implement error handling.
132 LOG(ERROR) << "OnRenderError()"; 134 LOG(ERROR) << "OnRenderError()";
133 } 135 }
134 136
135 void WebRtcAudioDeviceImpl::Capture( 137 void WebRtcAudioDeviceImpl::Capture(const std::vector<float*>& audio_data,
136 const std::vector<float*>& audio_data, 138 size_t number_of_frames,
137 size_t number_of_frames, 139 size_t audio_delay_milliseconds,
138 size_t audio_delay_milliseconds) { 140 double volume) {
139 DCHECK_LE(number_of_frames, input_buffer_size()); 141 DCHECK_LE(number_of_frames, input_buffer_size());
142 #if defined(OS_WIN) || defined(OS_MACOSX)
143 DCHECK_LE(volume, 1.0);
144 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
145 // We have a special situation on Linux where the microphone volume can be
146 // "higher than maximum". The input volume slider in the sound preference
147 // allows the user to set a scaling that is higher than 100%. It means that
148 // even if the reported maximum levels is N, the actual microphone level can
149 // go up to 1.5*N and that corresponds to a normalized |volume| of 1.5.
150 DCHECK_LE(volume, 1.5);
151 #endif
140 152
141 int output_delay_ms = 0; 153 int output_delay_ms = 0;
142 { 154 {
143 base::AutoLock auto_lock(lock_); 155 base::AutoLock auto_lock(lock_);
144 // Store the reported audio delay locally. 156 // Store the reported audio delay locally.
145 input_delay_ms_ = audio_delay_milliseconds; 157 input_delay_ms_ = audio_delay_milliseconds;
146 output_delay_ms = output_delay_ms_; 158 output_delay_ms = output_delay_ms_;
147 } 159 }
148 160
149 const int channels = audio_data.size(); 161 const int channels = audio_data.size();
150 DCHECK_LE(channels, input_channels()); 162 DCHECK_LE(channels, input_channels());
151 uint32_t new_mic_level = 0; 163 uint32_t new_mic_level = 0;
152 164
153 // Interleave, scale, and clip input to int16 and store result in 165 // Interleave, scale, and clip input to int16 and store result in
154 // a local byte buffer. 166 // a local byte buffer.
155 media::InterleaveFloatToInt16(audio_data, 167 media::InterleaveFloatToInt16(audio_data,
156 input_buffer_.get(), 168 input_buffer_.get(),
157 number_of_frames); 169 number_of_frames);
158 170
159 int samples_per_sec = input_sample_rate(); 171 int samples_per_sec = input_sample_rate();
160 if (samples_per_sec == 44100) { 172 if (samples_per_sec == 44100) {
161 // Even if the hardware runs at 44.1kHz, we use 44.0 internally. 173 // Even if the hardware runs at 44.1kHz, we use 44.0 internally.
162 samples_per_sec = 44000; 174 samples_per_sec = 44000;
163 } 175 }
164 const int samples_per_10_msec = (samples_per_sec / 100); 176 const int samples_per_10_msec = (samples_per_sec / 100);
165 const int bytes_per_10_msec = 177 const int bytes_per_10_msec =
166 channels * samples_per_10_msec * bytes_per_sample_; 178 channels * samples_per_10_msec * bytes_per_sample_;
167 size_t accumulated_audio_samples = 0; 179 size_t accumulated_audio_samples = 0;
180 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get());
168 181
169 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get()); 182 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
183 // webrtc::VoiceEngine.
184 uint32_t current_mic_level = static_cast<uint32_t>(volume * kMaxVolumeLevel);
170 185
171 // Write audio samples in blocks of 10 milliseconds to the registered 186 // Write audio samples in blocks of 10 milliseconds to the registered
172 // webrtc::AudioTransport sink. Keep writing until our internal byte 187 // webrtc::AudioTransport sink. Keep writing until our internal byte
173 // buffer is empty. 188 // buffer is empty.
174 while (accumulated_audio_samples < number_of_frames) { 189 while (accumulated_audio_samples < number_of_frames) {
175 // Deliver 10ms of recorded PCM audio. 190 // Deliver 10ms of recorded 16-bit linear PCM audio.
176 // TODO(henrika): add support for analog AGC?
177 audio_transport_callback_->RecordedDataIsAvailable( 191 audio_transport_callback_->RecordedDataIsAvailable(
178 audio_byte_buffer, 192 audio_byte_buffer,
179 samples_per_10_msec, 193 samples_per_10_msec,
180 bytes_per_sample_, 194 bytes_per_sample_,
181 channels, 195 channels,
182 samples_per_sec, 196 samples_per_sec,
183 input_delay_ms_ + output_delay_ms, 197 input_delay_ms_ + output_delay_ms,
184 0, // clock_drift 198 0, // TODO(henrika): |clock_drift| parameter is not utilized today.
185 0, // current_mic_level 199 current_mic_level,
186 new_mic_level); // not used 200 new_mic_level);
201
187 accumulated_audio_samples += samples_per_10_msec; 202 accumulated_audio_samples += samples_per_10_msec;
188 audio_byte_buffer += bytes_per_10_msec; 203 audio_byte_buffer += bytes_per_10_msec;
189 } 204 }
205
206 // The AGC returns a non-zero microphone level if it has been decided
207 // that a new level should be set.
208 if (new_mic_level != 0) {
209 // Use IPC and set the new level. Note that, it will take some time
210 // before the new level is effective due to the IPC scheme.
211 // During this time, |current_mic_level| will contain "non-valid" values
212 // and it might reduce the AGC performance. Measurements on Windows 7 have
213 // shown that we might receive old volume levels for one or two callbacks.
214 SetMicrophoneVolume(new_mic_level);
215 }
190 } 216 }
191 217
192 void WebRtcAudioDeviceImpl::OnCaptureError() { 218 void WebRtcAudioDeviceImpl::OnCaptureError() {
193 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 219 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop());
194 // TODO(henrika): Implement error handling. 220 // TODO(henrika): Implement error handling.
195 LOG(ERROR) << "OnCaptureError()"; 221 LOG(ERROR) << "OnCaptureError()";
196 } 222 }
197 223
198 void WebRtcAudioDeviceImpl::OnDeviceStarted(const std::string& device_id) { 224 void WebRtcAudioDeviceImpl::OnDeviceStarted(const std::string& device_id) {
199 DVLOG(1) << "OnDeviceStarted (device_id=" << device_id << ")"; 225 DVLOG(1) << "OnDeviceStarted (device_id=" << device_id << ")";
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 base::AutoLock auto_lock(lock_); 694 base::AutoLock auto_lock(lock_);
669 recording_ = false; 695 recording_ = false;
670 return 0; 696 return 0;
671 } 697 }
672 698
673 bool WebRtcAudioDeviceImpl::Recording() const { 699 bool WebRtcAudioDeviceImpl::Recording() const {
674 return recording_; 700 return recording_;
675 } 701 }
676 702
677 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { 703 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) {
678 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::SetAGC() " << "NOT IMPLEMENTED"; 704 // The current implementation does not support changing the AGC state while
679 return -1; 705 // recording. Using this approach simplifies the design and it is also
706 // inline with the latest WebRTC standard.
707 DCHECK(!recording_);
708 if (recording_) {
709 DLOG(ERROR) << "Failed to modify the AGC state since recording is active.";
710 return -1;
711 }
712
713 audio_input_device_->SetAutomaticGainControl(enable);
scherkus (not reviewing) 2012/03/26 22:41:04 nit: instead of a setter you may consider passing
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Thanks for the proposal. I'd like to keep the curr
714 agc_is_enabled_ = enable;
715 return 0;
680 } 716 }
681 717
682 bool WebRtcAudioDeviceImpl::AGC() const { 718 bool WebRtcAudioDeviceImpl::AGC() const {
683 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::AGC() " << "NOT IMPLEMENTED"; 719 // To reduce the usage of IPC messages, an internal AGC state is used.
684 return false; 720 // TODO(henrika): investigate if there is a need for a "deeper" getter.
721 return agc_is_enabled_;
685 } 722 }
686 723
687 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left, 724 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left,
688 uint16_t volume_right) { 725 uint16_t volume_right) {
689 NOTIMPLEMENTED(); 726 NOTIMPLEMENTED();
690 return -1; 727 return -1;
691 } 728 }
692 int32_t WebRtcAudioDeviceImpl::WaveOutVolume( 729 int32_t WebRtcAudioDeviceImpl::WaveOutVolume(
693 uint16_t* volume_left, 730 uint16_t* volume_left,
694 uint16_t* volume_right) const { 731 uint16_t* volume_right) const {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const { 784 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const {
748 NOTIMPLEMENTED(); 785 NOTIMPLEMENTED();
749 return -1; 786 return -1;
750 } 787 }
751 788
752 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const { 789 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const {
753 NOTIMPLEMENTED(); 790 NOTIMPLEMENTED();
754 return -1; 791 return -1;
755 } 792 }
756 793
757 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume( 794 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume(uint32_t* min_volume) const {
758 uint32_t* min_volume) const {
759 NOTIMPLEMENTED(); 795 NOTIMPLEMENTED();
760 return -1; 796 return -1;
761 } 797 }
762 798
763 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize( 799 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize(
764 uint16_t* step_size) const { 800 uint16_t* step_size) const {
765 NOTIMPLEMENTED(); 801 NOTIMPLEMENTED();
766 return -1; 802 return -1;
767 } 803 }
768 804
769 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) { 805 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) {
770 NOTIMPLEMENTED(); 806 NOTIMPLEMENTED();
771 return -1; 807 return -1;
772 } 808 }
773 809
774 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { 810 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
775 NOTIMPLEMENTED(); 811 DVLOG(1) << "SetMicrophoneVolume(" << volume << ")";
812 if (volume > kMaxVolumeLevel)
813 return -1;
814
815 // WebRTC uses a range of [0, 255] to represent the level of the microphone
816 // volume. The IPC channel between the renderer and browser process works
817 // with doubles in the [0.0, 1.0] range and we have to compensate for that.
818 double normalized_volume = static_cast<double>(volume / kMaxVolumeLevel);
819 audio_input_device_->SetVolume(normalized_volume);
820 return 0;
821 }
822
823 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
824 // The microphone level is fed to this class using the Capture() callback
825 // and this external API should not be used. Additional IPC messages are
826 // required if support for this API is ever needed.
827 NOTREACHED();
776 return -1; 828 return -1;
777 } 829 }
778 830
779 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { 831 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
780 NOTIMPLEMENTED(); 832 *max_volume = kMaxVolumeLevel;
781 return -1; 833 return 0;
782 } 834 }
783 835
784 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume( 836 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
785 uint32_t* max_volume) const { 837 *min_volume = 0;
786 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MaxMicrophoneVolume() " 838 return 0;
787 << "NOT IMPLEMENTED";
788 return -1;
789 }
790
791 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(
792 uint32_t* min_volume) const {
793 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MinMicrophoneVolume() "
794 << "NOT IMPLEMENTED";
795 return -1;
796 } 839 }
797 840
798 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize( 841 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize(
799 uint16_t* step_size) const { 842 uint16_t* step_size) const {
800 NOTIMPLEMENTED(); 843 NOTREACHED();
801 return -1; 844 return -1;
802 } 845 }
803 846
804 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) { 847 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) {
805 NOTIMPLEMENTED(); 848 NOTIMPLEMENTED();
806 return -1; 849 return -1;
807 } 850 }
808 851
809 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) { 852 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) {
810 NOTIMPLEMENTED(); 853 NOTIMPLEMENTED();
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 } 1031 }
989 1032
990 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { 1033 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const {
991 NOTIMPLEMENTED(); 1034 NOTIMPLEMENTED();
992 return -1; 1035 return -1;
993 } 1036 }
994 1037
995 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { 1038 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) {
996 session_id_ = session_id; 1039 session_id_ = session_id;
997 } 1040 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698