http://sofia-sip.sourceforge.net/refdocs/soa/index.html,翻译自官网的这张网页。
Sofia SIP soa模块是一个异步的SDP Offer/Answer引擎库。库的接口在<sofia-sip/soa.h>头文件中被定义。
SIP协议会使用SDP,以及一个被称为“SDP Offer-Answer Model”的协商过程用来建立多媒体会话。RFC 3264中规定了SDP Offer-Answer的协商具体细节。
soa引擎以面向对象方式实现。缺省的soa对象实现了基本的SDP协商和基本的SIP呼叫模型。更复杂的soa对象实现可以控制呼叫模型,并且可以代替应用程序执行初始化操作。
Offer/Answer机制提供的基本功能包括
offerer可以告知它有哪些能力:
answerer告知offer中的哪一部分是可以接受的:
能力指出生成SDP参与方可以接收哪些。他们可以发送对方可以接收的任何东西。
在会话描述中还可以包括加密秘钥等信息。
更高级能力也许需要包括两次或者更多轮次的负责协商。例如,RFC 3312中定义的会话前提条件扩展。另一个两阶段协商的例子在RFC 3264的10.2节,那展示了单个编码如何被选中。
为什么选择简单的接口?它是不是太简单了而没法在你的INVITE小时中包括SDP offer或者在200 OK消息中包括SDP answer。
我们的设计目标是让程序可以遵循简单的呼叫模型,即便底层非常复杂-早期会话、预设条件、会话计时器、第三方呼叫控制等。我们倾向于向没有经验的应用程序提供简单的接口,即便底层的呼叫遵循着3GPP选择的复杂的呼叫模型。
在SIP中使用SDP Offer/Answer是在RFC 3261,RFC 3262和RFC 3311中说明。
有一张列出很多包括SDP Offer/Answer的呼叫场景的页面,http://sofia-sip.sourceforge.net/refdocs/soa/soa_sdp_oa_use_cases.html。
发送offers的规则是:
PRACK消息当未确认的100rel消息(可靠的1XX系列响应)收到后才可发送。UPDATE消息在早期对话或者已建立好的对话期间才可发送。
只能有一条INVITE请求可在对话期间被挂起。只能有一条非INVITE请求可在对话期间被挂起(在一个方向上):如果对应PRACK消息的最终响应消息没收到那么不可以发送UPDATE消息。
如果offer/answer协商过程还在进行中,可以不发送offer。下面两种情况说明Offer/answer协商过程还在继续:offer已发送但answer未收到;offer已收到但响应还未生成。
发送answer的规则:
即便已经针对INVITE发送了2XX消息,在PRACK消息中的offer或answer也必须处理。
接收answer的规则:
终端必须忽略SDP的规则、条件:
发送re-INVITE和UPDATE消息有两个目的:更新或修改SIP状态,或者更新或修改相关的会话。会话定时器扩展(还未形成RFC)是第一个目的的例子。将一个Call置成保持,或者为一个语音会话增加视频功能是第二个目的的例子。因此,针对收到的re-INVITE消息必须做一些事情。应用程序可以只是携带着之前的SDP返回200 OK消息,有时必须指出Call已处于保持状态,有时会向使用人员询问授权(增加视频)。
解决冲突的规则(两个对端试图同时发送offer):
注意由于空间限制因素
被称为set_params
set_remote
gen_offer
gen_answer
proc_answer
这是一个基本的外呼呼叫模型。
APPL NUA SOA REMOTE | | | | 0 | | | | 1 |----INVITE---->| | | 2 | |--set_params-->| | 3 | |---gen_offer-->| | 4 | | | | 5 | |-------------------INVITE(sdp offer)-->| 6 | | | | 7 | | | | 8 | | | | 9 | |< - - - - - - - - - - 180 Ringing - - -| 10 |< - - 180 - - -| | | 11 | | | | 12 | |<-------------------200(sdp answer)----| 13 | |--set_remote-->| | 14 | |--proc_answer->| | 15 |<-----200------| | | 16 | | | | 17 | |----activate-->| | 18 |<----active----| | | 19 | |-------------------------ACK---------->| 20 | | | | 21 | | | | 22 | | | | | | | |
这是一个基本的呼入呼叫模型。
APPL NUA SOA REMOTE | | | | 0 | | | | 1 | |<------------------INVITE(sdp offer)---| 2 | | | | 3 | |--set_remote-->| | 4 | | | | 5 |<---INVITE-----| | | 6 | | | | 7 | | | | 8 |- - -180- - - >| | | 9 | |- - - - - - - - - - 180 Ringing - - - >| 10 | | | | 11 | | | | 12 |-----200------>| | | 13 | |--set_params-->| | 14 | | | | 15 | |--gen_answer-->| | 16 | | | | 17 |<----active----| | | 18 | |----activate-->| | 19 | |--------------------200 (sdp answer)-->| 20 | | | | 21 | | | | 22 | |<------------------------ACK-----------| 23 |<-----ACK------| | | 24 | | | | | | | |
第三方呼叫模型只是反转下呼叫方和被叫方的Offer/Answer角色。
t APPL NUA SOA REMOTE | | | | 0 | | | | 1 | |<----------------------INVITE----------| 2 | | | | 3 |<---INVITE-----| | | 4 | | | | 5 | | | | 6 | | | | 7 |----200 OK---->| | | 8 | |--set_params-->| | 9 | | | | 10 | |--gen_offer--->| | 11 | | | | 12 | | | | 13 | |----------------------200 (off) ------>| 14 | | | | 15 | | | | 16 | |<---------------------ACK (ans)--------| 17 | |--set_remote-->| | 18 | |--proc_answer->| | 19 |<----ACK-------| | | 20 |<----active----| | | 21 | |----activate-->| | 22 | | | | | | | |
在呼叫建立完成前构建起媒体会话是可能的。在这种情况下,180 Ringing消息中会携带SDP Answer。但在200 OK消息中还是会携带同样一份SDP Answer,因为180 Ringing消息是不需要回复确认消息的、它是有可能丢失的。
如果Ringing消息丢失了,就变成了上面所述的基本呼叫模型,这样终端就有多个机会来构建媒体会话。
t APPL NUA SOA REMOTE | | | | 0 | | | | 1 |----INVITE---->| | | 2 | |--set_params-->| | 3 | | | | 4 | |--gen_offer--->| | 5 | | | | 6 | | | | 7 | |-------------------INVITE(sdp offer)-->| 8 | | | | 9 | | | | 10 | | | | 11 | |<-------------------180(sdp answer)----| 12 | |--set_remote-->| | 13 |<-----180------|--proc_answer->| | 14 | | | | 15 | | | | 16 | | | | 17 | |<-----------------200(copy of answer)--| 18 | (copy is ignored) | | 19 | | | | 20 |<-----200------| | | 21 | |----activate-->| | 22 |<----active----| | | 23 | |-------------------------ACK---------->| 24 | | | | | | | |
与上一场景一致,只不过两个场景就像是在镜子里互相看自己:
t APPL NUA SOA REMOTE | | | | 0 | | | | 1 | |<------------------INVITE(sdp offer)---| 2 | |--set_remote-->| | 3 |<---INVITE-----| | | 4 | | | | 5 | | | | 6 |---180 Ring--->| | | 7 | |--set_params-->| | 8 | |--gen_offer--->| | 9 | | (Note 1) | 10 | | | | 11 | |-------------------180 (sdp answer)--->| 12 | | | | 13 | | | | 14 | | | | 15 |----200 OK---->| | | 16 | |--set_params-->| | 17 | | | | 18 | | | | 19 | |-----------------200 (copy of answer)->| 20 | |----activate-->| | 21 |<----active----| | | 22 | |<------------------------ACK-----------| 23 |<-----ACK------| | | 24 | | | | | | | |
注1: 被叫方发送振铃音给呼叫方,被叫方将忽略呼叫方法送的媒体数据直到通话真正建立(向呼叫方法送了200 OK消息)。
这里展示的是呼叫建立完成前第二种构建媒体会话的机会。在这个场景下,180 Ringing消息会包含SDP Answer。180 Ringing消息被可靠传送,即它被一个PRACK消息确认。
t APPL NUA SOA REMOTE | | | | 0 | | | | 1 |----INVITE---->| | | 2 | |--set_params-->| | 3 | | | | 4 | |--gen_offer--->| | 5 | | | | 6 | | | | 7 | |-------------------INVITE(sdp offer)-->| 8 | | | | 9 | | | | 10 | |<-------------------183(sdp answer)----| 11 | |--set_remote-->| | 12 | |--proc_answer->| | 13 |<-----183------| | | 14 | | | | 15 | |-----------------------PRACK---------->| 16 | |<--------------------200/PRACK---------| 17 |<--200/PRACK---| | | 18 | | | | 19 | | | | 20 | |<--------------------180 Ringing-------| 21 |<-----180------| | | 22 | |-----------------------PRACK---------->| 23 | |<--------------------200/PRACK---------| 24 |<--200/PRACK---| | | 25 | | | | 26 | | | | 27 | |<----------------------200 OK----------| 28 |<--200/INVITE--| | | 29 | |----activate-->| | 30 |<----active----| | | 31 | |-----------------------ACK------------>| 32 | | | | | | | |
与上一场景一致,只不过两个场景就像是在镜子里互相看自己:
t APPL NUA SOA REMOTE | | | | 0 | | | | 1 | |<------------------INVITE(sdp offer)---| 2 | |--set_remote-->| | 3 |<---INVITE-----| | | 4 | | | | 5 | | | | 6 |-183 Progress->| | | 7 | |--set_params-->| | 8 | |--gen_answer-->| | 9 | | | | 10 | |-------------------183 (sdp answer)--->| 11 | | | | 12 | |<----------------------PRACK-----------| 13 |<----PRACK-----| | | 14 | |---------------------200/PRACK-------->| 15 | | | | 16 |--180 Ringing->| | | 17 | |---------------------180 Ringing------>| 18 | | | | 19 | |<----------------------PRACK-----------| 20 |<----PRACK-----| | | 21 | |---------------------200/PRACK-------->| 22 | | | | 23 | | | | 24 | | | | 25 |----200 OK---->| | | 26 | |----activate-->| | 27 |<----active----| | | 28 | |---------------------200/INVITE------->| 29 | | | | 30 | |<-----------------------ACK------------| 31 |<-----ACK------| | | 32 | | | | | | | |
注 1:the被叫方发送振铃音给呼叫方,被叫方将忽略呼叫方法送的媒体数据直到通话真正建立在时序26步(向呼叫方法送了200 OK消息)。
应用程序在时序13步就开始向用户提示振铃,因为它已经意识到媒体会话已经成功构建。