| 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 |