基于JsSIP实现FreePBX监听/密语/插话功能时的DTMF问题
JsSIP对接FreePBX实现监听/密语/插话的问题与解决方案
FreePBX工作流程
根据FreePBX官方文档:
FreePBX功能码前缀可对指定分机执行监听/密语/插话操作。
使用方式:
- 拨打带556前缀的本地分机以进入监听模式
- 监听通话时,可通过以下DTMF输入切换模式:
- DTMF 4:监听模式
- DTMF 5:密语模式
- DTMF 6:插话模式
当前实现
以下是我用JsSIP连接FreePBX并尝试实现密语功能的代码:
let ua; let currentSession; const SIP_DOMAIN = "your-domain-here"; const init = async () => { if (ua && ua.isConnected()) return; JsSIP.debug.disable("JsSIP:*"); const session = await getSession(); if (!session) throw new Error("No active session found. Please log in."); const sipExtension = session.user.sip_config.sip_extension; const sipSecret = session.user.sip_config.sip_secret; if (!sipExtension || !sipSecret) throw new Error("SIP credentials not found in session."); const socket = new JsSIP.WebSocketInterface("wss://domain/ws"); const configuration = { sockets: [socket], uri: `sip:${sipExtension}@${SIP_DOMAIN}`, password: sipSecret, display_name: "Client", // 补充媒体配置,确保DTMF兼容 mediaConstraints: { audio: true, video: false }, rtcpMuxPolicy: 'negotiate' }; ua = new JsSIP.UA(configuration); ua.on("registered", () => { console.log("Connected to PBX"); }); ua.on("newRTCSession", (data) => { // 处理新会话,比如接听逻辑等 const newSession = data.session; if (newSession.direction === 'incoming') { // 按需处理来电 } }); ua.start(); }; const whisperCall = async (sipConfig) => { console.log("Whispering to:", sipConfig); if (!ua) throw new Error("SIP user agent is not initialized. Call init first."); if (currentSession) throw new Error( "Another call is in progress. End the current call first." ); // 关键:必须添加556前缀触发FreePBX监听逻辑 const targetUri = `sip:556${sipConfig.sip_extension}@${SIP_DOMAIN}`; currentSession = ua.call(targetUri); currentSession.on("confirmed", () => { console.log("Call established, sending DTMF 5 for whisper mode"); // 强制使用RFC2833发送DTMF,确保FreePBX识别 currentSession.sendDTMF(5, { transportType: "RFC2833" }); }); // 监听会话失败事件 currentSession.on("failed", (data) => { console.error("Whisper call failed:", data.cause); currentSession = null; }); currentSession.on("ended", () => { currentSession = null; }); return currentSession; };
遇到的问题
- 不确定发起通话时是否需要给分机添加556前缀,还是通过SIP URI其他结构处理
- 通话建立后发送DTMF 5,FreePBX未识别,无法进入密语模式
- 需要实现管理员向正在通话的坐席发起密语的功能
疑问解答与实现方案
1. 正确实现流程
严格遵循FreePBX的逻辑:
- 第一步:拨打带556前缀的目标分机,触发监听模式(这是FreePBX识别操作的核心,普通拨号不会触发监听逻辑)
- 第二步:通话建立后(
confirmed事件触发),发送对应DTMF切换模式:- 发送
4:切换到监听模式(仅管理员能听到通话) - 发送
5:切换到密语模式(管理员和坐席能互相听到,客户听不到管理员) - 发送
6:切换到插话模式(三方都能听到)
- 发送
2. SIP URI的正确写法
必须在SIP URI中包含556前缀,即:
const targetUri = `sip:556${sipConfig.sip_extension}@${SIP_DOMAIN}`;
FreePBX是通过拨号前缀来识别监听请求的,普通拨号分机只会建立普通通话,无法触发后续的模式切换逻辑。
3. DTMF兼容配置
要确保JsSIP发送的DTMF能被FreePBX识别,需注意以下几点:
- 强制使用RFC2833协议发送DTMF:在
sendDTMF时明确指定transportType: "RFC2833",这是FreePBX默认优先支持的DTMF传输方式 - UA配置中补充媒体相关设置:确保音频媒体正常协商,RTCP多路复用等配置正确(参考上面代码中的
mediaConstraints和rtcpMuxPolicy) - 检查FreePBX端配置:在FreePBX的「SIP设置」→「全局设置」或目标分机的设置中,确认开启了RFC2833 DTMF支持,禁用或降低INFO包DTMF的优先级
- 避免DTMF发送过早:必须在
confirmed事件触发后再发送DTMF,此时通话已完全建立,媒体通道正常
4. 管理员密语坐席的权限配置
确保管理员使用的分机在FreePBX中有对应的权限:
- 在FreePBX中进入「应用」→「权限管理」,给管理员分机添加「监听」「密语」「插话」相关的权限
- 确认目标坐席的分机设置中,允许被监听/密语(部分FreePBX版本需要在分机设置中开启「允许监听」选项)
内容的提问来源于stack exchange,提问作者Sandaru Shashinda
相关产品推荐
相关产品推荐

