Java SIP网关下,如何通过WebSocket向FreeSWITCH发送DTMF实现IVR功能
Java WebSocket对接FreeSWITCH发送DTMF及构造INFO SIP请求方案
一、避开手动拼接SIP请求的陷阱
手动构造SIP字符串极易忽略协议细节(比如CSeq序号递增、头字段一致性、Content-Length精准计算),推荐直接用成熟SIP库(如JAIN-SIP、Mobicents)生成请求,复用当前通话上下文的关键参数。
二、构造INFO请求发送带外DTMF
带外DTMF通过SIP INFO请求传递,核心是复用Invite请求中的通话上下文参数,具体步骤如下:
1. 提取通话核心参数
从已有的Invite请求(或会话对象)中获取以下关键信息:
- Call-ID:整个通话的唯一标识,必须与原请求完全一致
- From/To:包含URI和Tag,其中To的Tag需从Invite响应中获取,确保与当前通话匹配
- CSeq:序号需比之前的请求(如Invite的CSeq)递增1,方法改为
INFO - Via/Contact:复用原请求的头信息,保证WebSocket传输路径正确
2. JAIN-SIP构造INFO请求示例
import javax.sip.*; import javax.sip.address.Address; import javax.sip.header.*; import java.nio.charset.StandardCharsets; // 假设已初始化SipFactory、SipProvider,且持有InviteRequest对象inviteRequest SipFactory sipFactory = SipFactory.getInstance(); // 提取原请求核心头信息 FromHeader fromHeader = inviteRequest.getFromHeader(); ToHeader toHeader = inviteRequest.getToHeader(); CallIdHeader callIdHeader = inviteRequest.getCallIdHeader(); CSeqHeader originalCSeq = inviteRequest.getCSeqHeader(); ContactHeader contactHeader = inviteRequest.getContactHeader(); ViaHeader viaHeader = inviteRequest.getViaHeader(); // 生成INFO请求的CSeq(序号+1,方法改为INFO) CSeqHeader infoCSeq = sipFactory.createCSeqHeader(originalCSeq.getSeqNumber() + 1, "INFO"); // 创建INFO请求实例 Request infoRequest = sipFactory.createRequest( inviteRequest.getRequestURI(), "INFO", callIdHeader, infoCSeq, fromHeader, toHeader, contactHeader, viaHeader ); // 设置DTMF负载(application/dtmf-relay格式) String dtmfPayload = "Signal=1\r\nDuration=200"; // Signal为按键值,Duration为按键时长(毫秒) infoRequest.setContentTypeHeader(sipFactory.createContentTypeHeader("application", "dtmf-relay")); infoRequest.setContentLengthHeader(sipFactory.createContentLengthHeader(dtmfPayload.length())); infoRequest.setContentDispositionHeader(sipFactory.createContentDispositionHeader("signal")); infoRequest.setContent(dtmfPayload.getBytes(StandardCharsets.UTF_8)); // 通过WebSocket的SIP Provider发送请求 sipProvider.sendRequest(infoRequest);
3. 手动构造INFO请求的正确格式(仅作参考)
若必须手动拼接,严格遵循SIP协议格式,示例如下:
INFO sip:freeswitch@192.168.1.100:5060;transport=ws SIP/2.0 Via: SIP/2.0/WSS 192.168.1.200:8080;branch=z9hG4bK-789012 From: <sip:user@your-domain.com>;tag=abc123 To: <sip:freeswitch@192.168.1.100>;tag=def456 Call-ID: 456xyz@192.168.1.200 CSeq: 2 INFO Contact: <sip:user@192.168.1.200:8080;transport=ws> Content-Type: application/dtmf-relay Content-Length: 22 Signal=1 Duration=200
注意:
- CSeq序号必须大于当前通话的所有请求序号
- From/To的Tag必须与通话上下文完全一致
- Content-Length需精准计算Payload的字节数
- 头字段与内容之间必须保留一个空行
三、更简便的带内DTMF方案
如果FreeSWITCH支持,可直接通过WebRTC媒体流发送带内DTMF(RFC 4733),无需构造SIP请求:
// 假设持有WebRTC PeerConnection实例 peerConnection.sendDTMF("1", 200, 800); // 参数说明:按键字符串、按键时长(毫秒)、音量频率(赫兹)
需在FreeSWITCH的dialplan中配置支持RFC4733:
<action application="set" data="dtmf_type=rfc4733"/>
内容的提问来源于stack exchange,提问作者ringmedev
相关产品推荐
相关产品推荐

