remove echo cancellation from audio code

This commit is contained in:
Stephen Birarda 2013-06-26 16:22:54 -07:00
parent 59a9fc8eff
commit 1c0b256f92
3 changed files with 3 additions and 179 deletions

View file

@ -959,10 +959,6 @@ void Application::editPreferences() {
headCameraPitchYawScale->setValue(_headCameraPitchYawScale);
form->addRow("Head Camera Pitch/Yaw Scale:", headCameraPitchYawScale);
QCheckBox* audioEchoCancellation = new QCheckBox();
audioEchoCancellation->setChecked(_audio.isCancellingEcho());
form->addRow("Audio Echo Cancellation", audioEchoCancellation);
QDoubleSpinBox* leanScale = new QDoubleSpinBox();
leanScale->setValue(_myAvatar.getLeanScale());
form->addRow("Lean Scale:", leanScale);
@ -984,7 +980,6 @@ void Application::editPreferences() {
QUrl url(avatarURL->text());
_myAvatar.getVoxels()->setVoxelURL(url);
sendAvatarVoxelURLMessage(url);
_audio.setIsCancellingEcho( audioEchoCancellation->isChecked() );
_headCameraPitchYawScale = headCameraPitchYawScale->value();
_myAvatar.setLeanScale(leanScale->value());
_audioJitterBufferSamples = audioJitterBufferSamples->value();
@ -2794,9 +2789,6 @@ void Application::loadSettings(QSettings* settings) {
_viewFrustumOffsetDistance = loadSetting(settings, "viewFrustumOffsetDistance", 0.0f);
_viewFrustumOffsetUp = loadSetting(settings, "viewFrustumOffsetUp" , 0.0f);
settings->endGroup();
settings->beginGroup("Audio Echo Cancellation");
_audio.setIsCancellingEcho(settings->value("enabled", false).toBool());
settings->endGroup();
scanMenuBar(&Application::loadAction, settings);
getAvatar()->loadData(settings);
@ -2817,9 +2809,6 @@ void Application::saveSettings(QSettings* settings) {
settings->setValue("viewFrustumOffsetDistance", _viewFrustumOffsetDistance);
settings->setValue("viewFrustumOffsetUp", _viewFrustumOffsetUp);
settings->endGroup();
settings->beginGroup("Audio");
settings->setValue("echoCancellation", _audio.isCancellingEcho());
settings->endGroup();
scanMenuBar(&Application::saveAction, settings);
getAvatar()->saveData(settings);

View file

@ -56,18 +56,7 @@ static const int AEC_BUFFERED_FRAMES = 6;
static const int AEC_BUFFERED_SAMPLES_PER_CHANNEL = BUFFER_LENGTH_SAMPLES_PER_CHANNEL * AEC_BUFFERED_FRAMES;
static const int AEC_BUFFERED_SAMPLES = AEC_BUFFERED_SAMPLES_PER_CHANNEL * AEC_N_CHANNELS_PLAY;
static const int AEC_TMP_BUFFER_SIZE = (AEC_N_CHANNELS_MIC + // Temporary space for processing a
AEC_N_CHANNELS_PLAY) * BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // single frame
// Speex preprocessor and echo canceller configuration
static const int AEC_NOISE_REDUCTION = -80; // Noise reduction (important)
static const int AEC_RESIDUAL_ECHO_REDUCTION = -60; // Residual echo reduction
static const int AEC_RESIDUAL_ECHO_REDUCTION_ACTIVE = -45; // ~on active side
static const bool AEC_USE_AGC = true; // Automatic gain control
static const int AEC_AGC_MAX_GAIN = -30; // Gain in db
static const int AEC_AGC_TARGET_LEVEL = 9000; // Target reference level
static const int AEC_AGC_MAX_INC = 6; // Max increase in db/s
static const int AEC_AGC_MAX_DEC = 200; // Max decrease in db/s
static const bool AEC_USE_VAD = false; // Voice activity determination
AEC_N_CHANNELS_PLAY) * BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // single frame
// Ping test configuration
static const float PING_PITCH = 16.f; // Ping wavelength, # samples / radian
@ -86,8 +75,6 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
AgentList* agentList = AgentList::getInstance();
Application* interface = Application::getInstance();
Avatar* interfaceAvatar = interface->getAvatar();
eventuallyCancelEcho(inputLeft);
// Add Procedural effects to input samples
addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
@ -104,13 +91,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
_lastInputLoudness = loudness;
// add input (@microphone) data to the scope
#ifdef VISUALIZE_ECHO_CANCELLATION
if (! isCancellingEcho()) {
#endif
_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
#ifdef VISUALIZE_ECHO_CANCELLATION
}
#endif
Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
@ -276,19 +257,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
}
eventuallySendRecvPing(inputLeft, outputLeft, outputRight);
eventuallyRecordEcho(outputLeft, outputRight);
// add output (@speakers) data just written to the scope
#ifdef VISUALIZE_ECHO_CANCELLATION
if (! isCancellingEcho()) {
_scope->setColor(2, 0x00ffff);
#endif
_scope->addSamples(1, outputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
_scope->addSamples(2, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
#ifdef VISUALIZE_ECHO_CANCELLATION
}
#endif
gettimeofday(&_lastCallbackTime, NULL);
}
@ -342,11 +315,6 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
_totalPacketsReceived(0),
_firstPacketReceivedTime(),
_packetsReceivedThisPlayback(0),
_isCancellingEcho(false),
_echoDelay(0),
_echoSamplesLeft(0l),
_speexEchoState(NULL),
_speexPreprocessState(NULL),
_isSendingEchoPing(false),
_pingAnalysisPending(false),
_pingFramesToRecord(0),
@ -393,39 +361,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
}
_echoSamplesLeft = new int16_t[AEC_BUFFERED_SAMPLES + AEC_TMP_BUFFER_SIZE];
if (! _echoSamplesLeft) {
return;
}
memset(_echoSamplesLeft, 0, AEC_BUFFERED_SAMPLES * sizeof(int16_t));
_echoSamplesRight = _echoSamplesLeft + AEC_BUFFERED_SAMPLES_PER_CHANNEL;
_speexTmpBuf = _echoSamplesRight + AEC_BUFFERED_SAMPLES_PER_CHANNEL;
_speexPreprocessState = speex_preprocess_state_init(BUFFER_LENGTH_SAMPLES_PER_CHANNEL, SAMPLE_RATE);
if (_speexPreprocessState) {
_speexEchoState = speex_echo_state_init_mc(BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
AEC_FILTER_LENGTH, AEC_N_CHANNELS_MIC, AEC_N_CHANNELS_PLAY);
if (_speexEchoState) {
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_ECHO_STATE, _speexEchoState);
int tmp;
speex_echo_ctl(_speexEchoState, SPEEX_ECHO_SET_SAMPLING_RATE, &(tmp = SAMPLE_RATE));
tmp = AEC_NOISE_REDUCTION;
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &tmp);
tmp = AEC_RESIDUAL_ECHO_REDUCTION;
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &tmp);
tmp = AEC_RESIDUAL_ECHO_REDUCTION_ACTIVE;
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE, &tmp);
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_AGC, &(tmp = int(AEC_USE_AGC)));
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &(tmp = AEC_AGC_MAX_GAIN));
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_AGC_TARGET, &(tmp = AEC_AGC_TARGET_LEVEL));
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &(tmp = AEC_AGC_MAX_INC));
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &(tmp = AEC_AGC_MAX_DEC));
speex_preprocess_ctl(_speexPreprocessState, SPEEX_PREPROCESS_SET_VAD, &(tmp = int(AEC_USE_VAD)));
} else {
speex_preprocess_state_destroy(_speexPreprocessState);
_speexPreprocessState = NULL;
}
}
// start the stream now that sources are good to go
outputPortAudioError(Pa_StartStream(_stream));
@ -446,10 +383,6 @@ Audio::~Audio() {
outputPortAudioError(Pa_CloseStream(_stream));
outputPortAudioError(Pa_Terminate());
}
if (_speexEchoState) {
speex_preprocess_state_destroy(_speexPreprocessState);
speex_echo_state_destroy(_speexEchoState);
}
delete[] _echoSamplesLeft;
}
@ -639,83 +572,6 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) {
}
}
// -----------------------------
// Speex-based echo cancellation
// -----------------------------
bool Audio::isCancellingEcho() const {
return _isCancellingEcho && ! (_pingFramesToRecord != 0 || _pingAnalysisPending || ! _speexPreprocessState);
}
void Audio::setIsCancellingEcho(bool enable) {
if (enable && _speexPreprocessState) {
speex_echo_state_reset(_speexEchoState);
_echoWritePos = 0;
memset(_echoSamplesLeft, 0, AEC_BUFFERED_SAMPLES * sizeof(int16_t));
}
_isCancellingEcho = enable;
}
inline void Audio::eventuallyCancelEcho(int16_t* inputLeft) {
if (! isCancellingEcho()) {
return;
}
// Construct an artificial frame from the captured playback
// that contains the appropriately delayed output to cancel
unsigned n = BUFFER_LENGTH_SAMPLES_PER_CHANNEL, n2 = 0;
unsigned readPos = (_echoWritePos + AEC_BUFFERED_SAMPLES_PER_CHANNEL - _echoDelay) % AEC_BUFFERED_SAMPLES_PER_CHANNEL;
unsigned readEnd = readPos + n;
if (readEnd >= AEC_BUFFERED_SAMPLES_PER_CHANNEL) {
n2 = (readEnd -= AEC_BUFFERED_SAMPLES_PER_CHANNEL);
n -= n2;
}
// Use two subsequent buffers for the two stereo channels
int16_t* playBufferLeft = _speexTmpBuf + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
memcpy(playBufferLeft, _echoSamplesLeft + readPos, n * sizeof(int16_t));
memcpy(playBufferLeft + n, _echoSamplesLeft, n2 * sizeof(int16_t));
int16_t* playBufferRight = playBufferLeft + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
memcpy(playBufferRight, _echoSamplesRight + readPos, n * sizeof(int16_t));
memcpy(playBufferRight + n, _echoSamplesLeft, n2 * sizeof(int16_t));
#ifdef VISUALIZE_ECHO_CANCELLATION
// Visualize the input
_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
_scope->addSamples(1, playBufferLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
#endif
// Have Speex perform echo cancellation
speex_echo_cancellation(_speexEchoState, inputLeft, playBufferLeft, _speexTmpBuf);
memcpy(inputLeft, _speexTmpBuf, BUFFER_LENGTH_BYTES_PER_CHANNEL);
speex_preprocess_run(_speexPreprocessState, inputLeft);
#ifdef VISUALIZE_ECHO_CANCELLATION
// Visualize the result
_scope->setColor(2, 0x00ff00);
_scope->addSamples(2, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
#endif
}
inline void Audio::eventuallyRecordEcho(int16_t* outputLeft, int16_t* outputRight) {
if (! isCancellingEcho()) {
return;
}
// Copy playback data to circular buffers
unsigned n = BUFFER_LENGTH_SAMPLES_PER_CHANNEL, n2 = 0;
unsigned writeEnd = _echoWritePos + n;
if (writeEnd >= AEC_BUFFERED_SAMPLES_PER_CHANNEL) {
n2 = (writeEnd -= AEC_BUFFERED_SAMPLES_PER_CHANNEL);
n -= n2;
}
memcpy(_echoSamplesLeft + _echoWritePos, outputLeft, n * sizeof(int16_t));
memcpy(_echoSamplesLeft, outputLeft + n, n2 * sizeof(int16_t));
memcpy(_echoSamplesRight + _echoWritePos, outputRight, n * sizeof(int16_t));
memcpy(_echoSamplesRight, outputRight + n, n2 * sizeof(int16_t));
_echoWritePos = writeEnd;
}
// -----------------------------------------------------------
// Accoustic ping (audio system round trip time determination)
// -----------------------------------------------------------
@ -870,7 +726,6 @@ bool Audio::eventuallyAnalyzePing() {
}
_scope->inputPaused = true;
analyzePing();
setIsCancellingEcho(_isCancellingEcho);
_pingAnalysisPending = false;
return true;
}

View file

@ -47,11 +47,6 @@ public:
int getJitterBufferSamples() { return _jitterBufferSamples; };
void lowPassFilter(int16_t* inputBuffer);
void startEchoTest();
void renderEchoCompare();
void setIsCancellingEcho(bool enabled);
bool isCancellingEcho() const;
void ping();
@ -79,16 +74,8 @@ private:
int _totalPacketsReceived;
timeval _firstPacketReceivedTime;
int _packetsReceivedThisPlayback;
// Echo cancellation
volatile bool _isCancellingEcho;
unsigned _echoWritePos;
unsigned _echoDelay;
int16_t* _echoSamplesLeft;
int16_t* _echoSamplesRight;
int16_t* _speexTmpBuf;
SpeexEchoState* _speexEchoState;
SpeexPreprocessState* _speexPreprocessState;
// Ping analysis
int16_t* _echoSamplesLeft;
volatile bool _isSendingEchoPing;
volatile bool _pingAnalysisPending;
int _pingFramesToRecord;
@ -102,13 +89,6 @@ private:
// Audio callback in class context.
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);
// When echo cancellation is enabled, subtract recorded echo from the input.
// Called from 'performIO' before the input has been processed.
inline void eventuallyCancelEcho(int16_t* inputLeft);
// When EC is enabled, record output samples.
// Called from 'performIO' after the output has been generated.
inline void eventuallyRecordEcho(int16_t* outputLeft, int16_t* outputRight);
// When requested, sends/receives a signal for round trip time determination.
// Called from 'performIO'.
inline void eventuallySendRecvPing(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);