Problem
During voice calls (Gemini Live API), the model frequently cuts itself off mid-sentence when the iPhone is on speakerphone. The cause is server-side VAD: Gemini hears its own audio leaking back through the mic and treats it as a user interruption, so it stops generating.
Google's own cookbook acknowledges this — Get_started_LiveAPI.py and Get_started_LiveAPI_NativeAudio.py say:
Important: Use headphones. This script uses the system default audio input and output, which often won't include echo cancellation. So to prevent the model from interrupting itself it is important that you use headphones.
We can't ship a product that requires headphones. We need to handle this in the app.
Possible fixes (ranked by practicality for iOS)
- iOS hardware AEC via
.voiceChat mode — set AVAudioSession mode to .voiceChat + .defaultToSpeaker, check isEchoCancelledInputAvailable at runtime. Native platform solution.
- Client-side mic suppression — stop sending audio frames to the WebSocket while playback is active, resume ~200–500ms after playback stops. Simple half-duplex; prevents barge-in.
NO_INTERRUPTION activity handling — set activityHandling: NO_INTERRUPTION in the setup config. Model never gets interrupted but the user can't interrupt either.
- Disable auto-VAD + manual control —
automaticActivityDetection.disabled: true, then send ActivityStart/ActivityEnd manually. We already know when playback is happening, so we can suppress activity signals during echo.
- Tune VAD sensitivity —
startOfSpeechSensitivity: LOW. Reduces false positives but community reports this alone is insufficient for speakerphone.
- Proactive Audio (preview) — new feature where the model distinguishes speech directed at the device vs. background. Could help; unconfirmed and in preview.
Recommended layered strategy
References
Problem
During voice calls (Gemini Live API), the model frequently cuts itself off mid-sentence when the iPhone is on speakerphone. The cause is server-side VAD: Gemini hears its own audio leaking back through the mic and treats it as a user interruption, so it stops generating.
Google's own cookbook acknowledges this —
Get_started_LiveAPI.pyandGet_started_LiveAPI_NativeAudio.pysay:We can't ship a product that requires headphones. We need to handle this in the app.
Possible fixes (ranked by practicality for iOS)
.voiceChatmode — setAVAudioSessionmode to.voiceChat+.defaultToSpeaker, checkisEchoCancelledInputAvailableat runtime. Native platform solution.NO_INTERRUPTIONactivity handling — setactivityHandling: NO_INTERRUPTIONin the setup config. Model never gets interrupted but the user can't interrupt either.automaticActivityDetection.disabled: true, then sendActivityStart/ActivityEndmanually. We already know when playback is happening, so we can suppress activity signals during echo.startOfSpeechSensitivity: LOW. Reduces false positives but community reports this alone is insufficient for speakerphone.Recommended layered strategy
.voiceChatmode (hardware AEC)startOfSpeechSensitivitytoLOWas a baselineVoiceCoreReferences