Thanks — this is very helpful detail. I’m responding to your description of SIP bridging, VAD via AudioProcessor, and your TurnState state machine.
Quick assessment: the symptoms (TTS plays once, then caller audio isn’t picked up) usually come from one or more of these issues:
• The AI/TTS playback isn’t releasing the room audio or is muting/unsubscribing the inbound track and not restoring it.
• Turn-state transitions never return to USER_SPEAKING because VAD stops firing while TTS is active or the state machine is blocked during TTS playback.
• SIP/track lifecycle: the SIP bridge or LiveKit participant for the PSTN caller is being replaced or its track is being detached after the first turn.
I can help with concrete checks and fixes. To narrow to the right action, please confirm two quick things:
1. During TTS playback, does your app mute the PSTN participant’s publish track, or does it keep the caller publishing while you play TTS into the room?
2. After TTS finishes, do you see any VAD events (AudioProcessor) at all (even silence detection), or do VAD callbacks stop until you restart the call?
If you want immediate steps to try now, try these in order:
1. Ensure TTS is injected as a separate track/participant (agent) rather than muting the caller’s publish track. Playing TTS from the agent participant keeps the caller track live and VAD able to resume.
2. Add explicit short delay + VAD warmup after TTS finishes before declaring USER_SPEAKING — e.g., 200–500 ms to allow the PSTN audio path to stabilize and VAD to re-detect speech.
3. Make TTS playback non-blocking for the state machine: let the agent enter AI_SPEAKING but keep the audio pipeline accepting inbound frames; only transition to waiting-for-user once VAD signals user activity or silence timeout.
4. Watch participant/track events from LiveKit: confirm the PSTN participant remains connected and its audio track ID does not change after the first turn. If the track is replaced, re-subscribe logic may be needed.
5. Log RTP/SSRC or LiveKit track IDs during the session to confirm continuity across turns—if SSRC/track changes, map the new track to the existing participant and ensure your AudioProcessor is attached to the current stream.
6. If Spitch injects audio with different codec/clocking, ensure resampling or proper media format is used so the PSTN inbound path isn’t interfered with.
If you confirm answers to (1) and (2), I’ll provide specific code-level suggestions for where to change your state transitions and a small snippet showing a non-blocking TTS playback pattern and VAD warmup you can drop into AudioProcessor/TurnState handling.