1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <assert.h>
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stddef.h>
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stdlib.h>
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
17c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/common_audio/signal_processing/include/real_fft.h"
18c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
199fb16139d917ba32720e031d3c871987d418668fpbos@webrtc.org#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
20c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/modules/audio_processing/utility/ring_buffer.h"
21221798a7c4ad83ba7fb8b3ae39b99d44278bbe5aandrew@webrtc.org#include "webrtc/system_wrappers/interface/compile_assert_c.h"
22c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
23c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org#include "webrtc/typedefs.h"
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#ifdef AEC_DEBUG
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgFILE *dfile;
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgFILE *testfile;
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
30ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgconst int16_t WebRtcAecm_kCosTable[] = {
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8192,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8091,  8067,  8041,  8012,  7982,  7948,  7912,  7874,  7834,
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7791,  7745,  7697,  7647,  7595,  7540,  7483,  7424,  7362,
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7299,  7233,  7164,  7094,  7021,  6947,  6870,  6791,  6710,
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    6627,  6542,  6455,  6366,  6275,  6182,  6087,  5991,  5892,
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,  4930,
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    4815,  4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    3719,  3591,  3462,  3331,  3200,  3068,  2935,  2801,  2667,
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    2531,  2395,  2258,  2120,  1981,  1842,  1703,  1563,  1422,
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    1281,  1140,   998,   856,   713,   571,   428,   285,   142,
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       0,  -142,  -285,  -428,  -571,  -713,  -856,  -998, -1140,
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -1281, -1140,  -998,  -856,  -713,  -571,  -428,  -285,  -142,
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       0,   142,   285,   428,   571,   713,   856,   998,  1140,
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    1281,  1422,  1563,  1703,  1842,  1981,  2120,  2258,  2395,
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    2531,  2667,  2801,  2935,  3068,  3200,  3331,  3462,  3591,
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    3719,  3845,  3971,  4095,  4219,  4341,  4461,  4580,  4698,
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    4815,  4930,  5043,  5155,  5265,  5374,  5481,  5586,  5690,
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    5792,  5892,  5991,  6087,  6182,  6275,  6366,  6455,  6542,
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    6627,  6710,  6791,  6870,  6947,  7021,  7094,  7164,  7233,
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7299,  7362,  7424,  7483,  7540,  7595,  7647,  7697,  7745,
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7791,  7834,  7874,  7912,  7948,  7982,  8012,  8041,  8067,
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8091,  8112,  8130,  8147,  8160,  8172,  8180,  8187,  8190
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org};
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
73ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgconst int16_t WebRtcAecm_kSinTable[] = {
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       0,    142,    285,    428,    571,    713,    856,    998,
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    1140,   1281,   1422,   1563,   1703,   1842,   1981,   2120,
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    2258,   2395,   2531,   2667,   2801,   2935,   3068,   3200,
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    3331,   3462,   3591,   3719,   3845,   3971,   4095,   4219,
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    4341,   4461,   4580,   4698,   4815,   4930,   5043,   5155,
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    5265,   5374,   5481,   5586,   5690,   5792,   5892,   5991,
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    6087,   6182,   6275,   6366,   6455,   6542,   6627,   6710,
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    6791,   6870,   6947,   7021,   7094,   7164,   7233,   7299,
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7362,   7424,   7483,   7540,   7595,   7647,   7697,   7745,
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7791,   7834,   7874,   7912,   7948,   7982,   8012,   8041,
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8067,   8091,   8112,   8130,   8147,   8160,   8172,   8180,
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8187,   8190,   8191,   8190,   8187,   8180,   8172,   8160,
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    8147,   8130,   8112,   8091,   8067,   8041,   8012,   7982,
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7948,   7912,   7874,   7834,   7791,   7745,   7697,   7647,
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7595,   7540,   7483,   7424,   7362,   7299,   7233,   7164,
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    7094,   7021,   6947,   6870,   6791,   6710,   6627,   6542,
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    6455,   6366,   6275,   6182,   6087,   5991,   5892,   5792,
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    5690,   5586,   5481,   5374,   5265,   5155,   5043,   4930,
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    4815,   4698,   4580,   4461,   4341,   4219,   4096,   3971,
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    3845,   3719,   3591,   3462,   3331,   3200,   3068,   2935,
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    2801,   2667,   2531,   2395,   2258,   2120,   1981,   1842,
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    1703,   1563,   1422,   1281,   1140,    998,    856,    713,
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     571,    428,    285,    142,      0,   -142,   -285,   -428,
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    -571,   -713,   -856,   -998,  -1140,  -1281,  -1422,  -1563,
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -1703,  -1842,  -1981,  -2120,  -2258,  -2395,  -2531,  -2667,
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -2801,  -2935,  -3068,  -3200,  -3331,  -3462,  -3591,  -3719,
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -3845,  -3971,  -4095,  -4219,  -4341,  -4461,  -4580,  -4698,
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -4815,  -4930,  -5043,  -5155,  -5265,  -5374,  -5481,  -5586,
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -5690,  -5792,  -5892,  -5991,  -6087,  -6182,  -6275,  -6366,
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -6455,  -6542,  -6627,  -6710,  -6791,  -6870,  -6947,  -7021,
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7094,  -7164,  -7233,  -7299,  -7362,  -7424,  -7483,  -7540,
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7595,  -7647,  -7697,  -7745,  -7791,  -7834,  -7874,  -7912,
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7948,  -7982,  -8012,  -8041,  -8067,  -8091,  -8112,  -8130,
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8147,  -8160,  -8172,  -8180,  -8187,  -8190,  -8191,  -8190,
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8187,  -8180,  -8172,  -8160,  -8147,  -8130,  -8112,  -8091,
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -8067,  -8041,  -8012,  -7982,  -7948,  -7912,  -7874,  -7834,
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7791,  -7745,  -7697,  -7647,  -7595,  -7540,  -7483,  -7424,
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -7362,  -7299,  -7233,  -7164,  -7094,  -7021,  -6947,  -6870,
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -6791,  -6710,  -6627,  -6542,  -6455,  -6366,  -6275,  -6182,
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -6087,  -5991,  -5892,  -5792,  -5690,  -5586,  -5481,  -5374,
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -5265,  -5155,  -5043,  -4930,  -4815,  -4698,  -4580,  -4461,
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -4341,  -4219,  -4096,  -3971,  -3845,  -3719,  -3591,  -3462,
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -3331,  -3200,  -3068,  -2935,  -2801,  -2667,  -2531,  -2395,
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -2258,  -2120,  -1981,  -1842,  -1703,  -1563,  -1422,  -1281,
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org   -1140,   -998,   -856,   -713,   -571,   -428,   -285,   -142
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org};
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
121ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org// Initialization table for echo channel in 8 kHz
122ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgstatic const int16_t kChannelStored8kHz[PART_LEN1] = {
123ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    2040,   1815,   1590,   1498,   1405,   1395,   1385,   1418,
124ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1451,   1506,   1562,   1644,   1726,   1804,   1882,   1918,
125ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1953,   1982,   2010,   2025,   2040,   2034,   2027,   2021,
126ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    2014,   1997,   1980,   1925,   1869,   1800,   1732,   1683,
127ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1635,   1604,   1572,   1545,   1517,   1481,   1444,   1405,
128ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1367,   1331,   1294,   1270,   1245,   1239,   1233,   1247,
129ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1260,   1282,   1303,   1338,   1373,   1407,   1441,   1470,
130ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1499,   1524,   1549,   1565,   1582,   1601,   1621,   1649,
131ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1676
132ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org};
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
134ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org// Initialization table for echo channel in 16 kHz
135ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgstatic const int16_t kChannelStored16kHz[PART_LEN1] = {
136ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    2040,   1590,   1405,   1385,   1451,   1562,   1726,   1882,
137ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1953,   2010,   2040,   2027,   2014,   1980,   1869,   1732,
138ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1635,   1572,   1517,   1444,   1367,   1294,   1245,   1233,
139ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1260,   1303,   1373,   1441,   1499,   1549,   1582,   1621,
140ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    1676,   1741,   1802,   1861,   1921,   1983,   2040,   2102,
141ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    2170,   2265,   2375,   2515,   2651,   2781,   2922,   3075,
142ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    3253,   3471,   3738,   3976,   4151,   4258,   4308,   4288,
143ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    4270,   4253,   4237,   4179,   4086,   3947,   3757,   3484,
144ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    3153
145ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org};
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Moves the pointer to the next entry and inserts |far_spectrum| and
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// corresponding Q-domain in its buffer.
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Inputs:
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - self          : Pointer to the delay estimation instance
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - far_spectrum  : Pointer to the far end spectrum
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - far_q         : Q-domain of far end spectrum
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
155ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgvoid WebRtcAecm_UpdateFarHistory(AecmCore_t* self,
156ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org                                 uint16_t* far_spectrum,
157ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org                                 int far_q) {
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Get new buffer position
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  self->far_history_pos++;
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (self->far_history_pos >= MAX_DELAY) {
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    self->far_history_pos = 0;
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Update Q-domain buffer
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  self->far_q_domains[self->far_history_pos] = far_q;
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Update far end spectrum buffer
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         far_spectrum,
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         sizeof(uint16_t) * PART_LEN1);
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Returns a pointer to the far end spectrum aligned to current near end
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// called before AlignedFarend(...). Otherwise, you get the pointer to the
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// previous frame. The memory is only valid until the next call of
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtc_DelayEstimatorProcessFix(...).
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Inputs:
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - self              : Pointer to the AECM instance.
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - delay             : Current delay estimate.
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Output:
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - far_q             : The Q-domain of the aligned far end spectrum
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Return value:
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - far_spectrum      : Pointer to the aligned far end spectrum
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                            NULL - Error
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
188ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgconst uint16_t* WebRtcAecm_AlignedFarend(AecmCore_t* self,
189ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org                                         int* far_q,
190ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org                                         int delay) {
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int buffer_position = 0;
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(self != NULL);
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  buffer_position = self->far_history_pos - delay;
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Check buffer position
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (buffer_position < 0) {
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    buffer_position += MAX_DELAY;
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Get Q-domain
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  *far_q = self->far_q_domains[buffer_position];
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Return far end spectrum
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return &(self->far_history[buffer_position * PART_LEN1]);
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Declare function pointers.
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgCalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgStoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint WebRtcAecm_CreateCore(AecmCore_t **aecmInst)
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AecmCore_t *aecm = malloc(sizeof(AecmCore_t));
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    *aecmInst = aecm;
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm == NULL)
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
219db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
220db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org                                            sizeof(int16_t));
221db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    if (!aecm->farFrameBuf)
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_FreeCore(aecm);
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm = NULL;
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
228db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
229db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org                                                  sizeof(int16_t));
230db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    if (!aecm->nearNoisyFrameBuf)
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_FreeCore(aecm);
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm = NULL;
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
237db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
238db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org                                                  sizeof(int16_t));
239db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    if (!aecm->nearCleanFrameBuf)
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_FreeCore(aecm);
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm = NULL;
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
246db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
247db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org                                            sizeof(int16_t));
248db32d60125dfe78a1eb475f39672484c63b034b1andrew@webrtc.org    if (!aecm->outFrameBuf)
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_FreeCore(aecm);
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm = NULL;
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
255c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
256c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org                                                                     MAX_DELAY);
257c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    if (aecm->delay_estimator_farend == NULL) {
258c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org      WebRtcAecm_FreeCore(aecm);
259c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org      aecm = NULL;
260c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org      return -1;
261c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    }
262c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    aecm->delay_estimator =
263b5a182a9321ff847a24620c5e991e1749362549abjornv@webrtc.org        WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm->delay_estimator == NULL) {
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      WebRtcAecm_FreeCore(aecm);
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      aecm = NULL;
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return -1;
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
269b7c1e03761e4f90f48f36140ba6ff17d51c01e7bbjornv@webrtc.org    // TODO(bjornv): Explicitly disable robust delay validation until no
270b7c1e03761e4f90f48f36140ba6ff17d51c01e7bbjornv@webrtc.org    // performance regression has been established.  Then remove the line.
271b7c1e03761e4f90f48f36140ba6ff17d51c01e7bbjornv@webrtc.org    WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm->real_fft == NULL) {
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      WebRtcAecm_FreeCore(aecm);
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      aecm = NULL;
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return -1;
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Init some aecm pointers. 16 and 32 byte alignment is only necessary
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // for Neon code currently.
2823f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
2833f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
2843f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
2853f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
2863f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->channelStored = (int16_t*) (((uintptr_t)
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             aecm->channelStored_buf + 15) & ~ 15);
2883f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                              aecm->channelAdapt16_buf + 15) & ~ 15);
2903f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                              aecm->channelAdapt32_buf + 31) & ~ 31);
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2963f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgvoid WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const int16_t* echo_path)
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i = 0;
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reset the stored channel
3013f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reset the adapted channels
3033f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (i = 0; i < PART_LEN1; i++)
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
3073f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            (int32_t)(aecm->channelAdapt16[i]), 16);
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reset channel storing variables
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->mseAdaptOld = 1000;
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->mseStoredOld = 1000;
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->mseChannelCount = 0;
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic void CalcLinearEnergiesC(AecmCore_t* aecm,
3183f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                const uint16_t* far_spectrum,
3193f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                int32_t* echo_est,
3203f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                uint32_t* far_energy,
3213f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                uint32_t* echo_energy_adapt,
3223f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                uint32_t* echo_energy_stored)
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i;
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get energy for the delayed far end signal and estimated
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // echo using both stored and adapted channels.
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (i = 0; i < PART_LEN1; i++)
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           far_spectrum[i]);
3323f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org        (*far_energy) += (uint32_t)(far_spectrum[i]);
333ea2257fc3adfe9d4bd174426a5b09b1c78bdbca5bjornv@webrtc.org        *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
3343f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org        (*echo_energy_stored) += (uint32_t)echo_est[i];
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic void StoreAdaptiveChannelC(AecmCore_t* aecm,
3393f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                  const uint16_t* far_spectrum,
3403f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                                  int32_t* echo_est)
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i;
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // During startup we store the channel every block.
3453f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Recalculate echo estimate
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (i = 0; i < PART_LEN; i += 4)
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           far_spectrum[i]);
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           far_spectrum[i + 1]);
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           far_spectrum[i + 2]);
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           far_spectrum[i + 3]);
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       far_spectrum[i]);
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic void ResetAdaptiveChannelC(AecmCore_t* aecm)
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i;
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The stored channel has a significantly lower MSE than the adaptive one for
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // two consecutive calculations. Reset the adaptive channel.
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(aecm->channelAdapt16, aecm->channelStored,
3693f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org           sizeof(int16_t) * PART_LEN1);
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Restore the W32 channel
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (i = 0; i < PART_LEN; i += 4)
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
3743f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                (int32_t)aecm->channelStored[i], 16);
375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32(
3763f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                (int32_t)aecm->channelStored[i + 1], 16);
377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32(
3783f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                (int32_t)aecm->channelStored[i + 2], 16);
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32(
3803f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                (int32_t)aecm->channelStored[i + 3], 16);
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
3823f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)aecm->channelStored[i], 16);
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Initialize function pointers for ARM Neon platform.
386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#if (defined WEBRTC_DETECT_ARM_NEON || defined WEBRTC_ARCH_ARM_NEON)
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic void WebRtcAecm_InitNeon(void)
388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
395ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org// Initialize function pointers for MIPS platform.
396ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#if defined(MIPS32_LE)
397ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgstatic void WebRtcAecm_InitMips(void)
398ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org{
399ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#if defined(MIPS_DSP_R1_LE)
400ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org  WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
401ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org  WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
402ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#endif
403ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org  WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
404ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org}
405ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#endif
406ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtcAecm_InitCore(...)
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Input:
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - aecm            : Pointer to the Echo Suppression instance
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - samplingFreq   : Sampling Frequency
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Output:
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - aecm            : Initialized instance
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Return value         :  0 - Ok
418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                        -1 - Error
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i = 0;
4233f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t tmp32 = PART_LEN1 * PART_LEN1;
4243f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t tmp16 = PART_LEN1;
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (samplingFreq != 8000 && samplingFreq != 16000)
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        samplingFreq = 8000;
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // sanity check of sampling frequency
4323f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    aecm->mult = (int16_t)samplingFreq / 8000;
433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farBufWritePos = 0;
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farBufReadPos = 0;
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->knownDelay = 0;
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->lastKnownDelay = 0;
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_InitBuffer(aecm->farFrameBuf);
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_InitBuffer(aecm->outFrameBuf);
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->seed = 666;
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->totCount = 0;
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
452c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
453c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org      return -1;
454c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    }
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return -1;
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set far end histories to zero
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->far_history_pos = MAX_DELAY;
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->nlpFlag = 1;
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->fixedDelay = -1;
465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->dfaCleanQDomain = 0;
467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->dfaCleanQDomainOld = 0;
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->dfaNoisyQDomain = 0;
469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->dfaNoisyQDomainOld = 0;
470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farLogEnergy = 0;
473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize the echo channels with a stored shape.
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (samplingFreq == 8000)
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->noiseEstCtr = 0;
489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->cngMode = AecmTrue;
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Shape the initial noise level to an approximate pink noise.
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->noiseEst[i] = (tmp32 << 8);
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16--;
4993f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org        tmp32 -= (int32_t)((tmp16 << 1) + 1);
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (; i < PART_LEN1; i++)
502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->noiseEst[i] = (tmp32 << 8);
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farEnergyMaxMin = 0;
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         // beginning.
511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farEnergyMSE = 0;
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->currentVADValue = 0;
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->vadUpdateCount = 0;
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->firstVAD = 1;
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->startupState = 0;
517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGain = SUPGAIN_DEFAULT;
518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainOld = SUPGAIN_DEFAULT;
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Assert a preprocessor definition at compile-time. It's an assumption
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // used in assembly code, so check the assembly files before any change.
527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    COMPILE_ASSERT(PART_LEN % 16 == 0);
528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize function pointers.
530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#ifdef WEBRTC_DETECT_ARM_NEON
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    uint64_t features = WebRtc_GetCPUFeaturesARM();
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((features & kCPUFeatureNEON) != 0)
537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      WebRtcAecm_InitNeon();
539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#elif defined(WEBRTC_ARCH_ARM_NEON)
541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_InitNeon();
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
544ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#if defined(MIPS32_LE)
545ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org    WebRtcAecm_InitMips();
546ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.org#endif
547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(bjornv): This function is currently not used. Add support for these
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// parameters from a higher level
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag)
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->nlpFlag = nlpFlag;
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->fixedDelay = delay;
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint WebRtcAecm_FreeCore(AecmCore_t *aecm)
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm == NULL)
563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_FreeBuffer(aecm->farFrameBuf);
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_FreeBuffer(aecm->outFrameBuf);
571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_FreeDelayEstimator(aecm->delay_estimator);
573c7beae5a7f10192712a5d1a901f41a90f42daaffbjornv@webrtc.org    WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcSpl_FreeRealFFT(aecm->real_fft);
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    free(aecm);
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint WebRtcAecm_ProcessFrame(AecmCore_t * aecm,
5823f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            const int16_t * farend,
5833f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            const int16_t * nearendNoisy,
5843f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            const int16_t * nearendClean,
5853f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            int16_t * out)
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
5873f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
5883f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
5903f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t farFrame[FRAME_LEN];
591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int16_t* out_ptr = NULL;
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int size = 0;
593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Buffer the current frame.
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Fetch an older one corresponding to the delay.
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Buffer the synchronized far and near frames,
600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // to pass the smaller blocks individually.
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (nearendClean != NULL)
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Process as many blocks as possible.
609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int16_t far_block[PART_LEN];
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const int16_t* far_block_ptr = NULL;
613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int16_t near_noisy_block[PART_LEN];
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const int16_t* near_noisy_block_ptr = NULL;
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          PART_LEN);
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          (void**) &near_noisy_block_ptr,
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          near_noisy_block,
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          PART_LEN);
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (nearendClean != NULL)
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            int16_t near_clean_block[PART_LEN];
625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            const int16_t* near_clean_block_ptr = NULL;
626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              (void**) &near_clean_block_ptr,
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              near_clean_block,
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              PART_LEN);
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (WebRtcAecm_ProcessBlock(aecm,
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        far_block_ptr,
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        near_noisy_block_ptr,
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        near_clean_block_ptr,
635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        outBlock) == -1)
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                return -1;
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (WebRtcAecm_ProcessBlock(aecm,
642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        far_block_ptr,
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        near_noisy_block_ptr,
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        NULL,
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        outBlock) == -1)
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                return -1;
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stuff the out buffer if we have less than a frame to output.
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // This should only happen for the first frame.
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    size = (int) WebRtc_available_read(aecm->outFrameBuf);
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (size < FRAME_LEN)
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Obtain an output frame.
663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (out_ptr != out) {
665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // ReadBuffer() hasn't copied to |out| in this case.
666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtcAecm_AsymFilt(...)
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Performs asymmetric filtering.
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Inputs:
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - filtOld       : Previous filtered value.
678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - inVal         : New input value.
679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - stepSizePos   : Step size when we have a positive contribution.
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//      - stepSizeNeg   : Step size when we have a negative contribution.
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Output:
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Return: - Filtered value.
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
6863f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgint16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
6873f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            const int16_t stepSizePos,
6883f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                            const int16_t stepSizeNeg)
689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
6903f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t retVal;
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return inVal;
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    retVal = filtOld;
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (filtOld > inVal)
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg);
700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos);
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return retVal;
706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
70892e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org// ExtractFractionPart(a, zeros)
70992e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org//
71092e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org// returns the fraction part of |a|, with |zeros| number of leading zeros, as an
71192e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org// int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
71292e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org// number of zeros match.
71392e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.orgstatic int16_t ExtractFractionPart(uint32_t a, int zeros) {
71492e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org  return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
71592e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org}
71692e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org
717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtcAecm_CalcEnergies(...)
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This function calculates the log of energies for nearend, farend and estimated
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// echoes. There is also an update of energy decision levels, i.e. internal VAD.
721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  aecm         [i/o]   Handle of the AECM instance.
724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  far_spectrum [in]    Pointer to farend spectrum.
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  far_q        [in]    Q-domain of farend spectrum.
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  nearEner     [in]    Near end energy for current block in
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                              Q(aecm->dfaQDomain).
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  echoEst      [out]   Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid WebRtcAecm_CalcEnergies(AecmCore_t * aecm,
7313f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                             const uint16_t* far_spectrum,
7323f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                             const int16_t far_q,
7333f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                             const uint32_t nearEner,
7343f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                             int32_t * echoEst)
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Local variables
7373f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    uint32_t tmpAdapt = 0;
7383f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    uint32_t tmpStored = 0;
7393f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    uint32_t tmpFar = 0;
740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i;
742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
7433f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t zeros, frac;
7443f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t tmp16;
7453f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t increase_max_shifts = 4;
7463f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t decrease_max_shifts = 11;
7473f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t increase_min_shifts = 11;
7483f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t decrease_min_shifts = 3;
7493f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get log of near end energy and store in buffer
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Shift buffer
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
7553f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            sizeof(int16_t) * (MAX_BUF_LEN - 1));
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Logarithm of integrated magnitude spectrum (nearEner)
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    tmp16 = kLogLowValue;
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (nearEner)
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        zeros = WebRtcSpl_NormU32(nearEner);
76292e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org        frac = ExtractFractionPart(nearEner, zeros);
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // log2 in Q8
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8);
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->nearLogEnergy[0] = tmp16;
768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // END: Get log of near end energy
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Shift buffers
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
7743f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            sizeof(int16_t) * (MAX_BUF_LEN - 1));
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
7763f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            sizeof(int16_t) * (MAX_BUF_LEN - 1));
777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Logarithm of delayed far end energy
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    tmp16 = kLogLowValue;
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (tmpFar)
781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        zeros = WebRtcSpl_NormU32(tmpFar);
78392e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org        frac = ExtractFractionPart(tmpFar, zeros);
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // log2 in Q8
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8);
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farLogEnergy = tmp16;
789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Logarithm of estimated echo energy through adapted channel
791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    tmp16 = kLogLowValue;
792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (tmpAdapt)
793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        zeros = WebRtcSpl_NormU32(tmpAdapt);
79592e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org        frac = ExtractFractionPart(tmpAdapt, zeros);
796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //log2 in Q8
797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->echoAdaptLogEnergy[0] = tmp16;
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Logarithm of estimated echo energy through stored channel
803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    tmp16 = kLogLowValue;
804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (tmpStored)
805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        zeros = WebRtcSpl_NormU32(tmpStored);
80792e07ae02c00648f1a298eaaaa07d2407859db1ebjornv@webrtc.org        frac = ExtractFractionPart(tmpStored, zeros);
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //log2 in Q8
809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->echoStoredLogEnergy[0] = tmp16;
813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Update farend energy levels (min, max, vad, mse)
815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm->farLogEnergy > FAR_ENERGY_MIN)
816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (aecm->startupState == 0)
818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            increase_max_shifts = 2;
820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            decrease_min_shifts = 2;
821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            increase_min_shifts = 8;
822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 increase_min_shifts, decrease_min_shifts);
826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 increase_max_shifts, decrease_max_shifts);
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Dynamic VAD region size
831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 = 2560 - aecm->farEnergyMin;
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (tmp16 > 0)
833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
8343f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            tmp16 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9);
835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmp16 = 0;
838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16 += FAR_ENERGY_VAD_REGION;
840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // In startup phase or VAD update halted
844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (aecm->farEnergyVAD > aecm->farLogEnergy)
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy +
850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                            tmp16 -
851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                            aecm->farEnergyVAD,
852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                            6);
853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                aecm->vadUpdateCount = 0;
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else
855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                aecm->vadUpdateCount++;
857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Put MSE threshold higher than VAD
860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Update VAD variables
864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (aecm->farLogEnergy > aecm->farEnergyVAD)
865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // We are in startup or have significant dynamics in input speech level
869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->currentVADValue = 1;
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->currentVADValue = 0;
874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((aecm->currentVADValue) && (aecm->firstVAD))
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->firstVAD = 0;
878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // The estimated echo has higher energy than the near end signal.
881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // This means that the initialization was too aggressive. Scale
882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // down by a factor 8
883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            for (i = 0; i < PART_LEN1; i++)
884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                aecm->channelAdapt16[i] >>= 3;
886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Compensate the adapted echo energy level accordingly.
888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->echoAdaptLogEnergy[0] -= (3 << 8);
889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->firstVAD = 1;
890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtcAecm_CalcStepSize(...)
895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This function calculates the step size used in channel estimation
897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  aecm  [in]    Handle of the AECM instance.
900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of shifts.
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
9033f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgint16_t WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9063f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t tmp32;
9073f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t tmp16;
9083f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t mu = MU_MAX;
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Here we calculate the step size mu used in the
911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // following NLMS based Channel estimation algorithm
912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!aecm->currentVADValue)
913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Far end energy level too low, no channel update
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        mu = 0;
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else if (aecm->startupState > 0)
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (aecm->farEnergyMin >= aecm->farEnergyMax)
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            mu = MU_MIN;
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF);
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
9263f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            mu = MU_MIN - 1 - (int16_t)(tmp32);
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // The -1 is an alternative to rounding. This way we get a larger
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // stepsize, so we in some sense compensate for truncation in NLMS
929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (mu < MU_MAX)
931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return mu;
937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// WebRtcAecm_UpdateChannel(...)
940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This function performs channel estimation. NLMS and decision on channel storage.
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  aecm         [i/o]   Handle of the AECM instance.
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  far_spectrum [in]    Absolute value of the farend signal in Q(far_q)
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  far_q        [in]    Q-domain of the farend signal
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  dfa          [in]    Absolute value of the nearend signal (Q[aecm->dfaQDomain])
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  mu           [in]    NLMS step size.
949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  echoEst      [i/o]   Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid WebRtcAecm_UpdateChannel(AecmCore_t * aecm,
9523f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                              const uint16_t* far_spectrum,
9533f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                              const int16_t far_q,
9543f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                              const uint16_t * const dfa,
9553f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                              const int16_t mu,
9563f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                              int32_t * echoEst)
957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9593f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    uint32_t tmpU32no1, tmpU32no2;
9603f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t tmp32no1, tmp32no2;
9613f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t mseStored;
9623f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t mseAdapt;
963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int i;
965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9663f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
9673f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t shiftChFar, shiftNum, shift2ResChan;
9683f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t tmp16no1;
9693f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t xfaQ, dfaQ;
970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // This is the channel estimation algorithm. It is base on NLMS but has a variable step
972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // length, which was calculated above.
973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (mu)
974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (i = 0; i < PART_LEN1; i++)
976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Determine norm of channel and farend to make sure we don't get overflow in
978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // multiplication
979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
9803f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (zerosCh + zerosFar > 31)
982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Multiplication is safe
984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        far_spectrum[i]);
986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                shiftChFar = 0;
987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else
988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // We need to shift down before multiplication
990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                shiftChFar = 32 - zerosCh - zerosFar;
991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(
992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar),
993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    far_spectrum[i]);
994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Determine Q-domain of numerator
996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            zerosNum = WebRtcSpl_NormU32(tmpU32no1);
997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (dfa[i])
998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
9993f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else
1001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                zerosDfa = 32;
1003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
1005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                RESOLUTION_CHANNEL32 - far_q + shiftChFar;
1006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (zerosNum > tmp16no1 + 1)
1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                xfaQ = tmp16no1;
1009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                dfaQ = zerosDfa - 2;
1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else
1011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                xfaQ = zerosNum - 2;
1013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
1014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    shiftChFar + xfaQ;
1015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Add in the same Q-domain
1017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
10183f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
10193f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org            tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
1020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            zerosNum = WebRtcSpl_NormW32(tmp32no1);
1021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
1022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                //
1024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Update is needed
1025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                //
1026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // This is what we would like to compute
1027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                //
1028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
1029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // tmp32norm = (i + 1)
1030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // aecm->channelAdapt[i] += (2^mu) * tmp32no1
1031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                //                        / (tmp32norm * far_spectrum[i])
1032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                //
1033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Make sure we don't get overflow in multiplication.
1035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (zerosNum + zerosFar > 31)
1036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (tmp32no1 > 0)
1038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
10393f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
1040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                                        far_spectrum[i]);
1041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    } else
1042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
10433f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
1044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                                         far_spectrum[i]);
1045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
1046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    shiftNum = 0;
1047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                } else
1048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    shiftNum = 32 - (zerosNum + zerosFar);
1050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (tmp32no1 > 0)
1051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
10523f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(
1053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum),
1054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                far_spectrum[i]);
1055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    } else
1056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
10573f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(
1058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum),
1059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                far_spectrum[i]);
1060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
1061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Normalize with respect to frequency bin
1063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
1064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Make sure we are in the right Q-domain
1065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
1066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
1067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1068b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    tmp32no2 = WEBRTC_SPL_WORD32_MAX;
1069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                } else
1070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
1072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1073347671c843ed5c93d25bf1a23f9295d35ce3df4abjornv@webrtc.org                aecm->channelAdapt32[i] =
1074347671c843ed5c93d25bf1a23f9295d35ce3df4abjornv@webrtc.org                    WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
1075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (aecm->channelAdapt32[i] < 0)
1076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // We can never have negative channel gain
1078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    aecm->channelAdapt32[i] = 0;
1079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                aecm->channelAdapt16[i]
10813f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        = (int16_t)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16);
1082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // END: Adaptive channel update
1086b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Determine if we should store or restore the channel
1088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((aecm->startupState == 0) & (aecm->currentVADValue))
1089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // During startup we store the channel every block,
1091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // and we recalculate echo estimate
1092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
1094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (aecm->farLogEnergy < aecm->farEnergyMSE)
1096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->mseChannelCount = 0;
1098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
1099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->mseChannelCount++;
1101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Enough data for validation. Store channel if we can.
1103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
1104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // We have enough data.
1106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Calculate MSE of "Adapt" and "Stored" versions.
1107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // It is actually not MSE, but average absolute error.
1108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            mseStored = 0;
1109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            mseAdapt = 0;
1110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            for (i = 0; i < MIN_MSE_COUNT; i++)
1111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
11123f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
11133f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        - (int32_t)aecm->nearLogEnergy[i]);
1114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                mseStored += tmp32no2;
1116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11173f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
11183f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                        - (int32_t)aecm->nearLogEnergy[i]);
1119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                mseAdapt += tmp32no2;
1121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
1123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
1124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            * aecm->mseAdaptOld)))
1125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // The stored channel has a significantly lower MSE than the adaptive one for
1127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // two consecutive calculations. Reset the adaptive channel.
1128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WebRtcAecm_ResetAdaptiveChannel(aecm);
1129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
1130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
1131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // The adaptive channel has a significantly lower MSE than the stored one.
1133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // The MSE for the adaptive channel has also been low for two consecutive
1134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // calculations. Store the adaptive channel.
1135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Update threshold
1138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
1139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
1141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                } else
1142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt
1144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8);
1145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Reset counter
1150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->mseChannelCount = 0;
1151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Store the MSE values.
1153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->mseStoredOld = mseStored;
1154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            aecm->mseAdaptOld = mseAdapt;
1155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // END: Determine if we should store or reset channel estimate.
1158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// CalcSuppressionGain(...)
1161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
1162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This function calculates the suppression gain that is used in the Wiener filter.
1163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
1164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
1165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  aecm     [i/n]   Handle of the AECM instance.
1166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// @param  supGain  [out]   (Return value) Suppression gain with which to scale the noise
1167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                          level (Q14).
1168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
1169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
1170ff4fc2b37cf95b67e77d5d66003409606cefbc43andrew@webrtc.orgint16_t WebRtcAecm_CalcSuppressionGain(AecmCore_t * const aecm)
1171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
11723f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int32_t tmp32no1;
1173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11743f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t supGain = SUPGAIN_DEFAULT;
11753f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t tmp16no1;
11763f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t dE = 0;
1177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
1179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // end energy and echo estimation error.
1180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Adjust for the far end signal level. A low signal level indicates no far end signal,
1181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // hence we set the suppression gain to 0
1182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!aecm->currentVADValue)
1183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        supGain = 0;
1185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
1186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Adjust for possible double talk. If we have large variations in estimation error we
1188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // likely have double talk (or poor channel).
1189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
1190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (dE < ENERGY_DEV_TOL)
1193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Likely no double talk. The better estimation, the more we can suppress signal.
1195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Update counters
1196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (dE < SUPGAIN_EPC_DT)
1197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE);
1199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no1 += (SUPGAIN_EPC_DT >> 1);
12003f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                supGain = aecm->supGainErrParamA - tmp16no1;
1202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else
1203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD,
1205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                (ENERGY_DEV_TOL - dE));
1206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
12073f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
1208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        - SUPGAIN_EPC_DT));
1209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                supGain = aecm->supGainErrParamD + tmp16no1;
1210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else
1212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Likely in double talk. Use default value
1214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            supGain = aecm->supGainErrParamD;
1215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (supGain > aecm->supGainOld)
1219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16no1 = supGain;
1221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
1222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmp16no1 = aecm->supGainOld;
1224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->supGainOld = supGain;
1226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (tmp16no1 < aecm->supGain)
1227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
12283f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
1230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
12313f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // END: Update suppression gain
1235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return aecm->supGain;
1237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm,
12403f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org                               const int16_t* const farend,
1241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                               const int farLen)
1242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int writeLen = farLen, writePos = 0;
1244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if the write position must be wrapped
1246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
1247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Write to remaining buffer space before wrapping
1249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
1250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
12513f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org               sizeof(int16_t) * writeLen);
1252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farBufWritePos = 0;
1253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        writePos = writeLen;
1254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        writeLen = farLen - writeLen;
1255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
12583f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org           sizeof(int16_t) * writeLen);
1259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farBufWritePos += writeLen;
1260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
12623f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgvoid WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, int16_t * const farend,
1263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              const int farLen, const int knownDelay)
1264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int readLen = farLen;
1266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int readPos = 0;
1267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int delayChange = knownDelay - aecm->lastKnownDelay;
1268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farBufReadPos -= delayChange;
1270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if delay forces a read position wrap
1272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (aecm->farBufReadPos < 0)
1273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farBufReadPos += FAR_BUF_LEN;
1275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
1277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farBufReadPos -= FAR_BUF_LEN;
1279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->lastKnownDelay = knownDelay;
1282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if read position must be wrapped
1284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
1285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Read from remaining buffer space before wrapping
1288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        readLen = FAR_BUF_LEN - aecm->farBufReadPos;
1289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
12903f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org               sizeof(int16_t) * readLen);
1291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        aecm->farBufReadPos = 0;
1292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        readPos = readLen;
1293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        readLen = farLen - readLen;
1294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
12963f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org           sizeof(int16_t) * readLen);
1297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    aecm->farBufReadPos += readLen;
1298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1299