Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(392)

Unified Diff: webrtc/modules/audio_processing/echo_detector/echo_detector.cc

Issue 2419563003: Add algorithm for Residual Echo Detector. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698