zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    003_cd pushd popd三个命令的区别
    002_更新Nginx证书
    001_nginx常用参数查询
    001_shell经典案例
    001_chrome工具详解
    002_分布式搜索引擎Elasticsearch的查询与过滤
    004_加速国内docker源下载速度
    dango models and database ---- relation ship
    dango models and database ---- verbose name
    MySQL字符集详解
  • 原文地址:https://www.cnblogs.com/tonyxiao/p/15610165.html
Copyright © 2011-2022 走看看