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

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 volume updating on Mac 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)
(...skipping 14 matching lines...) Expand all
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
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
scherkus (not reviewing) 2012/03/20 13:49:41 I'm confused -- isn't it the audio_transport_callb
henrika (OOO until Aug 14) 2012/03/21 10:16:04 The last two parameters in RecordedDataIsAvailable
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
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 most common usage is to set the AGC state before recording starts.
681 return -1; 697 // The AudioInputDevice also supports changing the AGC state on the fly,
698 // i.e., it is possible to modify the AGC state while audio streaming is
699 // active.
scherkus (not reviewing) 2012/03/21 09:21:21 when you say "most common usage" do you actually m
henrika (OOO until Aug 14) 2012/03/21 10:16:04 I discussed it with Justin and it was OK to add su
700 audio_input_device_->SetAutomaticGainControl(enable);
701 agc_is_enabled_ = enable;
702 return 0;
682 } 703 }
683 704
684 bool WebRtcAudioDeviceImpl::AGC() const { 705 bool WebRtcAudioDeviceImpl::AGC() const {
685 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::AGC() " << "NOT IMPLEMENTED"; 706 // To reduce the usage of IPC messages, an internal AGC state is used.
686 return false; 707 // TODO(henrika): investigate if there is a need for a "deeper" getter.
708 return agc_is_enabled_;
687 } 709 }
688 710
689 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left, 711 int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left,
690 uint16_t volume_right) { 712 uint16_t volume_right) {
691 NOTIMPLEMENTED(); 713 NOTIMPLEMENTED();
692 return -1; 714 return -1;
693 } 715 }
694 int32_t WebRtcAudioDeviceImpl::WaveOutVolume( 716 int32_t WebRtcAudioDeviceImpl::WaveOutVolume(
695 uint16_t* volume_left, 717 uint16_t* volume_left,
696 uint16_t* volume_right) const { 718 uint16_t* volume_right) const {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const { 771 int32_t WebRtcAudioDeviceImpl::SpeakerVolume(uint32_t* volume) const {
750 NOTIMPLEMENTED(); 772 NOTIMPLEMENTED();
751 return -1; 773 return -1;
752 } 774 }
753 775
754 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const { 776 int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const {
755 NOTIMPLEMENTED(); 777 NOTIMPLEMENTED();
756 return -1; 778 return -1;
757 } 779 }
758 780
759 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume( 781 int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume(uint32_t* min_volume) const {
760 uint32_t* min_volume) const {
761 NOTIMPLEMENTED(); 782 NOTIMPLEMENTED();
762 return -1; 783 return -1;
763 } 784 }
764 785
765 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize( 786 int32_t WebRtcAudioDeviceImpl::SpeakerVolumeStepSize(
766 uint16_t* step_size) const { 787 uint16_t* step_size) const {
767 NOTIMPLEMENTED(); 788 NOTIMPLEMENTED();
768 return -1; 789 return -1;
769 } 790 }
770 791
771 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) { 792 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) {
772 NOTIMPLEMENTED(); 793 NOTIMPLEMENTED();
773 return -1; 794 return -1;
774 } 795 }
775 796
776 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { 797 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
777 NOTIMPLEMENTED(); 798 DVLOG(1) << "SetMicrophoneVolume(" << volume << ")";
799 if (volume > kMaxVolumeLevel)
800 return -1;
801
802 // WebRTC uses a range of [0, 255] to represent the level of the microphone
803 // volume. The IPC channel between the renderer and browser process works
804 // with doubles in the [0.0, 1.0] range and we have to compensate for that.
805 double normalized_volume = static_cast<double>(volume / kMaxVolumeLevel);
tommi (sloooow) - chröme 2012/03/16 13:31:05 is the cast needed?
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Good question. I don't think is required for funda
806 audio_input_device_->SetVolume(normalized_volume);
807 return 0;
808 }
809
810 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
811 // The microphone level is fed to this class using the Capture() callback
812 // and this external API should not be used. Additional IPC messages are
813 // required if support for this API is ever needed.
814 NOTREACHED();
778 return -1; 815 return -1;
779 } 816 }
780 817
781 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { 818 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
782 NOTIMPLEMENTED(); 819 *max_volume = kMaxVolumeLevel;
783 return -1; 820 return 0;
784 } 821 }
785 822
786 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume( 823 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
787 uint32_t* max_volume) const { 824 *min_volume = 0;
788 DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MaxMicrophoneVolume() " 825 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 } 826 }
799 827
800 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize( 828 int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize(
801 uint16_t* step_size) const { 829 uint16_t* step_size) const {
802 NOTIMPLEMENTED(); 830 NOTREACHED();
tommi (sloooow) - chröme 2012/03/16 13:31:05 A comment on why we never expect this to be called
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Good question. It is a method that have caused us
803 return -1; 831 return -1;
804 } 832 }
805 833
806 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) { 834 int32_t WebRtcAudioDeviceImpl::SpeakerMuteIsAvailable(bool* available) {
807 NOTIMPLEMENTED(); 835 NOTIMPLEMENTED();
808 return -1; 836 return -1;
809 } 837 }
810 838
811 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) { 839 int32_t WebRtcAudioDeviceImpl::SetSpeakerMute(bool enable) {
812 NOTIMPLEMENTED(); 840 NOTIMPLEMENTED();
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 } 1018 }
991 1019
992 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const { 1020 int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const {
993 NOTIMPLEMENTED(); 1021 NOTIMPLEMENTED();
994 return -1; 1022 return -1;
995 } 1023 }
996 1024
997 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) { 1025 void WebRtcAudioDeviceImpl::SetSessionId(int session_id) {
998 session_id_ = session_id; 1026 session_id_ = session_id;
999 } 1027 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698