JSSIP振铃挂断/接通挂断

65 阅读4分钟

一,基础实现 在 JSSIP 语音通话前端开发中,外呼振铃挂断和外呼接通的核心逻辑需基于 JSSIP.Session 事件监听实现,以下是关键步骤和代码示例:

  1. 外呼振铃挂断(未接通时终止呼叫)

当发起外呼后,在对方未接听(处于振铃状态)时挂断,需监听 progress 事件(表示呼叫进入振铃阶段),并调用 session.terminate() 终止会话。 // 1. 发起外呼后,监听振铃事件 const session = userAgent.makeCall(targetNumber, { mediaConstraints: { audio: true } });

// 监听 "progress" 事件(触发时表示对方正在振铃) session.on('progress', (e) => { console.log('外呼已振铃,等待对方接听'); // 若需主动挂断(如用户点击“挂断”按钮),调用 terminate() document.getElementById('hangup-btn').addEventListener('click', () => { if (session.status === 'progressing') { // 确认处于振铃阶段 session.terminate(); // 挂断振铃中的呼叫 console.log('振铃阶段已主动挂断'); } }); });

// 监听 "ended" 事件(确认挂断成功) session.on('ended', (e) => { console.log('呼叫已结束(振铃挂断),原因:', e.cause); }); 2. 外呼接通(监听通话建立事件)

当对方接听呼叫后,JSSIP 会触发 confirmed 事件,此时需处理媒体流(如播放对方音频),并绑定接通后的挂断逻辑。 // 监听 "confirmed" 事件(触发时表示呼叫已接通) session.on('confirmed', (e) => { console.log('外呼已接通,开始通话');

// 处理音频流(将对方音频绑定到 audio 标签) const remoteAudio = document.getElementById('remote-audio'); remoteAudio.srcObject = session.connection.getRemoteStreams()[0]; remoteAudio.play().catch(err => console.error('音频播放失败:', err));

// 接通后,点击“挂断”按钮终止通话 document.getElementById('hangup-btn').addEventListener('click', () => { if (session.status === 'confirmed') { // 确认处于通话中 session.terminate(); // 挂断已接通的通话 console.log('通话已主动挂断'); } }); });

// 监听 "ended" 事件(处理通话结束后的清理,如停止音频) session.on('ended', (e) => { console.log('通话已结束(接通后挂断),原因:', e.cause); const remoteAudio = document.getElementById('remote-audio'); remoteAudio.srcObject = null; // 清空音频流 }); 核心说明

• 关键事件:progress(振铃)、confirmed(接通)、ended(通话结束)是核心触发点,需根据 session.status 判断当前呼叫阶段,避免误操作。

• 挂断方法:无论振铃还是接通状态,均通过 session.terminate() 终止呼叫,区别仅在于触发时机(progressing 阶段 vs confirmed 阶段)。

• 媒体处理:接通后必须获取 remoteStream 并绑定到 audio 标签,才能播放对方声音,需处理浏览器音频自动播放限制(通常需用户交互触发)。

二. Vue2 监听 JSSIP 外呼“振铃挂断”与“接通后挂断”差异逻辑

核心是通过 session.ended 事件的 cause 参数 区分两种挂断场景:对方振铃时挂断(未接通)、对方接听后挂断(已接通),再分别调用不同接口。以下是完整实现代码及逻辑说明。

  1. 完整 Vue2 组件代码 .sip-call { display: flex; flex-direction: column; gap: 12px; padding: 20px; max-width: 300px; } input { padding: 8px; border: 1px solid #ddd; border-radius: 4px; } button { padding: 8px; background: #42b983; color: #fff; border: none; border-radius: 4px; cursor: pointer; } button:disabled { background: #ccc; cursor: not-allowed; } .call-status { color: #666; font-size: 14px; }
    1. 核心逻辑:如何区分两种挂断场景?

    关键靠 isCallConfirmed 标记 + session.ended 事件,逻辑闭环如下:

    1. 标记“是否接通”:

    • 当 session 触发 progress 事件(对方振铃)时,设置 isCallConfirmed = false(未接通);

    • 当 session 触发 confirmed 事件(对方接听)时,设置 isCallConfirmed = true(已接通)。

    1. 监听挂断事件:

    • 无论“对方主动挂断”还是“我方主动挂断”,最终都会触发 session.ended 事件;

    • 在 ended 事件中,通过 isCallConfirmed 的值判断场景:

    • isCallConfirmed = false → 对方振铃时挂断(或我方在振铃阶段挂断)→ 调用 振铃挂断接口;

    • isCallConfirmed = true → 对方接听后挂断(或我方在通话阶段挂断)→ 调用 接通后挂断接口。

    1. 补充说明

    • 挂断原因编码(可选):e.cause 会返回具体挂断原因(如 user_busy 对方忙、normal_clearing 正常挂断),可结合该参数进一步细化逻辑(如“对方拒接”也归为振铃挂断场景)。

    • 主动挂断的场景区分:我方点击“挂断”按钮时,同样通过 isCallConfirmed 判断当前是“振铃阶段”还是“通话阶段”,调用对应接口,保持逻辑统一。

    • 接口参数:可在接口中补充关键信息(如被叫号码、通话时长、挂断原因),示例中 getCallDuration 方法可计算通话时长(仅接通后有效)。

    1. 注意事项

    • 替换 initSIPUA 中的 SIP 服务器配置(uri/password/ws_servers)为你的实际项目参数;

    • 确保浏览器麦克风权限已允许(否则呼叫会失败);

    • 生产环境需使用 HTTPS(WebSocket 需 wss:// 协议,localhost 开发环境可例外)。