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