Skip to main content

Echo Cancellation

If your app plays audio and captures the microphone at the same time — a voice assistant, a call, any kind of barge-in — the microphone hears the speaker, and the far end hears itself. Acoustic echo cancellation removes it.

There are two ways to get it, and they can be combined:

  • The device's own canceller, configured on the Realtime engine. Costs no CPU, but the implementation belongs to the platform. On iOS this is one switch; on Android it is several settings that have to agree, and results vary by device.
  • A software AEC node in your graph, from the Speex or Superpowered extensions. Behaves identically everywhere, at the cost of CPU.

This page covers the device canceller on each platform.


iOS​

One key:

{
"type": "Switchboard.Realtime",
"config": {
"microphoneEnabled": true,
"voiceProcessingEnabled": true,
"graph": { }
}
}

This enables Apple's voice processing IO, which applies echo cancellation and automatic gain control to the microphone input. No audio-session setup or permissions beyond microphone access are needed.

It does change the output path, so note the constraints:

  • Only mono audio output is supported.
  • Various filters are applied to the output signal.
  • The user cannot set the volume to zero.

Android​

Android has no single switch. Two keys do the work, and the device canceller only engages when both are set:

{
"type": "Switchboard.Realtime",
"config": {
"microphoneEnabled": true,
"inputPreset": "VOICE_COMMUNICATION",
"audioManagerMode": "MODE_IN_COMMUNICATION",
"speakerphoneOn": true,
"graph": { }
}
}
KeyWhy it is needed
inputPreset: "VOICE_COMMUNICATION"Asks the capture path for echo cancellation, noise suppression and close-talk gain control
audioManagerMode: "MODE_IN_COMMUNICATION"Puts the process in a voice session, which is what arms the canceller on most devices. Some devices engage it from the input preset alone; others do not
speakerphoneOn: trueOptional. Routes to the loudspeaker rather than the earpiece — there is little echo to cancel on the earpiece, so it matters when testing

The common failure is setting only one of them. MODE_NORMAL leaves the canceller unarmed no matter how the input is configured, and inputPreset defaults to GENERIC, which does not request echo cancellation — so audioManagerMode on its own is not enough either.

outputUsage is not required. Setting it to "USAGE_VOICE_COMMUNICATION" puts playback on in-call volume and voice routing, which is usually what you want in a voice session, but it is a routing and volume choice rather than part of enabling the canceller.

Requirements​

Add the permission to your application's AndroidManifest.xml:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Without it, audioManagerMode silently does nothing. The SDK does not declare it for you.

These keys also need an application context. Switchboard.initialize(context, ...) provides one; if you initialize from C++ with Switchboard::initialize(...) — a React Native C++ TurboModule, a Flutter FFI plugin, or a plain NDK app — no Kotlin runs and the SDK never receives one, so hand it over once:

Switchboard.setApplicationContext(context.applicationContext)

Without a context both keys are ignored and a warning is logged; the engine still starts.

This is best-effort​

Android's specification says a device should provide echo cancellation for VOICE_COMMUNICATION capture — not must. The implementation is the manufacturer's, so results vary by device and OS version even with identical configuration. Known cases:

  • Some devices need MODE_IN_COMMUNICATION on top of the input preset; others engage the canceller from the preset alone.
  • VOICE_COMMUNICATION may only work in mono on some devices, and can prevent a low-latency stream in stereo.
  • A handful of devices return silence for VOICE_COMMUNICATION capture entirely, and need a different preset.

If you need echo cancellation that behaves identically everywhere, use the software AEC node instead of, or in addition to, the device canceller.


Reading​

Android references for the accepted values: