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_capturer.h" | 5 #include "content/renderer/media/webrtc_audio_capturer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 device_info_.device.input.sample_rate) == | 187 device_info_.device.input.sample_rate) == |
188 &kValidInputRates[arraysize(kValidInputRates)]) { | 188 &kValidInputRates[arraysize(kValidInputRates)]) { |
189 DLOG(ERROR) << device_info_.device.input.sample_rate | 189 DLOG(ERROR) << device_info_.device.input.sample_rate |
190 << " is not a supported input rate."; | 190 << " is not a supported input rate."; |
191 return false; | 191 return false; |
192 } | 192 } |
193 | 193 |
194 // Create and configure the default audio capturing source. | 194 // Create and configure the default audio capturing source. |
195 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id_), | 195 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id_), |
196 channel_layout, | 196 channel_layout, |
197 static_cast<float>(device_info_.device.input.sample_rate), | 197 static_cast<float>(device_info_.device.input.sample_rate)); |
198 device_info_.device.input.effects, | |
199 constraints_); | |
200 | 198 |
201 // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware | 199 // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware |
202 // information from the capturer. | 200 // information from the capturer. |
203 if (audio_device_) | 201 if (audio_device_) |
204 audio_device_->AddAudioCapturer(this); | 202 audio_device_->AddAudioCapturer(this); |
205 | 203 |
206 return true; | 204 return true; |
207 } | 205 } |
208 | 206 |
209 WebRtcAudioCapturer::WebRtcAudioCapturer( | 207 WebRtcAudioCapturer::WebRtcAudioCapturer( |
210 int render_view_id, | 208 int render_view_id, |
211 const StreamDeviceInfo& device_info, | 209 const StreamDeviceInfo& device_info, |
212 const blink::WebMediaConstraints& constraints, | 210 const blink::WebMediaConstraints& constraints, |
213 WebRtcAudioDeviceImpl* audio_device) | 211 WebRtcAudioDeviceImpl* audio_device) |
214 : constraints_(constraints), | 212 : constraints_(constraints), |
| 213 audio_processor_( |
| 214 new talk_base::RefCountedObject<MediaStreamAudioProcessor>( |
| 215 constraints, device_info.device.input.effects, audio_device)), |
215 running_(false), | 216 running_(false), |
216 render_view_id_(render_view_id), | 217 render_view_id_(render_view_id), |
217 device_info_(device_info), | 218 device_info_(device_info), |
218 volume_(0), | 219 volume_(0), |
219 peer_connection_mode_(false), | 220 peer_connection_mode_(false), |
220 key_pressed_(false), | 221 key_pressed_(false), |
221 need_audio_processing_(false), | 222 need_audio_processing_(false), |
222 audio_device_(audio_device) { | 223 audio_device_(audio_device) { |
223 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | 224 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; |
224 } | 225 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 // Clear the delegate to ensure that no more capture callbacks will | 262 // Clear the delegate to ensure that no more capture callbacks will |
262 // be sent to this sink. Also avoids a possible crash which can happen | 263 // be sent to this sink. Also avoids a possible crash which can happen |
263 // if this method is called while capturing is active. | 264 // if this method is called while capturing is active. |
264 if (removed_item.get()) | 265 if (removed_item.get()) |
265 removed_item->Reset(); | 266 removed_item->Reset(); |
266 } | 267 } |
267 | 268 |
268 void WebRtcAudioCapturer::SetCapturerSource( | 269 void WebRtcAudioCapturer::SetCapturerSource( |
269 const scoped_refptr<media::AudioCapturerSource>& source, | 270 const scoped_refptr<media::AudioCapturerSource>& source, |
270 media::ChannelLayout channel_layout, | 271 media::ChannelLayout channel_layout, |
271 float sample_rate, | 272 float sample_rate) { |
272 int effects, | |
273 const blink::WebMediaConstraints& constraints) { | |
274 DCHECK(thread_checker_.CalledOnValidThread()); | 273 DCHECK(thread_checker_.CalledOnValidThread()); |
275 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," | 274 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," |
276 << "sample_rate=" << sample_rate << ")"; | 275 << "sample_rate=" << sample_rate << ")"; |
277 scoped_refptr<media::AudioCapturerSource> old_source; | 276 scoped_refptr<media::AudioCapturerSource> old_source; |
278 bool restart_source = false; | 277 bool restart_source = false; |
279 { | 278 { |
280 base::AutoLock auto_lock(lock_); | 279 base::AutoLock auto_lock(lock_); |
281 if (source_.get() == source.get()) | 280 if (source_.get() == source.get()) |
282 return; | 281 return; |
283 | 282 |
(...skipping 10 matching lines...) Expand all Loading... |
294 old_source->Stop(); | 293 old_source->Stop(); |
295 | 294 |
296 // Dispatch the new parameters both to the sink(s) and to the new source, | 295 // Dispatch the new parameters both to the sink(s) and to the new source, |
297 // also apply the new |constraints|. | 296 // also apply the new |constraints|. |
298 // The idea is to get rid of any dependency of the microphone parameters | 297 // The idea is to get rid of any dependency of the microphone parameters |
299 // which would normally be used by default. | 298 // which would normally be used by default. |
300 // bits_per_sample is always 16 for now. | 299 // bits_per_sample is always 16 for now. |
301 int buffer_size = GetBufferSize(sample_rate); | 300 int buffer_size = GetBufferSize(sample_rate); |
302 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 301 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
303 channel_layout, 0, sample_rate, | 302 channel_layout, 0, sample_rate, |
304 16, buffer_size, effects); | 303 16, buffer_size, |
305 scoped_refptr<MediaStreamAudioProcessor> new_audio_processor( | 304 device_info_.device.input.effects); |
306 new talk_base::RefCountedObject<MediaStreamAudioProcessor>( | 305 |
307 params, constraints, effects, audio_device_)); | |
308 { | 306 { |
309 base::AutoLock auto_lock(lock_); | 307 base::AutoLock auto_lock(lock_); |
310 audio_processor_ = new_audio_processor; | 308 // Notify the |audio_processor_| of the new format. |
311 need_audio_processing_ = NeedsAudioProcessing(constraints, effects); | 309 audio_processor_->OnCaptureFormatChanged(params); |
312 | 310 |
| 311 need_audio_processing_ = NeedsAudioProcessing( |
| 312 constraints_, device_info_.device.input.effects); |
313 // Notify all tracks about the new format. | 313 // Notify all tracks about the new format. |
314 tracks_.TagAll(); | 314 tracks_.TagAll(); |
315 } | 315 } |
316 | 316 |
317 if (source.get()) | 317 if (source.get()) |
318 source->Initialize(params, this, session_id()); | 318 source->Initialize(params, this, session_id()); |
319 | 319 |
320 if (restart_source) | 320 if (restart_source) |
321 Start(); | 321 Start(); |
322 } | 322 } |
(...skipping 22 matching lines...) Expand all Loading... |
345 // Do nothing if the current buffer size is the WebRtc native buffer size. | 345 // Do nothing if the current buffer size is the WebRtc native buffer size. |
346 if (GetBufferSize(input_params.sample_rate()) == | 346 if (GetBufferSize(input_params.sample_rate()) == |
347 input_params.frames_per_buffer()) { | 347 input_params.frames_per_buffer()) { |
348 return; | 348 return; |
349 } | 349 } |
350 | 350 |
351 // Create a new audio stream as source which will open the hardware using | 351 // Create a new audio stream as source which will open the hardware using |
352 // WebRtc native buffer size. | 352 // WebRtc native buffer size. |
353 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), | 353 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), |
354 input_params.channel_layout(), | 354 input_params.channel_layout(), |
355 static_cast<float>(input_params.sample_rate()), | 355 static_cast<float>(input_params.sample_rate())); |
356 input_params.effects(), | |
357 constraints_); | |
358 } | 356 } |
359 | 357 |
360 void WebRtcAudioCapturer::Start() { | 358 void WebRtcAudioCapturer::Start() { |
| 359 DCHECK(thread_checker_.CalledOnValidThread()); |
361 DVLOG(1) << "WebRtcAudioCapturer::Start()"; | 360 DVLOG(1) << "WebRtcAudioCapturer::Start()"; |
362 base::AutoLock auto_lock(lock_); | 361 base::AutoLock auto_lock(lock_); |
363 if (running_ || !source_) | 362 if (running_ || !source_) |
364 return; | 363 return; |
365 | 364 |
366 // Start the data source, i.e., start capturing data from the current source. | 365 // Start the data source, i.e., start capturing data from the current source. |
367 // We need to set the AGC control before starting the stream. | 366 // We need to set the AGC control before starting the stream. |
368 source_->SetAutomaticGainControl(true); | 367 source_->SetAutomaticGainControl(true); |
369 source_->Start(); | 368 source_->Start(); |
370 running_ = true; | 369 running_ = true; |
371 } | 370 } |
372 | 371 |
373 void WebRtcAudioCapturer::Stop() { | 372 void WebRtcAudioCapturer::Stop() { |
| 373 DCHECK(thread_checker_.CalledOnValidThread()); |
374 DVLOG(1) << "WebRtcAudioCapturer::Stop()"; | 374 DVLOG(1) << "WebRtcAudioCapturer::Stop()"; |
375 scoped_refptr<media::AudioCapturerSource> source; | 375 scoped_refptr<media::AudioCapturerSource> source; |
376 TrackList::ItemList tracks; | 376 TrackList::ItemList tracks; |
377 { | 377 { |
378 base::AutoLock auto_lock(lock_); | 378 base::AutoLock auto_lock(lock_); |
379 if (!running_) | 379 if (!running_) |
380 return; | 380 return; |
381 | 381 |
382 source = source_; | 382 source = source_; |
383 tracks = tracks_.Items(); | 383 tracks = tracks_.Items(); |
384 tracks_.Clear(); | 384 tracks_.Clear(); |
385 running_ = false; | 385 running_ = false; |
386 } | 386 } |
387 | 387 |
388 // Remove the capturer object from the WebRtcAudioDeviceImpl. | 388 // Remove the capturer object from the WebRtcAudioDeviceImpl. |
389 if (audio_device_) | 389 if (audio_device_) |
390 audio_device_->RemoveAudioCapturer(this); | 390 audio_device_->RemoveAudioCapturer(this); |
391 | 391 |
| 392 // Stop the Aec dump. |
| 393 StopAecDump(); |
| 394 |
392 for (TrackList::ItemList::const_iterator it = tracks.begin(); | 395 for (TrackList::ItemList::const_iterator it = tracks.begin(); |
393 it != tracks.end(); | 396 it != tracks.end(); |
394 ++it) { | 397 ++it) { |
395 (*it)->Stop(); | 398 (*it)->Stop(); |
396 } | 399 } |
397 | 400 |
398 if (source.get()) | 401 if (source.get()) |
399 source->Stop(); | 402 source->Stop(); |
400 } | 403 } |
401 | 404 |
(...skipping 30 matching lines...) Expand all Loading... |
432 // allows the user to set a scaling that is higher than 100%. It means that | 435 // allows the user to set a scaling that is higher than 100%. It means that |
433 // even if the reported maximum levels is N, the actual microphone level can | 436 // even if the reported maximum levels is N, the actual microphone level can |
434 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x. | 437 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x. |
435 DCHECK_LE(volume, 1.6); | 438 DCHECK_LE(volume, 1.6); |
436 #endif | 439 #endif |
437 | 440 |
438 TrackList::ItemList tracks; | 441 TrackList::ItemList tracks; |
439 TrackList::ItemList tracks_to_notify_format; | 442 TrackList::ItemList tracks_to_notify_format; |
440 int current_volume = 0; | 443 int current_volume = 0; |
441 base::TimeDelta audio_delay; | 444 base::TimeDelta audio_delay; |
442 scoped_refptr<MediaStreamAudioProcessor> audio_processor; | |
443 bool need_audio_processing = true; | 445 bool need_audio_processing = true; |
444 { | 446 { |
445 base::AutoLock auto_lock(lock_); | 447 base::AutoLock auto_lock(lock_); |
446 if (!running_) | 448 if (!running_) |
447 return; | 449 return; |
448 | 450 |
449 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the | 451 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the |
450 // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the | 452 // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the |
451 // volume is higher than 255. | 453 // volume is higher than 255. |
452 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); | 454 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); |
453 current_volume = volume_; | 455 current_volume = volume_; |
454 audio_delay = base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 456 audio_delay = base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
455 audio_delay_ = audio_delay; | 457 audio_delay_ = audio_delay; |
456 key_pressed_ = key_pressed; | 458 key_pressed_ = key_pressed; |
457 tracks = tracks_.Items(); | 459 tracks = tracks_.Items(); |
458 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); | 460 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); |
459 audio_processor = audio_processor_; | |
460 | 461 |
461 // Set the flag to turn on the audio processing in PeerConnection level. | 462 // Set the flag to turn on the audio processing in PeerConnection level. |
462 // Note that, we turn off the audio processing in PeerConnection if the | 463 // Note that, we turn off the audio processing in PeerConnection if the |
463 // processor has already processed the data. | 464 // processor has already processed the data. |
464 need_audio_processing = need_audio_processing_ ? | 465 need_audio_processing = need_audio_processing_ ? |
465 !audio_processor->has_audio_processing() : false; | 466 !audio_processor_->has_audio_processing() : false; |
466 } | 467 } |
467 | 468 |
468 DCHECK(audio_processor->InputFormat().IsValid()); | 469 DCHECK(audio_processor_->InputFormat().IsValid()); |
469 DCHECK_EQ(audio_source->channels(), | 470 DCHECK_EQ(audio_source->channels(), |
470 audio_processor->InputFormat().channels()); | 471 audio_processor_->InputFormat().channels()); |
471 DCHECK_EQ(audio_source->frames(), | 472 DCHECK_EQ(audio_source->frames(), |
472 audio_processor->InputFormat().frames_per_buffer()); | 473 audio_processor_->InputFormat().frames_per_buffer()); |
473 | 474 |
474 // Notify the tracks on when the format changes. This will do nothing if | 475 // Notify the tracks on when the format changes. This will do nothing if |
475 // |tracks_to_notify_format| is empty. | 476 // |tracks_to_notify_format| is empty. |
476 media::AudioParameters output_params = audio_processor->OutputFormat(); | 477 media::AudioParameters output_params = audio_processor_->OutputFormat(); |
477 for (TrackList::ItemList::const_iterator it = tracks_to_notify_format.begin(); | 478 for (TrackList::ItemList::const_iterator it = tracks_to_notify_format.begin(); |
478 it != tracks_to_notify_format.end(); ++it) { | 479 it != tracks_to_notify_format.end(); ++it) { |
479 (*it)->OnSetFormat(output_params); | 480 (*it)->OnSetFormat(output_params); |
480 (*it)->SetAudioProcessor(audio_processor); | 481 (*it)->SetAudioProcessor(audio_processor_); |
481 } | 482 } |
482 | 483 |
483 // Push the data to the processor for processing. | 484 // Push the data to the processor for processing. |
484 audio_processor->PushCaptureData(audio_source); | 485 audio_processor_->PushCaptureData(audio_source); |
485 | 486 |
486 // Process and consume the data in the processor until there is not enough | 487 // Process and consume the data in the processor until there is not enough |
487 // data in the processor. | 488 // data in the processor. |
488 int16* output = NULL; | 489 int16* output = NULL; |
489 int new_volume = 0; | 490 int new_volume = 0; |
490 while (audio_processor->ProcessAndConsumeData( | 491 while (audio_processor_->ProcessAndConsumeData( |
491 audio_delay, current_volume, key_pressed, &new_volume, &output)) { | 492 audio_delay, current_volume, key_pressed, &new_volume, &output)) { |
492 // Feed the post-processed data to the tracks. | 493 // Feed the post-processed data to the tracks. |
493 for (TrackList::ItemList::const_iterator it = tracks.begin(); | 494 for (TrackList::ItemList::const_iterator it = tracks.begin(); |
494 it != tracks.end(); ++it) { | 495 it != tracks.end(); ++it) { |
495 (*it)->Capture(output, audio_delay, current_volume, key_pressed, | 496 (*it)->Capture(output, audio_delay, current_volume, key_pressed, |
496 need_audio_processing); | 497 need_audio_processing); |
497 } | 498 } |
498 | 499 |
499 if (new_volume) { | 500 if (new_volume) { |
500 SetVolume(new_volume); | 501 SetVolume(new_volume); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 *delay = audio_delay_; | 563 *delay = audio_delay_; |
563 *volume = volume_; | 564 *volume = volume_; |
564 *key_pressed = key_pressed_; | 565 *key_pressed = key_pressed_; |
565 } | 566 } |
566 | 567 |
567 void WebRtcAudioCapturer::SetCapturerSourceForTesting( | 568 void WebRtcAudioCapturer::SetCapturerSourceForTesting( |
568 const scoped_refptr<media::AudioCapturerSource>& source, | 569 const scoped_refptr<media::AudioCapturerSource>& source, |
569 media::AudioParameters params) { | 570 media::AudioParameters params) { |
570 // Create a new audio stream as source which uses the new source. | 571 // Create a new audio stream as source which uses the new source. |
571 SetCapturerSource(source, params.channel_layout(), | 572 SetCapturerSource(source, params.channel_layout(), |
572 static_cast<float>(params.sample_rate()), | 573 static_cast<float>(params.sample_rate())); |
573 params.effects(), | 574 } |
574 constraints_); | 575 |
| 576 void WebRtcAudioCapturer::StartAecDump( |
| 577 const base::PlatformFile& aec_dump_file) { |
| 578 DCHECK(thread_checker_.CalledOnValidThread()); |
| 579 DCHECK_NE(aec_dump_file, base::kInvalidPlatformFileValue); |
| 580 audio_processor_->StartAecDump(aec_dump_file); |
| 581 } |
| 582 |
| 583 void WebRtcAudioCapturer::StopAecDump() { |
| 584 DCHECK(thread_checker_.CalledOnValidThread()); |
| 585 audio_processor_->StopAecDump(); |
575 } | 586 } |
576 | 587 |
577 } // namespace content | 588 } // namespace content |
OLD | NEW |