| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 /* | 11 /* |
| 12 * The core AEC algorithm, which is presented with time-aligned signals. | 12 * The core AEC algorithm, which is presented with time-aligned signals. |
| 13 */ | 13 */ |
| 14 | 14 |
| 15 #include "webrtc/modules/audio_processing/aec/aec_core.h" | 15 #include "webrtc/modules/audio_processing/aec/aec_core.h" |
| 16 | 16 |
| 17 #ifdef WEBRTC_AEC_DEBUG_DUMP | 17 #ifdef WEBRTC_AEC_DEBUG_DUMP |
| 18 #include <stdio.h> | 18 #include <stdio.h> |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 #include <algorithm> |
| 21 #include <assert.h> | 22 #include <assert.h> |
| 22 #include <math.h> | 23 #include <math.h> |
| 23 #include <stddef.h> // size_t | 24 #include <stddef.h> // size_t |
| 24 #include <stdlib.h> | 25 #include <stdlib.h> |
| 25 #include <string.h> | 26 #include <string.h> |
| 26 | 27 |
| 27 extern "C" { | 28 extern "C" { |
| 28 #include "webrtc/common_audio/ring_buffer.h" | 29 #include "webrtc/common_audio/ring_buffer.h" |
| 29 } | 30 } |
| 30 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" | 31 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 43 namespace webrtc { | 44 namespace webrtc { |
| 44 | 45 |
| 45 // Buffer size (samples) | 46 // Buffer size (samples) |
| 46 static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. | 47 static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. |
| 47 | 48 |
| 48 // Metrics | 49 // Metrics |
| 49 static const size_t kSubCountLen = 4; | 50 static const size_t kSubCountLen = 4; |
| 50 static const size_t kCountLen = 50; | 51 static const size_t kCountLen = 50; |
| 51 static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz. | 52 static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz. |
| 52 | 53 |
| 54 // Divergence metric is based on audio level, which gets updated every |
| 55 // |kCountLen + 1| * 10 milliseconds. Divergence metric takes the statistics of |
| 56 // |kDivergentFilterFractionAggregationWindowSize| samples. Current value |
| 57 // corresponds to 0.5 seconds at 16 kHz. |
| 58 static const int kDivergentFilterFractionAggregationWindowSize = 25; |
| 59 |
| 53 // Quantities to control H band scaling for SWB input | 60 // Quantities to control H band scaling for SWB input |
| 54 static const float cnScaleHband = 0.4f; // scale for comfort noise in H band. | 61 static const float cnScaleHband = 0.4f; // scale for comfort noise in H band. |
| 55 // Initial bin for averaging nlp gain in low band | 62 // Initial bin for averaging nlp gain in low band |
| 56 static const int freqAvgIc = PART_LEN / 2; | 63 static const int freqAvgIc = PART_LEN / 2; |
| 57 | 64 |
| 58 // Matlab code to produce table: | 65 // Matlab code to produce table: |
| 59 // win = sqrt(hanning(63)); win = [0 ; win(1:32)]; | 66 // win = sqrt(hanning(63)); win = [0 ; win(1:32)]; |
| 60 // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); | 67 // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); |
| 61 ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = { | 68 ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = { |
| 62 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, | 69 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 WebRtcAecWindowData WebRtcAec_WindowData; | 150 WebRtcAecWindowData WebRtcAec_WindowData; |
| 144 | 151 |
| 145 __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) { | 152 __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) { |
| 146 return aRe * bRe - aIm * bIm; | 153 return aRe * bRe - aIm * bIm; |
| 147 } | 154 } |
| 148 | 155 |
| 149 __inline static float MulIm(float aRe, float aIm, float bRe, float bIm) { | 156 __inline static float MulIm(float aRe, float aIm, float bRe, float bIm) { |
| 150 return aRe * bIm + aIm * bRe; | 157 return aRe * bIm + aIm * bRe; |
| 151 } | 158 } |
| 152 | 159 |
| 160 // TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a |
| 161 // window, of which the length is 1 unit longer than indicated. Remove "+1" when |
| 162 // the code is refactored. |
| 153 PowerLevel::PowerLevel() | 163 PowerLevel::PowerLevel() |
| 154 // TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a | 164 : framelevel(kSubCountLen + 1), |
| 155 // window, of which the length is 1 unit longer than indicated. Remove "+1" | 165 averagelevel(kCountLen + 1) { |
| 156 // when the code is refactored. | 166 } |
| 157 : framelevel(kSubCountLen + 1), | 167 |
| 158 averagelevel(kCountLen + 1) { | 168 DivergentFilterFraction::DivergentFilterFraction() |
| 169 : count_(0), |
| 170 occurrence_(0), |
| 171 fraction_(-1.0) { |
| 172 } |
| 173 |
| 174 void DivergentFilterFraction::Reset() { |
| 175 Clear(); |
| 176 fraction_ = -1.0; |
| 177 } |
| 178 |
| 179 void DivergentFilterFraction::AddObservation(const PowerLevel& nearlevel, |
| 180 const PowerLevel& linoutlevel, |
| 181 const PowerLevel& nlpoutlevel) { |
| 182 const float near_level = nearlevel.framelevel.GetLatestMean(); |
| 183 const float level_increase = |
| 184 linoutlevel.framelevel.GetLatestMean() - near_level; |
| 185 const bool output_signal_active = nlpoutlevel.framelevel.GetLatestMean() > |
| 186 40.0 * nlpoutlevel.minlevel; |
| 187 // Level increase should be, in principle, negative, when the filter |
| 188 // does not diverge. Here we allow some margin (0.01 * near end level) and |
| 189 // numerical error (1.0). We count divergence only when the AEC output |
| 190 // signal is active. |
| 191 if (output_signal_active && |
| 192 level_increase > std::max(0.01 * near_level, 1.0)) |
| 193 occurrence_++; |
| 194 ++count_; |
| 195 if (count_ == kDivergentFilterFractionAggregationWindowSize) { |
| 196 fraction_ = static_cast<float>(occurrence_) / |
| 197 kDivergentFilterFractionAggregationWindowSize; |
| 198 Clear(); |
| 199 } |
| 200 } |
| 201 |
| 202 float DivergentFilterFraction::GetLatestFraction() const { |
| 203 return fraction_; |
| 204 } |
| 205 |
| 206 void DivergentFilterFraction::Clear() { |
| 207 count_ = 0; |
| 208 occurrence_ = 0; |
| 159 } | 209 } |
| 160 | 210 |
| 161 // TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor. | 211 // TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor. |
| 162 AecCore::AecCore() = default; | 212 AecCore::AecCore() = default; |
| 163 | 213 |
| 164 static int CmpFloat(const void* a, const void* b) { | 214 static int CmpFloat(const void* a, const void* b) { |
| 165 const float* da = (const float*)a; | 215 const float* da = (const float*)a; |
| 166 const float* db = (const float*)b; | 216 const float* db = (const float*)b; |
| 167 | 217 |
| 168 return (*da > *db) - (*da < *db); | 218 return (*da > *db) - (*da < *db); |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 self->stateCounter = 0; | 605 self->stateCounter = 0; |
| 556 InitLevel(&self->farlevel); | 606 InitLevel(&self->farlevel); |
| 557 InitLevel(&self->nearlevel); | 607 InitLevel(&self->nearlevel); |
| 558 InitLevel(&self->linoutlevel); | 608 InitLevel(&self->linoutlevel); |
| 559 InitLevel(&self->nlpoutlevel); | 609 InitLevel(&self->nlpoutlevel); |
| 560 | 610 |
| 561 InitStats(&self->erl); | 611 InitStats(&self->erl); |
| 562 InitStats(&self->erle); | 612 InitStats(&self->erle); |
| 563 InitStats(&self->aNlp); | 613 InitStats(&self->aNlp); |
| 564 InitStats(&self->rerl); | 614 InitStats(&self->rerl); |
| 615 |
| 616 self->divergent_filter_fraction.Reset(); |
| 565 } | 617 } |
| 566 | 618 |
| 567 static float CalculatePower(const float* in, size_t num_samples) { | 619 static float CalculatePower(const float* in, size_t num_samples) { |
| 568 size_t k; | 620 size_t k; |
| 569 float energy = 0.0f; | 621 float energy = 0.0f; |
| 570 | 622 |
| 571 for (k = 0; k < num_samples; ++k) { | 623 for (k = 0; k < num_samples; ++k) { |
| 572 energy += in[k] * in[k]; | 624 energy += in[k] * in[k]; |
| 573 } | 625 } |
| 574 return energy / num_samples; | 626 return energy / num_samples; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 598 | 650 |
| 599 const float noisyPower = 300000.0f; | 651 const float noisyPower = 300000.0f; |
| 600 | 652 |
| 601 float actThreshold; | 653 float actThreshold; |
| 602 float echo, suppressedEcho; | 654 float echo, suppressedEcho; |
| 603 | 655 |
| 604 if (aec->echoState) { // Check if echo is likely present | 656 if (aec->echoState) { // Check if echo is likely present |
| 605 aec->stateCounter++; | 657 aec->stateCounter++; |
| 606 } | 658 } |
| 607 | 659 |
| 660 if (aec->linoutlevel.framelevel.EndOfBlock()) { |
| 661 aec->divergent_filter_fraction.AddObservation(aec->nearlevel, |
| 662 aec->linoutlevel, |
| 663 aec->nlpoutlevel); |
| 664 } |
| 665 |
| 608 if (aec->farlevel.averagelevel.EndOfBlock()) { | 666 if (aec->farlevel.averagelevel.EndOfBlock()) { |
| 609 if (aec->farlevel.minlevel < noisyPower) { | 667 if (aec->farlevel.minlevel < noisyPower) { |
| 610 actThreshold = actThresholdClean; | 668 actThreshold = actThresholdClean; |
| 611 } else { | 669 } else { |
| 612 actThreshold = actThresholdNoisy; | 670 actThreshold = actThresholdNoisy; |
| 613 } | 671 } |
| 614 | 672 |
| 615 const float far_average_level = aec->farlevel.averagelevel.GetLatestMean(); | 673 const float far_average_level = aec->farlevel.averagelevel.GetLatestMean(); |
| 616 | 674 |
| 617 // The last condition is to let estimation be made in active far-end | 675 // The last condition is to let estimation be made in active far-end |
| (...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1892 | 1950 |
| 1893 int WebRtcAec_system_delay(AecCore* self) { | 1951 int WebRtcAec_system_delay(AecCore* self) { |
| 1894 return self->system_delay; | 1952 return self->system_delay; |
| 1895 } | 1953 } |
| 1896 | 1954 |
| 1897 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) { | 1955 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) { |
| 1898 assert(delay >= 0); | 1956 assert(delay >= 0); |
| 1899 self->system_delay = delay; | 1957 self->system_delay = delay; |
| 1900 } | 1958 } |
| 1901 } // namespace webrtc | 1959 } // namespace webrtc |
| OLD | NEW |