Chapter 12:Dialog Invite Session and Usage

12.1 Introduction

对话邀请会话是高级别的邀请会话管理,应用可以使用它来管理邀请会话(包括SDP的管理)。邀请绘画设计为完全抽象的基础对话,所以应用在使用邀请会话的API时不需要使用基本对话API。

应用可以为每个对话创建一个对话邀请会话。对话邀请会话被对话invite usage管理,这是个PJSIP模型。对话invite usage将事件分发到相应的邀请会话,也能处理forked dialog。

对话邀请会话和实例在单独的静态库中,如pjsip-ua库。应用必须包含头文件 <pjsip-ua/sip_inv.h>来使用对话邀请会话/实例的功能。或者,应用可以包含一个头文件<pjsip-ua.h>来获取pjsip-ua库中的函数。

12.1.1 Terms

对话邀请会话是一个对话中的邀请会话。如果应用要使用高级别的邀请会话管理,需要为每个对话创建一个并且是唯一的对话邀请会话实例。

对话invite usage是一个PJSIP模型,注册到PJSIP endpoint。当一个对话有对话邀请会话时,这个模型需要注册到指定的对话以作为一个对话实例。邀请会话创建的时候自动完成这些。

12.1.2 Features

对话邀请会话为应用提供以下功能:

#会话的进度报告(如会话进度,连接,确认,断开连接)

#自动认证处理(收到401/407后重试请求)

#SDP协商处理

#高级别forking处理

#会话超时(周期)

#会话扩展,比如会话计时器,可信任的临时响应

12.1.3 Invite Session State

对话invite usage提供回调来通知应用会话的进度。这个对电话应用很有用,会话的状态通常和电话的通话状态相关联。

一个邀请会话的进度在下面的图表的展示:

下面是每种状态的描述

PJSIP_INV_STATE_NULL:会话首次创建时的状态。这个时候没有任何的发送和接收的消息。

PJSIP_INV_STATE_CALLING:第一次发送INVITE后的会话状态,但是在收到临时响应之前。

PJSIP_INV_STATE_INCOMING:第一次收到INVITE消息后的会话状态,但是在发出任何临时响应之前。

PJSIP_INV_STATE_EARLY:对话已经发送或接收来自INVITE请求的响应,有To tag时。

PJSIP_INV_STATE_CONNECTING:发送或接收到2xx的最终响应。

PJSIP_INV_STATE_CONFIRMED:收到或发送ACK请求后。

PJSIP_INV_STATE_DISCONNECTED:会话断开连接,或者INVITE/BYE请求没有收到成功的最终响应。

12.1.4 Invite Session Creation

对于传出的对话(如caller),应用需要调用pjsip_dlg_create_uac()来创建UAC对话。应用之后会调用 pjsip_inv_create_uac()创建邀请会话,将UAC对话实例作为其中之一的参数传递。应用绝不能在邀请会话创建之前发送INVITE请求,否则邀请会话的一些事件会受影响。

对于传入的对话,应用通过pjsip_inv_verify_request()调用来首先验证这个请求是许可的。这个函数验证Supported, Require和请求的消息体来确认接受这个请求。如果这个请求不被接受,将创建对应的拒绝响应。如果请求被接受,应用通过调用 pjsip_dlg_create_uas()来创建UAS对话。应用之后调用 pjsip_inv_create_uas()来为这个对话创建邀请会话,UAS对话实例作为其中的一个参数传递。邀请会话创建之前,应用绝不能发送任何响应,否则会影响邀请会话的事件。

当一个传出对话forked,或者当一个邀请会话在源对话中存在,invite usage模块将为新(forked)对话自动创建邀请会话。应用通过回调函数通知新会话的创建。

邀请会话创建函数(即pjsip_inv_create_uac()和pjsip_inv_create_uas()函数)自动注册邀请会话实例到对话中。应用不需要调用 pjsip_dlg_add_usage()来注册invite usage模型到对话中。

12.1.5 Messages Handling

邀请会话处理所有的可能改变会话状态的SIP methods。这个版本的PJSIP,邀请会话处理INVITE, BYE,ACK, CANCEL, UPDATE, 和 PRACK 方法。

应用必须使用邀请会话API来创建和发送上述方法的请求和响应。因为确保邀请和响应的消息已被正确处理是必要的,也包括对话正在使用的一些特性(比如可靠的临时响应)。

应用也可以使用基本的对话API来创建和发送不止于以上方法的请求和响应消息。例如,应用可以使用基本的对话API在对话内创建和发送MESSAGE 请求。

12.1.6 Extending the Dialog

如上所述,邀请会话处理对话中出现的INVITE, BYE, ACK, CANCEL,UPDATE和 PRACK 消息。当应用想要支持和处理其他类型的消息,必须自己注册到对话上作为一个对话实例。这个使应用能够处理已存在对话实例不能够处理的传入请求。

应用设置正确的模型级别是很重要的。应用级别设为 PJSIP_MOD_PRIORITY_APPLICATION。invite usage设为 PJSIP_MOD_PRIORITY_APPLICATION-1。这样保证invite usage能够在应用之前检测到传入的请求。

12.1.7 Extending the Invite Session

以后,邀请会话可能扩展支持更多的SIP扩展,比如呼叫转移,对话目标锁定等。目前应用应该能通过手动构造消息来体现这些功能。

12.2 Reference

12.2.1 Data Structure

头文件 <pjsip-ua/sip_inv.h>中声明了邀请会话的函数。

下面的代码展示了可用于一个会话的多种选项。创建一个会话的时候要指定这些选项的位掩码组合。对话创建后(包括early), pjsip_inv_session的成员options展示两个endpoint中那些功能是通用的。

 12.2.2 Invite Usage Module

invite usage模型在任何会话创建之前都必须已经被初始化。

pj_status_t pjsip_inv_usage_init( pjsip_endpoint *endpt,

pjsip_module *app_module,

const pjsip_inv_callback *callback);

初始化invite usage模型,并注册到endpoint。callback参数包含邀请会话中发生事件的函数指针的回调。

pjsip_module* pjsip_inv_usage_instance(void);

获取invite usage模型的实例。

12.2.3 Session Callback

pjsip_inv_callback结构体包含了可以由应用程序注册以便invite usage模块接收关于invite会话事件的通知的函数指针。

下面是回调函数。

void on_state_changed( pjsip_inv_session *inv_ses,

pjsip_event *e);

会话状态改变时调用。

应用可以检测会话状态(inv_sess->state)来得到当前的状态。

这个回调时强制性的。

void on_new_session(pjsip_inv_session *inv_ses, pjsip_event *e);

当invite usage模型为forked 传出请求创建了一个新的对话和邀请时的回调。

void on_tsx_state_changed( pjsip_inv_session *inv_ses,

pjsip_transaction *tsx,

pjsip_event *e );

会话中的任何事物改变了他们的状态时的回调。应用可以执行这个回调,比如监测发出请求的进度。

这个回调是可选的。

void on_rx_offer( pjsip_inv_session *inv_ses,

const pjmedia_sdp_session *offer );

邀请会话从对端收到一个新的offer时的回调。应用调用pjsip_inv_set_sdp_answer()设置本地应答 。这个函数不会发送传出消息。只是保留SDP协商进程的应答,并被包含在之后发送的请求或响应中。

这个回调时可选的。当没有指定时,默认的行为是用会话的初始能力协商远端。

void on_media_update( pjsip_inv_session *inv_ses, pj_status_t status );

SDP offer/answer会话已经完成后的回调。status参数表示offer/answer的状态,由pjmedia_sdp_neg_negotiation()返回。

这个回调是可选的(从框架的角度),但是所有有用的应用通常都需要执行这个回调。

12.2.4 Session Creation and Termination

pj_status_t pjsip_inv_create_uac( pjsip_dialog *dlg,

const pjmedia_sdp_session *local_sdp,

unsigned options,

pjsip_inv_session **inv_sess);

dlg中的对话创建UAC邀请会话。如果应用已经确定了媒体能力,可以在local_sdp中指定SDP。否则为NULL,让远端的UAS来指定一个offer。options参数是pjsip_inv_options枚举中SIP特性的位掩码组合。

成功返回时,邀请会话将放入inv_sess参数中,函数返回PJ_SUCCESS。否则将返回响应的错误状态。

pj_status_t pjsip_inv_verify_request(pjsip_rx_data *rdata,

unsigned *options,

const pjmedia_sdp_session *local_sdp,

pjsip_dialog *dlg,

pjsip_endpoint *endpt,

pjsip_tx_data **tdata);

在创建INVITE会话(甚至对话)之前,应用程序应该在收到rdata中的初始INVITE请求时调用此函数,来验证邀请会话可以处理INVITE 请求。这个函数验证本地endpoint能够处理请求和媒体中所需的SIP扩展(如头字段),如果请求中有媒体描述的话。

调用这个函数时,options参数必须包含希望应用到会话中的SIP扩展,在请求中已经有Supported,Require和Allow头之后。

如果本地的媒体能力已经确定了,如果想要验证INVITE请求中的协商媒体是否能够处理,必须验证local_sdp中的媒体能力。如果不指定,这个函数不会验证媒体能力。

如果所有的都协商成功了,函数将返回PJ_SUCCESS。否则返回失败原因。

这个函数能够创建合适的响应消息当验证失败时。如果tdata指定了,将创建并返回一个非2xx的最终响应,当验证失败时。如果一个对话在调用函数前已经创建了,必须指定dlg参数。否则应用必须指定endpt参数(这是有用处的,比如应用想要发送有状态的响应)。

pj_status_t pjsip_inv_create_uas( pjsip_dialog *dlg,

pjsip_rx_data *rdata,

const pjmedia_sdp_session *local_sdp,

unsigned options,

pjsip_inv_session **inv_sess);

dlg中指定的的对话创建UAS邀请会话。应用必须在rdata中指定收到的INVITE请求。邀请会话需要检查收到的请求来确认请求是否包含支持的特性。

应用必须在调用这个函数之前先调用认证函数,来确保成功创建会话。

如果应用已经确定了媒体能力,它可以在local_sdp中指定这个能力。如果在初始的INVITE中收到了SDP,UAS的local_sdp中指定的能力和收到的offer中的不一致;SDP的协商者能够重新在响应中加上offer匹配的媒体能力。

options参数是pjsip_inv_options枚举中的SIP特性的位掩码组合。

成功返回时,邀请会话放入inv_sess 参数中并且函数返回PJ_SUCCESS。否则失败的相应错误。

pj_status_t pjsip_inv_terminate( pjsip_inv_session *inv,

int st_code,

pj_bool_t notify );

提前终止邀请会话并且销毁对话(如果对话没有其他实例)。这个函数只在初始化INVITE会话失败的时候调用。一般的情形下,应用必须调用 pjsip_inv_end_session()来终止INVITE会话。

st_code参数指定了SIP状态码作为连接断开的原因。如果notify是true,应用回调被调用。

12.2.5 Session Operations

pj_status_t pjsip_inv_invite( pjsip_inv_session *inv,

pjsip_tx_data **tdata );

为会话创建初始请求。这个函数只能被UAC会话调用。这个初始INVITE请求将放入到tdata中如果成功创建。

如果会话创建的时候本地媒体能力指定了,这个函数会把SDP放到发出的INVITE中。否则发送的请求就不包含SDP体。

pj_status_t pjsip_inv_answer( pjsip_inv_session *inv,

int st_code,

const pj_str_t *st_text,

const pjmedia_sdp_session *local_sdp,

pjsip_tx_data **tdata );

为初始INVITE请求创建响应消息。st_code包含了被发送的状态码,可能是临时或最终响应。如果需要自定义状态文本,可以指定st_text;否则这个参数就是NULL,使用默认的状态文本。

如果应用已经在创建UAS邀请会话期间指定了媒体能力,local_sdp必须是NULL。这是因为在单独的INVITE事务中应用不能有超过一个的SDP answer/offer会话。

如果在此期间没有指定,可能或必须指定local_sdp参数,这个取决于st_code是否表示2xx最终响应。

pj_status_t pjsip_inv_end_session( pjsip_inv_session *inv,

int st_code,

const pj_str_t *st_text,

pjsip_tx_data **tdata );

创建一个SIP消息来启动邀请会话的终止。取决于会话的状态,这个函数可能返回CANCEL请求,一个非2xx最终响应,或者一个BYE请求。如果会话没有应答收到的INVITE,这个函数创建一个非2xx最终响应,指定st_code和可选的st_text

pj_status_t pjsip_inv_reinvite( pjsip_inv_session *inv,

const pj_str_t *new_contact,

const pjmedia_sdp_session *new_offer,

pjsip_tx_data **tdata );

创建重邀请会话。如果应用想要去更新本地contact并通知peer用新contact更新target,可以指定new_contact参数为新的contact;否则这个参数是NULL。

如果没有绑定的应答要发送或接收,应用可以启动一个新的SDP offer/answer在请求中。应用可以通过邀请会话的SDP协商状态来检查这种情形。如果新的offer要发送到远端,offer必须放入new_offer,否则为NULL。

pj_status_t pjsip_inv_update ( pjsip_inv_session *inv,

const pj_str_t *new_contact,

const pjmedia_sdp_session *new_offer,

pjsip_tx_data **tdata );

创建一个UPDATE请求。如果应用想要去更新本地contact并通知peer用新contact更新target,可以指定new_contact参数为新的contact;否则这个参数是NULL。如果没有绑定的应答要发送或接收,应用可以启动一个新的SDP offer/answer在请求中。应用可以通过邀请会话的SDP协商状态来检查这种情形。如果新的offer要发送到远端,offer必须放入new_offer,否则为NULL。(和上面的函数描述一样?)

pj_status_t pjsip_inv_send_msg( pjsip_inv_session *inv,

pjsip_tx_data *tdata,

void *token );

tdata中发送请求或响应消息。token是一个任意的应用程序数据,它将放在事务的mod_data数组中,位于应用模块的索引处。

12.2.6 Auxiliary API

pjsip_inv_session* pjsip_dlg_get_inv_session( pjsip_dialog *dlg );

获取与dlg相关联的邀请会话实例,或NULL。

pjsip_inv_session* pjsip_tsx_get_inv_session( pjsip_transaction *tsx );

获取与tsx事务相关联的邀请会话实例,或NULL。

翻译-pjsip开发者指南(十二)对话邀请会话和用法相关推荐

  1. 翻译-pjsip开发者指南(十一)SDP协商框架

    Chapter 11:SDP Offer/Answer Framework SDP offer/answer框架是基于 RFC 3264 "An Offer/Answer Model wit ...

  2. VR系列——Oculus Rift 开发者指南:二、初始化和传感器枚举

    初始化和传感器枚举 这是初始化LibOVR的例子,需要可用HMD的相关知识. 看以下的代码: // 引用OculusVR SDK #include <OVR_CAPI.h> void Ap ...

  3. Kotlin实战指南十二:data class

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/94649274 本文出自[赵彦军的博客] 文章目录 前言 正文 toString( ...

  4. c#编程指南(十二) 平台调用P-INVOKE完全掌握, 结构体边界对齐和内存布局

    在使用结构体指针,进行C#和C++的互相调用.边界对齐是一个大问题,因为边界对齐问题,结构体的成员并不是顺序在内存一个挨着一个的排序. 而且在C++中可以使用#pragma pack(n)改变边界对齐 ...

  5. #ASM 翻译系列第三十二弹:ASM INTERNAL Find block in ASM

    原文: Find block in ASM 作者: Bane Radulovic 译者:魏兴华,沃趣科技高级技术专家,主要参与公司一体机产品.监控产品.容灾产品.DBaaS平台的研发和设计.曾就职于东 ...

  6. 2021年大数据常用语言Scala(三十二):scala高级用法 样例类

    目录 样例类 定义样例类 样例类方法 样例对象 样例类 样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于Java POJO类),而且它会自动生成apply方法,允许我们快速地创建样例 ...

  7. 官宣!《新程序员·开发者黄金十年》正式发布

    "在互联网还不发达的时代,就是<程序员>伴我成长的." "怀念啊,曾经<程序员>的日子." "我是看着<程序员>长 ...

  8. 新程序员001:开发者黄金十年

    官宣!<新程序员·开发者黄金十年>正式发布_<程序员>官方BLOG-CSDN博客 开发者黄金十年:讲述新程序员时代 从全球来看,开发者市场拥有三大红利: 一.全民编程,人人都是 ...

  9. 第七十二章 方法关键字 - PublicList

    文章目录 第七十二章 方法关键字 - PublicList 用法 详解 默认 第七十二章 方法关键字 - PublicList 指定此方法的公共变量.仅当方法是用ObjectScript编写并且是过程 ...

最新文章

  1. python编辑器,作为初学者该如何抉择?
  2. 实际测试例子+源码分析的方式解剖MyBatis缓存的概念
  3. Java简单知识梳理
  4. SemEval-2022组队参赛啦!八节课带你入门全球最大的语义测评大赛
  5. [LeetCode]547. Friend Circles朋友圈数量--不相邻子图问题
  6. Ubuntu 12.04下安装Oracle Express 11gR2
  7. java perl5compiler,Java中正则表达式使用方法详解(四)
  8. [html] html5中的meta标签http-equiv属性有什么作用?
  9. linux+shell+func,Linux shell编程笔记总结
  10. Entropay(欧贝通)
  11. 安卓动态调试七种武器之离别钩 – Hooking(下)
  12. 品质创新,江铃控股携手华天软件CAPP系统决战SUV中高端市场
  13. 【Computer Organization笔记11】多周期CPU
  14. oracle 锁表查询及解决、表字段查询
  15. python 打印的异常回溯和代码不对应
  16. DS3400 RDAC for RedHat5.3安装文档-sunleii@DC
  17. Redis实战篇(视频学习来自黑马程序员)
  18. 前端实现鼠标拖拽功能
  19. win32应用程序_教你打开程序提示不是有效的win32程序怎么办
  20. 《简单的逻辑学》阅读笔记(思维导图)

热门文章

  1. js实现字符串转json对象的四种方法
  2. java打印代码执行耗时
  3. 华为HCNA实验操作之常用操作命令11-20
  4. (转)魔兽地图加密脚本和反作弊脚本原理一览
  5. C语言中全局变量和局部变量,内部函数和外部函数的区别
  6. python如何将文件内容合并_python如何将两个txt文件内容合并
  7. 计网——(数据报与虚电路)
  8. 串口控制语音模块XY-V17B
  9. 学校计算机室的管理员,电脑室管理员岗位责任
  10. john 探测(爆破)弱口令(包含linux机器,aix小机)/linux上的shadow文件破解,亲测可用