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

基于PJSUA/PJSIP如何检测被叫方拒接呼叫并处理异常

解决PJSUA/PJSIP被叫拒接时无法正确捕获状态的问题

核心排查与处理方案

被叫拒接却触发PJSIP_INV_STATE_CONFIRMED,本质是运营商/网关的特殊处理逻辑:拒接时先返回200 OK建立媒体通道,通过播放提示音告知呼叫失败,而非直接返回486(用户忙)、603(拒绝)这类错误响应。这种场景下不能仅依赖on_call_state的状态变更,需结合以下优雅方案处理:

1. 监听SIP错误响应与Reason头

在on_call_rx_msg回调中解析收到的SIP消息,捕获错误状态码或Reason头来判断拒接:

static void on_call_rx_msg(pjsua_call_id call_id, pjsip_rx_data *rdata)
{
    pjsip_msg *msg = rdata->msg_info.msg;
    if (PJSIP_IS_RESPONSE(msg)) {
        pjsip_status_code status = PJSIP_MSG_STATUS_CODE(msg);
        if (status >= 400) {
            // 检查Reason头是否包含拒接/忙线标识
            pjsip_generic_string_hdr *reason_hdr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_REASON, NULL);
            if (reason_hdr && (strstr(reason_hdr->hvalue.ptr, "busy") || strstr(reason_hdr->hvalue.ptr, "rejected"))) {
                pjsua_call_hangup(call_id, 0, NULL, NULL);
                return;
            }
            // 直接根据标准错误状态码处理
            if (status == 486 || status == 603) {
                pjsua_call_hangup(call_id, 0, NULL, NULL);
            }
        }
    }
}

2. 监控媒体通道无活动状态

播放完拒接提示音后,媒体通道会进入长时间静音状态,可在on_call_media_state中检测并结束呼叫:

static void on_call_media_state(pjsua_call_id call_id)
{
    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);
    
    if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
        pjsua_conf_port_info conf_info;
        pjsua_conf_get_port_info(ci.conf_slot, &conf_info);
        
        static pj_time_val last_inactive_ts;
        pj_time_val now;
        pj_gettimeofday(&now);
        
        // 检测端口是否持续静音(阈值可根据需求调整)
        if (conf_info.tx_level < -60 && conf_info.rx_level < -60) {
            if (last_inactive_ts.sec == 0) {
                last_inactive_ts = now;
            } else {
                pj_int32_t diff = pj_time_val_subtract(&now, &last_inactive_ts);
                if (diff >= 3000) { // 持续3秒无活动
                    pjsua_call_hangup(call_id, 0, NULL, NULL);
                    last_inactive_ts.sec = 0;
                }
            }
        } else {
            last_inactive_ts.sec = 0;
        }
    }
}

3. 补充on_call_state的状态判断逻辑

即使收到PJSIP_INV_STATE_CONFIRMED,也要结合呼叫信息中的最后状态码做校验:

static void on_call_state(pjsua_call_id call_id)
{
    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);
    
    // 覆盖特殊场景:状态为确认但实际收到错误响应
    if (ci.state == PJSIP_INV_STATE_CONFIRMED && ci.last_status >= 400) {
        pjsua_call_hangup(call_id, 0, NULL, NULL);
        return;
    }
    
    // 原有状态处理逻辑...
}

额外调试建议

  • 用pjsua --log-level 5开启详细SIP日志,查看被叫拒接时实际收到的消息内容,确认网关的处理逻辑。
  • 部分网关会在提示音播放后主动发送BYE消息,此时on_call_state会收到PJSIP_INV_STATE_DISCONNECTED,无需额外处理。

内容的提问来源于stack exchange,提问作者Olejan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:05:12