mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Backed out 2 changesets (bug 1226347) for build bustage CLOSED TREE
Backed out changeset da34ad5d6957 (bug 1226347) Backed out changeset 63d13b6b43ee (bug 1226347) --HG-- extra : commitid : 4yYcYyidto4
This commit is contained in:
parent
593a471c03
commit
dba42704d1
@ -23,8 +23,6 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#endif
|
||||
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/voice_engine/include/voe_errors.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
#include "browser_logging/WebRtcLog.h"
|
||||
@ -233,25 +231,9 @@ MediaConduitErrorCode WebrtcAudioConduit::Init()
|
||||
return kMediaConduitSessionNotInited;
|
||||
}
|
||||
#endif
|
||||
webrtc::Config config;
|
||||
bool aec_extended_filter = true; // Always default to the extended filter length
|
||||
bool aec_delay_agnostic = false;
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
prefs->GetBoolPref("media.getusermedia.aec_extended_filter", &aec_extended_filter);
|
||||
rv = prefs->GetBoolPref("media.getusermedia.aec_delay_agnostic", &aec_delay_agnostic);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Only override platform setting if pref is defined.
|
||||
config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(aec_delay_agnostic));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(aec_extended_filter));
|
||||
|
||||
// Per WebRTC APIs below function calls return nullptr on failure
|
||||
if(!(mVoiceEngine = webrtc::VoiceEngine::Create(config)))
|
||||
if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
|
@ -396,10 +396,15 @@ class MediaPipelineTest : public ::testing::Test {
|
||||
// Setup transport flows
|
||||
InitTransports(aIsRtcpMux);
|
||||
|
||||
#if 0 //DEBUG(pkerr)
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnable(&p1_, &TestAgent::CreatePipelines_s, aIsRtcpMux));
|
||||
#else
|
||||
NS_DispatchToMainThread(
|
||||
WrapRunnable(&p1_, &TestAgent::CreatePipelines_s, aIsRtcpMux),
|
||||
NS_DISPATCH_SYNC);
|
||||
|
||||
#endif
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnable(&p2_, &TestAgent::CreatePipelines_s, aIsRtcpMux));
|
||||
|
@ -104,13 +104,9 @@ ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
|
||||
1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
|
||||
2.0000f};
|
||||
|
||||
// Delay Agnostic AEC parameters, still under development and may change.
|
||||
// TODO(bjornv): These parameters will be tuned.
|
||||
static const float kDelayQualityThresholdMax = 0.07f;
|
||||
static const float kDelayQualityThresholdMin = 0.01f;
|
||||
static const int kInitialShiftOffset = 5;
|
||||
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_GONK)
|
||||
static const int kDelayCorrectionStart = 1500; // 10 ms chunks
|
||||
#endif
|
||||
|
||||
// Target suppression levels for nlp modes.
|
||||
// log{0.001, 0.00001, 0.00000001}
|
||||
@ -824,11 +820,8 @@ static void UpdateDelayMetrics(AecCore* self) {
|
||||
// negative (anti-causal system) or larger than the AEC filter length.
|
||||
{
|
||||
int num_delays_out_of_bounds = self->num_delay_values;
|
||||
const int histogram_length = sizeof(self->delay_histogram) /
|
||||
sizeof(self->delay_histogram[0]);
|
||||
for (i = lookahead; i < lookahead + self->num_partitions; ++i) {
|
||||
if (i < histogram_length)
|
||||
num_delays_out_of_bounds -= self->delay_histogram[i];
|
||||
num_delays_out_of_bounds -= self->delay_histogram[i];
|
||||
}
|
||||
self->fraction_poor_delays = (float)num_delays_out_of_bounds /
|
||||
self->num_delay_values;
|
||||
@ -866,28 +859,10 @@ static void TimeToFrequency(float time_data[PART_LEN2],
|
||||
}
|
||||
}
|
||||
|
||||
static int MoveFarReadPtrWithoutSystemDelayUpdate(AecCore* self, int elements) {
|
||||
WebRtc_MoveReadPtr(self->far_buf_windowed, elements);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_MoveReadPtr(self->far_time_buf, elements);
|
||||
#endif
|
||||
return WebRtc_MoveReadPtr(self->far_buf, elements);
|
||||
}
|
||||
|
||||
static int SignalBasedDelayCorrection(AecCore* self) {
|
||||
int delay_correction = 0;
|
||||
int last_delay = -2;
|
||||
assert(self != NULL);
|
||||
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_GONK)
|
||||
// On desktops, turn on correction after |kDelayCorrectionStart| frames. This
|
||||
// is to let the delay estimation get a chance to converge. Also, if the
|
||||
// playout audio volume is low (or even muted) the delay estimation can return
|
||||
// a very large delay, which will break the AEC if it is applied.
|
||||
if (self->frame_count < kDelayCorrectionStart) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. Check for non-negative delay estimate. Note that the estimates we get
|
||||
// from the delay estimation are not compensated for lookahead. Hence, a
|
||||
// negative |last_delay| is an invalid one.
|
||||
@ -905,22 +880,15 @@ static int SignalBasedDelayCorrection(AecCore* self) {
|
||||
(WebRtc_last_delay_quality(self->delay_estimator) >
|
||||
self->delay_quality_threshold)) {
|
||||
int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
|
||||
// Allow for a slack in the actual delay, defined by a |lower_bound| and an
|
||||
// |upper_bound|. The adaptive echo cancellation filter is currently
|
||||
// |num_partitions| (of 64 samples) long. If the delay estimate is negative
|
||||
// or at least 3/4 of the filter length we open up for correction.
|
||||
const int lower_bound = 0;
|
||||
const int upper_bound = self->num_partitions * 3 / 4;
|
||||
const int do_correction = delay <= lower_bound || delay > upper_bound;
|
||||
if (do_correction == 1) {
|
||||
// Allow for a slack in the actual delay. The adaptive echo cancellation
|
||||
// filter is currently |num_partitions| (of 64 samples) long. If the
|
||||
// delay estimate indicates a delay of at least one quarter of the filter
|
||||
// length we open up for correction.
|
||||
if (delay <= 0 || delay > (self->num_partitions / 4)) {
|
||||
int available_read = (int)WebRtc_available_read(self->far_buf);
|
||||
// With |shift_offset| we gradually rely on the delay estimates. For
|
||||
// positive delays we reduce the correction by |shift_offset| to lower the
|
||||
// risk of pushing the AEC into a non causal state. For negative delays
|
||||
// we rely on the values up to a rounding error, hence compensate by 1
|
||||
// element to make sure to push the delay into the causal region.
|
||||
delay_correction = -delay;
|
||||
delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
|
||||
// Adjust w.r.t. a |shift_offset| to account for not as reliable estimates
|
||||
// in the beginning, hence we are more conservative.
|
||||
delay_correction = -(delay - self->shift_offset);
|
||||
self->shift_offset--;
|
||||
self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
|
||||
if (delay_correction > available_read - self->mult - 1) {
|
||||
@ -999,8 +967,6 @@ OpenCoreDebugFiles(AecCore* aec, int *aec_instance_count)
|
||||
aec->instance_index, aec->debug_dump_count, process_rate);
|
||||
ReopenWav(&aec->outLinearFile, "aec_out_linear",
|
||||
aec->instance_index, aec->debug_dump_count, process_rate);
|
||||
ReopenWav(&aec->e_fft_file, "aec_fft",
|
||||
aec->instance_index, aec->debug_dump_count, process_rate);
|
||||
++aec->debug_dump_count;
|
||||
}
|
||||
} else {
|
||||
@ -1016,10 +982,7 @@ OpenCoreDebugFiles(AecCore* aec, int *aec_instance_count)
|
||||
if (aec->outLinearFile) {
|
||||
rtc_WavClose(aec->outLinearFile);
|
||||
}
|
||||
if (aec->e_fft_file) {
|
||||
rtc_WavClose(aec->e_fft_file);
|
||||
}
|
||||
aec->outLinearFile = aec->outFile = aec->nearFile = aec->farFile = aec->e_fft_file = NULL;
|
||||
aec->outLinearFile = aec->outFile = aec->nearFile = aec->farFile = NULL;
|
||||
aec->debugWritten = 0;
|
||||
}
|
||||
}
|
||||
@ -1033,8 +996,7 @@ static void NonLinearProcessing(AecCore* aec,
|
||||
float fft[PART_LEN2];
|
||||
float scale, dtmp;
|
||||
float nlpGainHband;
|
||||
int i;
|
||||
size_t j;
|
||||
int i, j;
|
||||
|
||||
// Coherence and non-linear filter
|
||||
float cohde[PART_LEN1], cohxd[PART_LEN1];
|
||||
@ -1249,8 +1211,8 @@ static void NonLinearProcessing(AecCore* aec,
|
||||
memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN);
|
||||
|
||||
// Copy the current block to the old position for H band
|
||||
for (j = 0; j < aec->num_bands - 1; ++j) {
|
||||
memcpy(aec->dBufH[j], aec->dBufH[j] + PART_LEN, sizeof(float) * PART_LEN);
|
||||
for (i = 0; i < aec->num_bands - 1; ++i) {
|
||||
memcpy(aec->dBufH[i], aec->dBufH[i] + PART_LEN, sizeof(float) * PART_LEN);
|
||||
}
|
||||
|
||||
memmove(aec->xfwBuf + PART_LEN1,
|
||||
@ -1259,7 +1221,7 @@ static void NonLinearProcessing(AecCore* aec,
|
||||
}
|
||||
|
||||
static void ProcessBlock(AecCore* aec) {
|
||||
size_t i;
|
||||
int i;
|
||||
float y[PART_LEN], e[PART_LEN];
|
||||
float scale;
|
||||
|
||||
@ -1443,13 +1405,6 @@ static void ProcessBlock(AecCore* aec) {
|
||||
ef[1][i] = fft[2 * i + 1];
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
if (aec->e_fft_file) {
|
||||
rtc_WavWriteSamples(aec->e_fft_file, &ef[0][0],
|
||||
sizeof(ef[0][0]) * PART_LEN1 * 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aec->metricsMode == 1) {
|
||||
// Note that the first PART_LEN samples in fft (before transformation) are
|
||||
// zero. Hence, the scaling by two in UpdateLevel() should not be
|
||||
@ -1485,23 +1440,26 @@ static void ProcessBlock(AecCore* aec) {
|
||||
#endif
|
||||
}
|
||||
|
||||
AecCore* WebRtcAec_CreateAec() {
|
||||
int WebRtcAec_CreateAec(AecCore** aecInst) {
|
||||
int i;
|
||||
AecCore* aec = malloc(sizeof(AecCore));
|
||||
if (!aec) {
|
||||
return NULL;
|
||||
*aecInst = aec;
|
||||
if (aec == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float));
|
||||
if (!aec->nearFrBuf) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aec->outFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float));
|
||||
if (!aec->outFrBuf) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
|
||||
@ -1509,13 +1467,15 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
sizeof(float));
|
||||
if (!aec->nearFrBufH[i]) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
aec->outFrBufH[i] = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
|
||||
sizeof(float));
|
||||
if (!aec->outFrBufH[i]) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1524,13 +1484,15 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * 2 * PART_LEN1);
|
||||
if (!aec->far_buf) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
aec->far_buf_windowed =
|
||||
WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * 2 * PART_LEN1);
|
||||
if (!aec->far_buf_windowed) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
aec->instance_index = webrtc_aec_instance_count;
|
||||
@ -1538,9 +1500,10 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * PART_LEN);
|
||||
if (!aec->far_time_buf) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
aec->farFile = aec->nearFile = aec->outFile = aec->outLinearFile = aec->e_fft_file = NULL;
|
||||
aec->farFile = aec->nearFile = aec->outFile = aec->outLinearFile = NULL;
|
||||
aec->debug_dump_count = 0;
|
||||
aec->debugWritten = 0;
|
||||
OpenCoreDebugFiles(aec, &webrtc_aec_instance_count);
|
||||
@ -1549,7 +1512,8 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
|
||||
if (aec->delay_estimator_farend == NULL) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
// We create the delay_estimator with the same amount of maximum lookahead as
|
||||
// the delay history size (kHistorySizeBlocks) for symmetry reasons.
|
||||
@ -1557,18 +1521,16 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
aec->delay_estimator_farend, kHistorySizeBlocks);
|
||||
if (aec->delay_estimator == NULL) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
return NULL;
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_GONK)
|
||||
aec->delay_agnostic_enabled = 1; // DA-AEC enabled by default.
|
||||
#ifdef WEBRTC_ANDROID
|
||||
// DA-AEC assumes the system is causal from the beginning and will self adjust
|
||||
// the lookahead when shifting is required.
|
||||
WebRtc_set_lookahead(aec->delay_estimator, 0);
|
||||
#else
|
||||
aec->delay_agnostic_enabled = 0;
|
||||
WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
|
||||
#endif
|
||||
aec->extended_filter_enabled = 0;
|
||||
|
||||
// Assembly optimization
|
||||
WebRtcAec_FilterFar = FilterFar;
|
||||
@ -1598,13 +1560,13 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
|
||||
aec_rdft_init();
|
||||
|
||||
return aec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAec_FreeAec(AecCore* aec) {
|
||||
int WebRtcAec_FreeAec(AecCore* aec) {
|
||||
int i;
|
||||
if (aec == NULL) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_FreeBuffer(aec->nearFrBuf);
|
||||
@ -1625,13 +1587,13 @@ void WebRtcAec_FreeAec(AecCore* aec) {
|
||||
rtc_WavClose(aec->nearFile);
|
||||
rtc_WavClose(aec->outFile);
|
||||
rtc_WavClose(aec->outLinearFile);
|
||||
rtc_WavClose(aec->e_fft_file);
|
||||
}
|
||||
#endif
|
||||
WebRtc_FreeDelayEstimator(aec->delay_estimator);
|
||||
WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
|
||||
|
||||
free(aec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
@ -1646,7 +1608,7 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
} else {
|
||||
aec->normal_mu = 0.5f;
|
||||
aec->normal_error_threshold = 1.5e-6f;
|
||||
aec->num_bands = (size_t)(sampFreq / 16000);
|
||||
aec->num_bands = sampFreq / 16000;
|
||||
}
|
||||
|
||||
WebRtc_InitBuffer(aec->nearFrBuf);
|
||||
@ -1684,8 +1646,14 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
aec->previous_delay = -2; // (-2): Uninitialized.
|
||||
aec->delay_correction_count = 0;
|
||||
aec->shift_offset = kInitialShiftOffset;
|
||||
aec->delay_quality_threshold = kDelayQualityThresholdMin;
|
||||
aec->delay_quality_threshold = 0;
|
||||
|
||||
#ifdef WEBRTC_ANDROID
|
||||
aec->reported_delay_enabled = 0; // Disabled by default.
|
||||
#else
|
||||
aec->reported_delay_enabled = 1;
|
||||
#endif
|
||||
aec->extended_filter_enabled = 0;
|
||||
aec->num_partitions = kNormalNumPartitions;
|
||||
|
||||
// Update the delay estimator with filter length. We use half the
|
||||
@ -1698,16 +1666,14 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
// all the time and the APIs to turn it on/off will be removed. Hence, remove
|
||||
// this line then.
|
||||
WebRtc_enable_robust_validation(aec->delay_estimator, 1);
|
||||
aec->frame_count = 0;
|
||||
|
||||
// Default target suppression mode.
|
||||
aec->nlp_mode = 1;
|
||||
|
||||
// Sampling frequency multiplier w.r.t. 8 kHz.
|
||||
// In case of multiple bands we process the lower band in 16 kHz, hence the
|
||||
// multiplier is always 2.
|
||||
// Sampling frequency multiplier
|
||||
// SWB is processed as 160 frame size
|
||||
if (aec->num_bands > 1) {
|
||||
aec->mult = 2;
|
||||
aec->mult = (short)aec->sampFreq / 16000;
|
||||
} else {
|
||||
aec->mult = (short)aec->sampFreq / 8000;
|
||||
}
|
||||
@ -1803,21 +1769,24 @@ void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend) {
|
||||
}
|
||||
|
||||
int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) {
|
||||
int elements_moved = MoveFarReadPtrWithoutSystemDelayUpdate(aec, elements);
|
||||
int elements_moved = WebRtc_MoveReadPtr(aec->far_buf_windowed, elements);
|
||||
WebRtc_MoveReadPtr(aec->far_buf, elements);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_MoveReadPtr(aec->far_time_buf, elements);
|
||||
#endif
|
||||
aec->system_delay -= elements_moved * PART_LEN;
|
||||
return elements_moved;
|
||||
}
|
||||
|
||||
void WebRtcAec_ProcessFrames(AecCore* aec,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
size_t num_samples,
|
||||
int num_bands,
|
||||
int num_samples,
|
||||
int knownDelay,
|
||||
float* const* out) {
|
||||
size_t i, j;
|
||||
int i, j;
|
||||
int out_elements = 0;
|
||||
|
||||
aec->frame_count++;
|
||||
// For each frame the process is as follows:
|
||||
// 1) If the system_delay indicates on being too small for processing a
|
||||
// frame we stuff the buffer with enough data for 10 ms.
|
||||
@ -1865,7 +1834,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec,
|
||||
WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1));
|
||||
}
|
||||
|
||||
if (!aec->delay_agnostic_enabled) {
|
||||
if (aec->reported_delay_enabled) {
|
||||
// 2 a) Compensate for a possible change in the system delay.
|
||||
|
||||
// TODO(bjornv): Investigate how we should round the delay difference;
|
||||
@ -1876,27 +1845,42 @@ void WebRtcAec_ProcessFrames(AecCore* aec,
|
||||
// which should be investigated. Maybe, allow for a non-symmetric
|
||||
// rounding, like -16.
|
||||
int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
|
||||
int moved_elements =
|
||||
MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
|
||||
int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements);
|
||||
WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements);
|
||||
aec->knownDelay -= moved_elements * PART_LEN;
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_MoveReadPtr(aec->far_time_buf, move_elements);
|
||||
#endif
|
||||
} else {
|
||||
// 2 b) Apply signal based delay correction.
|
||||
int move_elements = SignalBasedDelayCorrection(aec);
|
||||
int moved_elements =
|
||||
MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
|
||||
int far_near_buffer_diff = WebRtc_available_read(aec->far_buf) -
|
||||
WebRtc_available_read(aec->nearFrBuf) / PART_LEN;
|
||||
int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements);
|
||||
WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_MoveReadPtr(aec->far_time_buf, move_elements);
|
||||
#endif
|
||||
WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
|
||||
WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
|
||||
moved_elements);
|
||||
aec->signal_delay_correction += moved_elements;
|
||||
// If we rely on reported system delay values only, a buffer underrun here
|
||||
// can never occur since we've taken care of that in 1) above. Here, we
|
||||
// apply signal based delay correction and can therefore end up with
|
||||
// buffer underruns since the delay estimation can be wrong. We therefore
|
||||
// stuff the buffer with enough elements if needed.
|
||||
if (far_near_buffer_diff < 0) {
|
||||
WebRtcAec_MoveFarReadPtr(aec, far_near_buffer_diff);
|
||||
// TODO(bjornv): Investigate if this is reasonable. I had to add this
|
||||
// guard when the signal based delay correction replaces the system based
|
||||
// one. Otherwise there was a buffer underrun in the "qa-new/01/"
|
||||
// recording when adding 44 ms extra delay. This was not seen if we kept
|
||||
// both delay correction algorithms running in parallel.
|
||||
// A first investigation showed that we have a drift in this case that
|
||||
// causes the buffer underrun. Compared to when delay correction was
|
||||
// turned off, we get buffer underrun as well which was triggered in 1)
|
||||
// above. In addition there was a shift in |knownDelay| later increasing
|
||||
// the buffer. When running in parallel, this if statement was not
|
||||
// triggered. This suggests two alternatives; (a) use both algorithms, or
|
||||
// (b) allow for smaller delay corrections when we operate close to the
|
||||
// buffer limit. At the time of testing we required a change of 6 blocks,
|
||||
// but could change it to, e.g., 2 blocks. It requires some testing
|
||||
// though.
|
||||
if ((int)WebRtc_available_read(aec->far_buf) < (aec->mult + 1)) {
|
||||
// We don't have enough data so we stuff the far-end buffers.
|
||||
WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1979,28 +1963,28 @@ void WebRtcAec_SetConfigCore(AecCore* self,
|
||||
}
|
||||
// Turn on delay logging if it is either set explicitly or if delay agnostic
|
||||
// AEC is enabled (which requires delay estimates).
|
||||
self->delay_logging_enabled = delay_logging || self->delay_agnostic_enabled;
|
||||
self->delay_logging_enabled = delay_logging || !self->reported_delay_enabled;
|
||||
if (self->delay_logging_enabled) {
|
||||
memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable) {
|
||||
self->delay_agnostic_enabled = enable;
|
||||
void WebRtcAec_enable_reported_delay(AecCore* self, int enable) {
|
||||
self->reported_delay_enabled = enable;
|
||||
}
|
||||
|
||||
int WebRtcAec_delay_agnostic_enabled(AecCore* self) {
|
||||
return self->delay_agnostic_enabled;
|
||||
int WebRtcAec_reported_delay_enabled(AecCore* self) {
|
||||
return self->reported_delay_enabled;
|
||||
}
|
||||
|
||||
void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
|
||||
void WebRtcAec_enable_delay_correction(AecCore* self, int enable) {
|
||||
self->extended_filter_enabled = enable;
|
||||
self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
|
||||
// Update the delay estimator with filter length. See InitAEC() for details.
|
||||
WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
|
||||
}
|
||||
|
||||
int WebRtcAec_extended_filter_enabled(AecCore* self) {
|
||||
int WebRtcAec_delay_correction_enabled(AecCore* self) {
|
||||
return self->extended_filter_enabled;
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#define FRAME_LEN 80
|
||||
@ -53,8 +51,8 @@ typedef struct Stats {
|
||||
|
||||
typedef struct AecCore AecCore;
|
||||
|
||||
AecCore* WebRtcAec_CreateAec(); // Returns NULL on error.
|
||||
void WebRtcAec_FreeAec(AecCore* aec);
|
||||
int WebRtcAec_CreateAec(AecCore** aec);
|
||||
int WebRtcAec_FreeAec(AecCore* aec);
|
||||
int WebRtcAec_InitAec(AecCore* aec, int sampFreq);
|
||||
void WebRtcAec_InitAec_SSE2(void);
|
||||
#if defined(MIPS_FPU_LE)
|
||||
@ -67,8 +65,8 @@ void WebRtcAec_InitAec_neon(void);
|
||||
void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend);
|
||||
void WebRtcAec_ProcessFrames(AecCore* aec,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
size_t num_samples,
|
||||
int num_bands,
|
||||
int num_samples,
|
||||
int knownDelay,
|
||||
float* const* out);
|
||||
|
||||
@ -105,17 +103,19 @@ void WebRtcAec_SetConfigCore(AecCore* self,
|
||||
int delay_logging);
|
||||
|
||||
// Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable);
|
||||
void WebRtcAec_enable_reported_delay(AecCore* self, int enable);
|
||||
|
||||
// Returns non-zero if delay agnostic (i.e., signal based delay estimation) is
|
||||
// enabled and zero if disabled.
|
||||
int WebRtcAec_delay_agnostic_enabled(AecCore* self);
|
||||
// Returns non-zero if reported delay is enabled and zero if disabled.
|
||||
int WebRtcAec_reported_delay_enabled(AecCore* self);
|
||||
|
||||
// Enables or disables extended filter mode. Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_extended_filter(AecCore* self, int enable);
|
||||
// We now interpret delay correction to mean an extended filter length feature.
|
||||
// We reuse the delay correction infrastructure to avoid changes through to
|
||||
// libjingle. See details along with |DelayCorrection| in
|
||||
// echo_cancellation_impl.h. Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_delay_correction(AecCore* self, int enable);
|
||||
|
||||
// Returns non-zero if extended filter mode is enabled and zero if disabled.
|
||||
int WebRtcAec_extended_filter_enabled(AecCore* self);
|
||||
// Returns non-zero if delay correction is enabled and zero if disabled.
|
||||
int WebRtcAec_delay_correction_enabled(AecCore* self);
|
||||
|
||||
// Returns the current |system_delay|, i.e., the buffered difference between
|
||||
// far-end and near-end.
|
||||
|
@ -101,7 +101,7 @@ struct AecCore {
|
||||
|
||||
int mult; // sampling frequency multiple
|
||||
int sampFreq;
|
||||
size_t num_bands;
|
||||
int num_bands;
|
||||
uint32_t seed;
|
||||
|
||||
float normal_mu; // stepsize
|
||||
@ -142,11 +142,10 @@ struct AecCore {
|
||||
int delay_correction_count;
|
||||
int shift_offset;
|
||||
float delay_quality_threshold;
|
||||
int frame_count;
|
||||
|
||||
// 0 = delay agnostic mode (signal based delay correction) disabled.
|
||||
// Otherwise enabled.
|
||||
int delay_agnostic_enabled;
|
||||
// 0 = reported delay mode disabled (signal based delay correction enabled).
|
||||
// otherwise enabled
|
||||
int reported_delay_enabled;
|
||||
// 1 = extended filter mode enabled, 0 = disabled.
|
||||
int extended_filter_enabled;
|
||||
// Runtime selection of number of filter partitions.
|
||||
@ -166,7 +165,6 @@ struct AecCore {
|
||||
rtc_WavWriter* nearFile;
|
||||
rtc_WavWriter* outFile;
|
||||
rtc_WavWriter* outLinearFile;
|
||||
rtc_WavWriter* e_fft_file;
|
||||
uint32_t debugWritten;
|
||||
#endif
|
||||
};
|
||||
|
@ -40,8 +40,14 @@ static int EstimateSkew(const int* rawSkew,
|
||||
int absLimit,
|
||||
float* skewEst);
|
||||
|
||||
void* WebRtcAec_CreateResampler() {
|
||||
return malloc(sizeof(AecResampler));
|
||||
int WebRtcAec_CreateResampler(void** resampInst) {
|
||||
AecResampler* obj = malloc(sizeof(AecResampler));
|
||||
*resampInst = obj;
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
|
||||
@ -57,24 +63,26 @@ int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAec_FreeResampler(void* resampInst) {
|
||||
int WebRtcAec_FreeResampler(void* resampInst) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
free(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAec_ResampleLinear(void* resampInst,
|
||||
const float* inspeech,
|
||||
size_t size,
|
||||
int size,
|
||||
float skew,
|
||||
float* outspeech,
|
||||
size_t* size_out) {
|
||||
int* size_out) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
|
||||
float* y;
|
||||
float be, tnew;
|
||||
size_t tn, mm;
|
||||
int tn, mm;
|
||||
|
||||
assert(size <= 2 * FRAME_LEN);
|
||||
assert(!(size < 0 || size > 2 * FRAME_LEN));
|
||||
assert(resampInst != NULL);
|
||||
assert(inspeech != NULL);
|
||||
assert(outspeech != NULL);
|
||||
@ -93,7 +101,7 @@ void WebRtcAec_ResampleLinear(void* resampInst,
|
||||
y = &obj->buffer[FRAME_LEN]; // Point at current frame
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (size_t)tnew;
|
||||
tn = (int)tnew;
|
||||
|
||||
while (tn < size) {
|
||||
|
||||
|
@ -20,10 +20,10 @@ enum {
|
||||
kResamplerBufferSize = FRAME_LEN * 4
|
||||
};
|
||||
|
||||
// Unless otherwise specified, functions return 0 on success and -1 on error.
|
||||
void* WebRtcAec_CreateResampler(); // Returns NULL on error.
|
||||
// Unless otherwise specified, functions return 0 on success and -1 on error
|
||||
int WebRtcAec_CreateResampler(void** resampInst);
|
||||
int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz);
|
||||
void WebRtcAec_FreeResampler(void* resampInst);
|
||||
int WebRtcAec_FreeResampler(void* resampInst);
|
||||
|
||||
// Estimates skew from raw measurement.
|
||||
int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
|
||||
@ -31,9 +31,9 @@ int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
|
||||
// Resamples input using linear interpolation.
|
||||
void WebRtcAec_ResampleLinear(void* resampInst,
|
||||
const float* inspeech,
|
||||
size_t size,
|
||||
int size,
|
||||
float skew,
|
||||
float* outspeech,
|
||||
size_t* size_out);
|
||||
int* size_out);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
|
||||
|
@ -111,35 +111,41 @@ static void EstBufDelayNormal(Aec* aecInst);
|
||||
static void EstBufDelayExtended(Aec* aecInst);
|
||||
static int ProcessNormal(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew);
|
||||
static void ProcessExtended(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew);
|
||||
|
||||
void* WebRtcAec_Create() {
|
||||
Aec* aecpc = malloc(sizeof(Aec));
|
||||
|
||||
if (!aecpc) {
|
||||
return NULL;
|
||||
int32_t WebRtcAec_Create(void** aecInst) {
|
||||
Aec* aecpc;
|
||||
if (aecInst == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecpc->aec = WebRtcAec_CreateAec();
|
||||
if (!aecpc->aec) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
aecpc = malloc(sizeof(Aec));
|
||||
*aecInst = aecpc;
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
aecpc->resampler = WebRtcAec_CreateResampler();
|
||||
if (!aecpc->resampler) {
|
||||
|
||||
if (WebRtcAec_CreateAec(&aecpc->aec) == -1) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
// Create far-end pre-buffer. The buffer size has to be large enough for
|
||||
// largest possible drift compensation (kResamplerBufferSize) + "almost" an
|
||||
@ -148,24 +154,26 @@ void* WebRtcAec_Create() {
|
||||
WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(float));
|
||||
if (!aecpc->far_pre_buf) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecpc->initFlag = 0;
|
||||
aecpc->lastError = 0;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
aecpc->bufFile = aecpc->skewFile = aecpc->delayFile = NULL;
|
||||
OpenDebugFiles(aecpc, &webrtc_aec_instance_count);
|
||||
#endif
|
||||
|
||||
return aecpc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAec_Free(void* aecInst) {
|
||||
int32_t WebRtcAec_Free(void* aecInst) {
|
||||
Aec* aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_FreeBuffer(aecpc->far_pre_buf);
|
||||
@ -182,6 +190,8 @@ void WebRtcAec_Free(void* aecInst) {
|
||||
WebRtcAec_FreeAec(aecpc->aec);
|
||||
WebRtcAec_FreeResampler(aecpc->resampler);
|
||||
free(aecpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
@ -192,22 +202,26 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
sampFreq != 16000 &&
|
||||
sampFreq != 32000 &&
|
||||
sampFreq != 48000) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->sampFreq = sampFreq;
|
||||
|
||||
if (scSampFreq < 1 || scSampFreq > 96000) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->scSampFreq = scSampFreq;
|
||||
|
||||
// Initialize echo canceller core
|
||||
if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
|
||||
return AEC_UNSPECIFIED_ERROR;
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
|
||||
return AEC_UNSPECIFIED_ERROR;
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_InitBuffer(aecpc->far_pre_buf);
|
||||
@ -231,10 +245,7 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
aecpc->checkBuffSize = 1;
|
||||
aecpc->firstVal = 0;
|
||||
|
||||
// We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
|
||||
// but not extended_filter mode.
|
||||
aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
|
||||
!WebRtcAec_delay_agnostic_enabled(aecpc->aec);
|
||||
aecpc->startup_phase = WebRtcAec_reported_delay_enabled(aecpc->aec);
|
||||
aecpc->bufSizeStart = 0;
|
||||
aecpc->checkBufSizeCtr = 0;
|
||||
aecpc->msInSndCardBuf = 0;
|
||||
@ -257,48 +268,37 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
aecConfig.delay_logging = kAecFalse;
|
||||
|
||||
if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
|
||||
return AEC_UNSPECIFIED_ERROR;
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns any error that is caused when buffering the
|
||||
// far-end signal.
|
||||
int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples) {
|
||||
Aec* aecpc = aecInst;
|
||||
|
||||
if (!farend)
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
|
||||
if (aecpc->initFlag != initCheck)
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// only buffer L band for farend
|
||||
int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples) {
|
||||
int16_t nrOfSamples) {
|
||||
Aec* aecpc = aecInst;
|
||||
size_t newNrOfSamples = nrOfSamples;
|
||||
int newNrOfSamples = (int)nrOfSamples;
|
||||
float new_farend[MAX_RESAMP_LEN];
|
||||
const float* farend_ptr = farend;
|
||||
|
||||
// Get any error caused by buffering the farend signal.
|
||||
int32_t error_code = WebRtcAec_GetBufferFarendError(aecInst, farend,
|
||||
nrOfSamples);
|
||||
if (farend == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (error_code != 0)
|
||||
return error_code;
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
// Resample and get a new number of samples
|
||||
@ -312,11 +312,11 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
}
|
||||
|
||||
aecpc->farend_started = 1;
|
||||
WebRtcAec_SetSystemDelay(
|
||||
aecpc->aec, WebRtcAec_system_delay(aecpc->aec) + (int)newNrOfSamples);
|
||||
WebRtcAec_SetSystemDelay(aecpc->aec,
|
||||
WebRtcAec_system_delay(aecpc->aec) + newNrOfSamples);
|
||||
|
||||
// Write the time-domain data to |far_pre_buf|.
|
||||
WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
|
||||
WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, (size_t)newNrOfSamples);
|
||||
|
||||
// Transform to frequency domain if we have enough data.
|
||||
while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
|
||||
@ -341,37 +341,42 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
|
||||
int32_t WebRtcAec_Process(void* aecInst,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t nrOfSamples,
|
||||
int16_t msInSndCardBuf,
|
||||
int32_t skew) {
|
||||
Aec* aecpc = aecInst;
|
||||
int32_t retVal = 0;
|
||||
|
||||
if (out == NULL) {
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msInSndCardBuf < 0) {
|
||||
msInSndCardBuf = 0;
|
||||
retVal = AEC_BAD_PARAMETER_WARNING;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
} else if (msInSndCardBuf > kMaxTrustedDelayMs) {
|
||||
// The clamping is now done in ProcessExtended/Normal().
|
||||
retVal = AEC_BAD_PARAMETER_WARNING;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
|
||||
// This returns the value of aec->extended_filter_enabled.
|
||||
if (WebRtcAec_extended_filter_enabled(aecpc->aec)) {
|
||||
if (WebRtcAec_delay_correction_enabled(aecpc->aec)) {
|
||||
ProcessExtended(aecpc,
|
||||
nearend,
|
||||
num_bands,
|
||||
@ -380,13 +385,15 @@ int32_t WebRtcAec_Process(void* aecInst,
|
||||
msInSndCardBuf,
|
||||
skew);
|
||||
} else {
|
||||
retVal = ProcessNormal(aecpc,
|
||||
nearend,
|
||||
num_bands,
|
||||
out,
|
||||
nrOfSamples,
|
||||
msInSndCardBuf,
|
||||
skew);
|
||||
if (ProcessNormal(aecpc,
|
||||
nearend,
|
||||
num_bands,
|
||||
out,
|
||||
nrOfSamples,
|
||||
msInSndCardBuf,
|
||||
skew) != 0) {
|
||||
retVal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
@ -408,26 +415,31 @@ int32_t WebRtcAec_Process(void* aecInst,
|
||||
int WebRtcAec_set_config(void* handle, AecConfig config) {
|
||||
Aec* self = (Aec*)handle;
|
||||
if (self->initFlag != initCheck) {
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
self->skewMode = config.skewMode;
|
||||
|
||||
if (config.nlpMode != kAecNlpConservative &&
|
||||
config.nlpMode != kAecNlpModerate &&
|
||||
config.nlpMode != kAecNlpAggressive) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
|
||||
return AEC_BAD_PARAMETER_ERROR;
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAec_SetConfigCore(
|
||||
@ -438,10 +450,12 @@ int WebRtcAec_set_config(void* handle, AecConfig config) {
|
||||
int WebRtcAec_get_echo_status(void* handle, int* status) {
|
||||
Aec* self = (Aec*)handle;
|
||||
if (status == NULL) {
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*status = WebRtcAec_echo_state(self->aec);
|
||||
@ -462,10 +476,12 @@ int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
|
||||
return -1;
|
||||
}
|
||||
if (metrics == NULL) {
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp);
|
||||
@ -550,24 +566,32 @@ int WebRtcAec_GetDelayMetrics(void* handle,
|
||||
float* fraction_poor_delays) {
|
||||
Aec* self = handle;
|
||||
if (median == NULL) {
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (std == NULL) {
|
||||
return AEC_NULL_POINTER_ERROR;
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
return AEC_UNINITIALIZED_ERROR;
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (WebRtcAec_GetDelayMetricsCore(self->aec, median, std,
|
||||
fraction_poor_delays) ==
|
||||
-1) {
|
||||
// Logging disabled.
|
||||
return AEC_UNSUPPORTED_FUNCTION_ERROR;
|
||||
self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAec_get_error_code(void* aecInst) {
|
||||
Aec* aecpc = aecInst;
|
||||
return aecpc->lastError;
|
||||
}
|
||||
|
||||
AecCore* WebRtcAec_aec_core(void* handle) {
|
||||
if (!handle) {
|
||||
@ -578,14 +602,14 @@ AecCore* WebRtcAec_aec_core(void* handle) {
|
||||
|
||||
static int ProcessNormal(Aec* aecpc,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t nrOfSamples,
|
||||
int16_t msInSndCardBuf,
|
||||
int32_t skew) {
|
||||
int retVal = 0;
|
||||
size_t i;
|
||||
size_t nBlocks10ms;
|
||||
short i;
|
||||
short nBlocks10ms;
|
||||
// Limit resampling to doubling/halving of signal
|
||||
const float minSkewEst = -0.5f;
|
||||
const float maxSkewEst = 1.0f;
|
||||
@ -603,7 +627,7 @@ static int ProcessNormal(Aec* aecpc,
|
||||
retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
|
||||
if (retVal == -1) {
|
||||
aecpc->skew = 0;
|
||||
retVal = AEC_BAD_PARAMETER_WARNING;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
}
|
||||
|
||||
aecpc->skew /= aecpc->sampFactor * nrOfSamples;
|
||||
@ -710,7 +734,9 @@ static int ProcessNormal(Aec* aecpc,
|
||||
}
|
||||
} else {
|
||||
// AEC is enabled.
|
||||
if (WebRtcAec_reported_delay_enabled(aecpc->aec)) {
|
||||
EstBufDelayNormal(aecpc);
|
||||
}
|
||||
|
||||
// Call the AEC.
|
||||
// TODO(bjornv): Re-structure such that we don't have to pass
|
||||
@ -729,12 +755,12 @@ static int ProcessNormal(Aec* aecpc,
|
||||
|
||||
static void ProcessExtended(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew) {
|
||||
size_t i;
|
||||
int i;
|
||||
const int delay_diff_offset = kDelayDiffOffsetSamples;
|
||||
#if defined(WEBRTC_UNTRUSTED_DELAY)
|
||||
reported_delay_ms = kFixedDelayMs;
|
||||
@ -772,21 +798,16 @@ static void ProcessExtended(Aec* self,
|
||||
// measurement.
|
||||
int startup_size_ms =
|
||||
reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
|
||||
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_GONK)
|
||||
int target_delay = startup_size_ms * self->rate_factor * 8;
|
||||
#else
|
||||
// To avoid putting the AEC in a non-causal state we're being slightly
|
||||
// conservative and scale by 2. On Android we use a fixed delay and
|
||||
// therefore there is no need to scale the target_delay.
|
||||
int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
|
||||
#endif
|
||||
int overhead_elements =
|
||||
(WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
|
||||
int overhead_elements = (WebRtcAec_system_delay(self->aec) -
|
||||
startup_size_ms / 2 * self->rate_factor * 8) /
|
||||
PART_LEN;
|
||||
WebRtcAec_MoveFarReadPtr(self->aec, overhead_elements);
|
||||
self->startup_phase = 0;
|
||||
}
|
||||
|
||||
EstBufDelayExtended(self);
|
||||
if (WebRtcAec_reported_delay_enabled(self->aec)) {
|
||||
EstBufDelayExtended(self);
|
||||
}
|
||||
|
||||
{
|
||||
// |delay_diff_offset| gives us the option to manually rewind the delay on
|
||||
|
@ -57,6 +57,8 @@ typedef struct {
|
||||
|
||||
RingBuffer* far_pre_buf; // Time domain far-end pre-buffer.
|
||||
|
||||
int lastError;
|
||||
|
||||
int farend_started;
|
||||
|
||||
AecCore* aec;
|
||||
|
@ -11,8 +11,6 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Errors
|
||||
@ -66,10 +64,19 @@ extern "C" {
|
||||
|
||||
/*
|
||||
* Allocates the memory needed by the AEC. The memory needs to be initialized
|
||||
* separately using the WebRtcAec_Init() function. Returns a pointer to the
|
||||
* object or NULL on error.
|
||||
* separately using the WebRtcAec_Init() function.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void** aecInst Pointer to the AEC instance to be created
|
||||
* and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
void* WebRtcAec_Create();
|
||||
int32_t WebRtcAec_Create(void** aecInst);
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAec_Create().
|
||||
@ -77,8 +84,13 @@ void* WebRtcAec_Create();
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
void WebRtcAec_Free(void* aecInst);
|
||||
int32_t WebRtcAec_Free(void* aecInst);
|
||||
|
||||
/*
|
||||
* Initializes an AEC instance.
|
||||
@ -91,7 +103,7 @@ void WebRtcAec_Free(void* aecInst);
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
|
||||
@ -109,30 +121,11 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Reports any errors that would arise if buffering a farend buffer
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
* const float* farend In buffer containing one frame of
|
||||
* farend signal for L band
|
||||
* int16_t nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 12000-12050: error code
|
||||
*/
|
||||
int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples);
|
||||
int16_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the echo canceller on an 80 or 160 sample blocks of data.
|
||||
@ -155,13 +148,13 @@ int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
|
||||
* float* const* out Out buffer, one frame of processed nearend
|
||||
* for each band
|
||||
* int32_t return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_Process(void* aecInst,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
int num_bands,
|
||||
float* const* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t nrOfSamples,
|
||||
int16_t msInSndCardBuf,
|
||||
int32_t skew);
|
||||
|
||||
@ -177,7 +170,7 @@ int32_t WebRtcAec_Process(void* aecInst,
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_set_config(void* handle, AecConfig config);
|
||||
|
||||
@ -193,7 +186,7 @@ int WebRtcAec_set_config(void* handle, AecConfig config);
|
||||
* int* status 0: Almost certainly nearend single-talk
|
||||
* 1: Might not be neared single-talk
|
||||
* int return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_get_echo_status(void* handle, int* status);
|
||||
|
||||
@ -209,7 +202,7 @@ int WebRtcAec_get_echo_status(void* handle, int* status);
|
||||
* AecMetrics* metrics Struct which will be filled out with the
|
||||
* current echo metrics.
|
||||
* int return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics);
|
||||
|
||||
@ -228,13 +221,26 @@ int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics);
|
||||
* cause the AEC to perform poorly.
|
||||
*
|
||||
* int return 0: OK
|
||||
* 12000-12050: error code
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetDelayMetrics(void* handle,
|
||||
int* median,
|
||||
int* std,
|
||||
float* fraction_poor_delays);
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 11000-11100: error code
|
||||
*/
|
||||
int32_t WebRtcAec_get_error_code(void* aecInst);
|
||||
|
||||
// Returns a pointer to the low level AEC handle.
|
||||
//
|
||||
// Input:
|
||||
|
@ -207,15 +207,21 @@ CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
|
||||
StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
|
||||
ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
|
||||
|
||||
AecmCore* WebRtcAecm_CreateCore() {
|
||||
int WebRtcAecm_CreateCore(AecmCore** aecmInst) {
|
||||
AecmCore* aecm = malloc(sizeof(AecmCore));
|
||||
*aecmInst = aecm;
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
|
||||
sizeof(int16_t));
|
||||
if (!aecm->farFrameBuf)
|
||||
{
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
|
||||
@ -223,7 +229,8 @@ AecmCore* WebRtcAecm_CreateCore() {
|
||||
if (!aecm->nearNoisyFrameBuf)
|
||||
{
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
|
||||
@ -231,7 +238,8 @@ AecmCore* WebRtcAecm_CreateCore() {
|
||||
if (!aecm->nearCleanFrameBuf)
|
||||
{
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
|
||||
@ -239,20 +247,23 @@ AecmCore* WebRtcAecm_CreateCore() {
|
||||
if (!aecm->outFrameBuf)
|
||||
{
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
|
||||
MAX_DELAY);
|
||||
if (aecm->delay_estimator_farend == NULL) {
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
aecm->delay_estimator =
|
||||
WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
|
||||
if (aecm->delay_estimator == NULL) {
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
// TODO(bjornv): Explicitly disable robust delay validation until no
|
||||
// performance regression has been established. Then remove the line.
|
||||
@ -261,7 +272,8 @@ AecmCore* WebRtcAecm_CreateCore() {
|
||||
aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
|
||||
if (aecm->real_fft == NULL) {
|
||||
WebRtcAecm_FreeCore(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Init some aecm pointers. 16 and 32 byte alignment is only necessary
|
||||
@ -277,7 +289,7 @@ AecmCore* WebRtcAecm_CreateCore() {
|
||||
aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
|
||||
aecm->channelAdapt32_buf + 31) & ~ 31);
|
||||
|
||||
return aecm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
|
||||
@ -534,9 +546,10 @@ int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAecm_FreeCore(AecmCore* aecm) {
|
||||
if (aecm == NULL) {
|
||||
return;
|
||||
int WebRtcAecm_FreeCore(AecmCore* aecm) {
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_FreeBuffer(aecm->farFrameBuf);
|
||||
@ -549,6 +562,8 @@ void WebRtcAecm_FreeCore(AecmCore* aecm) {
|
||||
WebRtcSpl_FreeRealFFT(aecm->real_fft);
|
||||
|
||||
free(aecm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAecm_ProcessFrame(AecmCore* aecm,
|
||||
|
@ -134,18 +134,27 @@ typedef struct {
|
||||
} AecmCore;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CreateCore()
|
||||
// WebRtcAecm_CreateCore(...)
|
||||
//
|
||||
// Allocates the memory needed by the AECM. The memory needs to be
|
||||
// initialized separately using the WebRtcAecm_InitCore() function.
|
||||
// Returns a pointer to the instance and a nullptr at failure.
|
||||
AecmCore* WebRtcAecm_CreateCore();
|
||||
//
|
||||
// Input:
|
||||
// - aecm : Instance that should be created
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Created instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
//
|
||||
int WebRtcAecm_CreateCore(AecmCore** aecm);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_InitCore(...)
|
||||
//
|
||||
// This function initializes the AECM instant created with
|
||||
// WebRtcAecm_CreateCore()
|
||||
// WebRtcAecm_CreateCore(...)
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - samplingFreq : Sampling Frequency
|
||||
@ -165,7 +174,11 @@ int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq);
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
//
|
||||
void WebRtcAecm_FreeCore(AecmCore* aecm);
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
// 11001-11016: Error
|
||||
//
|
||||
int WebRtcAecm_FreeCore(AecmCore* aecm);
|
||||
|
||||
int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag);
|
||||
|
||||
|
@ -68,6 +68,8 @@ typedef struct
|
||||
// Structures
|
||||
RingBuffer *farendBuf;
|
||||
|
||||
int lastError;
|
||||
|
||||
AecmCore* aecmCore;
|
||||
} AecMobile;
|
||||
|
||||
@ -78,15 +80,28 @@ static int WebRtcAecm_EstBufDelay(AecMobile* aecmInst, short msInSndCardBuf);
|
||||
// Stuffs the farend buffer if the estimated delay is too large
|
||||
static int WebRtcAecm_DelayComp(AecMobile* aecmInst);
|
||||
|
||||
void* WebRtcAecm_Create() {
|
||||
AecMobile* aecm = malloc(sizeof(AecMobile));
|
||||
int32_t WebRtcAecm_Create(void **aecmInst)
|
||||
{
|
||||
AecMobile* aecm;
|
||||
if (aecmInst == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm = malloc(sizeof(AecMobile));
|
||||
*aecmInst = aecm;
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcSpl_Init();
|
||||
|
||||
aecm->aecmCore = WebRtcAecm_CreateCore();
|
||||
if (!aecm->aecmCore) {
|
||||
if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
|
||||
@ -94,10 +109,12 @@ void* WebRtcAecm_Create() {
|
||||
if (!aecm->farendBuf)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
return NULL;
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->initFlag = 0;
|
||||
aecm->lastError = 0;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
|
||||
@ -110,14 +127,16 @@ void* WebRtcAecm_Create() {
|
||||
aecm->preCompFile = fopen("preComp.pcm", "wb");
|
||||
aecm->postCompFile = fopen("postComp.pcm", "wb");
|
||||
#endif // AEC_DEBUG
|
||||
return aecm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAecm_Free(void* aecmInst) {
|
||||
int32_t WebRtcAecm_Free(void *aecmInst)
|
||||
{
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL) {
|
||||
return;
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
@ -134,6 +153,8 @@ void WebRtcAecm_Free(void* aecmInst) {
|
||||
WebRtcAecm_FreeCore(aecm->aecmCore);
|
||||
WebRtc_FreeBuffer(aecm->farendBuf);
|
||||
free(aecm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
|
||||
@ -148,14 +169,16 @@ int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
|
||||
|
||||
if (sampFreq != 8000 && sampFreq != 16000)
|
||||
{
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->sampFreq = sampFreq;
|
||||
|
||||
// Initialize AECM core
|
||||
if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
|
||||
{
|
||||
return AECM_UNSPECIFIED_ERROR;
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize farend buffer
|
||||
@ -186,65 +209,63 @@ int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
|
||||
|
||||
if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
|
||||
{
|
||||
return AECM_UNSPECIFIED_ERROR;
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns any error that is caused when buffering the
|
||||
// farend signal.
|
||||
int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, const int16_t *farend,
|
||||
size_t nrOfSamples) {
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
return -1;
|
||||
|
||||
if (farend == NULL)
|
||||
return AECM_NULL_POINTER_ERROR;
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
return AECM_UNINITIALIZED_ERROR;
|
||||
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
|
||||
size_t nrOfSamples) {
|
||||
int16_t nrOfSamples)
|
||||
{
|
||||
AecMobile* aecm = aecmInst;
|
||||
int32_t retVal = 0;
|
||||
|
||||
const int32_t err =
|
||||
WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples);
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (farend == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(unknown): Is this really a good idea?
|
||||
if (!aecm->ECstartup)
|
||||
{
|
||||
WebRtcAecm_DelayComp(aecm);
|
||||
}
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
// TODO: Is this really a good idea?
|
||||
if (!aecm->ECstartup)
|
||||
{
|
||||
WebRtcAecm_DelayComp(aecm);
|
||||
}
|
||||
|
||||
WebRtc_WriteBuffer(aecm->farendBuf, farend, (size_t) nrOfSamples);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
|
||||
const int16_t *nearendClean, int16_t *out,
|
||||
size_t nrOfSamples, int16_t msInSndCardBuf)
|
||||
int16_t nrOfSamples, int16_t msInSndCardBuf)
|
||||
{
|
||||
AecMobile* aecm = aecmInst;
|
||||
int32_t retVal = 0;
|
||||
size_t i;
|
||||
short i;
|
||||
short nmbrOfFilledBuffers;
|
||||
size_t nBlocks10ms;
|
||||
size_t nFrames;
|
||||
short nBlocks10ms;
|
||||
short nFrames;
|
||||
#ifdef AEC_DEBUG
|
||||
short msInAECBuf;
|
||||
#endif
|
||||
@ -256,32 +277,38 @@ int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
|
||||
|
||||
if (nearendNoisy == NULL)
|
||||
{
|
||||
return AECM_NULL_POINTER_ERROR;
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out == NULL)
|
||||
{
|
||||
return AECM_NULL_POINTER_ERROR;
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
return AECM_UNINITIALIZED_ERROR;
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
{
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msInSndCardBuf < 0)
|
||||
{
|
||||
msInSndCardBuf = 0;
|
||||
retVal = AECM_BAD_PARAMETER_WARNING;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
} else if (msInSndCardBuf > 500)
|
||||
{
|
||||
msInSndCardBuf = 500;
|
||||
retVal = AECM_BAD_PARAMETER_WARNING;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
msInSndCardBuf += 10;
|
||||
aecm->msInSndCardBuf = msInSndCardBuf;
|
||||
@ -444,18 +471,21 @@ int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
return AECM_UNINITIALIZED_ERROR;
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
|
||||
{
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->aecmCore->cngMode = config.cngMode;
|
||||
|
||||
if (config.echoMode < 0 || config.echoMode > 4)
|
||||
{
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->echoMode = config.echoMode;
|
||||
|
||||
@ -512,6 +542,33 @@ int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
|
||||
{
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->cngMode = aecm->aecmCore->cngMode;
|
||||
config->echoMode = aecm->echoMode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes)
|
||||
@ -523,16 +580,19 @@ int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
return -1;
|
||||
}
|
||||
if (echo_path == NULL) {
|
||||
return AECM_NULL_POINTER_ERROR;
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
// Input channel size does not match the size of AECM
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
return AECM_UNINITIALIZED_ERROR;
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
|
||||
@ -551,16 +611,19 @@ int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
return -1;
|
||||
}
|
||||
if (echo_path == NULL) {
|
||||
return AECM_NULL_POINTER_ERROR;
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
// Input channel size does not match the size of AECM
|
||||
return AECM_BAD_PARAMETER_ERROR;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
return AECM_UNINITIALIZED_ERROR;
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
|
||||
@ -572,6 +635,17 @@ size_t WebRtcAecm_echo_path_size_bytes()
|
||||
return (PART_LEN1 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
int32_t WebRtcAecm_get_error_code(void *aecmInst)
|
||||
{
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aecm->lastError;
|
||||
}
|
||||
|
||||
static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
|
||||
short delayNew, nSampSndCard;
|
||||
|
@ -42,31 +42,45 @@ extern "C" {
|
||||
/*
|
||||
* Allocates the memory needed by the AECM. The memory needs to be
|
||||
* initialized separately using the WebRtcAecm_Init() function.
|
||||
* Returns a pointer to the instance and a nullptr at failure.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void** aecmInst Pointer to the AECM instance to be
|
||||
* created and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
void* WebRtcAecm_Create();
|
||||
int32_t WebRtcAecm_Create(void **aecmInst);
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAecm_Create()
|
||||
*
|
||||
* Inputs Description
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
void WebRtcAecm_Free(void* aecmInst);
|
||||
int32_t WebRtcAecm_Free(void *aecmInst);
|
||||
|
||||
/*
|
||||
* Initializes an AECM instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* int32_t sampFreq Sampling frequency of data
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq);
|
||||
|
||||
@ -83,30 +97,11 @@ int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq);
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_BufferFarend(void* aecmInst,
|
||||
const int16_t* farend,
|
||||
size_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Reports any errors that would arise when buffering a farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* int16_t* farend In buffer containing one frame of
|
||||
* farend signal
|
||||
* int16_t nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
*/
|
||||
int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
|
||||
const int16_t* farend,
|
||||
size_t nrOfSamples);
|
||||
int16_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the AECM on an 80 or 160 sample blocks of data.
|
||||
@ -131,13 +126,13 @@ int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
|
||||
* -------------------------------------------------------------------
|
||||
* int16_t* out Out buffer, one frame of processed nearend
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_Process(void* aecmInst,
|
||||
const int16_t* nearendNoisy,
|
||||
const int16_t* nearendClean,
|
||||
int16_t* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t nrOfSamples,
|
||||
int16_t msInSndCardBuf);
|
||||
|
||||
/*
|
||||
@ -152,10 +147,26 @@ int32_t WebRtcAecm_Process(void* aecmInst,
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecmConfig* config Pointer to the config instance that
|
||||
* all properties will be written to
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set the echo path on-the-fly.
|
||||
*
|
||||
@ -168,7 +179,7 @@ int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config);
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
@ -187,7 +198,7 @@ int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* 1200-12004,12100: error/warning
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
@ -202,6 +213,18 @@ int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
*/
|
||||
size_t WebRtcAecm_echo_path_size_bytes();
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 11000-11100: error code
|
||||
*/
|
||||
int32_t WebRtcAecm_get_error_code(void *aecmInst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -67,9 +67,8 @@ EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
|
||||
was_stream_drift_set_(false),
|
||||
stream_has_echo_(false),
|
||||
delay_logging_enabled_(false),
|
||||
extended_filter_enabled_(false),
|
||||
delay_agnostic_enabled_(false) {
|
||||
}
|
||||
delay_correction_enabled_(true), // default to long AEC tail in Mozilla
|
||||
reported_delay_enabled_(true) {}
|
||||
|
||||
EchoCancellationImpl::~EchoCancellationImpl() {}
|
||||
|
||||
@ -91,7 +90,7 @@ int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
|
||||
err = WebRtcAec_BufferFarend(
|
||||
my_handle,
|
||||
audio->split_bands_const_f(j)[kBand0To8kHz],
|
||||
audio->num_frames_per_band());
|
||||
static_cast<int16_t>(audio->num_frames_per_band()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return GetHandleError(my_handle); // TODO(ajm): warning possible?
|
||||
@ -133,7 +132,7 @@ int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
audio->split_bands_const_f(i),
|
||||
audio->num_bands(),
|
||||
audio->split_bands_f(i),
|
||||
audio->num_frames_per_band(),
|
||||
static_cast<int16_t>(audio->num_frames_per_band()),
|
||||
apm_->stream_delay_ms(),
|
||||
stream_drift_samples_);
|
||||
|
||||
@ -280,14 +279,6 @@ bool EchoCancellationImpl::is_delay_logging_enabled() const {
|
||||
return delay_logging_enabled_;
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::is_delay_agnostic_enabled() const {
|
||||
return delay_agnostic_enabled_;
|
||||
}
|
||||
|
||||
bool EchoCancellationImpl::is_extended_filter_enabled() const {
|
||||
return extended_filter_enabled_;
|
||||
}
|
||||
|
||||
// TODO(bjornv): How should we handle the multi-channel case?
|
||||
int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
|
||||
float fraction_poor_delays = 0;
|
||||
@ -336,13 +327,22 @@ int EchoCancellationImpl::Initialize() {
|
||||
}
|
||||
|
||||
void EchoCancellationImpl::SetExtraOptions(const Config& config) {
|
||||
extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled;
|
||||
delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled;
|
||||
#if 0
|
||||
delay_correction_enabled_ = config.Get<DelayCorrection>().enabled;
|
||||
#endif
|
||||
reported_delay_enabled_ = config.Get<ReportedDelay>().enabled;
|
||||
Configure();
|
||||
}
|
||||
|
||||
void* EchoCancellationImpl::CreateHandle() const {
|
||||
return WebRtcAec_Create();
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcAec_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void EchoCancellationImpl::DestroyHandle(void* handle) const {
|
||||
@ -368,12 +368,10 @@ int EchoCancellationImpl::ConfigureHandle(void* handle) const {
|
||||
config.skewMode = drift_compensation_enabled_;
|
||||
config.delay_logging = delay_logging_enabled_;
|
||||
|
||||
WebRtcAec_enable_extended_filter(
|
||||
WebRtcAec_aec_core(static_cast<Handle*>(handle)),
|
||||
extended_filter_enabled_ ? 1 : 0);
|
||||
WebRtcAec_enable_delay_agnostic(
|
||||
WebRtcAec_aec_core(static_cast<Handle*>(handle)),
|
||||
delay_agnostic_enabled_ ? 1 : 0);
|
||||
WebRtcAec_enable_delay_correction(WebRtcAec_aec_core(
|
||||
static_cast<Handle*>(handle)), delay_correction_enabled_ ? 1 : 0);
|
||||
WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(
|
||||
static_cast<Handle*>(handle)), reported_delay_enabled_ ? 1 : 0);
|
||||
return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
|
||||
}
|
||||
|
||||
@ -384,6 +382,6 @@ int EchoCancellationImpl::num_handles_required() const {
|
||||
|
||||
int EchoCancellationImpl::GetHandleError(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
@ -32,22 +32,19 @@ class EchoCancellationImpl : public EchoCancellation,
|
||||
// EchoCancellation implementation.
|
||||
bool is_enabled() const override;
|
||||
int stream_drift_samples() const override;
|
||||
SuppressionLevel suppression_level() const override;
|
||||
bool is_drift_compensation_enabled() const override;
|
||||
|
||||
// ProcessingComponent implementation.
|
||||
int Initialize() override;
|
||||
void SetExtraOptions(const Config& config) override;
|
||||
|
||||
bool is_delay_agnostic_enabled() const;
|
||||
bool is_extended_filter_enabled() const;
|
||||
|
||||
private:
|
||||
// EchoCancellation implementation.
|
||||
int Enable(bool enable) override;
|
||||
int enable_drift_compensation(bool enable) override;
|
||||
bool is_drift_compensation_enabled() const override;
|
||||
void set_stream_drift_samples(int drift) override;
|
||||
int set_suppression_level(SuppressionLevel level) override;
|
||||
SuppressionLevel suppression_level() const override;
|
||||
int enable_metrics(bool enable) override;
|
||||
bool are_metrics_enabled() const override;
|
||||
bool stream_has_echo() const override;
|
||||
@ -77,8 +74,8 @@ class EchoCancellationImpl : public EchoCancellation,
|
||||
bool was_stream_drift_set_;
|
||||
bool stream_has_echo_;
|
||||
bool delay_logging_enabled_;
|
||||
bool extended_filter_enabled_;
|
||||
bool delay_agnostic_enabled_;
|
||||
bool delay_correction_enabled_;
|
||||
bool reported_delay_enabled_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -40,6 +40,22 @@ int16_t MapSetting(EchoControlMobile::RoutingMode mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioProcessing::Error MapError(int err) {
|
||||
switch (err) {
|
||||
case AECM_UNSUPPORTED_FUNCTION_ERROR:
|
||||
return AudioProcessing::kUnsupportedFunctionError;
|
||||
case AECM_NULL_POINTER_ERROR:
|
||||
return AudioProcessing::kNullPointerError;
|
||||
case AECM_BAD_PARAMETER_ERROR:
|
||||
return AudioProcessing::kBadParameterError;
|
||||
case AECM_BAD_PARAMETER_WARNING:
|
||||
return AudioProcessing::kBadStreamParameterWarning;
|
||||
default:
|
||||
// AECM_UNSPECIFIED_ERROR
|
||||
// AECM_UNINITIALIZED_ERROR
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
size_t EchoControlMobile::echo_path_size_bytes() {
|
||||
@ -80,7 +96,7 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
|
||||
err = WebRtcAecm_BufferFarend(
|
||||
my_handle,
|
||||
audio->split_bands_const(j)[kBand0To8kHz],
|
||||
audio->num_frames_per_band());
|
||||
static_cast<int16_t>(audio->num_frames_per_band()));
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
return GetHandleError(my_handle); // TODO(ajm): warning possible?
|
||||
@ -125,7 +141,7 @@ int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
|
||||
noisy,
|
||||
clean,
|
||||
audio->split_bands(i)[kBand0To8kHz],
|
||||
audio->num_frames_per_band(),
|
||||
static_cast<int16_t>(audio->num_frames_per_band()),
|
||||
apm_->stream_delay_ms());
|
||||
|
||||
if (err != apm_->kNoError) {
|
||||
@ -234,7 +250,14 @@ int EchoControlMobileImpl::Initialize() {
|
||||
}
|
||||
|
||||
void* EchoControlMobileImpl::CreateHandle() const {
|
||||
return WebRtcAecm_Create();
|
||||
Handle* handle = NULL;
|
||||
if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
|
||||
handle = NULL;
|
||||
} else {
|
||||
assert(handle != NULL);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void EchoControlMobileImpl::DestroyHandle(void* handle) const {
|
||||
@ -273,6 +296,6 @@ int EchoControlMobileImpl::num_handles_required() const {
|
||||
|
||||
int EchoControlMobileImpl::GetHandleError(void* handle) const {
|
||||
assert(handle != NULL);
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
@ -37,18 +37,6 @@ class LevelEstimator;
|
||||
class NoiseSuppression;
|
||||
class VoiceDetection;
|
||||
|
||||
struct ExtendedFilter {
|
||||
ExtendedFilter() : enabled(false) {}
|
||||
explicit ExtendedFilter(bool enabled) : enabled(enabled) {}
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct DelayAgnostic {
|
||||
DelayAgnostic() : enabled(false) {}
|
||||
explicit DelayAgnostic(bool enabled) : enabled(enabled) {}
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
// Use to enable the delay correction feature. This now engages an extended
|
||||
// filter mode in the AEC, along with robustness measures around the reported
|
||||
// system delays. It comes with a significant increase in AEC complexity, but is
|
||||
|
@ -849,10 +849,6 @@ Channel::Channel(int32_t channelId,
|
||||
|
||||
Config audioproc_config;
|
||||
audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
|
||||
audioproc_config.Set<ExtendedFilter>(
|
||||
new ExtendedFilter(config.Get<ExtendedFilter>().enabled));
|
||||
audioproc_config.Set<DelayAgnostic>(
|
||||
new DelayAgnostic(config.Get<DelayAgnostic>().enabled));
|
||||
rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
|
||||
}
|
||||
|
||||
|
@ -46,11 +46,10 @@ ChannelOwner::ChannelRef::ChannelRef(class Channel* channel)
|
||||
: channel(channel), ref_count(1) {}
|
||||
|
||||
ChannelManager::ChannelManager(uint32_t instance_id, const Config& config)
|
||||
: config_(config),
|
||||
instance_id_(instance_id),
|
||||
: instance_id_(instance_id),
|
||||
last_channel_id_(-1),
|
||||
lock_(CriticalSectionWrapper::CreateCriticalSection())
|
||||
{}
|
||||
lock_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
config_(config) {}
|
||||
|
||||
ChannelOwner ChannelManager::CreateChannel() {
|
||||
return CreateChannelInternal(config_);
|
||||
|
@ -109,7 +109,6 @@ class ChannelManager {
|
||||
void DestroyAllChannels();
|
||||
|
||||
size_t NumOfChannels() const;
|
||||
const Config& config_;
|
||||
|
||||
private:
|
||||
// Create a channel given a configuration, |config|.
|
||||
@ -122,6 +121,8 @@ class ChannelManager {
|
||||
rtc::scoped_ptr<CriticalSectionWrapper> lock_;
|
||||
std::vector<ChannelOwner> channels_;
|
||||
|
||||
const Config& config_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ChannelManager);
|
||||
};
|
||||
} // namespace voe
|
||||
|
@ -424,7 +424,7 @@ int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
|
||||
}
|
||||
|
||||
if (!audioproc) {
|
||||
audioproc = AudioProcessing::Create(_shared->channel_manager().config_);
|
||||
audioproc = AudioProcessing::Create();
|
||||
if (!audioproc) {
|
||||
LOG(LS_ERROR) << "Failed to create AudioProcessing.";
|
||||
_shared->SetLastError(VE_NO_MEMORY);
|
||||
|
@ -439,12 +439,6 @@ pref("media.getusermedia.noise_enabled", false);
|
||||
pref("media.getusermedia.aec_enabled", true);
|
||||
pref("media.getusermedia.noise_enabled", true);
|
||||
#endif
|
||||
pref("media.getusermedia.aec_extended_filter", true);
|
||||
#if defined(ANDROID)
|
||||
pref("media.getusermedia.aec_delay_agnostic", true);
|
||||
#else
|
||||
pref("media.getusermedia.aec_delay_agnostic", false);
|
||||
#endif
|
||||
pref("media.getusermedia.noise", 1);
|
||||
pref("media.getusermedia.agc_enabled", false);
|
||||
pref("media.getusermedia.agc", 1);
|
||||
|
Loading…
Reference in New Issue
Block a user