pjSIP注册呼叫流程简介

注册注销

电话呼叫

 

在《SIP开源库pjSIP简介》中介绍了pjSIP的基本框架,本节对pjSIP中SIP的注册与呼叫具体流程进行简要说明。

注册注销

SIP通过register进行注册请求:

  • 终端向VoIP服务器发送register请求:URL中包含注册服务器的域名地址,To头域中包含准备生成的地址记录,Contact头域中表明此次注册所要绑定的地址(其中Expire表示绑定失效时长);

  • VoIP服务器返回401响应,要求用户鉴权;

  • 终端发送带鉴权信息的注册请求;

  • 注册完成;

SIP的注销流程与注册流程基本相同,只是Expires参数为0(标识注销)

 

注册接口

pjSIP中通过pjsua_acc_add来添加用户信息并完成注册;若不用默认的5060注册端口,则需要增加代理设置,以便客户端能正确地连接;注册成功后会返回注册账户id(非负数)。

#define PJ_User "1000"
#define PJ_Psw  "1234"
#define PJ_Server "192.168.1.100"
#define PJ_Port "5060"

pj_acc_id g_accId = -1;

int pjRegister(){
  pjsua_acc_config accConfig;
  psua_acc_config_default(&accConfig);
  accConfig.id = pj_str("sip:" PJ_User "@" PJ_Server);
  accConfig.reg_uri = pj_str("sip:" PJ_Server);  // Comment, if not need register

  // Cred
  accConfig.cred_count = 1;
  auto &cred = accConfig.cred_info[0];
  cred.realm = pj_str(PJ_Server);
  cred.scheme = pj_str("digest");
  cred.username = pj_str(PJ_User);
  cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
  cred.data = pj_str(PJ_Psw);

  if(stod(PJ_Port) != 5060){
    accConfig.proxy_cnt=1;
    accConfig.proxy[0]=pj_str("sip:" PJ_Server ":" PJ_Port)
  }

  auto nStatus = pjsua_acc_add(&accConfig, PJ_FALSE, &g_accId);
  if (!PjRetsuccess(nStatus)){
    ...
  }

  ...
}

pjsua_acc_add主要是添加客户端账户信息,后续呼叫时,就使用此账户信息;即使直呼(不需要注册直接呼叫,此时不要设定reg_uri)也需用调用此接口增加账户信息。账户不再需要时,通过pjsua_acc_del来删除账户(若注册过,则会自动注销)。

注册事件

注册完成后(无论成功还是失败),都会触发注册状态改变事件(初始化pjSUA时设定的Onregstate回调);在此事件中,即可获取注册状态。

static void OnRegState(pjsua_acc_id accId){
  pjsua_acc_info accInfo;
  auto nStatus = pjsua_acc_get_info(accId, &accInfo);

  bool bReged = accInfo.has_registration
    && (accInfo.expires > 0)
    && (accInfo.status / 100 == 2);

  // To log wheather registered
}

电话呼叫

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接听。

#define PJ_Called 3000
int pjMakeCall(){
  auto toCall = pj_str("sip:" PJ_Called "@" PJ_Server)
  auto nStatus = pjsua_call_make_call(g_accId, &toCall, NULL, NULL, NULL, NULL);
  if (!PjRetsuccess(nStatus)){
    ...
  }

  ...
}

呼叫事件

呼叫状态改变时,会触发呼叫状态改变事件(初始化pjSUA时设定的OnCallState回调);在此事件中可获取具体通话状态。

static void OnCallState(pjsua_call_id callId, pjsip_event *pEvent){
  pjsua_call_info callInfo;
  auto nStatus = pjsua_call_info(callId, &callInfo);

  if(callInfo.state == PJSIP_INV_STATE_DISCONNECTED){
    // Call hanguped
    ToStopMedia(callInfo);
    // ... other clear
  }
}

通话真正开始(RTP媒体流建立),会触发媒体状态改变事件(初始化pjSUA时设定的OnMediaState回调),此时可以对媒体处理(如关联麦克风、扬声器等)。

static void OnMediaState(pjsua_call_id callId){
  pjsua_call_info callInfo;
  auto nStatus = pjsua_call_info(callId, &callInfo);

  if(callInfo.media_status == PJSUA_CALL_MEDIA_ACTIVE){
    // has started trans media
    ToStartMedia(callInfo);

    // 若只是与声卡设备连接,执行连接0端口即可
    // pjsua_conf_connect(ci.conf_slot, 0);
    // pjsua_conf_connect(0, ci.conf_slot);
  }
}

如若非直接通过声卡收发媒体,则需要自己去创建媒体处理端口,具体如何处理后续章节再讲。

 

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pjsip是一个开源的SIP协议栈,可以用于实现基于SIP协议的电话呼叫。以下是一个简单的pjsip电话呼叫的示例代码: ```c #include <pjsua-lib/pjsua.h> int main() { pj_status_t status; pj_caching_pool cp; pj_pool_t *pool; pjsua_config cfg; pjsua_logging_config log_cfg; pjmedia_transport_config media_cfg; pjmedia_transport *media_transport; pjsua_acc_id acc_id; pjsua_call_id call_id; pj_str_t uri = pj_str("sip:username@domain.com"); // Initialize pjsua status = pj_init(); pj_caching_pool_init(&cp, NULL, 0); pool = pj_pool_create(&cp.factory, "pjsua", 4000, 4000, NULL); pjsua_config_default(&cfg); cfg.cb.on_incoming_call = NULL; cfg.cb.on_call_media_state = NULL; cfg.cb.on_call_state = NULL; cfg.cb.on_reg_state = NULL; pjsua_logging_config_default(&log_cfg); log_cfg.console_level = 4; log_cfg.level = 4; status = pjsua_init(&cfg, &log_cfg, NULL); pjsua_transport_config cfg_transport; pjsua_transport_config_default(&cfg_transport); cfg_transport.port = 5060; status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg_transport, NULL); pjsua_start(); // Register with SIP server pjsua_acc_config acc_cfg; pjsua_acc_config_default(&acc_cfg); acc_cfg.id = pj_str("sip:username@domain.com"); acc_cfg.reg_uri = pj_str("sip:domain.com"); acc_cfg.cred_count = 1; acc_cfg.cred_info[0].realm = pj_str("domain.com"); acc_cfg.cred_info[0].scheme = pj_str("digest"); acc_cfg.cred_info[0].username = pj_str("username"); acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; acc_cfg.cred_info[0].data = pj_str("password"); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &acc_id); // Make outgoing call pjsua_call_setting call_setting; pjsua_call_setting_default(&call_setting); status = pjsua_call_make_call(acc_id, &uri, &call_setting, NULL, NULL, &call_id); // Destroy pjsua pjsua_destroy(); pj_pool_release(pool); pj_caching_pool_destroy(&cp); return 0; } ``` 这段代码首先初始化了pjsua,然后注册到SIP服务器,最后发起一个呼叫。具体的调用过程可以参考pjsip官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值