Index: content/renderer/media/webrtc/processed_local_audio_source.cc |
diff --git a/content/renderer/media/webrtc/processed_local_audio_source.cc b/content/renderer/media/webrtc/processed_local_audio_source.cc |
deleted file mode 100644 |
index 863542761ea6201bc222e050f5ae991c90b8003b..0000000000000000000000000000000000000000 |
--- a/content/renderer/media/webrtc/processed_local_audio_source.cc |
+++ /dev/null |
@@ -1,389 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/renderer/media/webrtc/processed_local_audio_source.h" |
- |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/strings/stringprintf.h" |
-#include "content/renderer/media/audio_device_factory.h" |
-#include "content/renderer/media/media_stream_audio_processor_options.h" |
-#include "content/renderer/media/media_stream_constraints_util.h" |
-#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" |
-#include "content/renderer/media/webrtc_audio_device_impl.h" |
-#include "content/renderer/media/webrtc_logging.h" |
-#include "content/renderer/render_frame_impl.h" |
-#include "media/audio/sample_rates.h" |
-#include "media/base/channel_layout.h" |
-#include "third_party/webrtc/api/mediaconstraintsinterface.h" |
-#include "third_party/webrtc/media/base/mediachannel.h" |
- |
-namespace content { |
- |
-namespace { |
-// Used as an identifier for ProcessedLocalAudioSource::From(). |
-void* const kClassIdentifier = const_cast<void**>(&kClassIdentifier); |
-} // namespace |
- |
-ProcessedLocalAudioSource::ProcessedLocalAudioSource( |
- int consumer_render_frame_id, |
- const StreamDeviceInfo& device_info, |
- PeerConnectionDependencyFactory* factory) |
- : MediaStreamAudioSource(true /* is_local_source */), |
- consumer_render_frame_id_(consumer_render_frame_id), |
- pc_factory_(factory), |
- volume_(0), |
- allow_invalid_render_frame_id_for_testing_(false) { |
- DCHECK(pc_factory_); |
- DVLOG(1) << "ProcessedLocalAudioSource::ProcessedLocalAudioSource()"; |
- MediaStreamSource::SetDeviceInfo(device_info); |
-} |
- |
-ProcessedLocalAudioSource::~ProcessedLocalAudioSource() { |
- DVLOG(1) << "ProcessedLocalAudioSource::~ProcessedLocalAudioSource()"; |
- EnsureSourceIsStopped(); |
-} |
- |
-// static |
-ProcessedLocalAudioSource* ProcessedLocalAudioSource::From( |
- MediaStreamAudioSource* source) { |
- if (source && source->GetClassIdentifier() == kClassIdentifier) |
- return static_cast<ProcessedLocalAudioSource*>(source); |
- return nullptr; |
-} |
- |
-void ProcessedLocalAudioSource::SetSourceConstraints( |
- const blink::WebMediaConstraints& constraints) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(!constraints.isNull()); |
- DCHECK(!source_); |
- constraints_ = constraints; |
-} |
- |
-void* ProcessedLocalAudioSource::GetClassIdentifier() const { |
- return kClassIdentifier; |
-} |
- |
-bool ProcessedLocalAudioSource::EnsureSourceIsStarted() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- if (source_) |
- return true; |
- |
- // Sanity-check that the consuming RenderFrame still exists. This is required |
- // to initialize the audio source. |
- if (!allow_invalid_render_frame_id_for_testing_ && |
- !RenderFrameImpl::FromRoutingID(consumer_render_frame_id_)) { |
- WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails " |
- " because the render frame does not exist."); |
- return false; |
- } |
- |
- WebRtcLogMessage(base::StringPrintf( |
- "ProcessedLocalAudioSource::EnsureSourceIsStarted. render_frame_id=%d" |
- ", channel_layout=%d, sample_rate=%d, buffer_size=%d" |
- ", session_id=%d, paired_output_sample_rate=%d" |
- ", paired_output_frames_per_buffer=%d, effects=%d. ", |
- consumer_render_frame_id_, device_info().device.input.channel_layout, |
- device_info().device.input.sample_rate, |
- device_info().device.input.frames_per_buffer, device_info().session_id, |
- device_info().device.matched_output.sample_rate, |
- device_info().device.matched_output.frames_per_buffer, |
- device_info().device.input.effects)); |
- |
- // Sanity-check that the constraints, plus the additional input effects are |
- // valid when combined. |
- const MediaAudioConstraints audio_constraints( |
- constraints_, device_info().device.input.effects); |
- if (!audio_constraints.IsValid()) { |
- WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails " |
- " because MediaAudioConstraints are not valid."); |
- return false; |
- } |
- |
- // Build an AudioOptions by applying relevant constraints to it, and then use |
- // it to create a webrtc::AudioSourceInterface instance. |
- cricket::AudioOptions rtc_options; |
- rtc_options.echo_cancellation = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::echoCancellation); |
- rtc_options.delay_agnostic_aec = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::googDAEchoCancellation); |
- rtc_options.auto_gain_control = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::googAutoGainControl); |
- rtc_options.experimental_agc = ConstraintToOptional( |
- constraints_, |
- &blink::WebMediaTrackConstraintSet::googExperimentalAutoGainControl); |
- rtc_options.noise_suppression = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::googNoiseSuppression); |
- rtc_options.experimental_ns = ConstraintToOptional( |
- constraints_, |
- &blink::WebMediaTrackConstraintSet::googExperimentalNoiseSuppression); |
- rtc_options.highpass_filter = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::googHighpassFilter); |
- rtc_options.typing_detection = ConstraintToOptional( |
- constraints_, |
- &blink::WebMediaTrackConstraintSet::googTypingNoiseDetection); |
- rtc_options.stereo_swapping = ConstraintToOptional( |
- constraints_, &blink::WebMediaTrackConstraintSet::googAudioMirroring); |
- MediaAudioConstraints::ApplyFixedAudioConstraints(&rtc_options); |
- if (device_info().device.input.effects & |
- media::AudioParameters::ECHO_CANCELLER) { |
- // TODO(hta): Figure out if we should be looking at echoCancellation. |
- // Previous code had googEchoCancellation only. |
- const blink::BooleanConstraint& echoCancellation = |
- constraints_.basic().googEchoCancellation; |
- if (echoCancellation.hasExact() && !echoCancellation.exact()) { |
- StreamDeviceInfo modified_device_info(device_info()); |
- modified_device_info.device.input.effects &= |
- ~media::AudioParameters::ECHO_CANCELLER; |
- SetDeviceInfo(modified_device_info); |
- } |
- rtc_options.echo_cancellation = rtc::Optional<bool>(false); |
- } |
- rtc_source_ = pc_factory_->CreateLocalAudioSource(rtc_options); |
- if (rtc_source_->state() != webrtc::MediaSourceInterface::kLive) { |
- WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails " |
- " because the rtc LocalAudioSource is not live."); |
- return false; |
- } |
- |
- // Create the MediaStreamAudioProcessor, bound to the WebRTC audio device |
- // module. |
- WebRtcAudioDeviceImpl* const rtc_audio_device = |
- pc_factory_->GetWebRtcAudioDevice(); |
- if (!rtc_audio_device) { |
- WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails " |
- " because there is no WebRtcAudioDeviceImpl instance."); |
- return false; |
- } |
- audio_processor_ = new rtc::RefCountedObject<MediaStreamAudioProcessor>( |
- constraints_, device_info().device.input, rtc_audio_device); |
- |
- // If KEYBOARD_MIC effect is set, change the layout to the corresponding |
- // layout that includes the keyboard mic. |
- media::ChannelLayout channel_layout = static_cast<media::ChannelLayout>( |
- device_info().device.input.channel_layout); |
- if ((device_info().device.input.effects & |
- media::AudioParameters::KEYBOARD_MIC) && |
- audio_constraints.GetGoogExperimentalNoiseSuppression()) { |
- if (channel_layout == media::CHANNEL_LAYOUT_STEREO) { |
- channel_layout = media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC; |
- DVLOG(1) << "Changed stereo layout to stereo + keyboard mic layout due " |
- << "to KEYBOARD_MIC effect."; |
- } else { |
- DVLOG(1) << "KEYBOARD_MIC effect ignored, not compatible with layout " |
- << channel_layout; |
- } |
- } |
- |
- DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; |
- UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
- channel_layout, media::CHANNEL_LAYOUT_MAX + 1); |
- |
- // Verify that the reported input channel configuration is supported. |
- if (channel_layout != media::CHANNEL_LAYOUT_MONO && |
- channel_layout != media::CHANNEL_LAYOUT_STEREO && |
- channel_layout != media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { |
- WebRtcLogMessage(base::StringPrintf( |
- "ProcessedLocalAudioSource::EnsureSourceIsStarted() fails " |
- " because the input channel layout (%d) is not supported.", |
- static_cast<int>(channel_layout))); |
- return false; |
- } |
- |
- DVLOG(1) << "Audio input hardware sample rate: " |
- << device_info().device.input.sample_rate; |
- media::AudioSampleRate asr; |
- if (media::ToAudioSampleRate(device_info().device.input.sample_rate, &asr)) { |
- UMA_HISTOGRAM_ENUMERATION( |
- "WebRTC.AudioInputSampleRate", asr, media::kAudioSampleRateMax + 1); |
- } else { |
- UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", |
- device_info().device.input.sample_rate); |
- } |
- |
- // Determine the audio format required of the AudioCapturerSource. Then, pass |
- // that to the |audio_processor_| and set the output format of this |
- // ProcessedLocalAudioSource to the processor's output format. |
- media::AudioParameters params( |
- media::AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
- device_info().device.input.sample_rate, 16, |
- GetBufferSize(device_info().device.input.sample_rate)); |
- params.set_effects(device_info().device.input.effects); |
- DCHECK(params.IsValid()); |
- audio_processor_->OnCaptureFormatChanged(params); |
- MediaStreamAudioSource::SetFormat(audio_processor_->OutputFormat()); |
- |
- // Start the source. |
- VLOG(1) << "Starting WebRTC audio source for consumption by render frame " |
- << consumer_render_frame_id_ << " with input parameters={" |
- << params.AsHumanReadableString() << "} and output parameters={" |
- << GetAudioParameters().AsHumanReadableString() << '}'; |
- source_ = |
- AudioDeviceFactory::NewAudioCapturerSource(consumer_render_frame_id_); |
- source_->Initialize(params, this, device_info().session_id); |
- // We need to set the AGC control before starting the stream. |
- source_->SetAutomaticGainControl(true); |
- source_->Start(); |
- |
- // Register this source with the WebRtcAudioDeviceImpl. |
- rtc_audio_device->AddAudioCapturer(this); |
- |
- return true; |
-} |
- |
-void ProcessedLocalAudioSource::EnsureSourceIsStopped() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- if (!source_) |
- return; |
- |
- if (WebRtcAudioDeviceImpl* rtc_audio_device = |
- pc_factory_->GetWebRtcAudioDevice()) { |
- rtc_audio_device->RemoveAudioCapturer(this); |
- } |
- |
- // Note: Stopping the source while holding the |volume_lock_| because the |
- // SetVolume() method needs to know whether |source_| is valid. |
- { |
- base::AutoLock auto_lock(volume_lock_); |
- source_->Stop(); |
- source_ = nullptr; |
- } |
- |
- // Stop the audio processor to avoid feeding render data into the processor. |
- audio_processor_->Stop(); |
- |
- VLOG(1) << "Stopped WebRTC audio pipeline for consumption by render frame " |
- << consumer_render_frame_id_ << '.'; |
-} |
- |
-void ProcessedLocalAudioSource::SetVolume(int volume) { |
- DVLOG(1) << "ProcessedLocalAudioSource::SetVolume()"; |
- DCHECK_LE(volume, MaxVolume()); |
- double normalized_volume = static_cast<double>(volume) / MaxVolume(); |
- base::AutoLock auto_lock(volume_lock_); |
- if (source_) |
- source_->SetVolume(normalized_volume); |
-} |
- |
-int ProcessedLocalAudioSource::Volume() const { |
- base::AutoLock auto_lock(volume_lock_); |
- return volume_; |
-} |
- |
-int ProcessedLocalAudioSource::MaxVolume() const { |
- return WebRtcAudioDeviceImpl::kMaxVolumeLevel; |
-} |
- |
-void ProcessedLocalAudioSource::Capture(const media::AudioBus* audio_bus, |
- int audio_delay_milliseconds, |
- double volume, |
- bool key_pressed) { |
-#if defined(OS_WIN) || defined(OS_MACOSX) |
- DCHECK_LE(volume, 1.0); |
-#elif (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_OPENBSD) |
- // We have a special situation on Linux where the microphone volume can be |
- // "higher than maximum". The input volume slider in the sound preference |
- // allows the user to set a scaling that is higher than 100%. It means that |
- // even if the reported maximum levels is N, the actual microphone level can |
- // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x. |
- DCHECK_LE(volume, 1.6); |
-#endif |
- |
- // TODO(miu): Plumbing is needed to determine the actual capture timestamp |
- // of the audio, instead of just snapshotting TimeTicks::Now(), for proper |
- // audio/video sync. http://crbug.com/335335 |
- const base::TimeTicks reference_clock_snapshot = base::TimeTicks::Now(); |
- |
- // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC. |
- // The volume can be higher than 255 on Linux, and it will be cropped to |
- // 255 since AGC does not allow values out of range. |
- int current_volume = static_cast<int>((volume * MaxVolume()) + 0.5); |
- { |
- base::AutoLock auto_lock(volume_lock_); |
- volume_ = current_volume; |
- } |
- current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_; |
- |
- // Sanity-check the input audio format in debug builds. Then, notify the |
- // tracks if the format has changed. |
- // |
- // Locking is not needed here to read the audio input/output parameters |
- // because the audio processor format changes only occur while audio capture |
- // is stopped. |
- DCHECK(audio_processor_->InputFormat().IsValid()); |
- DCHECK_EQ(audio_bus->channels(), audio_processor_->InputFormat().channels()); |
- DCHECK_EQ(audio_bus->frames(), |
- audio_processor_->InputFormat().frames_per_buffer()); |
- |
- // Figure out if the pre-processed data has any energy or not. This |
- // information will be passed to the level calculator to force it to report |
- // energy in case the post-processed data is zeroed by the audio processing. |
- const bool force_report_nonzero_energy = !audio_bus->AreFramesZero(); |
- |
- // Push the data to the processor for processing. |
- audio_processor_->PushCaptureData( |
- *audio_bus, |
- base::TimeDelta::FromMilliseconds(audio_delay_milliseconds)); |
- |
- // Process and consume the data in the processor until there is not enough |
- // data in the processor. |
- media::AudioBus* processed_data = nullptr; |
- base::TimeDelta processed_data_audio_delay; |
- int new_volume = 0; |
- while (audio_processor_->ProcessAndConsumeData( |
- current_volume, key_pressed, |
- &processed_data, &processed_data_audio_delay, &new_volume)) { |
- DCHECK(processed_data); |
- |
- level_calculator_.Calculate(*processed_data, force_report_nonzero_energy); |
- |
- MediaStreamAudioSource::DeliverDataToTracks( |
- *processed_data, reference_clock_snapshot - processed_data_audio_delay); |
- |
- if (new_volume) { |
- SetVolume(new_volume); |
- |
- // Update the |current_volume| to avoid passing the old volume to AGC. |
- current_volume = new_volume; |
- } |
- } |
-} |
- |
-void ProcessedLocalAudioSource::OnCaptureError(const std::string& message) { |
- WebRtcLogMessage("ProcessedLocalAudioSource::OnCaptureError: " + message); |
-} |
- |
-media::AudioParameters ProcessedLocalAudioSource::GetInputFormat() const { |
- return audio_processor_ ? audio_processor_->InputFormat() |
- : media::AudioParameters(); |
-} |
- |
-int ProcessedLocalAudioSource::GetBufferSize(int sample_rate) const { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
-#if defined(OS_ANDROID) |
- // TODO(henrika): Re-evaluate whether to use same logic as other platforms. |
- return (2 * sample_rate / 100); |
-#endif |
- |
- // If audio processing is turned on, require 10ms buffers. |
- if (audio_processor_->has_audio_processing()) |
- return (sample_rate / 100); |
- |
- // If audio processing is off and the native hardware buffer size was |
- // provided, use it. It can be harmful, in terms of CPU/power consumption, to |
- // use smaller buffer sizes than the native size (http://crbug.com/362261). |
- if (int hardware_buffer_size = device_info().device.input.frames_per_buffer) |
- return hardware_buffer_size; |
- |
- // If the buffer size is missing from the StreamDeviceInfo, provide 10ms as a |
- // fall-back. |
- // |
- // TODO(miu): Identify where/why the buffer size might be missing, fix the |
- // code, and then require it here. |
- return (sample_rate / 100); |
-} |
- |
-} // namespace content |