Bidirectional Stream与Gather搭配时无法触发/respond请求的问题
问题解决:Twilio Stream 与 Gather 共存或全Stream模式下获取ID
问题背景
当前使用的TwiML如下:
<?xml version="1.0" encoding="UTF-8"?> <Response> <Connect> <Stream url="wss://..."/> </Connect> <Gather speechTimeout="auto" speechModel="phone_call" enhanced="true" input="speech" action="/respond"/> </Response>
双向语音Stream可正常运行,但<Gather>无法触发/respond请求;移除<Connect>部分后,<Gather>工作正常。需求分为两个方向:
- 完全基于Stream实现,但无法同时获取StreamId、ConnectionId和CallId;
- 保留
<Gather>的语音检测能力,同时搭配Bidirectional Stream使用。
需求1:全Stream模式下获取三个ID
当WebSocket连接建立后,Twilio会立即发送一条start事件的JSON消息,其中包含所需的三个ID:
streamSid:对应StreamIdconnectionSid:对应ConnectionIdcallSid:对应CallId
示例初始消息结构:
{ "event": "start", "start": { "streamSid": "STXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "connectionSid": "CONXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "callSid": "CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "mediaFormat": { "encoding": "audio/x-mulaw", "sampleRate": 8000, "channels": 1 } } }
在你的WebSocket客户端代码中,监听onmessage事件,解析这条初始消息即可提取三个ID,无需额外调用API。
需求2:Gather与Bidirectional Stream共存
Twilio的TwiML执行逻辑中,<Connect>会独占媒体流处理,导致后续的<Gather>无法监听语音输入,因此不能直接并行使用。提供两种可行方案:
方案一:先Gather再启动Stream
调整TwiML执行顺序,先用<Gather>完成语音检测,触发action后,在/respond的响应TwiML中启动<Connect>流:
- 初始TwiML仅保留
<Gather>:
<?xml version="1.0" encoding="UTF-8"?> <Response> <Gather speechTimeout="auto" speechModel="phone_call" enhanced="true" input="speech" action="/respond"/> </Response>
- 用户停止说话后,Twilio触发
/respond,在该接口的响应TwiML中添加<Connect>:
<?xml version="1.0" encoding="UTF-8"?> <Response> <Connect> <Stream url="wss://..."/> </Connect> <!-- 可添加其他TwiML指令,如Say等 --> </Response>
此方案利用<Gather>的原生语音端点检测能力,完成检测后再启动双向流进行后续交互。
方案二:在Stream中自行实现语音端点检测(VAD)
如果需要同时进行流传输和语音检测,需放弃原生<Gather>,在Stream中自行处理:
- 接收Twilio Stream发送的音频帧(每帧20ms的mulaw编码音频);
- 使用语音活动检测(VAD)库(如WebRTC VAD、Pyannote等)分析音频帧,判断用户是否停止说话;
- 当检测到用户停止说话(模拟
speechTimeout="auto"的逻辑),自行触发后续API调用,并使用之前获取的StreamId等ID进行交互。
内容的提问来源于stack exchange,提问作者JoyDBoy
相关产品推荐
相关产品推荐

