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

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

Issue 37793005: move the APM to chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added a switch, it uses the APM in WebRtc if the switch is off, otherwise use the APM in Chrome. Created 7 years, 1 month 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_local_audio_track.h" 5 #include "content/renderer/media/webrtc_local_audio_track.h"
6 6
7 #include "content/renderer/media/webaudio_capturer_source.h" 7 #include "content/renderer/media/webaudio_capturer_source.h"
8 #include "content/renderer/media/webrtc_audio_capturer.h" 8 #include "content/renderer/media/webrtc_audio_capturer.h"
9 #include "content/renderer/media/webrtc_audio_capturer_sink_owner.h" 9 #include "content/renderer/media/webrtc_audio_capturer_sink_owner.h"
10 #include "content/renderer/media/webrtc_audio_processor.h"
10 #include "content/renderer/media/webrtc_local_audio_source_provider.h" 11 #include "content/renderer/media/webrtc_local_audio_source_provider.h"
11 #include "media/base/audio_fifo.h" 12 #include "media/base/audio_fifo.h"
12 #include "third_party/libjingle/source/talk/media/base/audiorenderer.h" 13 #include "third_party/libjingle/source/talk/media/base/audiorenderer.h"
13 14
14 namespace content { 15 namespace content {
15 16
16 static const size_t kMaxNumberOfBuffersInFifo = 2;
17 static const char kAudioTrackKind[] = "audio"; 17 static const char kAudioTrackKind[] = "audio";
18 18
19 namespace {
20
21 using webrtc::MediaConstraintsInterface;
22
23 // This helper function checks if any audio constraints are set that require
24 // audio processing to be applied. Right now this is a big, single switch for
25 // all of the properties, but in the future they'll be handled one by one.
26 bool NeedsAudioProcessing(
27 const webrtc::MediaConstraintsInterface* constraints) {
28 if (!constraints)
29 return false;
30
31 static const char* kAudioProcessingProperties[] = {
32 MediaConstraintsInterface::kEchoCancellation,
33 MediaConstraintsInterface::kExperimentalEchoCancellation,
34 MediaConstraintsInterface::kAutoGainControl,
35 MediaConstraintsInterface::kExperimentalAutoGainControl,
36 MediaConstraintsInterface::kNoiseSuppression,
37 MediaConstraintsInterface::kHighpassFilter,
38 MediaConstraintsInterface::kTypingNoiseDetection,
39 };
40
41 for (size_t i = 0; i < arraysize(kAudioProcessingProperties); ++i) {
42 bool value = false;
43 if (webrtc::FindConstraint(constraints, kAudioProcessingProperties[i],
44 &value, NULL) &&
45 value) {
46 return true;
47 }
48 }
49
50 return false;
51 }
52
53 } // namespace.
54
55 // This is a temporary audio buffer with parameters used to send data to
56 // callbacks.
57 class WebRtcLocalAudioTrack::ConfiguredBuffer :
58 public base::RefCounted<WebRtcLocalAudioTrack::ConfiguredBuffer> {
59 public:
60 ConfiguredBuffer() : sink_buffer_size_(0) {}
61
62 void Initialize(const media::AudioParameters& params) {
63 DCHECK(params.IsValid());
64 params_ = params;
65
66 // Use 10ms as the sink buffer size since that is the native packet size
67 // WebRtc is running on.
68 sink_buffer_size_ = params.sample_rate() / 100;
69 audio_wrapper_ =
70 media::AudioBus::Create(params.channels(), sink_buffer_size_);
71 buffer_.reset(new int16[sink_buffer_size_ * params.channels()]);
72
73 // The size of the FIFO should be at least twice of the source buffer size
74 // or twice of the sink buffer size.
75 int buffer_size = std::max(
76 kMaxNumberOfBuffersInFifo * params.frames_per_buffer(),
77 kMaxNumberOfBuffersInFifo * sink_buffer_size_);
78 fifo_.reset(new media::AudioFifo(params.channels(), buffer_size));
79 }
80
81 void Push(media::AudioBus* audio_source) {
82 DCHECK(fifo_->frames() + audio_source->frames() <= fifo_->max_frames());
83 fifo_->Push(audio_source);
84 }
85
86 bool Consume() {
87 if (fifo_->frames() < audio_wrapper_->frames())
88 return false;
89
90 fifo_->Consume(audio_wrapper_.get(), 0, audio_wrapper_->frames());
91 audio_wrapper_->ToInterleaved(audio_wrapper_->frames(),
92 params_.bits_per_sample() / 8,
93 buffer());
94 return true;
95 }
96
97 int16* buffer() const { return buffer_.get(); }
98 const media::AudioParameters& params() const { return params_; }
99 int sink_buffer_size() const { return sink_buffer_size_; }
100
101 private:
102 ~ConfiguredBuffer() {}
103 friend class base::RefCounted<WebRtcLocalAudioTrack::ConfiguredBuffer>;
104
105 media::AudioParameters params_;
106 scoped_ptr<media::AudioBus> audio_wrapper_;
107 scoped_ptr<media::AudioFifo> fifo_;
108 scoped_ptr<int16[]> buffer_;
109 int sink_buffer_size_;
110 };
111
112 scoped_refptr<WebRtcLocalAudioTrack> WebRtcLocalAudioTrack::Create( 19 scoped_refptr<WebRtcLocalAudioTrack> WebRtcLocalAudioTrack::Create(
113 const std::string& id, 20 const std::string& id,
114 const scoped_refptr<WebRtcAudioCapturer>& capturer, 21 const scoped_refptr<WebRtcAudioCapturer>& capturer,
115 WebAudioCapturerSource* webaudio_source, 22 WebAudioCapturerSource* webaudio_source,
116 webrtc::AudioSourceInterface* track_source, 23 webrtc::AudioSourceInterface* track_source,
117 const webrtc::MediaConstraintsInterface* constraints) { 24 const webrtc::MediaConstraintsInterface* constraints,
25 WebRtcAudioDeviceImpl* audio_device) {
118 talk_base::RefCountedObject<WebRtcLocalAudioTrack>* track = 26 talk_base::RefCountedObject<WebRtcLocalAudioTrack>* track =
119 new talk_base::RefCountedObject<WebRtcLocalAudioTrack>( 27 new talk_base::RefCountedObject<WebRtcLocalAudioTrack>(
120 id, capturer, webaudio_source, track_source, constraints); 28 id, capturer, webaudio_source, track_source,
29 constraints, audio_device);
121 return track; 30 return track;
122 } 31 }
123 32
124 WebRtcLocalAudioTrack::WebRtcLocalAudioTrack( 33 WebRtcLocalAudioTrack::WebRtcLocalAudioTrack(
125 const std::string& label, 34 const std::string& label,
126 const scoped_refptr<WebRtcAudioCapturer>& capturer, 35 const scoped_refptr<WebRtcAudioCapturer>& capturer,
127 WebAudioCapturerSource* webaudio_source, 36 WebAudioCapturerSource* webaudio_source,
128 webrtc::AudioSourceInterface* track_source, 37 webrtc::AudioSourceInterface* track_source,
129 const webrtc::MediaConstraintsInterface* constraints) 38 const webrtc::MediaConstraintsInterface* constraints,
39 WebRtcAudioDeviceImpl* audio_device)
130 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), 40 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label),
131 capturer_(capturer), 41 capturer_(capturer),
132 webaudio_source_(webaudio_source), 42 webaudio_source_(webaudio_source),
133 track_source_(track_source), 43 track_source_(track_source),
134 need_audio_processing_(NeedsAudioProcessing(constraints)) { 44 audio_processor_(new WebRtcAudioProcessor(constraints)),
45 source_provider_(new WebRtcLocalAudioSourceProvider()),
46 audio_device_(audio_device) {
135 DCHECK(capturer.get() || webaudio_source); 47 DCHECK(capturer.get() || webaudio_source);
48 DCHECK(audio_processor_.get());
49 DCHECK(source_provider_.get());
50 AddSink(source_provider_.get());
136 DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()"; 51 DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()";
137 } 52 }
138 53
139 WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() { 54 WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
140 DCHECK(thread_checker_.CalledOnValidThread()); 55 DCHECK(thread_checker_.CalledOnValidThread());
141 DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()"; 56 DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()";
142 // Users might not call Stop() on the track. 57 // Users might not call Stop() on the track.
143 Stop(); 58 Stop();
144 } 59 }
145 60
146 void WebRtcLocalAudioTrack::Capture(media::AudioBus* audio_source, 61 void WebRtcLocalAudioTrack::Capture(media::AudioBus* audio_source,
147 int audio_delay_milliseconds, 62 int audio_delay_milliseconds,
148 int volume, 63 int volume,
149 bool key_pressed) { 64 bool key_pressed) {
150 scoped_refptr<WebRtcAudioCapturer> capturer; 65 scoped_refptr<WebRtcAudioCapturer> capturer;
151 std::vector<int> voe_channels; 66 std::vector<int> voe_channels;
152 int sample_rate = 0;
153 int number_of_channels = 0;
154 int number_of_frames = 0;
155 SinkList sinks; 67 SinkList sinks;
68 media::AudioParameters params;
156 bool is_webaudio_source = false; 69 bool is_webaudio_source = false;
157 scoped_refptr<ConfiguredBuffer> current_buffer;
158 { 70 {
159 base::AutoLock auto_lock(lock_); 71 base::AutoLock auto_lock(lock_);
160 capturer = capturer_; 72 capturer = capturer_;
161 voe_channels = voe_channels_; 73 voe_channels = voe_channels_;
162 current_buffer = buffer_;
163 sample_rate = current_buffer->params().sample_rate();
164 number_of_channels = current_buffer->params().channels();
165 number_of_frames = current_buffer->sink_buffer_size();
166 sinks = sinks_; 74 sinks = sinks_;
75 params = sink_params_;
167 is_webaudio_source = (webaudio_source_.get() != NULL); 76 is_webaudio_source = (webaudio_source_.get() != NULL);
168 } 77 }
78 DCHECK(params.IsValid());
79 DCHECK(params.frames_per_buffer() == params.sample_rate() / 100);
169 80
170 // Push the data to the fifo. 81 audio_processor_->Push(audio_source);
171 current_buffer->Push(audio_source);
172 82
83 // Turn off the audio processing in WebRtc when the audio processor in Chrome
84 // is on.
85 bool need_audio_processing = !audio_processor_->has_audio_processing();
173 // When the source is WebAudio, turn off the audio processing if the delay 86 // When the source is WebAudio, turn off the audio processing if the delay
174 // value is 0 even though the constraint is set to true. In such case, it 87 // value is 0 even though the constraint is set to true. In such case, it
175 // indicates the data is not from microphone. 88 // indicates the data is not from microphone.
176 // TODO(xians): remove the flag when supporting one APM per audio track.
177 // See crbug/264611 for details.
178 bool need_audio_processing = need_audio_processing_;
179 if (is_webaudio_source && need_audio_processing) 89 if (is_webaudio_source && need_audio_processing)
180 need_audio_processing = (audio_delay_milliseconds != 0); 90 need_audio_processing = (audio_delay_milliseconds != 0);
181 91
182 int current_volume = volume; 92 int current_volume = volume;
183 while (current_buffer->Consume()) { 93 while (audio_processor_->ProcessAndConsume10MsData(
94 audio_delay_milliseconds, volume, key_pressed)) {
95 // TODO(xians): Get the new volume and set it to |current_volume|.
184 // Feed the data to the sinks. 96 // Feed the data to the sinks.
185 // TODO (jiayl): we should not pass the real audio data down if the track is 97 // TODO (jiayl): we should not pass the real audio data down if the track is
186 // disabled. This is currently done so to feed input to WebRTC typing 98 // disabled. This is currently done so to feed input to WebRTC typing
187 // detection and should be changed when audio processing is moved from 99 // detection and should be changed when audio processing is moved from
188 // WebRTC to the track. 100 // WebRTC to the track.
189 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) { 101 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) {
190 int new_volume = (*it)->CaptureData(voe_channels, 102 int new_volume = (*it)->CaptureData(voe_channels,
191 current_buffer->buffer(), 103 audio_processor_->OutputBuffer(),
192 sample_rate, 104 params.sample_rate(),
193 number_of_channels, 105 params.channels(),
194 number_of_frames, 106 params.frames_per_buffer(),
195 audio_delay_milliseconds, 107 audio_delay_milliseconds,
196 current_volume, 108 current_volume,
197 need_audio_processing, 109 need_audio_processing,
198 key_pressed); 110 key_pressed);
199 if (new_volume != 0 && capturer.get()) { 111 if (new_volume != 0 && capturer.get()) {
200 // Feed the new volume to WebRtc while changing the volume on the 112 // Feed the new volume to WebRtc while changing the volume on the
201 // browser. 113 // browser.
202 capturer->SetVolume(new_volume); 114 capturer->SetVolume(new_volume);
203 current_volume = new_volume; 115 current_volume = new_volume;
204 } 116 }
205 } 117 }
206 } 118 }
207 } 119 }
208 120
209 void WebRtcLocalAudioTrack::SetCaptureFormat( 121 void WebRtcLocalAudioTrack::SetCaptureFormat(
210 const media::AudioParameters& params) { 122 const media::AudioParameters& params) {
211 if (!params.IsValid()) 123 DCHECK(params.IsValid());
212 return;
213 124
214 scoped_refptr<ConfiguredBuffer> new_buffer(new ConfiguredBuffer()); 125 audio_processor_->SetFormat(params);
215 new_buffer->Initialize(params);
216
217 SinkList sinks; 126 SinkList sinks;
218 { 127 {
219 base::AutoLock auto_lock(lock_); 128 base::AutoLock auto_lock(lock_);
220 buffer_ = new_buffer; 129 source_params_ = params;
130 sink_params_ = audio_processor_->OutputFormat();
221 sinks = sinks_; 131 sinks = sinks_;
222 } 132 }
223 133
224 // Update all the existing sinks with the new format. 134 // Update all the existing sinks with the new format.
225 for (SinkList::const_iterator it = sinks.begin(); 135 for (SinkList::const_iterator it = sinks.begin();
226 it != sinks.end(); ++it) { 136 it != sinks.end(); ++it) {
227 (*it)->SetCaptureFormat(params); 137 (*it)->SetCaptureFormat(sink_params_);
228 } 138 }
229 } 139 }
230 140
231 void WebRtcLocalAudioTrack::AddChannel(int channel_id) { 141 void WebRtcLocalAudioTrack::AddChannel(int channel_id) {
232 DVLOG(1) << "WebRtcLocalAudioTrack::AddChannel(channel_id=" 142 DVLOG(1) << "WebRtcLocalAudioTrack::AddChannel(channel_id="
233 << channel_id << ")"; 143 << channel_id << ")";
234 base::AutoLock auto_lock(lock_); 144 base::AutoLock auto_lock(lock_);
235 if (std::find(voe_channels_.begin(), voe_channels_.end(), channel_id) != 145 if (std::find(voe_channels_.begin(), voe_channels_.end(), channel_id) !=
236 voe_channels_.end()) { 146 voe_channels_.end()) {
237 // We need to handle the case when the same channel is connected to the 147 // We need to handle the case when the same channel is connected to the
(...skipping 24 matching lines...) Expand all
262 } 172 }
263 173
264 std::string WebRtcLocalAudioTrack::kind() const { 174 std::string WebRtcLocalAudioTrack::kind() const {
265 return kAudioTrackKind; 175 return kAudioTrackKind;
266 } 176 }
267 177
268 void WebRtcLocalAudioTrack::AddSink(WebRtcAudioCapturerSink* sink) { 178 void WebRtcLocalAudioTrack::AddSink(WebRtcAudioCapturerSink* sink) {
269 DCHECK(thread_checker_.CalledOnValidThread()); 179 DCHECK(thread_checker_.CalledOnValidThread());
270 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()"; 180 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
271 base::AutoLock auto_lock(lock_); 181 base::AutoLock auto_lock(lock_);
272 if (buffer_.get()) 182
273 sink->SetCaptureFormat(buffer_->params()); 183 if (sink_params_.IsValid())
184 sink->SetCaptureFormat(sink_params_);
274 185
275 // Verify that |sink| is not already added to the list. 186 // Verify that |sink| is not already added to the list.
276 DCHECK(std::find_if( 187 DCHECK(std::find_if(
277 sinks_.begin(), sinks_.end(), 188 sinks_.begin(), sinks_.end(),
278 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)) == sinks_.end()); 189 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)) == sinks_.end());
279 190
280 // Create (and add to the list) a new WebRtcAudioCapturerSinkOwner which owns 191 // Create (and add to the list) a new WebRtcAudioCapturerSinkOwner which owns
281 // the |sink| and delagates all calls to the WebRtcAudioCapturerSink 192 // the |sink| and delagates all calls to the WebRtcAudioCapturerSink
282 // interface. 193 // interface.
283 sinks_.push_back(new WebRtcAudioCapturerSinkOwner(sink)); 194 sinks_.push_back(new WebRtcAudioCapturerSinkOwner(sink));
(...skipping 11 matching lines...) Expand all
295 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)); 206 WebRtcAudioCapturerSinkOwner::WrapsSink(sink));
296 if (it != sinks_.end()) { 207 if (it != sinks_.end()) {
297 // Clear the delegate to ensure that no more capture callbacks will 208 // Clear the delegate to ensure that no more capture callbacks will
298 // be sent to this sink. Also avoids a possible crash which can happen 209 // be sent to this sink. Also avoids a possible crash which can happen
299 // if this method is called while capturing is active. 210 // if this method is called while capturing is active.
300 (*it)->Reset(); 211 (*it)->Reset();
301 sinks_.erase(it); 212 sinks_.erase(it);
302 } 213 }
303 } 214 }
304 215
216 void WebRtcLocalAudioTrack::OnRenderData(const int16* render_audio,
217 int sample_rate,
218 int number_of_channels,
219 int number_of_frames,
220 int render_delay_ms) {
221 audio_processor_->FeedRenderDataToAudioProcessing(render_audio,
222 sample_rate,
223 number_of_channels,
224 number_of_frames,
225 render_delay_ms);
226 }
227
228 void WebRtcLocalAudioTrack::OnRenderClosing() {
229 base::AutoLock auto_lock(lock_);
230 audio_device_ = NULL;
231 }
232
305 void WebRtcLocalAudioTrack::Start() { 233 void WebRtcLocalAudioTrack::Start() {
306 DCHECK(thread_checker_.CalledOnValidThread()); 234 DCHECK(thread_checker_.CalledOnValidThread());
307 DVLOG(1) << "WebRtcLocalAudioTrack::Start()"; 235 DVLOG(1) << "WebRtcLocalAudioTrack::Start()";
308 if (webaudio_source_.get()) { 236 if (webaudio_source_.get()) {
309 // If the track is hooking up with WebAudio, do NOT add the track to the 237 // If the track is hooking up with WebAudio, do NOT add the track to the
310 // capturer as its sink otherwise two streams in different clock will be 238 // capturer as its sink otherwise two streams in different clock will be
311 // pushed through the same track. 239 // pushed through the same track.
312 WebRtcLocalAudioSourceProvider* source_provider = NULL; 240 webaudio_source_->Start(this, capturer_.get());
313 if (capturer_.get()) {
314 source_provider = static_cast<WebRtcLocalAudioSourceProvider*>(
315 capturer_->audio_source_provider());
316 }
317 webaudio_source_->Start(this, source_provider);
318 return; 241 return;
319 } 242 }
320 243
321 if (capturer_.get()) 244 if (capturer_.get())
322 capturer_->AddTrack(this); 245 capturer_->AddTrack(this);
246
247 if (audio_device_)
248 audio_device_->RemoveRenderDataObserver(this);
323 } 249 }
324 250
325 void WebRtcLocalAudioTrack::Stop() { 251 void WebRtcLocalAudioTrack::Stop() {
326 DCHECK(thread_checker_.CalledOnValidThread()); 252 DCHECK(thread_checker_.CalledOnValidThread());
327 DVLOG(1) << "WebRtcLocalAudioTrack::Stop()"; 253 DVLOG(1) << "WebRtcLocalAudioTrack::Stop()";
328 if (!capturer_.get() && !webaudio_source_.get()) 254 if (!capturer_.get() && !webaudio_source_.get())
329 return; 255 return;
330 256
331 if (webaudio_source_.get()) { 257 if (webaudio_source_.get()) {
332 // Called Stop() on the |webaudio_source_| explicitly so that 258 // Called Stop() on the |webaudio_source_| explicitly so that
333 // |webaudio_source_| won't push more data to the track anymore. 259 // |webaudio_source_| won't push more data to the track anymore.
334 // Also note that the track is not registered as a sink to the |capturer_| 260 // Also note that the track is not registered as a sink to the |capturer_|
335 // in such case and no need to call RemoveTrack(). 261 // in such case and no need to call RemoveTrack().
336 webaudio_source_->Stop(); 262 webaudio_source_->Stop();
337 } else {
338 capturer_->RemoveTrack(this);
339 } 263 }
340 264
341 // Protect the pointers using the lock when accessing |sinks_| and 265 // Protect the pointers using the lock when accessing |sinks_| and
342 // setting the |capturer_| to NULL. 266 // setting the |capturer_| to NULL.
343 SinkList sinks; 267 SinkList sinks;
344 { 268 {
345 base::AutoLock auto_lock(lock_); 269 base::AutoLock auto_lock(lock_);
346 sinks = sinks_; 270 sinks = sinks_;
347 webaudio_source_ = NULL; 271 webaudio_source_ = NULL;
348 capturer_ = NULL; 272 capturer_ = NULL;
273 if (audio_device_)
274 audio_device_->RemoveRenderDataObserver(this);
275 audio_device_ = NULL;
349 } 276 }
350 277
351 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) 278 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it)
352 (*it)->Reset(); 279 (*it)->Reset();
353 } 280 }
354 281
355 } // namespace content 282 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698