一个成功的INVITE请求既会创建一个基于两个用户之间的对话,也会基于请求/应答模式(offer-answer)创建一个会话。上一节讲述了如何通过target refresh 请求来修改一个现存的会话(比如,修改对话的remote target URI)。本节描述如何修改实际的会话(session)。
这个修改可以包括修改地址或者端口、增加媒体流、删除媒体流等等。这是通过发起新的INVITE请求来完成的,并且这个新的INVITE请求是基于建立会话相同的对话。在一个现存对话中发出INVITE请求就是re-INVITE。
注意:单个的re-INVITE请求可以同时更改对话和会话的参数。呼叫方或者被叫方都可以更改现存的会话。
UA检测本地媒体有效性是基于自身的策略的。但是,我们并不建议自动产生re-INVITE或者BYE请求,因为这样可能会导致网络上的阻塞。在任何情况下,如果某些消息将被自动发送,那么他们应当等待一个随机的时间间隔。
注意:上边的这些描述是特指自动产生的BYE和re-INVITE。如果用户由于媒体不兼容而挂机,UA应当正常发出BYE请求,而不视为自动产生的BYE。
UAC行为
与INVITE相同的会话描述协商offer-answer模式在re-INVITE中也一样采用。假设UAS希望增进一个媒体流,那么UAC将会创建一个新的offer包含这个媒体流,并且发送INVITE请求给他的对方。特别需要注意的是,这个会话的全描述,而不是变化部分需要传送。这个支持无状态的会话处理,并且支持错误恢复机制。当然,UAC可以发送一个re-INVITE请求而不包含会话描述,在这样的情况下,就是在这个re-INVITE的第一个可靠的非失败的应答中将会包含这个会话描述offer。
如果会话描述格式具有版本号码,那么这个协商的offer应当标志这个变化了的媒体描述版本。
re-INVITE请求中的To,From,Call-ID,Cseq,Request-URI头域应当和正常的在对话中的请求构造方法一样。
在re-INVITE请求中,UAC可以选择不增加一个Alert-Infor头域或者具有Content-Disposition=“alert”的消息体。因为UAS通常不会要求提示操作者来响应这个re-INVITE请求。
和INVITE不同的是,INVITE可以分支(分岔成为多份INVITE),re-INVITE是不会分支的,所以,只会由一个单个的终结应答。re-INVITE不会分岔的原因是因为Request-URI标志的是建立对话的UA的目标地址,而不是用户的address-of-record地址。
需要注意的是,在相同的对话中,UAC不能在上一个INVITE请求完成前(无论是那一方发起的INVITE)再次发起一个新的INVITE。
1、如果有正在处理的INVITE客户事务,TU必须等待这个事务终结或者完成,才能初始化一个新的INVITE。
2、如果有正在处理的INVITE服务事务,TU必须等待这个事务确认或者终结,才能开始处理一个新的INVITE。
不过,UA可以在INVITE事务正在处理的同时,处理一个普通的事务。也可以在一个普通事务正在处理的同时来初始化一个INVITE事务。如果UA接收到一个针对re-INVITE的非2xx终结应答,则会话参数不能改变,应当就像没有收到过这个re-INVITE请求一样。
注意:如果非2xx终结应答是一个481(Call/Transaction Does NotExists),或者一个408(Request Timeout),或者完全没有re-INVITE请求的应答(也就是说从INVITE客户事务端返回一个超时),UAC会终止这个对话。
如果UAC收到一个re-INVITE的491应答,他应当启动一个值为T的时钟,这个T的取值如下:
1、如果UAC是这个dialog ID的Call-ID的拥有者。(也就是说是UAC产生的Call-ID),那么T取值为一个到4秒的随机数,单位是10毫秒。
2、如果UAC并非是dialog ID的Call-ID的拥有者,T应当取值是0到2秒的随机数,单位是10毫秒。
当这个时钟到了,如果UAC还希望再次尝试更改会话参数,UAC应当再次尝试re-INVITE请求一次。这个意思是说,如果这个呼叫已经被BYE所挂掉了,那么re-INVITE请求就没有再发的必要。
发送re-INVITE请求的规则,以及针对re-INVITE请求产生的2xx应答而产生的ACK请求的发送规则,等同于初始的INVITE请求。
UAS行为
上节描述了区分初始的INVITE请求和re-INVITE请求的方法,以及处理对现存的对话中处理re-INVITE请求的步骤。
UAS在发送第一个INVITE的终结应答之前,收到第二个INVITE请求,并且这个请求的Cseq序列号大于第一个INVITE请求,那么就应当给第二个INVITE请求返回一个500(服务器内部错误)应答,并且必须包含一个Retry-After头域,这个头域中应当包含一个0-10秒的随机数。
如果UAS正在处理一个INVITE请求的时候又收到了一个在同一个对话上的INVITE请求必须返回一个491(Request Pending)应答给接收到的INVITE。
如果UA接收到一个对现存的对话的re-INVITE请求,那么就必须检查有关会话描述(session description)的版本标志(version identifiers),或者,如果没有版本标志,那么就需要检查会话描述的正文看看有没有变化。如果会话描述改变了,UAS必须由此调整会话参数,在调整参数的时候可能会要求用户确认。
会话描述的版本可以用来提供给会议的新近加入者,增加或者删除媒体,或者由单点会议更改成为多方会议。
如果新的会话描述是不能被UA接受的,UAS可以用返回一个488(Not Acceptable Here)来拒绝这个re-INVITE请求。这个响应应当包含一个Warning头域(用来提供给请求方,提供这个拒绝的原因)。如果UAS产生一个2xx应答,但是没有收到ACK,它应当产生一个BYE来结束这个对话。
UAS可以不产生180(Ringing)应答给re-INVITE,因为UAC一般不展示这个信息给用户。同样的,UAS可以增加一个Alert-Info头域或者一个由Content-Disposition=“alert”的消息体来应答给re-INVITE来让UAC展示这个信息。
如果UAS在2xx应答中提供了一个媒体协商offer(因为INVITE没有包含一个offer),那么它应当当作新呼叫一样的构造这个offer,遵循发送更改现有的会话的offer的限制。特别需要注意的是,这个意味着它应当包含全部的UA支持的媒体类型和媒体格式。UAS必须确保会话描述在媒体格式,通讯方式,或者其他要求对方支持的参数上,新的会话描述和旧的会话描述一样。这个可以避免对方拒绝这个会话描述。如果,UAC仍然是不能接受这个会话描述,UAC应当产生一个它能够接受的会话描述应答,并且发送一个BYE来结束这个会话。