在大部分的企业客户的电话呼叫业务中,特别是从运营商到企业IPPBX端的呼入业务中,有很多不同的呼叫涉及了多种SIP流程的操作,而且其流程和实际的IPPBX,代理和SIP终端存在着非常密切的关系。排查这些技术问题耗费相当多的时间。另外,因为越来越多的用户开始使用基于开源的软交换平台和媒体服务器(例如,Asterisk或FreeSWITCH,Kamailio等),用户更容易获得技术产品,因此,他们更容易接触到企业通信平台技术,导致其入门门槛也相对比较低,技术人员可能完全不了解系统底层的流程。而且不幸的是,在实际使用过程中,很多技术人员也仅仅停留在通过系统界面配置一个呼叫业务流程,他们根本没有了解和关注真正底层的呼叫流程和其细节,而且他们对真正的SIP消息之间的互相通信过程可能并不是非常熟悉。笔者发现,其中一个原因是他们没有太多学习渠道获得一些非常直观和权威的可参考的示例。
大家经常谈论SIP呼叫业务,但是,究竟哪些SIP呼叫业务是企业用户所要求的? 关于SIP业务呼叫,RFC5359对18个最常用的SIP业务呼叫流程给出了完整的SIP流程图例,这些呼叫业务为企业用户解决方案部署提供了一个比较权威的参考。因此,笔者希望通过此文章完整列出所有18个关于SIP呼叫业务的SIP流程和其相应的图例说明,并且加以适当讨论和说明来解释这些呼叫功能中可能出现的问题或部署时应该注意到地方,以便帮助技术人员或者销售工程师能够对其产品或者周边应用终端有一个完整的比较深入的理解。提醒大家,笔者的解释和图例介绍仅针对标准的SIP流程来加以说明,完全以RFC5359为基础,不会涉及其他的设备,可能有时结合开源媒体服务器,软交换的功能加以说明是为了方便用户理解和实践。
在关于SIP呼叫服务的规范协议RFC5359中,对其18个SIP呼叫流程做了完整的流程示例演示。当然,RFC5359定义的这18个示例不是一个规范标准,这18个SIP呼叫业务仅表示根据RFC5359作者建议的最常用的18个呼叫业务,不是一个强制执行的要求。这18个最常用的SIP呼叫业务功能包括:
下面,我们对这18个最常用的SIP呼叫业务分别加以解释。另外,在所有的示例中,有几个专有说明需要提前解释:
图例中所列举的假设用户是Alice,Bob,Carol
100 Trying没有显示
Via和Max-Forwards头没有显示
From,To,Call-ID,Cseq,Contact,Route和 Record-Route和其他的头依赖于实际案例
图例中使用假设域名来说明用户域名,例如,atlanta.ex.com, biloxi.ex.com和chicago.ex.com
Tag和Call-ID替换为响应的用户关联的设置方式
RFC5359中可能存在的描述错误,请用户和官方核实
SIP呼叫业务的中文名称是笔者自己翻译,非任何官方翻译定义。因此,中文名称的准确性有待用户自己确认
1、Call Hold
Call Hold,此呼叫业务称之为呼叫保持。呼叫保持的流程实现需要经过几个步骤来完成。以下是RFC5359中的呼叫流程图例(25个flow):
这里假设,Alice呼叫Bob,呼叫接听后,Bob通过终端电话按键Hold键把呼叫设置为保持状态。然后Bob解除呼叫保持状态,Alice挂机。注意,呼叫保持事实上是一个单向的功能。但是,执行保持的一方可以对第三方停止媒体发送,这样可能导致双方无媒体流交互。旧的处理方式是连接到地址0.0.0.0。现在新的处理方式是在SDP的a=中实现,a=inactive 表示无媒体发送;a=sendonly 表示仍有媒体发送。
注意,在F10和F11中使用了渲染功能tag(rfc4235)来表示Bob终端不再渲染,例如Bob已经设置为保持状态。下面,我们通过完整的流程图附带SIP消息的说明来具体介绍呼叫保持的流程。
Alice对P1发出INVITE请求,然后通过P1呼叫Bob。
Bob呼叫振铃,Alice振铃(F4,F5):
Alice收到 200 OK(F6/F7)消息:
Alice发送到ACK确认信息到P1(F8),然后P1发送到Bob(F9)的 流程。
Bob对P1发出INVITE消息执行F10,然后,P1对Alice发出INVITE消息执行F11。这里,开始双方正式进入呼叫保持状态。读者要注意, 结合我们开始时说明的,Bob使用了渲染 tag,并且o= 的version是增加的。前面在F6,F7时仍然是2890844527,这里已经增加到了2890844528。因为是一个RE-INVITE携带了a=sendonly。
Alice接受了呼叫保持请求,并且回复200 OK(F12, F13),在SDP中携带了a=reconly。
Bob回复ACK消息(F14/Bob->P1,F15/P1->Alice)。
Bob关闭呼叫保持状态,用户通过按键Hold再次关闭保持功能。RE-INVITE中的SDP没有包括a=sendonly。执行F16(Bob到P1),F17(P1到Alice)流程。
Alice回复200 OK,发送的消息中没有带SDP的a=reconly。执行F18(Alice->P1),F19流程(P1->Bob)。
Bob回复ACK,执行F20(Bob到P1),F21(P1到Alice)流程。他们之间重新创建RTP媒体流。
Alice发送BYE消息到P1,P1发送BYE消息到Bob,执行流程F22和F23。
然后各自发送最后的200 OK,执行流程F24(Bob到P1),F25(P1到Alice)。
到此为止,整个呼叫保持流程结束。
2、Consultation Hold
Consultation Hold,我们称之为持入呼叫保持或者驻留呼叫保持。呼叫方A呼叫被呼叫方B以后,被呼叫方B将通话设置为呼叫保持状态(通过终端的Hold键),然后被呼叫方B再呼叫其他第三方呼叫方C。B挂机以后,重新对被设置为呼叫保持的呼叫方A进行操作,呼叫方A关闭呼叫保持,然后呼叫方A挂机。其流程经过38个呼叫流程的处理。
这里,读者一定要注意,驻留呼叫保持和电话转接的区别。电话转接(transfer)从概念上我们就可以识别清楚,在呼叫流程中涉及了转接方或者中间方。而驻留呼叫保持中的中间方完全没有介入其他两个被呼叫方,他们都是各自独立的呼叫。例如,在以上的图例中,Alice呼叫Bob,Bob呼叫Carol。Carol和Alice没有任何直接呼叫关系。下面,我们通过完整的流程讨论分别说明这38个呼叫流程的处理方式。
驻留呼叫保持同样在F10的流程中使用了渲染tag来表示开启驻留呼叫保持状态。事实上,从呼叫业务流程的控制来说,驻留呼叫保持相对于呼叫保持,处理流程更加简单。Alice到P1的F1,P1到Bob的F2呼叫流程,发起INVITE消息。
双方终端振铃,经过F4,F5处理流程。这里忽略了F3(Proxy到Alice的100 trying)。
Bob对Proxy执行的F6,Proxy执行Proxy到Alice的F7呼叫流程。Bob对Proxy发送200 OK,Proxy对Alice发送200 OK。
Alice到P的ACK消息,和P1到Bob的ACK消息,执行流程F8,F9。
开启RTP媒体流,然后Bob发送INVITE到P1,P1发送INVITE到Alice,执行F10,F11流程,并且表示开启呼叫保持状态,使用了渲染功能表示保持状态启用。
Alice对Proxy发送 200 OK(F12),带SDPa=reconly, 接受保持状态。Proxy发送200 OK到Bob,执行F13流程。
Bob对Proxy发送最终ACK确认,执行F14;Proxy对Alice发送ACK确认消息,执行F15流程。至此,呼叫保持状态开启(Bob/Alice之间)。
Bob呼叫Carol。Bob对Proxy发起INVITE消息(F16),Proxy对Carol发送INVITE消息(F17)。
这里,忽略了F18(100 trying)。Carol 对Proxy发送 180 振铃(F19),Proxy对Bob发送180振铃(F20)。
执行对INVITE确认流程。Carol对Proxy发送200 ok(F21),Proxy对Bob发送 200 ok(F22)。
双方最后发送ACK确认信息。Bob发送ACK消息到Proxy(F23),Proxy发送ACK到Carol消息(F24)。双方开始媒体流互通。
经过双方电话互通以后,Bob首先挂机,对Proxy发送BYE消息(F25),然后Proxy对Carol发送BYE消息挂机(F26)。
对此次呼叫进行最终确认挂机。Carol对Proxy发送200 OK(F27),Proxy对Bob发送200 OK(F28)。到此为止,Bob和Carol的呼叫正式结束。
现在开始重新开启对Alice的呼叫保持状态。重新发送INVITE消息。Bob对Proxy发送INVITE消息(F29),Proxy对Alice发送INVITE消息(F30)。
接下来对INVITE进行确认。Alice对Proxy发送200 OK,接受INVITE。Proxy对Bob发送200 OK。
Bob收到200 OK以后,对此次INVITE发送最终确认的ACK消息。Bob对Proxy发送ACK(F33),然后Proxy对Alice发送ACK(F34)。确认完成后,双方开始媒体流互通。
双方完成呼叫以后,Alice发送对proxyBYE消息(F35),Proxy对Bob发送BYE消息(F36)。
最后,确认双方的BYE消息,互相发送最后的200 OK。Bob对Proxy发送200 OK(F37),Proxy对Alice发送200 OK(F38)。到此为止,整个驻留呼叫保持的处理流程正式结束。
3、Music on Hold
Music on Hold(MoH),我们称之为呼叫音乐等待或者音乐等待。顾名思义,就是在等待过程中同时对等待方播放音乐媒体或者语音提示。通过音乐等待的方式会增加用户的体验,让用户不再感觉等待时间的烦躁。RFC7088 专门定义了语音等待的规范。IPPBX的功能热键可启用MoH功能。
音乐等待具体的实现方式是,当呼叫方(Alice)呼叫被呼叫方(Bob)后,接听以后,被呼叫方用户(Bob)设置此呼叫为等待状态,在等待状态时,通过媒体服务器对呼叫方播放音乐,或者其他的自定义的语音流。被呼叫方通过对媒体服务器或者音乐播放服务器发送一个REFER消息,携带呼叫方信息。然后媒体服务器对呼叫方发起INVITE,替换已经创建的会话中的被呼叫方。然后,媒体服务器对被呼叫方(Alice)发送音乐媒体流服务。一定时间后,Bob重新设置等待的呼叫,对呼叫方(Alice)发送INVITE消息,然后替换会话中的媒体服务器,变成Bob和Alice之间的通话。注意,这里仍然使用了渲染功能,但是在F5流程中实现,表示其等待状态开启。如果Alice拒绝对端的音乐播放,则Alice仍然会处于等待功能,但是会是静音状态(无声音)。
通过以上呼叫流程我们知道,完成音乐等待流程处理需要23个flows。其中,F5开启音乐等待功能,F12开始媒体服务器替换了Bob,媒体服务器对Alice发送音乐数据流确认。在F12的流程中使用了渲染功能,增加了对automation和byeless功能标签的支持。关于automation tag 的功能在rfc3840中定义,关于byeless tag 的支持在rfc4235中定义。rfc3840定义了媒体服务器的能力支持,rfc4235定义了自动对话事件包管理机制。具体的细节读者可以参考链接资源。以下是一个完整的音乐等待的呼叫流程,配合了SIP消息。我们根据此图例来进一步说明具体的呼叫流程。
首先是Alice对Bob发送INVITE消息(F1),表示要对Bob进行呼叫。
Bob对Alice发送180 振铃消息(F2):
紧接着,Bob对Alice发送200 OK消息(F3):
Alice对Bob发送确认ACK(F4),开始语音流传输通话。
之后,Bob把Alice呼叫设置为音乐等待。Bob重新发送一个新的INVITE携带了SDP,并且包含了一个a=sendonly,表示等待开启。执行F5流程。
然后,Alice回复Bob 200 OK消息(F6),在SDP中增加了a=reconly 表示接受等待。
Bob回复Alice确认ACK,无RTP语音流。此时,Bob准备开始执行音乐媒体流服务。
Bob对媒体服务器发送REFER消息,通知媒体服务器使用Alice替换Bob。
媒体服务器对Bob发送202 消息,表示接受这个请求(F9)。
然后媒体服务器发送NOTIFY消息(F10):
Bob发送200 OK(F11):
接下来,媒体服务器对Alice发送INVITE消息,替换Bob(F12),注意这里的SIP消息中增加了渲染功能的支持,包括automation和byeless功能标签,需要启用事件包处理,媒体服务器能力支持等渲染功能。
以上图例中没有显示contact中的渲染功能标签,但是在RFC5359中的音乐等待(F12)中的消息细节是:
F12 INVITE Music Server -> Alice
INVITE sips:[email protected];gr SIP/2.0
Via: SIP/2.0/TLS server.example.com:5061
;branch=z9hG4bK74rf
Max-Forwards: 70
From:
To:
Call-ID: [email protected]
CSeq: 1 INVITE
Referred-By:
;+sip.byeless;+sip.rendering="no"
Require: replaces
Replaces: [email protected]
;from-tag=23431;to-tag=1234567
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
Supported: replaces
Content-Type: application/sdp
Content-Length: …
Alice接受媒体服务器的请求,对媒体服务器发送200 OK(F13):
媒体服务器收到200 OK以后,对Alice发送确认ACK消息(F14),然后对Alice发送音乐媒体流,Alice现在可以听到媒体服务器对Alice播放的音乐文件。
因为已经播放媒体流流程开始,Alice对Bob发送BYE消息(F16):
Bob接受来自于Alice的BYE消息,对Alice发送200 OK(F16)。
媒体服务器对Bob发送NOTIFY消息(F17),表示媒体播放成功,并且包含一个200 OK的响应消息。
Bob对媒体服务器响应了一个200 OK(F18),表示收到此提示,同时包含了dialog的确认内容,包括了REFER需要的call-id,to tga和from tag。
到此为止,Alice被完全驻留在媒体服务器的会话中。接下来,Bob可能需要重新接听Alice的电话,那么,Bob就会重新对Alice发送INVITE请求消息(F19),然后替换会话中的媒体服务器。
Alice对Bob回复200 OK消息,表示接受替换,重新恢复到通话状态(F20)。
Bob最后对Alice回复确认ACK(F21),可以恢复正常通话状态。
双方通话以后,因为媒体服务器仍然和Alice有会话的绑定关系,因此为了结束媒体播放,Alice仍然需要对媒体服务器发送一个BYE消息,表示音乐等待播放结束(F22):
媒体服务器收到200 OK以后,对Alice发送一个最后的200 OK(F23),告知媒体服务器已经收到Alice的响应,媒体服务器正式释放被驻留在媒体服务器的会话,解除Alice对媒体服务器的绑定关系。Bob和Alice的正常通话才算成功完成,双方开始正式的通话过程。
在音乐等待的处理流程中使用了REFER的method来帮助处理音乐等待,具体的RFER规范在RFC3515中定义,读者可以查阅学习。
我们的讨论中使用了一般的IPPBX媒体服务器来替换音乐媒体服务器,用户也可以通过第三方的音乐服务的服务器端来处理音乐文件,用户使用过程中可能可以获得更多的体验。另外,很多媒体服务器也可以对其播放文件实现自定义处理。例如,在Asterisk/FreePBX或者FreeSWITCH开源平台都可以通过修改配置文件来实现自定义的MoH文件支持。
在上面的讨论中,我们仅根据呼叫流程的正常状态说明的整个MoH的处理过程。实际上,在MOH的实际部署过程中,读者会遇到很多的其他的技术问题。例如,播放文件的格式支持问题,终端兼容性问题,语音播放的带宽消耗问题,音乐播放的服务会话的管理问题,回复消息失败问题等。所以,一般的MoH功能仅在内网环境下使用一般不会出现太多问题。但是,如果通过第三方的媒体平台提供所谓比较灵活的媒体播放业务,读者一定要注意以上问题。
4、Transfer - Unattended
Transfer - Unattended或者Blind Transfer,我们称之为呼叫盲转功能。呼叫盲转简单来说,就是A呼叫B,然后B把A转接到C,B挂机。A会对B报告一个NOTIFY消息,表示成功转接。如果转接C失败,A会对B重新创建INVITE请求。以下是一个盲转呼叫示例流程图:
另外读者一定要注意,尽管被呼叫方发送了BYE消息(F9),但是Alice和Bob之间的Dialog仍然存在,这个dialog结束是根据REFER创建的订阅来决定的。订阅的NOTIFY中包含订阅状态的结果消息或者NOTIFY响应的481:
F15 NOTIFY Bob -> Alice
NOTIFY sips:[email protected] SIP/2.0
Via: SIP/2.0/TLS client.biloxi.example.com:5061
;branch=z9hG4bKnashds67
Max-Forwards: 70
From: Bob
To: Alice
Call-ID: [email protected]
CSeq: 3 NOTIFY
Event: refer Subscription-State: terminated;reason=noresource
Contact:
Content-Type: message/sipfrag
我们会根据以上图例,结合具体的SIP消息和每个呼叫流程做进一步的介绍。
首先,Bob呼叫Alice(F1):
然后Alice对Bob回复一个180 振铃(F2):
紧接着,Alice继续对Bob发送一个200 OK(F3):
Bob对Alice发送ACK确认消息,然后双方执行RTP媒体流交互,开始通话。
通话后,Alice需要把Bob电话转接到Carol第三方(F5):
Bob对Alice回复202 Accepted(F6):
然后Bob对Alice发送NOTIFY(F7),创建订阅消息包:
Alice收到NOTIFY以后,回复200 OK(F8):
紧接着,Alice会继续对Bob发送一个BYE消息(F9):此时RTP媒体流已经中断,双方不再继续通话。
Bob也根据收到的BYE消息,对Alice发送一个200 OK消息(F10),到此为止,双方语音完全断开。根据我们上面的讨论,事实上,双方仍然存在一个订阅关系,因为电话转接(Bob被转接到Carol)是否成功仍然没有进行最后的确定。接下来,Bob电话被转接到Carol。呼叫流程开始执行真正的电话转接流程。
根据以前的REFER消息,Bob对Carol发送INVITE消息,并且携带了“refer by” 的消息,说明来自于Alice的转接(F11):
Carol然后对Bob发送180振铃(F12):
紧接着,Carol对Bob发送200 OK(F13):
Bob收到200 OK以后,发送ACK确认(F14),双方正式开始通话。
现在,为了保持订阅关系的一致性,Bob需要给Alice发送一个NOTIFY(F15),通知Alice,Bob和Carol转接成功,可以正常通话。这里,也可能Alice忽略这些订阅消息。
Alice最后发送200 OK(F16),Bob和Carol进行通话。
通过16个流程的处理,一个完整的盲转才可以完成。很多IPPBX或者媒体服务器(Asterisk/FreePBX/FreeSWITCH)都支持Blind transfer的功能热键。用户也可以通过SIP电话终端屏幕上的按键来实现转接。
例如,在示例的呼叫中,Bob呼叫Alice,Alice就可以通过功能热键实现电话转接功能。例如,在asterisk中定义的盲转方式:
[featuremap]
blindxfer = #1 // FreeSWITCH使用*1实现盲转。
atxfer = *2 // FreeSWITCH使用*4实现询转。
很多情况下,电话转接失败的概率很高,因为有可能第三方处于接听状态,有可能不在线等问题,或者DTMF设置不当,转接失败。这些问题用户都需要通过配置IPPBX来进行妥善处理。
5、Transfer - Attended
Transfer - Attended,我们称之为呼叫询转。简单来说,Alice呼叫Bob,通过通话,Alice可能需要把电话转接到Carol,然后Bob把Alice设置为等待状态。Bob继续呼叫Carol,同时对Carol说明Bob需要把电话转接给Alice。同时,Bob与Carol的通话接通后,替换双方之间的会话。Carol然后对Bob挂机。然后Alice对Bob发送一个报告,说明Alice和Carol的电话转接已经成功。然后Bob对Alice挂机。
通过上面的介绍,读者可能已经发现,Transfer-Unattended(Blind Transfer)和Transfer-Attended之间有所不同的。最大的不同之处在于盲转过程中,电话转接到终端不会询问第三方是否可以转接,不关心转接到第三方是否同意或者接受这个电话转接(所以称之为“盲”)。而询转则有所不同,它和会转接到第三方提前询问,是否接受这个电话的转接,然后再进行电话转接流程(所以称之为“询”)。
另外,在上面的例子中,Bob插入了Replace 头 Refer-To URL。具体的Replace 头的规范,读者可以参考RFC3891。注意,Refer-To URL是一个Contact URL,它是询转接受方(Carol)在F10中返回的200 OK响应消息中的Contact URL。这样可以保证正确的Carol的URL可达。在F10流程中,Contact URL中的参数gr表示Contact URL是一个GRUU,它表示是一个dialog之外的全球路由方式(RFC5627)。
GRUU具有以下几个特征,首先,它定义了指定的具体的用户代理。其次,从理论上来说,可以支持全球路由方式。最后,它的存活周期很长。我们简单查看一下关于GRUU的使用方式。如果支持了GRUU的SIP终端登录的话,其请求可能被复制出几个不同的终端设备地址。
但是,如果对某一台指定的设备发送请求消息的话,请求消息会根据不同的设备URL来发送,它会专门发送到指定的终端设备,例如,sip:user@domain;opaque=user:epid:UghFocauauCHBHoLhAAA;gruu
发送到其他终端以后,那么,其他的设备就不会收到这个请求消息。
在一些关于SIP的其他应用中,例如SBC的部署环境中,GRUU也支持了公开的GRUU和临时的GRUU,区别在于其存活周期的设定不同。具体的语法示例如下:
pub-gruu=" Sip:[email protected];gr=urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
;temp-gruu="sip:[email protected];gr";
在询转过程中,如果示例中的Bob不知道Contact URL中的gruu,Bob必须自己修复这个问题。如果触发的INVITE失败,Bob必须重新使用refer带Refer-To URL来连接Carol,但是需要支持另外一个要求条件,Replace头中必须弃用Refer-To头。
以上是关于电话询转到呼叫流程图,处理过程需要27个具体的步骤。现在,我们配合详细的SIP消息来进一步解释以上流程。
首先是Alice对Bob发起INVITE请求,进行呼叫(F1):
然后,Bob对Alice发送180 振铃(F2):
紧接着,Bob对Alice发送 200 OK(F3):‘’
Alice对Bob发送ACK确认消息(F4),双方呼叫接通。
Bob对Alice发送INVITE消息,开启等待状态(F5)。
Alice对Bob发送200 OK(F6):
Bo对Alice发送ACK确认(F7):
然后,Bob对Carol发送INVITE请求消息,要求完成Alice的电话转接:
参考资料:
https://tools.ietf.org/html/rfc4579
https://www.rfc-editor.org/rfc/rfc5359.txt
https://tools.ietf.org/html/rfc7088
https://www.rfc-editor.org/rfc/rfc3515.txt
https://tools.ietf.org/html/rfc3840
https://tools.ietf.org/html/rfc3891
https://www.rfc-editor.org/rfc/rfc6665.txt
http://file.scirp.org/Html/1-1730003_32286.htm
https://arrow.dit.ie/cgi/viewcontent.cgi?
referer=https://www.google.com/&httpsredir=1&article=1005&context=ittscicon
http://www.cs.columbia.edu/~nahum/papers/sip-multicore-journal.pdf
https://support.sonus.net/display/SBXDOC51/GRUU+Support
https://www.tech-invite.com/fo-sip/tinv-fo-sip-service-99.html
www.freepbx.org.cn
https://svn.resiprocate.org/viewsvn/resiprocate/main/resip/recon/MOHParkServer/doc/MOHParkServer_User_Documentation.pdf?revision=8937&view=co
http://ijsetr.com/uploads/463152IJSETR13872-273.pdf
https://tools.ietf.org/html/rfc3665
https://tools.ietf.org/html/rfc3265
https://tools.ietf.org/html/rfc3515
https://tools.ietf.org/html/rfc4317