Chromium Code Reviews| Index: webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
| diff --git a/webrtc/modules/audio_processing/echo_detector/echo_detector.cc b/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
| index 3885c1fb0716389c9f6d6293761cefaa9b9db2fa..22d31ea7e9b2ff543364ed3eec06f25807a5fa55 100644 |
| --- a/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
| +++ b/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
| @@ -8,21 +8,141 @@ |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| +#include "webrtc/base/checks.h" |
| #include "webrtc/modules/audio_processing/echo_detector/echo_detector.h" |
|
hlundin-webrtc
2016/10/14 08:00:39
Aways include the corresponding .h file before any
ivoc
2016/10/17 16:05:08
Done.
|
| +#include <math.h> |
|
hlundin-webrtc
2016/10/14 08:00:39
System includes go before own project's includes (
ivoc
2016/10/17 16:05:07
Done.
|
| + |
| +namespace { |
| + |
| +float power(const float* farend, size_t nr_samples) { |
|
hlundin-webrtc
2016/10/14 08:00:39
Power with capital P.
hlundin-webrtc
2016/10/14 08:00:39
With my suggestion in the previous CL to use Array
peah-webrtc
2016/10/14 08:18:57
It is not superimportant, but if you instead use t
peah-webrtc
2016/10/14 08:18:58
Capital P in the function name.
peah-webrtc
2016/10/14 08:18:58
Since you are using this for both farend and neare
kwiberg-webrtc
2016/10/14 08:58:54
The docs suggest that, unless you ask it nicely fo
hlundin-webrtc
2016/10/14 09:15:28
But the current implementation does float * float
peah-webrtc
2016/10/14 13:39:40
In this case, nr_samples is limited to 160. I real
kwiberg-webrtc
2016/10/14 20:33:33
I was going to say that the current implementation
kwiberg-webrtc
2016/10/14 20:33:33
OK, doing it all in float would simplify things. :
hlundin-webrtc
2016/10/14 21:15:46
It seems to me that storing the intermediate as fl
ivoc
2016/10/17 16:05:07
Thanks for all the comments, this seems to be a po
hlundin-webrtc
2016/10/17 18:49:39
Good call!
|
| + double result = 0.; |
|
peah-webrtc
2016/10/14 08:18:58
I think you can use float for the power computatio
ivoc
2016/10/17 16:05:07
Done.
|
| + for (size_t i = 0; i < nr_samples; i++) { |
|
peah-webrtc
2016/10/14 08:18:58
++i is faster
hlundin-webrtc
2016/10/14 21:15:46
Not for a simple scalar. https://google.github.io/
|
| + result += farend[i] * farend[i]; |
| + } |
| + return static_cast<float>(result); |
|
peah-webrtc
2016/10/14 08:18:58
If you use float, you don't need the cast.
|
| +} |
| + |
| +} // namespace |
| + |
| namespace webrtc { |
| -void EchoDetector::BufferFarend(const float* /*farend*/, |
| - size_t /*num_samples*/) { |
| - // TODO(ivoc): Add implementation. |
| +void MeanVarianceEstimator::UpdateEstimate(float value) { |
| + mean_ = (1.f - alpha_) * mean_ + alpha_ * value; |
| + variance_ = |
| + (1.f - alpha_) * variance_ + alpha_ * (value - mean_) * (value - mean_); |
| +} |
| + |
| +float MeanVarianceEstimator::SigmaEstimate() { |
| + // Variance is >= 0, so this is okay. |
|
hlundin-webrtc
2016/10/14 08:00:39
DCHECK this assumption.
ivoc
2016/10/17 16:05:08
Done.
|
| + return sqrtf(variance_); |
| +} |
| + |
| +float MeanVarianceEstimator::MeanEstimate() { |
| + return mean_; |
| +} |
| + |
| +void MeanVarianceEstimator::Clear() { |
| + mean_ = 0.f; |
| + variance_ = 0.f; |
| +} |
| + |
| +void CovarianceEstimator::UpdateCovarianceEstimate(float x, |
|
peah-webrtc
2016/10/14 08:18:58
I don't think that covariance is fully correct her
ivoc
2016/10/17 16:05:07
Done.
|
| + float x_mean, |
| + float x_sigma, |
| + float y, |
| + float y_mean, |
| + float y_sigma) { |
| + covariance_ = |
| + (1.f - alpha_) * covariance_ + alpha_ * (x - x_mean) * (y - y_mean); |
|
peah-webrtc
2016/10/14 08:18:58
The style guide mentions that abbreviations should
ivoc
2016/10/17 16:05:07
I chose normalized_cross_correlation.
|
| + PCC_ = covariance_ / (x_sigma * y_sigma + .0001f); |
| +} |
| + |
| +float CovarianceEstimator::PCCEstimate() { |
|
peah-webrtc
2016/10/14 08:18:58
Please change this method name to avoid the abbrev
ivoc
2016/10/17 16:05:07
Done.
|
| + return PCC_; |
| +} |
| + |
| +void CovarianceEstimator::Clear() { |
| + covariance_ = 0.f; |
| + PCC_ = 0.f; |
| +} |
| + |
| +CircularBuffer::CircularBuffer(int size) : buffer_(size), size_(size) {} |
| +CircularBuffer::~CircularBuffer() {} |
|
hlundin-webrtc
2016/10/14 08:00:39
Replace {} with "= default".
peah-webrtc
2016/10/14 08:18:57
Alternatively you can use = default;
ivoc
2016/10/17 16:05:07
Done.
|
| + |
| +void CircularBuffer::Insert(float value) { |
| + buffer_[next_insertion_index_] = value; |
|
peah-webrtc
2016/10/14 08:18:57
Please add a DCHECK that next_insertion_index_ < b
ivoc
2016/10/17 16:05:07
Done.
|
| + next_insertion_index_++; |
|
peah-webrtc
2016/10/14 08:18:57
++next_insertion_index_ is faster.
ivoc
2016/10/17 16:05:07
For scalars I don't think it is, but you're right
|
| + next_insertion_index_ %= size_; |
|
peah-webrtc
2016/10/14 08:18:58
buffer_.size() here and elsewhere.
ivoc
2016/10/17 16:05:07
Done.
|
| +} |
| + |
| +float CircularBuffer::GetValue(int delay) { |
| + RTC_DCHECK(delay >= 0 && delay < size_); |
|
hlundin-webrtc
2016/10/14 08:00:39
Separate into two DCHECKs to get better printouts.
ivoc
2016/10/17 16:05:07
Since I changed delay to size_t, the >=0 check doe
|
| + const int index = (size_ + next_insertion_index_ - delay - 1) % size_; |
|
hlundin-webrtc
2016/10/14 08:00:39
size_t
ivoc
2016/10/17 16:05:07
Done.
|
| + return buffer_[index]; |
|
peah-webrtc
2016/10/14 08:18:58
Please add a DCHECK that index < buffer_.size() an
ivoc
2016/10/17 16:05:07
Done.
|
| +} |
| + |
| +void CircularBuffer::Clear() { |
| + std::fill(buffer_.begin(), buffer_.end(), 0.f); |
| + next_insertion_index_ = 0; |
| +} |
| + |
| +EchoDetector::EchoDetector() |
| + : render_buffer_(render_buffer_size_), |
|
peah-webrtc
2016/10/14 08:18:58
Do you need to have these in the initializer list?
ivoc
2016/10/17 16:05:07
Good idea!
|
| + render_power_(lookback_periods_), |
| + render_power_mean_(lookback_periods_), |
| + render_power_sigma_(lookback_periods_) {} |
| + |
| +EchoDetector::~EchoDetector() {} |
|
hlundin-webrtc
2016/10/14 08:00:39
= default
peah-webrtc
2016/10/14 08:18:58
Alternatively you can use = default;
ivoc
2016/10/17 16:05:07
Done.
|
| + |
| +void EchoDetector::BufferFarend(const float* farend, size_t num_samples) { |
|
peah-webrtc
2016/10/14 08:18:57
After some discussions I think we will be changing
ivoc
2016/10/17 16:05:07
Done.
|
| + float pow = power(farend, num_samples); |
|
peah-webrtc
2016/10/14 08:18:57
If you change the name of the power method to Powe
ivoc
2016/10/17 16:05:07
Done.
|
| + render_buffer_.Insert(pow); |
| + render_buffer_delay_ = |
| + std::min(render_buffer_delay_ + 1, render_buffer_size_ - 1); |
|
peah-webrtc
2016/10/14 08:18:57
Why is this minimum needed?
|
| +} |
| + |
| +void EchoDetector::Process(const float* nearend, size_t num_samples) { |
| + const float cap_pow = power(nearend, num_samples); |
|
hlundin-webrtc
2016/10/14 08:00:39
cap_* sounds like a value capped by something.
peah-webrtc
2016/10/14 08:18:57
I think that along the style guide abbreviation ru
ivoc
2016/10/17 16:05:08
Done.
|
| + capture_variance_.UpdateEstimate(cap_pow); |
| + const float cap_mean = capture_variance_.MeanEstimate(); |
| + const float cap_sigma = capture_variance_.SigmaEstimate(); |
| + float echo_likelihood = 0.f; |
| + |
| + const float latest_ren_pow = render_buffer_.GetValue(render_buffer_delay_); |
|
peah-webrtc
2016/10/14 08:18:58
This delay is only used to access the most recentl
ivoc
2016/10/17 16:05:07
As discussed offline, I moved the buffer size into
|
| + render_buffer_delay_ = std::max(0, render_buffer_delay_ - 1); |
| + render_variance_.UpdateEstimate(latest_ren_pow); |
| + render_power_.Insert(latest_ren_pow); |
| + render_power_mean_.Insert(render_variance_.MeanEstimate()); |
| + render_power_sigma_.Insert(render_variance_.SigmaEstimate()); |
| + |
| + for (int delay = 0; delay < lookback_periods_; delay++) { |
|
hlundin-webrtc
2016/10/14 08:00:39
size_t
peah-webrtc
2016/10/14 08:18:57
size_t ?
peah-webrtc
2016/10/14 08:18:57
size_t
peah-webrtc
2016/10/14 08:18:58
++delay
peah-webrtc
2016/10/14 08:18:58
This name is not fully clear to me. What is meant
peah-webrtc
2016/10/14 08:18:58
Use covariance_.size()
ivoc
2016/10/17 16:05:07
Done.
|
| + const float ren_pow = render_power_.GetValue(delay); |
| + const float ren_mean = render_power_mean_.GetValue(delay); |
| + const float ren_sigma = render_power_sigma_.GetValue(delay); |
| + covariance_[delay].UpdateCovarianceEstimate(cap_pow, cap_mean, cap_sigma, |
| + ren_pow, ren_mean, ren_sigma); |
| + echo_likelihood = |
|
hlundin-webrtc
2016/10/14 08:00:39
No need for the local variable echo_likelihood. Yo
ivoc
2016/10/17 16:05:08
Done.
|
| + std::max(echo_likelihood, covariance_[delay].PCCEstimate()); |
| + } |
| + echo_likelihood_ = echo_likelihood; |
| } |
| -void EchoDetector::Process(const float* /*nearend*/, size_t /*num_samples*/) { |
| - // TODO(ivoc): Add implementation. |
| +void EchoDetector::Initialize(int sample_rate_hz) { |
|
hlundin-webrtc
2016/10/14 08:00:39
sample_rate_hz not used? Delete it.
ivoc
2016/10/17 16:05:08
Done.
|
| + render_buffer_.Clear(); |
| + render_power_.Clear(); |
| + render_power_mean_.Clear(); |
| + render_power_sigma_.Clear(); |
| + render_variance_.Clear(); |
| + capture_variance_.Clear(); |
| + for (auto& cov : covariance_) { |
| + cov.Clear(); |
| + } |
| + echo_likelihood_ = 0.f; |
| } |
| -void EchoDetector::Initialize(int /*sample_rate_hz*/) { |
| - // TODO(ivoc): Add implementation. |
| +float EchoDetector::EchoLikelihood() { |
|
peah-webrtc
2016/10/14 08:18:57
const
ivoc
2016/10/17 16:05:08
Done.
|
| + return echo_likelihood_; |
| } |
| } // namespace webrtc |