SIP注冊呼叫流程簡介


本文鏈接:https://blog.csdn.net/alwaysrun/article/details/103939541, 感謝作者。

PJSIP注冊呼叫流程簡介

標簽: C++與VC  VoIP與音視頻

 
 

注冊注銷

電話呼叫

 

在《SIP開源庫pjSIP簡介》中介紹了pjSIP的基本框架,本節對pjSIP中SIP的注冊與呼叫具體流程進行簡要說明。

注冊注銷

SIP通過register進行注冊請求:

  • 終端向VoIP服務器發送register請求:URL中包含注冊服務器的域名地址,To頭域中包含准備生成的地址記錄,Contact頭域中表明此次注冊所要綁定的地址(其中Expire表示綁定失效時長);

  • VoIP服務器返回401響應,要求用戶鑒權;

  • 終端發送帶鑒權信息的注冊請求;

  • 注冊完成;

SIP的注銷流程與注冊流程基本相同,只是Expires參數為0(標識注銷)

 

注冊接口

pjSIP中通過pjsua_acc_add來添加用戶信息並完成注冊;若不用默認的5060注冊端口,則需要增加代理設置,以便客戶端能正確地連接;注冊成功后會返回注冊賬戶id(非負數)。

  1.  
    #define PJ_User "1000"
  2.  
    #define PJ_Psw  "1234"
  3.  
    #define PJ_Server "192.168.1.100"
  4.  
    #define PJ_Port "5060"
  5.  
     
  6.  
    pj_acc_id g_accId =  -1;
  7.  
     
  8.  
    int pjRegister(){
  9.  
      pjsua_acc_config accConfig;
  10.  
      psua_acc_config_default(&accConfig);
  11.  
      accConfig.id = pj_str( "sip:" PJ_User "@" PJ_Server);
  12.  
      accConfig.reg_uri = pj_str( "sip:" PJ_Server);  // Comment, if not need register
  13.  
     
  14.  
       // Cred
  15.  
      accConfig.cred_count =  1;
  16.  
       auto &cred = accConfig.cred_info[0];
  17.  
      cred.realm = pj_str(PJ_Server);
  18.  
      cred.scheme = pj_str( "digest");
  19.  
      cred.username = pj_str(PJ_User);
  20.  
      cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
  21.  
      cred.data = pj_str(PJ_Psw);
  22.  
     
  23.  
       if(stod(PJ_Port) != 5060){
  24.  
        accConfig.proxy_cnt= 1;
  25.  
        accConfig.proxy[ 0]=pj_str("sip:" PJ_Server ":" PJ_Port)
  26.  
      }
  27.  
     
  28.  
       auto nStatus = pjsua_acc_add(&accConfig, PJ_FALSE, &g_accId);
  29.  
       if (!PjRetsuccess(nStatus)){
  30.  
        ...
  31.  
      }
  32.  
     
  33.  
      ...
  34.  
    }

pjsua_acc_add主要是添加客戶端賬戶信息,后續呼叫時,就使用此賬戶信息;即使直呼(不需要注冊直接呼叫,此時不要設定reg_uri)也需用調用此接口增加賬戶信息。賬戶不再需要時,通過pjsua_acc_del來刪除賬戶(若注冊過,則會自動注銷)。

注冊事件

注冊完成后(無論成功還是失敗),都會觸發注冊狀態改變事件(初始化pjSUA時設定的Onregstate回調);在此事件中,即可獲取注冊狀態。

  1.  
    static void OnRegState(pjsua_acc_id accId){
  2.  
      pjsua_acc_info accInfo;
  3.  
       auto nStatus = pjsua_acc_get_info(accId, &accInfo);
  4.  
     
  5.  
       bool bReged = accInfo.has_registration
  6.  
        && (accInfo.expires >  0)
  7.  
        && (accInfo.status /  100 == 2);
  8.  
     
  9.  
       // To log wheather registered
  10.  
    }

電話呼叫

SIP終端通過向代理(如,VoIP Server)發invite消息實現:

  • SIP終端A向代理發送invite請求:消息體中有終端A的媒體屬性SDP描述;

  • 代理返回407響應,要求鑒權;

  • SIP終端A重發帶鑒權信息的invite請求;

  • 代理返回100 Tring響應,並轉發invite請求到終端B;

  • 終端B振鈴,並返回(給代理)180 Ringing響應,代理再轉發給終端A;

  • 終端B摘機,返回200 OK響應:消息體中有終端B的媒體屬性SDP描述,代理再轉發給終端A;

  • 終端A返回ACK確認;

A與B注冊在不同代理的情形:

 

呼叫接口

pjSIP中通過pjsua_call_make_call實現電話呼叫,呼叫之前必須保證已添加了賬戶信息;通話完成后,通過pjsua_call_hangup/pjsua_call_hangup_all掛機,有來電時通過pjsua_call_answer接聽。

  1.  
    #define PJ_Called 3000
  2.  
    int pjMakeCall(){
  3.  
       auto toCall = pj_str("sip:" PJ_Called "@" PJ_Server)
  4.  
       auto nStatus = pjsua_call_make_call(g_accId, &toCall, NULL, NULL, NULL, NULL);
  5.  
       if (!PjRetsuccess(nStatus)){
  6.  
        ...
  7.  
      }
  8.  
     
  9.  
      ...
  10.  
    }

呼叫事件

呼叫狀態改變時,會觸發呼叫狀態改變事件(初始化pjSUA時設定的OnCallState回調);在此事件中可獲取具體通話狀態。

  1.  
    static void OnCallState(pjsua_call_id callId, pjsip_event *pEvent){
  2.  
      pjsua_call_info callInfo;
  3.  
       auto nStatus = pjsua_call_info(callId, &callInfo);
  4.  
     
  5.  
       if(callInfo.state == PJSIP_INV_STATE_DISCONNECTED){
  6.  
         // Call hanguped
  7.  
        ToStopMedia(callInfo);
  8.  
         // ... other clear
  9.  
      }
  10.  
    }

通話真正開始(RTP媒體流建立),會觸發媒體狀態改變事件(初始化pjSUA時設定的OnMediaState回調),此時可以對媒體處理(如關聯麥克風、揚聲器等)。

  1.  
    static void OnMediaState(pjsua_call_id callId){
  2.  
      pjsua_call_info callInfo;
  3.  
       auto nStatus = pjsua_call_info(callId, &callInfo);
  4.  
     
  5.  
       if(callInfo.media_status == PJSUA_CALL_MEDIA_ACTIVE){
  6.  
         // has started trans media
  7.  
        ToStartMedia(callInfo);
  8.  
     
  9.  
         // 若只是與聲卡設備連接,執行連接0端口即可
  10.  
         // pjsua_conf_connect(ci.conf_slot, 0);
  11.  
         // pjsua_conf_connect(0, ci.conf_slot);
  12.  
      }
  13.  
    }

如若非直接通過聲卡收發媒體,則需要自己去創建媒體處理端口,具體如何處理后續章節再講。

 

 
版權聲明:本文為alwaysrun原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/alwaysrun/article/details/103939541


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM