landuochong 发表于 2011-12-23 03:58

Doubango voip 框架分析之tinysip 协议栈

<p style="margin-bottom: 0cm;"> <span style="font-family: DejaVu Serif,serif;">Doubango
voip </span>
框架分析之<span style="font-family: DejaVu Serif,serif;">tinysip</span>
协议栈</p>
<p style="margin-bottom: 0cm;">&nbsp; <br></p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">1.
tinysip </span>
介绍 :</p>
<p style="margin-bottom: 0cm;">&nbsp;<br></p>
<p style="margin-bottom: 0cm;">兼容性 : <span style="font-family: DejaVu Serif,serif;">SIP
(RFC 3261) </span>
以及 <span style="font-family: DejaVu Serif,serif;">3GPP
IMS/LTE (TS 24.229) implementation</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp; <br></p>
<p style="margin-bottom: 0cm;">依赖 <span style="font-family: DejaVu Serif,serif;">tinySAK,
tinyNET, tinySDP, tinyMEDIA, tinyHTTP and tinyIPSec.</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;</p>
<p style="margin-bottom: 0cm;">&nbsp;</p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">2.
SIP</span>
协议 <span style="font-family: DejaVu Serif,serif;">-tinysip</span>
的实现机制</p>
<p style="margin-bottom: 0cm;">&nbsp; <br></p>
<p style="margin-bottom: 0cm;">   
<span style="font-family: DejaVu Serif,serif;">SIP</span>
是一个分层结构的协议,这意味着它的行为是根据一组平等独立的处理阶段来描述,每一阶段之间只是松耦合。协议分层描述是为了表达,从而允许功能的描述可在一个部分跨越几个元素。它不指定任何方式的实现。当我们说某元素包含某层,我们是指它顺从该层定义的规则集。</p>
<p style="margin-bottom: 0cm;">&nbsp;不是协议规定的每个元素都包含各层。而且,由<span style="font-family: DejaVu Serif,serif;">SIP</span>
规定的元素是逻辑元素,不是物理元素。一个物理实现可以选择作为不同的逻辑元素,甚至可能在一个个事务的基础上。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">SIP</span>
的最底层是语法和编码。它的编码使用增强<span style="font-family: DejaVu Serif,serif;">Backus-Nayr</span>
形式语法(<span style="font-family: DejaVu Serif,serif;">BNF</span>
)来规定。</p>
<p style="margin-bottom: 0cm;">&nbsp;第二层是传输层。它定义了网络上一个客户机如何发送请求和接收响应以及一个服务器如何接收请求和发送响应。所有的<span style="font-family: DejaVu Serif,serif;">SIP</span>
元素包含传输层。</p>
<p style="margin-bottom: 0cm;">&nbsp;</p>
<p style="margin-bottom: 0cm;">      
第三层是事务层。事务是<span style="font-family: DejaVu Serif,serif;">SIP</span>
的基本元素。一个事务是由客户机事务发送给服务器事务的请求(使用传输层),以及对应该请求的从服务器事务发送回客户机的所有响应组成。事务层处理应用层重传,匹配响应到请求,以及应用层超时。任何用户代理客户机(<span style="font-family: DejaVu Serif,serif;">UAC</span>
)完成的任务使用一组事务产生。用户代理包含一个事务层,有状态的代理也有。无状态的代理不包含事务层。事务层具有客户机组成部分(称为客户机事务)和服务器组成部分(称为服务器事务),每个代表有限的状态机,它被构造来处理特定的请求。</p>
<p style="margin-bottom: 0cm;">&nbsp;事务层之上的层称为事务用户(<span style="font-family: DejaVu Serif,serif;">TU</span>
)。每个<span style="font-family: DejaVu Serif,serif;">SIP</span>
实体,除了无状态代理,都是事务用户。当一个<span style="font-family: DejaVu Serif,serif;">TU</span>
希望发送请求,它生成一个客户机事务实例并且向它传递请求和<span style="font-family: DejaVu Serif,serif;">IP</span>
地址,端口,和用来发送请求的传输机制。一个<span style="font-family: DejaVu Serif,serif;">TU</span>
生成客户机事务也能够删除它。当客户机取消一个事务时,它请求服务器停止进一步的处理,将状态恢复到事务初始化之前,并且生成特定的错误响应到该事务。这由<span style="font-family: DejaVu Serif,serif;">CANCEL</span>
请求完成,它构成自己的事务,但涉及要取消的事务。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">SIP</span>
通过<span style="font-family: DejaVu Serif,serif;">EMAIL</span>
形式的地址来标明用户地址。每一用户通过一等级化的<span style="font-family: DejaVu Serif,serif;">URL</span>
来标识,它通过诸如用户电话号码或主机名等元素来构造(例如:<span style="font-family: DejaVu Serif,serif;">SIP:vision-com.com</span>
)。因为它与<span style="font-family: DejaVu Serif,serif;">EMAIL</span>
地址的相似性,<span style="font-family: DejaVu Serif,serif;">SIP
URLs</span>
容易与用户的<span style="font-family: DejaVu Serif,serif;">EMAIL</span>
地址关联。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">SIP</span>
提供它自己的可靠性机制从而独立于分组层,并且只需不可靠的数据包服务即可。<span style="font-family: DejaVu Serif,serif;">SIP</span>
可典型地用于<span style="font-family: DejaVu Serif,serif;">UDP</span>
或<span style="font-family: DejaVu Serif,serif;">TCP</span>
之上。
</p>
<p style="margin-bottom: 0cm;">&nbsp;<br></p>
<p style="margin-bottom: 0cm;">                                    
<span style="font-family: DejaVu Serif,serif;">Register,Invite, Options …</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Nat Tranversal</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Dialog Layer</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Transaction Layer</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Parsing Layer</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Transport Layer </span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">sip </span>
协议栈分层结构图</p>
<p style="margin-bottom: 0cm;">&nbsp;根据<span style="font-family: DejaVu Serif,serif;">sip
</span>
消息流向可以分为<span style="font-family: DejaVu Serif,serif;">incoming
message </span>
和<span style="font-family: DejaVu Serif,serif;">outgoing message,
incoming </span>
消息从 下到上,即<span style="font-family: DejaVu Serif,serif;">Transport
Layer → Register,Invite, Options; outgoing message </span>
消息流向与此相反。</p>
<p style="margin-bottom: 0cm;">&nbsp; <br></p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">3
.</span>
根据以上定义<span style="font-family: DejaVu Serif,serif;">,tinysip
</span>
分如下模块:</p>
<p style="margin-bottom: 0cm;">&nbsp; <br></p>
<p style="margin-bottom: 0cm;">   <span style="font-family: DejaVu Serif,serif;">1).api
</span>
外部接口,对<span style="font-family: DejaVu Serif,serif;">sip</span>
协议支持的方法的接口封装,协议栈提供的发起请求及接受请求对应的接口<span style="font-family: DejaVu Serif,serif;">,</span>
包括
<span style="font-family: DejaVu Serif,serif;">registar layer, presence
layer</span>
等上层应用,当前版本支持如下请求:</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">REGISTER
</span>
,<span style="font-family: DejaVu Serif,serif;">SUBSCRIBE(</span>
订阅<span style="font-family: DejaVu Serif,serif;">),MESSAGE(</span>
即时通信<span style="font-family: DejaVu Serif,serif;">),PUBLISH</span>
(状态展示)<span style="font-family: DejaVu Serif,serif;">,OPTIONS</span>
(查询服务器能力),<span style="font-family: DejaVu Serif,serif;">INVITE</span>
(发起请求),<span style="font-family: DejaVu Serif,serif;">Cancel</span>
(取消一个请求),</p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">BYE</span>
(结束通话)。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">2).
Nat traversal </span>
:<span style="font-family: DejaVu Serif,serif;">Nat
</span>
穿越层<span style="font-family: DejaVu Serif,serif;">,tinysip</span>
目前支持<span style="font-family: DejaVu Serif,serif;">stun</span>
,<span style="font-family: DejaVu Serif,serif;">turn</span>
穿透。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">3).Dialog</span>

会话模块,一路呼叫的唯一标识<span style="font-family: DejaVu Serif,serif;">,</span>
处于<span style="font-family: DejaVu Serif,serif;">sip
</span>
事务层之上。</p>
<p style="margin-bottom: 0cm;">   <span style="font-family: DejaVu Serif,serif;">4).parsers
</span>
,<span style="font-family: DejaVu Serif,serif;">sip</span>
消息解析,处于
<span style="font-family: DejaVu Serif,serif;">sip </span>
语法层,解析从传输层传递的数据包为协议栈理解的结构。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">5).
transactions</span>
, 事务层,事务是一个请求以及与此请求相关的所有响应组成,用
<span style="font-family: DejaVu Serif,serif;">transaction id
</span>
唯一标识,由于<span style="font-family: DejaVu Serif,serif;">sip</span>
信令一般由<span style="font-family: DejaVu Serif,serif;">udp</span>
承载,所以不能保证信息的可靠到达,所以事务层必须提供一种机制处理<span style="font-family: DejaVu Serif,serif;">udp</span>
所不能提供的功能,这里一般通过定时器及一个有限状态机来实现。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">6).
transports ,</span>
传输层,即 <span style="font-family: DejaVu Serif,serif;">udp
, TCP, TLS, SCTP socket </span>
系统调用系列,此层隐藏了所有传输层的细节,对于<span style="font-family: DejaVu Serif,serif;">incoming
sip message </span>
, 此层为<span style="font-family: DejaVu Serif,serif;">sip</span>
消息的入口<span style="font-family: DejaVu Serif,serif;">,</span>
对于<span style="font-family: DejaVu Serif,serif;">outgoing
sip message, </span>
此层为<span style="font-family: DejaVu Serif,serif;">sip</span>
消息的出口。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">4.
doubango sip </span>
协议栈使用流程:</p>
<p style="margin-bottom: 0cm;">&nbsp;<br></p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">1</span>
)<span style="font-family: DejaVu Serif,serif;">.
</span>
初始化</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">doubango
sip
</span>
协议栈依赖于<span style="font-family: DejaVu Serif,serif;">tinyNET</span>
模块,所以必须先调用<span style="font-family: DejaVu Serif,serif;">tnet_startup</span>
函数初始化,退出时调用<span style="font-family: DejaVu Serif,serif;">tnet_cleanup</span>
清除资源,初始化<span style="font-family: DejaVu Serif,serif;">sip</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;协议栈之前必须设置用户的域<span style="font-family: DejaVu Serif,serif;">(realm
</span>
参见(<span style="font-family: DejaVu Serif,serif;">1</span>
)<span style="font-family: DejaVu Serif,serif;">)</span>
及用户的私有(<span style="font-family: DejaVu Serif,serif;">IMPI</span>
(<span style="font-family: DejaVu Serif,serif;">2</span>
))及共有标别(<span style="font-family: DejaVu Serif,serif;">IMPU</span>
(<span style="font-family: DejaVu Serif,serif;">3</span>
))<span style="font-family: DejaVu Serif,serif;">,</span>
这些为<span style="font-family: DejaVu Serif,serif;">ims
</span>
引入的概念。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">(1)
realm </span>
解释:<span style="font-family: DejaVu Serif,serif;">reaml
</span>
为域名,用来作客户端认证用(<span style="font-family: DejaVu Serif,serif;">authenticate</span>
)<span style="font-family: DejaVu Serif,serif;">.
</span>
必须是一个有效的 <span style="font-family: DejaVu Serif,serif;">sip
uri </span>
如:<span style="font-family: DejaVu Serif,serif;">sip:vision-com.com.cn
</span>
,<span style="font-family: DejaVu Serif,serif;">realm </span>
为<span style="font-family: DejaVu Serif,serif;">sip
</span>
协议栈启动之前必须设置的选项,一旦协议栈启动<span style="font-family: DejaVu Serif,serif;">realm</span>
就不可以更改,如果不填写<span style="font-family: DejaVu Serif,serif;">sip
</span>
代理服务器地址,则系统会用<span style="font-family: DejaVu Serif,serif;">realm
</span>
通过 <span style="font-family: DejaVu Serif,serif;">dns NAPTR + SRV </span>
或者<span style="font-family: DejaVu Serif,serif;">DHCP
(</span>
还没实现<span style="font-family: DejaVu Serif,serif;">)</span>
动态
查找机制确定<span style="font-family: DejaVu Serif,serif;">sip </span>
服务器地址。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">(2)
</span>
用户私有标识,为用户所属网络赋予的唯一值,用来做验证,为<span style="font-family: DejaVu Serif,serif;">IMS
</span>
中的概念,如果用<span style="font-family: DejaVu Serif,serif;">doubango
sip</span>
协议栈作为普通<span style="font-family: DejaVu Serif,serif;">sip
</span>
功能,即非<span style="font-family: DejaVu Serif,serif;">IMS</span>
网络中的<span style="font-family: DejaVu Serif,serif;">sip</span>
功能,此处的<span style="font-family: DejaVu Serif,serif;">impi
</span>
意义与<span style="font-family: DejaVu Serif,serif;">sip </span>
协议栈中的验证域名相同。</p>
<p style="margin-bottom: 0cm;">&nbsp;(<span style="font-family: DejaVu Serif,serif;">3</span>
)用户公有标识,<span style="font-family: DejaVu Serif,serif;">ims</span>
网络中
一个<span style="font-family: DejaVu Serif,serif;">impi</span>
可以对应多个<span style="font-family: DejaVu Serif,serif;">impu.
</span>
对比理解,比如我们的手机只能属于一个地方,而当我们到不同外地后会有漫游,此处的<span style="font-family: DejaVu Serif,serif;">impi</span>
即是我们手机本地给的唯一标识,而<span style="font-family: DejaVu Serif,serif;">impu</span>
是手机到外地后,当地网络给的一个标识。</p>&nbsp; <br><p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">2</span>
)<span style="font-family: DejaVu Serif,serif;">.</span>
创建以及启动</p>

<p style="margin-bottom: 0cm;"><br></p>
<p style="margin-bottom: 0cm;">通过调用 <span style="font-family: DejaVu Serif,serif;">tsip_stack_create
</span>
创建协议栈, 调用<span style="font-family: DejaVu Serif,serif;">tsip_stack_start
</span>
启动,</p>
<p style="margin-bottom: 0cm;">&nbsp;完整例子:</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">tsip_stack_handle_t
*stack = tsk_null;</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">int
ret;</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">const
char* realm_uri = "sip:vision-com.com.cn";</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">const
char* impi_uri = "lideping@vision-com.com.cn";</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">const
char* impu_uri = "sip:bob@vision-com.com.cn";</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp; <span style="font-family: DejaVu Serif,serif;">//
...</span>
必须先初始化<span style="font-family: DejaVu Serif,serif;">tnet</span>
工具</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">tnet_startup();</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">// ...</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//</span>
创建协议栈,指定回调函数,参数为域名,公有及私有标识。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">stack
= tsip_stack_create(sip_callback, realm_uri, impi_uri, impu_uri,</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">TSIP_STACK_SET_PASSWORD("yourpassword"),</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//
...other macros...</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//</span>
此处初始化
其他信息,比如代理服务器地址,编码信息等。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">tsip_stack_start(stack)
//</span>
启动协议栈</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">TSIP_STACK_SET_NULL());
//</span>
用来终止传给<span style="font-family: DejaVu Serif,serif;">app_callback</span>
的参数。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">TSK_OBJECT_SAFE_FREE(stack);</span>
</p>

<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">tnet_cleanup();</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//
</span>
释放资源</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//</span>
事件回调</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">int
sip_callback(const tsip_event_t *sipevent)</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">//</span>
事件类型</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">switch(sipevent-&gt;type){</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_register:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
REGISTER */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break;</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_invite:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
INVITE */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_message:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
MESSAGE */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_publish:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{
/* PUBLISH */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>

<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">                case
tsip_event_subscribe:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
SUBSCRIBE */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_options:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
OPTIONS */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">case
tsip_event_dialog:</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">{        /*
Common to all dialogs */</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">break</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">/*
case …*/</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">}</span>
</p>
<p style="margin-bottom: 0cm;">&nbsp;<br></p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">3</span>
)<span style="font-family: DejaVu Serif,serif;">.</span>
代码分析</p>
<p style="margin-bottom: 0cm;">&nbsp;首先调用<span style="font-family: DejaVu Serif,serif;">tsip_stack_create</span>
创建协议栈
,<span style="font-family: DejaVu Serif,serif;">tsip_stack_create
</span>
内部首先检查参数是否合法,然后创建协议栈结构<span style="font-family: DejaVu Serif,serif;">tsip_stack_t</span>
,设置<span style="font-family: DejaVu Serif,serif;">realm,
IMPI and IMPU</span>
,初始化一些协议栈默认值。创建
<span style="font-family: DejaVu Serif,serif;">SigComp </span>
信令压缩模块(可选)
创建<span style="font-family: DejaVu Serif,serif;">dns</span>
处理模宽,<span style="font-family: DejaVu Serif,serif;">DHCP
context </span>
,接下来创建上面提到的<span style="font-family: DejaVu Serif,serif;">sip
</span>
协议栈各层,分别调用<span style="font-family: DejaVu Serif,serif;">tsip_dialog_layer_create</span>
,<span style="font-family: DejaVu Serif,serif;">tsip_transac_layer_create,tsip_transport_layer_create
</span>
创建会话层,事务层及传输层。至此,创建协议栈毕。</p>
<p style="margin-bottom: 0cm;">&nbsp;在真正启动协议栈之前,即
<span style="font-family: DejaVu Serif,serif;">tsip_stack_create
</span>
与<span style="font-family: DejaVu Serif,serif;">tsip_stack_start</span>
之间
可调用协议栈提供的<span style="font-family: DejaVu Serif,serif;">api</span>
初始化其他参数,
然后调用<span style="font-family: DejaVu Serif,serif;">tsip_stack_start
</span>
启动协议栈,首先启动定时器线程,这里定时器主要在事务层提供状态机功调度功能。然后设置传输层类型,设置是否用<span style="font-family: DejaVu Serif,serif;">ipsec</span>
把<span style="font-family: DejaVu Serif,serif;">sip
</span>
信令加密,
然后如果协议栈是处于客户端模式并且代理服务器地址没有设置则用认证的域名查找代理服务器的地址(用<span style="font-family: DejaVu Serif,serif;">S
NAPTR+SRV),</span>
然后设置<span style="font-family: DejaVu Serif,serif;">Runnable
</span>
回调,启动<span style="font-family: DejaVu Serif,serif;">run </span>
线程,<span style="font-family: DejaVu Serif,serif;">run
</span>
内部不断从消息队列里取消息,这里的消息是从传输层从下到上传送过来,最终串联到消息队列,然后调用协议栈创建时指定的回调<span style="font-family: DejaVu Serif,serif;">sip_callback</span>
,所有<span style="font-family: DejaVu Serif,serif;">incoming
sip</span>
消息以及媒体信息的改变最终都会走到此回调函数,此函数内部根据消息类型的不同调用相应的<span style="font-family: DejaVu Serif,serif;">handler</span>

接下来启动<span style="font-family: DejaVu Serif,serif;">nat
</span>
穿越模块,设置<span style="font-family: DejaVu Serif,serif;">stun</span>
地址。然后调用<span style="font-family: DejaVu Serif,serif;">tsip_transport_layer_start</span>
启动传输层线程,在<span style="font-family: DejaVu Serif,serif;">sip
</span>
端口<span style="font-family: DejaVu Serif,serif;">5060</span>
接收数据,最后,设置<span style="font-family: DejaVu Serif,serif;">stack-&gt;started
= tsk_true; </span>
至此协议栈启动完毕,各层在相应端口或状态机上监听,不断轮询到来的事件并处理。</p>
<p style="margin-bottom: 0cm;">&nbsp;</p>
<p style="margin-bottom: 0cm;">驱动过程:</p>
<p style="margin-bottom: 0cm;">协议栈启动完毕后,对于每一个<span style="font-family: DejaVu Serif,serif;">incoming
</span>
及<span style="font-family: DejaVu Serif,serif;">outgoing </span>
消息的
入口是不一样的,下面分别分析对于呼入请求<span style="font-family: DejaVu Serif,serif;">(incoming)</span>
及外乎请求<span style="font-family: DejaVu Serif,serif;">(outgoing)</span>
的代码流程。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">a.
</span>
呼入请求</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">1</span>
)客户端传输层在<span style="font-family: DejaVu Serif,serif;">5060</span>
端口上接收到<span style="font-family: DejaVu Serif,serif;">udp</span>
包,语法层解析成识别的<span style="font-family: DejaVu Serif,serif;">sip</span>
消息后传给事务层。</p>
<p style="margin-bottom: 0cm;"> <span style="font-family: DejaVu Serif,serif;">2</span>
)事务层锁住本地事务链表,根据<span style="font-family: DejaVu Serif,serif;">sip</span>
消息的
事务<span style="font-family: DejaVu Serif,serif;">id</span>
在事务链查找是否存在匹配的事务,没有则创建。</p>
<p style="margin-bottom: 0cm;"> <span style="font-family: DejaVu Serif,serif;">3</span>
)一旦找到事务或创建新事务完毕,释放锁并把消息传递到会话层。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">4</span>
)会话层收到<span style="font-family: DejaVu Serif,serif;">sip
</span>
消息后查找会话链,找不到则创建会话,同时根据消息类型(<span style="font-family: DejaVu Serif,serif;">invite,
ack </span>
等)设置此消息的状态机,状态机内指定具体事件的回调。</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">b.
</span>
呼出请求</p>
<p style="margin-bottom: 0cm;">&nbsp;........</p>
<p style="margin-bottom: 0cm;">&nbsp; 外部编程接口</p>
<p style="margin-bottom: 0cm;">&nbsp;为了在<span style="font-family: DejaVu Serif,serif;">android
</span>
上层通过<span style="font-family: DejaVu Serif,serif;">java
</span>
访问<span style="font-family: DejaVu Serif,serif;">doubango</span>
核心,<span style="font-family: DejaVu Serif,serif;">imsdroid
</span>
对<span style="font-family: DejaVu Serif,serif;">doubango voip
</span>
框架做了面向对象封装,根据具体模块功能抽象成具体<span style="font-family: DejaVu Serif,serif;">Java
</span>
类供应用层使用,应用层通过<span style="font-family: DejaVu Serif,serif;">jni</span>
访问<span style="font-family: DejaVu Serif,serif;">doubango</span>
核心,同时,在<span style="font-family: DejaVu Serif,serif;">imsdroid
2.0
</span>
版本中,根据<span style="font-family: DejaVu Serif,serif;">android</span>
上应用层的架构抽象出一个类库,<span style="font-family: DejaVu Serif,serif;">doubango-ngn-stack,</span>
利用此类库我们可以在<span style="font-family: DejaVu Serif,serif;">android</span>
上自己开发一些客户端应用程序,包括语音,视频,即时通信,多媒体共享,会议等应用。<span style="font-family: DejaVu Serif,serif;">Imsdroid
2.0</span>
即是构建在 <span style="font-family: DejaVu Serif,serif;">doubango-ngn-stack
</span>
上的一个具体应用。</p>

<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">Doubango-ngn-stack
</span>
原理</p>
<p style="margin-bottom: 0cm;"><span style="font-family: DejaVu Serif,serif;">doubango-ngn-stack</span>
是对<span style="font-family: DejaVu Serif,serif;">doubango
voip</span>
框架的一个<span style="font-family: DejaVu Serif,serif;">java</span>
层封装,内部通过<span style="font-family: DejaVu Serif,serif;">java</span>
本地调用技术实现<span style="font-family: DejaVu Serif,serif;">(jni),</span>
这与<span style="font-family: DejaVu Serif,serif;">android</span>
上的框架设计是相符的<span style="font-family: DejaVu Serif,serif;">(</span>

<span style="font-family: DejaVu Serif,serif;">java</span>
类库提供的摄像头功能即依赖于底层驱动,上层通过<span style="font-family: DejaVu Serif,serif;">jni</span>
访问底层驱动<span style="font-family: DejaVu Serif,serif;">)</span>
,</p>
<p style="margin-bottom: 0cm;">&nbsp;<span style="font-family: DejaVu Serif,serif;">doubango/bindings/java</span>
</p>
页: [1]
查看完整版本: Doubango voip 框架分析之tinysip 协议栈