Commit ba5b0d78 authored by xians's avatar xians Committed by Commit bot

Avoid reporting 0 as input level when AudioProcessing zero out the audio data.

When the microphone volume is low, the pre-processed audio data contains energy, while the post-processed audio data has only 0, we report 0 as energy before this patch, which is wrong since the audio flow contains energy.

This patch fix the problem by checking the energy of pre-processed data before reporting 0 as energy.

BUG=424149
TEST=1, use a USB headset.
2, set the microphone volume low, like below 50%.
3, join a hangout call.
4, open chrome://webrtc-internals, and look at the energy of input stream, constantly it is 0 there.

Review URL: https://codereview.chromium.org/661693003

Cr-Commit-Position: refs/heads/master@{#300274}
parent fbf0dae3
......@@ -38,9 +38,11 @@ MediaStreamAudioLevelCalculator::MediaStreamAudioLevelCalculator()
MediaStreamAudioLevelCalculator::~MediaStreamAudioLevelCalculator() {
}
int MediaStreamAudioLevelCalculator::Calculate(const int16* audio_data,
int number_of_channels,
int number_of_frames) {
int MediaStreamAudioLevelCalculator::Calculate(
const int16* audio_data,
int number_of_channels,
int number_of_frames,
bool force_report_nonzero_energy) {
DCHECK(thread_checker_.CalledOnValidThread());
// |level_| is updated every 10 callbacks. For the case where callback comes
// every 10ms, |level_| will be updated approximately every 100ms.
......@@ -50,7 +52,8 @@ int MediaStreamAudioLevelCalculator::Calculate(const int16* audio_data,
max_amplitude_ = std::max(max_amplitude_, max);
if (counter_++ == kUpdateFrequency) {
level_ = max_amplitude_;
level_ = (max_amplitude_ == 0 ?
force_report_nonzero_energy : max_amplitude_);
// Decay the absolute maximum amplitude by 1/4.
max_amplitude_ >>= 2;
......
......@@ -21,8 +21,14 @@ class MediaStreamAudioLevelCalculator {
// Calculates the signal level of the audio data.
// Returns the absolute value of the amplitude of the signal.
// |force_report_nonzero_energy| is a flag forcing the calculator to
// report nonzero energy even if the energy of the processed audio is zero.
// Since |audio_data| is post processed data, and the audio processing might
// zero all the audio data, when the caller detects the pre processed data
// contain energy, it could pass |force_report_nonzero_energy| as true to
// force calculator to report 1 as energy when |audio_data| is all zero.
int Calculate(const int16* audio_data, int number_of_channels,
int number_of_frames);
int number_of_frames, bool force_report_nonzero_energy);
private:
// Used to DCHECK that the constructor and Calculate() are always called on
......
......@@ -292,7 +292,7 @@ class SpeechRecognitionAudioSinkTest : public testing::Test {
for (uint32 i = 0; i < buffers; ++i)
native_track()->Capture(source_data(),
base::TimeDelta::FromMilliseconds(0), 1, false,
false);
false, false);
}
// Used to simulate a problem with sockets.
......
......@@ -127,7 +127,7 @@ void WebAudioCapturerSource::consumeAudio(
params_.bits_per_sample() / 8,
audio_data_.get());
track_->Capture(audio_data_.get(), delay, volume, key_pressed,
need_audio_processing);
need_audio_processing, false);
}
}
......
......@@ -74,14 +74,14 @@ TEST_F(WebRtcLocalAudioTrackAdapterTest, AddAndRemoveSink) {
EXPECT_CALL(*sink,
OnData(_, 16, params_.sample_rate(), params_.channels(),
params_.frames_per_buffer()));
track_->Capture(data.get(), base::TimeDelta(), 255, false, false);
track_->Capture(data.get(), base::TimeDelta(), 255, false, false, false);
// Remove the sink from the webrtc track.
webrtc_track->RemoveSink(sink.get());
sink.reset();
// Verify that no more callback gets into the sink.
track_->Capture(data.get(), base::TimeDelta(), 255, false, false);
track_->Capture(data.get(), base::TimeDelta(), 255, false, false, false);
}
TEST_F(WebRtcLocalAudioTrackAdapterTest, GetSignalLevel) {
......
......@@ -21,6 +21,24 @@
namespace content {
namespace {
// Method to check if any of the data in |audio_source| has energy.
bool HasDataEnergy(const media::AudioBus& audio_source) {
for (int ch = 0; ch < audio_source.channels(); ++ch) {
const float* channel_ptr = audio_source.channel(ch);
for (int frame = 0; frame < audio_source.frames(); ++frame) {
if (channel_ptr[frame] != 0)
return true;
}
}
// All the data is zero.
return false;
}
} // namespace
// Reference counted container of WebRtcLocalAudioTrack delegate.
// TODO(xians): Switch to MediaStreamAudioSinkOwner.
class WebRtcAudioCapturer::TrackOwner
......@@ -33,14 +51,16 @@ class WebRtcAudioCapturer::TrackOwner
base::TimeDelta delay,
double volume,
bool key_pressed,
bool need_audio_processing) {
bool need_audio_processing,
bool force_report_nonzero_energy) {
base::AutoLock lock(lock_);
if (delegate_) {
delegate_->Capture(audio_data,
delay,
volume,
key_pressed,
need_audio_processing);
need_audio_processing,
force_report_nonzero_energy);
}
}
......@@ -487,6 +507,12 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
(*it)->SetAudioProcessor(audio_processor_);
}
// Figure out if the pre-processed data has any energy or not, the
// information will be passed to the track to force the calculator
// to report energy in case the post-processed data is zeroed by the audio
// processing.
const bool force_report_nonzero_energy = HasDataEnergy(*audio_source);
// Push the data to the processor for processing.
audio_processor_->PushCaptureData(audio_source);
......@@ -500,7 +526,7 @@ void WebRtcAudioCapturer::Capture(const media::AudioBus* audio_source,
for (TrackList::ItemList::const_iterator it = tracks.begin();
it != tracks.end(); ++it) {
(*it)->Capture(output, audio_delay, current_volume, key_pressed,
need_audio_processing);
need_audio_processing, force_report_nonzero_energy);
}
if (new_volume) {
......
......@@ -42,13 +42,14 @@ void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
base::TimeDelta delay,
int volume,
bool key_pressed,
bool need_audio_processing) {
bool need_audio_processing,
bool force_report_nonzero_energy) {
DCHECK(capture_thread_checker_.CalledOnValidThread());
// Calculate the signal level regardless if the track is disabled or enabled.
int signal_level = level_calculator_->Calculate(
audio_data, audio_parameters_.channels(),
audio_parameters_.frames_per_buffer());
audio_parameters_.frames_per_buffer(), force_report_nonzero_energy);
adapter_->SetSignalLevel(signal_level);
scoped_refptr<WebRtcAudioCapturer> capturer;
......
......@@ -70,7 +70,8 @@ class CONTENT_EXPORT WebRtcLocalAudioTrack
base::TimeDelta delay,
int volume,
bool key_pressed,
bool need_audio_processing);
bool need_audio_processing,
bool force_report_nonzero_energy);
// Method called by the capturer to set the audio parameters used by source
// of the capture data..
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment