You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 05:20:33