When your app plays audio through the device speaker while the recognizer is listening (for example, reading a prompt aloud or providing audio feedback), the microphone picks up both the user’s voice and the playback audio. This can significantly degrade recognition accuracy because the recognizer processes everything the microphone captures.

Acoustic Echo Cancellation (AEC) filters out the device’s own audio output from the microphone signal, allowing the recognizer to focus on the user’s speech. Note that AEC is not needed when the user is wearing a headset, since the audio output is acoustically decoupled from the microphone.

AEC is best suited for scenarios where recognition accuracy is more important than pronunciation scoring, such as voice command interfaces or interactive dialog systems that need to listen for a response while audio is still playing.

iOS

On iOS, AEC uses the platform’s built-in Voice Processing I/O audio unit. Enable it by calling setAECEnabled: on the recognizer instance:

[[KIOSRecognizer sharedInstance] performEchoCancellation:YES];

Once enabled, echo cancellation remains active for all subsequent listening sessions until explicitly disabled.

Android

On Android, enabling echo cancellation requires both the SDK setting and configuring the AudioManager to route audio through the speakerphone in communication mode. This ensures the platform’s hardware AEC can properly reference the outgoing audio signal.

KASRRecognizer recognizer = KASRRecognizer.sharedInstance();
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

// Save the current audio mode so we can restore it when disabling AEC
int originalAudioMode = audioManager.getMode();

// Switch to the communication audio path and enable the speakerphone
// so the platform's hardware AEC can reference the outgoing audio
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
// MODE_IN_COMMUNICATION routes audio through the earpiece by default.
// Switch to the loudspeaker if desired.
audioManager.setSpeakerphoneOn(true);

// Enable AEC on the recognizer
recognizer.performEchoCancellation(true);

To disable AEC and restore normal audio routing:

recognizer.performEchoCancellation(false);
audioManager.setSpeakerphoneOn(false);
audioManager.setMode(originalAudioMode);

When AEC is enabled, audio playback must use STREAM_VOICE_CALL so that the audio goes through the communication audio path. This provides the AEC with the correct reference signal. Note that the communication audio path attenuates the signal compared to the music stream, so you may need to boost the volume to compensate. When AEC is off, use STREAM_MUSIC as usual.

mMediaPlayer = new MediaPlayer();
// Use STREAM_VOICE_CALL when AEC is on so playback goes through the
// communication audio path, needed for proper AEC reference signal
if (aecEnabled) {
    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
    // boost the audio output to compensate for communication path attenuation
    int maxVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
    mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, maxVol, 0);
} else {
    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
android.content.res.AssetFileDescriptor afd = getResources().openRawResourceFd(resId);
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mMediaPlayer.prepare();
mMediaPlayer.start();

AEC availability depends on the device hardware and Android version. On devices that do not support hardware AEC, enabling it may have no effect.