sip信令超时时间调整

Pjsip在使用过程中,如果网络环境不好,sip信令在交互过程中,会出现超时的情况,此时,sip信令会重复发送信令,直到收到信令的反馈或者sip会话超时退出通话。

针对上诉的情况,需要修改sip信令的超时时间,以便适应复杂的网络情况。

sip信令的传输代码主要在:pjsip/src/pjsip/sip_transaction.c中。

sip_transaction.c实现了一个状态机,根据sip信令交互的不同的信令,切换状态机。

UAC (呼叫方)状态机转换如下:

刚开始呼叫时,sip_transaction的状态机处于tsx_on_state_null状态,拨打电话发出INVITE信令后,状态机转为Calling状态,处理函数:tsx_on_state_calling,应用可以收到Calling的状态通知。

之后会收到被叫方发来的100 try信令,状态机转为Processing状态,处理函数:tsx_on_state_proceeding_uac

在收到180 ringing的信令后,还是在tsx_on_state_proceeding_uac中处理,应用会收到Early的状态通知。

如果被叫方接听了该呼叫,会收到被叫方的200 OK信令,状态机会转为Terminated状态,处理函数:tsx_on_state_terminated,应用会收到Connecting的状态通知,之后会通过timeout方式,把状态转为Destroyed。Call的状态也转为Confirmed。

Bye信令状态转换:

发出Bye信令时,状态机转为Calling状态(tsx_on_state_calling),在收到200OK信令时,转为Completed状态(tsx_on_state_completed_uac),应用会收到Disconnected的状态通知

,之后通过timeout的方式,状态转为Terminated和Destroyed

UAS(被叫方)状态机转换如下:

Bye状态转换:


被叫方的转换和呼叫方类似。

sip的超时时间修改:

INVITE发送超时时间修改,在函数:tsx_on_state_null中

sip信令一般使用UDP进行传输,属于不可靠的传输,所以在发送完INVITE信令后,会加入超时机制。超时时间为t1_timer_val时间间隔。

        /* Start Timer A (or timer E) for retransmission only if unreliable 
         * transport is being used.
         */
        if (!tsx->is_reliable)  {
            tsx->retransmit_count = 0;
            if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
                tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
            } else {
                tsx_schedule_timer(tsx, &tsx->retransmit_timer,
                                   &t1_timer_val, RETRANSMIT_TIMER);
            }
        }

        /* Move state. */
        tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, 
                       PJSIP_EVENT_TX_MSG, tdata, 0);
t1_timer_val的定义在,文件的开头:

/* Timer timeout value constants */
static pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, 
                                    PJSIP_T1_TIMEOUT%1000 };
/** Transaction T1 timeout value. */
#if !defined(PJSIP_T1_TIMEOUT)
#  define PJSIP_T1_TIMEOUT      500
#endif

所以INVITE发送后,首次的超时时间为500ms,第二次超时在tsx_on_state_calling函数中

    if (event->type == PJSIP_EVENT_TIMER && 
        event->body.timer.entry == &tsx->retransmit_timer) 
    {
        pj_status_t status;

        /* Retransmit the request. */
        status = tsx_retransmit( tsx, 1 );
        if (status != PJ_SUCCESS) {
            return status;
        }

    }
 /*
  * Retransmit last message sent.
  */
 static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched)
{
    pj_status_t status;

    if (resched && pj_timer_entry_running(&tsx->retransmit_timer)) {
        /* We've been asked to reschedule but the timer is already rerunning.
         * This can only happen in a race condition where, between removing
         * this retransmit timer from the heap and actually scheduling it,
         * another thread has got in and rescheduled the timer itself.  In
         * this scenario, the transmission has already happened and so we
         * should just quit out immediately, without either resending the
         * message or restarting the timer.
         */
        return PJ_SUCCESS;
    }

    PJ_ASSERT_RETURN(tsx->last_tx!=NULL, PJ_EBUG);

    PJ_LOG(5,(tsx->obj_name, "Retransmiting %s, count=%d, restart?=%d", 
              pjsip_tx_data_get_info(tsx->last_tx), 
              tsx->retransmit_count, resched));

    ++tsx->retransmit_count;

    /* Restart timer T1 first before sending the message to ensure that
     * retransmission timer is not engaged when loop transport is used.
     */
    if (resched) {
        pj_assert(tsx->state != PJSIP_TSX_STATE_CONFIRMED);
        if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
            tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
        } else {
            tsx_resched_retransmission(tsx);
        }
    }

    status = tsx_send_msg( tsx, tsx->last_tx);
    if (status != PJ_SUCCESS) {
        return status;
    }

    return PJ_SUCCESS;
}
/*
 * Retransmit last message sent.
 */
static void tsx_resched_retransmission( pjsip_transaction *tsx )
{
    pj_uint32_t msec_time;

    pj_assert((tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) == 0);

    if (tsx->role==PJSIP_ROLE_UAC && tsx->status_code >= 100)
        msec_time = pjsip_cfg()->tsx.t2;
    else
        msec_time = (1 << (tsx->retransmit_count)) * pjsip_cfg()->tsx.t1;
......
}


第二次的超时:msec_time = (1 << (tsx->retransmit_count)) * pjsip_cfg()->tsx.t1 ;就是第一次的超时*2,在1秒钟,第三次,在*2,知道timeout触发。

INVITE周期的timeout时间修改,在tsx_on_state_null函数中,只要修改timeout_timer_val的值即可:

            lock_timer(tsx);
            tsx_cancel_timer( tsx, &tsx->timeout_timer );
            tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout_timer_val,
                            TIMEOUT_TIMER);
            unlock_timer(tsx);





猜你喜欢

转载自blog.csdn.net/croop520/article/details/78666799