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) |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |