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 |