当前页

处理呼叫失败

2026-10-10

功能简介

实时音视频呼叫场景中,当接听方网络不可用、设备离线或长时间无应答时,若呼叫方一直静默等待,会严重损害用户体验。 对齐系统电话的呼叫交互体验:当接听方不可达或呼叫超时时,及时、明确地向呼叫方给出失败提示。

处理呼叫失败效果展示:

  • 接听方不在线(未登录、无法收到呼叫邀请)时,呼叫方快速收到"无法接通"提示。
  • 接听方已登录但在设定时长内未接听时,呼叫方收到"对方无应答"提示。两类失败分开表达,均伴随系统提示音。

前提条件

  • 呼叫方与接听方均已集成 ZIM SDK 并完成登录,呼叫邀请功能可用。
  • SDK 版本 ≥ 2.9.0(callUserStateChanged 回调的最低支持版本)。
  • 启用呼叫连通性检查需 SDK 版本 ≥ 2.15.0(enableNotReceivedCheck 生效版本)。

实现方案

设计原则与提示策略

  • 快速失败反馈:开启 enableNotReceivedCheck 主动确认接听方可达性,而非单纯依赖接听方回包。
  • 可区分的反馈信息:不可达、无应答、已拒接三类失败信息,避免语义混同(见下方“呼叫方关键状态与处理”)。
  • 状态机驱动体验:以 ZIMCallUserState 的流转统一驱动 UI 与提示,避免接收、呼叫状态混乱。
  • 提示音对齐原生体验:SIT 音(Special Information Tone,特殊信息音)+ 语音播报组合,贴近用户对系统电话失败反馈的预期。
  • 超时分级设计,覆盖"不可达"与"不接听"两类失败场景:
    • 快速失败:5 秒快速失败在呼叫发起阶段即确认接听方是否正常收到邀请,避免无意义的等待。
    • 兜底超时:“接听方已收到邀请但长时间不接听”的场景。
呼叫方关键状态与处理
关键状态触发时间呼叫方表现
NotYetReceived(9)5 秒快速失败(可配置为 3 / 4 秒)播放 SIT 音 + 语音提示"无法接通",结束等待态
Received(5)接听方收到邀请时UI 切换为"响铃中",继续等待接听
Timeout(6)timeout 设定的兜底时长到期播放 SIT 音 + 语音提示"对方无应答"
Rejected(2)接听方主动拒绝时提示"对方已拒接",与不可达区分开
呼叫失败判定链路图

呼叫连通性检查

呼叫连通性检查通过 callInvite 的 enableNotReceivedCheck 参数开启(属于 ZIMCallInviteConfig,默认值为 false)。 传入 true 时,本次呼叫邀请以及后续呼叫都会检测邀请是否送达。接听方因断网、未上线等原因未收到邀请时,判定为未送达,状态变为 notYetReceived(暂未送达);若接听方在呼叫超时前上线,状态会流转为 received(已送达)。

版本兼容:2.15.0 及以后版本向低版本客户端(2.14.0 及之前)发送开启送达检测的呼叫邀请时,低版本将继续展示 inviting 状态而非 notYetReceived。若业务要求全量用户体验一致,需在发版时引导升级。

注意

离线边界:接听方处于离线状态时,离线推送通知本身也会返回 NotYetReceived 状态,造成"接听方实为离线、却被判定为不可达"的边界情况。呼叫方可能在呼叫离线用户时直接失败,此时业务侧在收到离线推送通知后尽快触发一次登录(重新完成注册),即可规避该误判。

接入示例

// 发起呼叫并开启呼叫连通性检查
const invitees = ['user02'];
const config: ZIMCallInviteConfig = {
  mode: 0,                        // 普通模式
  timeout: 30,                    // 兜底无应答超时,单位秒,取值范围 [1, 600],默认 90
  enableNotReceivedCheck: true,   // 开启未送达检测,2.15.0 及以上生效
  extendedData: '',
};
zim.callInvite(invitees, config)
  .then((res: ZIMCallInvitationSentResult) => {
    const callID = res.callID;    // 后续取消 / 接受 / 拒绝均使用该 ID
  })
  .catch((err: ZIMError) => { /* 发起失败处理 */ });

// 监听接听方状态并驱动 UI
zim.on('callUserStateChanged', (zim: ZIM, data: ZIMCallUserStateChangedEventResult) => {
  if (data.callID !== currentCallID) return;
  data.callUserList.forEach((userInfo) => {
    switch (userInfo.state) {
      case 9: // NotYetReceived:接听方 5 秒内未收到邀请,快速失败
        playSIT();
        showTip('您拨打的用户无法接通');
        break;
      case 5: // Received:接听方已收到邀请,进入响铃等待
        setCallStatus('ringing');
        break;
      case 6: // Timeout:接听方收到但超时未接听
        playSIT();
        showTip('对方无应答,请稍后再拨');
        break;
      case 2: // Rejected:接听方主动拒绝
        playSIT();
        showTip('对方已拒接');
        break;
    }
  });
});

常见问题

最常见的原因是推送通道与实时通道的差异——接听方 App 处于离线 / 被系统回收状态时,送达检测在判定窗口内拿不到回包。请按「呼叫连通性检查」小节中离线边界的规避方案做重登兜底,并确认接听方端的推送注册状态正常。

可以。默认 5 秒,可联系 ZEGO 技术支持配置为 3 秒或 4 秒。建议不要设得过短,否则弱网下的正常呼叫也会被误判。

取值范围为 [1, 600] 秒,默认 90 秒。对齐系统电话体验建议设为 30 - 60 秒;若业务偏"留言 / 异步"形态可适当拉长。

2.14.0 及之前版本的接听方会持续展示 inviting。需要在发版时升级,或者在低版本走兜底超时逻辑。

适用。callUserStateChanged 会返回本呼叫中所有状态发生变化的成员列表,呼叫方需按成员逐个判定,多人场景请按成员状态分别处理。

2026-10-10

上一篇

实现消息送达状态与回执

下一篇

实现消息阅后即焚与定时销毁

当前页

返回到顶部