企业通信电话系统是企业员工和客户之间语音沟通的桥梁,虽然现在的语音业务收入处于下滑状态,但是,根据各种通信工具使用效率的调查来看,整体来说,通信效率最高的仍然是语音呼叫。因为环境的变化,语音呼叫的模式正在发生革命性的变化。这些变化的“”始作俑者或者做局者”就是目前的网络运营商和语音解决方案提供商,例如,大家比较熟悉的包括微软,Verizon,思科和ATT等。这些大鳄的经营策略的变革会引起一连串市场上的产品业务流程管理的变革。呼叫业务流程的变革可能就是这个变革的其中之一。
呼叫业务流程中,电话抓接是常用功能。因此,我们首先讨论一点和本文章主题相关的主要话题-电话转接功能。在企业电话系统或者IPPBX的通信应用环境中,员工打电话时经常会使用的一个呼叫功能就是电话的转接。电话转接的流程涉及了至少三个实体UA,他们之间的处理结果会直接影响电话是否可以成功转接的结果。有时,因为终端可能是部署在异地或者通过外网进行的呼叫,呼叫转接可能涉及到其他的网元设备,例如SBC,ALG设置等也会影响电话转接的成功率。从以上变化我们可以看出,终端,服务器端,呼叫路径等业务场景已经具备了互相分离,分布式/远程,低耦合的特点。
从更宽泛的视野来看,当前语音业务场景发生了根本性的变化,云服务和移动端的部署更加增加了电话转接成功的难度。目前语音业务基本发展模式的趋势是从传统的本地部署IPPBX,电话系统到云平台访问和UCaaS,移动端支持。这是当前绝大部分用户的使用场景。但是,无论用户场景和手机端APP如何灵活如何便捷,用户仍然需要安装手机APP来实现通话。
以前的应用场景或者部署模式基本上是网络运营商和访问提供商之间的互相分离的,水龙头的出水口始终掌握在网络运营商手中,并且语音业务增长放缓,出现了有庞大市场但是无利润的尴尬局面。另外,微软的TEAMS,思科的Webex Go,RingCentral等需要业务增长,网络运营商和服务提供商合作模式重新塑造了新的语音服务的模式。网络运营商通过多张SIM卡模式或E-SIM卡模式为经常需要通话服务的人士(例如,远程办公员工,一线工作人员,居家办公员工)提供不同的呼叫服务。
如果用户需要呼叫自己个人联系方式可以通过个人SIM卡呼叫,如果需要联系公司客户时可以通过公司或者个人购买的另外一张SIM卡呼叫。这样,服务提供商绑定了网络运营商,他们集成的服务为用户提供了更好的呼叫体验。 这种语音应用场景已经通过微软,思科,ATT等网络运营商和服务提供商的结合重新塑造了语音市场的电话流程,当然也会影响我们本文章中将要讨论的主题,那就是关于呼叫转接复杂处理的讨论和最佳实践。
在本文章中,笔者根据RFC5589所推荐的关于呼叫转接的最佳实践,和读者分享关于SIP呼叫中各种复杂呼叫转接的处理和建议,其最终目的是帮助读者了解呼叫转接的复杂环境中的流程处理以及可能面临的技术风险。
在本文章中,笔者主要针对SIP转接的一些复杂流程和转接失败,询转的其他字段支持做进一步说明,主要讨论的内容包括:转接的主要核心实体,呼叫转接实现的六个基本要求,关于REFER介绍,dialog的重用问题,基本转接流程,询转/半询转处理机制,转接失败的回退流程,转接中的Referred-By使用,多方转接的说明等几个主要分享。
核心实体和承担角色的概述本文档介绍针对SIP协议中的呼叫转接能力进行说明。呼叫机制的处理绝大部分和传统呼叫转接,基础转接以及询转相关。在呼叫转接时,同时也使用了REFER和Replaces,关于这两个methods的细节,读者可以参考RFC3515和RFC3891。从基本的转接流程来看,我们都可以知道,呼叫转接会涉及多个实体,这几个实体承担着不同的角色和功能。在转接事件中,有三个主要的核心关联实体和四个其实体承担的角色,三个核心的关联实体和角色分别是:
- 被转接方(Transferee):被转接到转接目的地的一方。
- 转接方(Transferor):发起转接的一方。
- 转接目的方(Transfer Target):一个新的呼叫转接的第三方实体方,后续可能会和被转接方进行通信。
笔者在以上的章节中介绍了关于呼叫转接的三个核心实体,以下是三个核心实体在呼叫转移过程中所承担的四个不同的角色。
- Originator或者发起方:希望呼叫接收方。此角色是会话中第一个INVITE的来源,可以是Facilitator或Screener。
- Facilitator或者呼叫协调方: 收到一个呼叫或者接收来自带外请求,通过呼叫过滤方和呼叫接收方创建通话,并将发起方桥接到呼叫接收方。通常情况下,呼叫协调方代表呼叫发起方。
- Screener或者呼叫过滤方:收到呼叫,这个呼叫最终目的地是呼叫接收方。如果条件合适,将呼叫来电转接给呼叫接收方。通常情况下,呼叫过滤方代表呼叫接收方。
- Recipient或者呼叫接收方,最终和呼叫发起方进行呼叫关联的一方。
呼叫转接实现的六个基本要求
- 在SIP会话中的任何一方必须能够在该会话的任何时刻将该会话中的任何其他一方进行转接。
- 作为转接事务的一个部分,一定不能从会话中移除呼叫转接方和被转接方。这里需要注意,此要求可能和一般交换机(PBX)所期望的处理体验方式不同。有的需求存在这样的要求,客户端可以保持当前的体验。在实际生产环境中,如果没有这个要求,某些形式的场景(例如转接失败时播放的回铃音)将会丢失。
- 呼叫转接方必须知道呼叫转接是否成功。
- 呼叫被转接方可以将一个新的dialog插入到现存的dialog中。
- 呼叫转接方和被转接方应该指示实现呼叫转接所需要的基本要求。
- 呼叫转接方应该向被转接方提供转接目的地,并且被转接方根据所提供的转接信息进行转接操作。为了满足这个要求,转移操作可以通过规范方式为三方临时会议进行支持,此细节再后续章节进行讨论。
使用REFER实现呼叫转接
实现呼叫转接的处理流程可以通过REFER method来实现支持,Refer来自于RFC3515的规范,呼叫转接发起方启动一个Refer method,这样会导致接收方向转接目的地发起一个INVITE请求。这里要注意,一个成功的REFER事务不会终止呼叫转接方和被接收方之间的会话。如果这些参与方希望终止它们的会话,它们必须通过后续的BYE请求来结束会话。转接方和被转接目的地之间已协商的媒体不会受被转接方和被转接方之间已完成的协商的媒体的影响。具体来说,由转接方发出的INVITE将具有与接收方自己发起该INVITE时相同的会话描述协议(SDP)主体。此外,REFER method不会改变呼叫转接方和被转接方之间媒体流的属性。
代理可以通过额外信令来修改会话媒体。例如,他们可以使用SIP使用re-INVITE重新发起邀请或使用会议框架[RFC4353]中描述的会议扩展来实现支持。
为了执行呼叫转移,转接方和被转接方可以重用现有的dialog,这个现有的dialog是通过INVITE来发送REFER。这样的操作会导致两个使用场景分享一个dialog-一个是为了INVITE使用和一个订阅使用。此过程的呼叫流程如下:
但是,读者应该注意,本文档中描述的方法中避免使用dialog的重用。这样操作会出现很多问题,具体的问题读者参考RFC5057-6章节,避免重用dialog。当然,重用dialog有一些需求,重用现有dialog的目的包括:
- 无法确保在新dialog中的REFER能够到达涉及转接的特定终端。可能有很多的因素,包括实现方式和INVITE和REFER之间代理路由的变化,都可能导致REFER发送到错误的位置。将REFER发送到现有的dialog中可以确保它能够到达已经开始通信的终端上。
- 目前仍然缺乏比较清晰的流程,如何将现有的INVITE使用场景与在新dialog中到达的REFER进行关联处理,可以非常明显地看出,当REFER出现在INVITE使用的dialog中时,这里的关联是非常必要的。
- 对于授权dialog之外的REFER也存在一些问题。大多数部署环境中,REFER的授权策略是基于INVITE的授权策略。
以上的这些问题有一定的解决办法。全局可路由的UA URIs(GRUUs)[SIP-GRUU]可用于解决问题1。问题 2可以使用[RFC4538]中定义的Target-Dialog头字段来解决。在短期内,这个解决方案可以重用现有的REFER授权策略。因此,如果被转接方支持Target-Dialog扩展并且转接方知道Contact URI在dialog之外可路由的话,那么REFER应该发送到新的dialog中。如果不知道联系人URI的属性或者不知道是否支持Target-Dialog扩展,REFER应该发送到现有的dialog中。被转接方必须准备接收在dialog中的或dialog外的REFER。转接方可以通过验证方式来验证Contact URI是否支持可路由,可以发送OPTIONS并接收响应来验证或满足GRUU规范中描述的属性来确认是否可路由。
再次说明,本文档不是按照准确的规定流程和示例来解释,而是希望通过流程说明来解释最佳实践的基本原则,以实现转移功能。
在下面的大多数示例中,转接方设置在atlanta.example.com域,被转接方设置在biloxi.example.com,而转接目的地方设置在chicago.example.com域。
基本转接
基本呼叫转接通过呼叫转接方提供呼叫转接目标的contact给呼叫转接接收方构成。被转接方尝试使用contact来创建会话,并将尝试报告结果给呼叫转接接收方。呼叫转接方和呼叫接收方之间的信令关系不会终止,因此如果无法联系到转接目的地目标的话,呼叫通话是可以恢复的。这里要注意,转接目标的contact信息已经暴露给了呼叫接收方。已提供的contact可以在将来用来进行新的呼叫通话。
在基本呼叫转移的流程中,多个参与方应该指示对REFER和NOTIFY method的支持,指示方式是通过在INVITE、200 OK所对应的 INVITE和OPTIONS消息的Allow头字段增加这样的支持。参与者也应该在Supported头字段中指示对Target-Dialog的支持。
在以下基本呼叫转接示例中显示了每个消息的第一行。图例中的的第一列显示了该特定消息中使用的dialog。在这些图例中,媒体通过re-INVITE对媒体进行保持管理,但其他机制(例如,在用户代理中进行多个媒体流混音或使用会议扩展协议)也是一种有效的机制。
以下每个流程都显示了在REFER处理过程中,呼叫转让方和被转接方保持连接的dialog。这样处理的好处是可以提供最大程度地灵活性,快速恢复故障,但是这样的保持状态不一定是必要的。如果呼叫转接方的代理终端不希望参与剩余的REFER处理过程的话,并且也没有意图帮助恢复转移失败后的处理流程,它可以在REFER事务完成后立即向被转接方发送一个BYE请求。这个转接流程有时被称之为“盲转”。
以下图例中显示了被抓接方使用GRUU并且支持target-dialog扩展,还将此消息发送给了转接方。因此,转接方在INVITE dialog之外发送一个REFER。被转接方能够针对现存的dailog,使用在REFER中的target-dialog头字段进行匹配。这里要特别注意关于dialog的描述和dialog的完整性。
成功的呼叫转接流程,这里读者需要注意F3和F5的处理。
以下是呼叫被成功转接的处理流程:
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee
REFER sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKna9
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: tdialog
Refer-To: <sips:transfertarget@chicago.example.com> // 转接目的地地址
Target-Dialog: 090459243588173445;local-tag=7553452 // 携带了tdialog
;remote-tag=31kdl4i3k
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F4 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 73 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, tdialog
Event: refer
Subscription-State: active;expires=60
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 100 Trying
F5 INVITE Transferee -> Transfer Target // 执行被转接方和转接目的地的通信
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas41234
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=j3kso3iqhq
Call-ID: 90422f3sd23m4g56832034
CSeq: 521 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F6 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 74 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, tdialog
Event: refer
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
带有dialog重用的呼叫转接
某些呼叫转接的执行场景中,转接方不知道被转接方的contact URL属性,也不清楚被转接方是否支持Target-Dialog头字段。因此,REFER需要在INVITE dialog内发送。以下流程就是重用dialog1的示例流程。
带有dialog重用的呼叫转移流程:
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee // 无Target-Dialog 支持
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKna9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=7553452
From: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
Call-ID: 090459243588173445
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Refer-To: <sips:transfertarget@chicago.example.com>
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F4 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29888 INVITE
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer
Subscription-State: active;expires=60
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 100 Trying
F5 INVITE Transferee -> Transfer Target // 转接到目的地地址
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas41234
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=j3kso3iqhq
Call-ID: 90422f3sd23m4g56832034
CSeq: 521 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Content-Type: application/sdp
Content-Length: ...
F6 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29889 INVITE
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
通过以下INVITE和REFER method 可以两者之间的不同。在重用dialog的呼叫中,INVITE中没有关于tdialog支持的指示,但是在不重用dialog中,我们可以看到支持的Target-Dialog。另外,发送REFER的方式也有区别,在不重用的处理流程中,直接指示了Target-Dialog地址,而重用的抓接中直接使用了refer-to, 没有Target-Dialog支持。还有,重用dialog的呼叫流程中,Call-ID: 090459243588173445一直是第一个dialog 1的Call-ID,而另外一个则是dialog 2的Call-ID。
转接失败处理
以下两个示例展示了呼叫转移失败的示例。在转移呼叫失败发生后,转接方将被转接方取消保持状态,然后重启会话。以下是一个转接目的地忙,导致转接失败的处理流程。
转接目的地未应答,转接失败的处理流程:
询转呼叫处理流程
询转呼叫是指在实际转接发生之前,呼叫转接方和被转接目的地之间涉及了一次会话流程。这是通过上述所描述的SIP保持和转移来实现的。对于转接方来说,一个比较好的功能是让转接目的地方知道这个会话是与期望的转接方相关。因为许多UA显示display 名称,具体来说是通过在From头字段中display name为用户显示其名称,询转INVITE请求可以包含一个字符串来显示其身份,例如,”Incoming consultation from Transferor with intent to transfer Transferee”,并且包含了呼叫转移方和被转接方的显示名称。通过这样的显示方式,可以极大方便呼叫转接的处理。
呼叫转接目的地号码是否显示给第三方也是我们需要讨论的问题。一种处理方式是将暴露呼叫转接目的地,另外一种方式是保护或者隐藏呼叫转接目的地号码。
关于暴露转接目的地的处理讨论
呼叫转接方首先将被转接方设置为呼叫保持状态,然后与转接目的地创建一个通话来提醒它们之间将发生一个呼叫转接,并且结束和呼叫转接目的地方的连接,按照以上询转方式进行呼叫转接处理。这种处理策略的变化可以用来提供和当前PBX和Centrex用户所预期的那样的用户体。为了提高流程的简洁度,非REFER事务已经合并为一个指示标识,使用箭头显示其请求的方向。
保护转接目的地号码的处理讨论
呼叫转接方将被转接方设置为呼叫保持状态,和呼叫转接目的地方创建一个通话,然后反转它们的角色,将原始的呼叫目的地方切换为原始的被转接方。这样做的好处是隐藏了原始转接目标的方的信息,使得原始被叫方不知道其目的地方的真实信息。另外,被转接方的体验会与当前系统体验有所不同。被转接方实际上是被转接目的地方执行了一个电话回拨。当然,这种最简单的保护转接目的地的实现方式存在一些问题,其中问题之一就是,被转接方正在接收一个来自转接目标的一个新的呼叫。
另外一个局限性是除非被转接方的代理支持一种可靠的方式,能够将这个新的呼叫与其已经与转接方所进行的呼叫成功关联起来,否则被转接方将不得不用另外一个状态上提醒这个新的呼叫。如果没有这样的状态界面的话,或者其他类似于呼叫等待的用户界面的话,被转接方可能会卡在对被转接目的地方符合一个忙状态的处理中,可能发生转移失败的概率增加。当然,这里也涉及了很多的方式会出现一些相关性的问题。例如,在Refer-To URI头字段参数中提供dialog参数,这个dialog参数可以作为一个头字段参数。具体使用方式参考RFC3891,在RFC3891-7章节的示例中所使用的这种替换机制就可以很好地解决这个问题。
针对以下流程中,dialog1表示dialog identifier 1, 这个标识符1由dialog1中的 Replaces 头的参数组成。在RFC3891中包括了Call-ID、To-tag和From-tag。这里要注意,作为处理Replaces 头的直接输出结果,被转接方代理发送一个BYE给转接方代理。
呼叫转接方从被转接方和转接目标目的地的200 OK响应所包含的Supported字段中知道被转接方和转接目标目的都支持Replace头字段。
在这个使用场景中,被转接方利用了GRUU作为contact URI,具体原因已在以上章节中已讨论。
请注意,这里重用了SIP的关于Torture Test Messages(RFC4475规范)中的约定惯例,特别是<allOneLine> tag 。
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31431
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=384i32lw3>
Content-Type: application/sdp
Content-Length: ...
F4 200 OK Transfer Target -> Transferor
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Content-Type: application/sdp
Content-Length: ...
F5 REFER Transferor -> Transfer Target
REFER sips:482n4z24kdg@chicago.example.com;gr=8594958 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: tdialog
<allOneLine>
Refer-To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha
?Replaces=090459243588173445%3Bto-tag%3D7553452%3Bfrom-tag%3D31431>
</allOneLine>
Target-Dialog: 592435881734450904;local-tag=9m2n3wq
;remote-tag=763231
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F6 INVITE Transfer Target -> Transferee
INVITE sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS client.chicago.example.com;branch=z9hG4bKnaslu84
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transfertarget@chicago.example.com>;tag=341234
Call-ID: kmzwdle3dl3d08
CSeq: 41 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Replaces: 090459243588173445;to-tag=7553452;from-tag=31431
Content-Type: application/sdp
Content-Length: ...
呼叫询转
转接方将被转接方设置为呼叫保持状态,然后和转接目的地方建立一个通话来提醒它们要进行呼叫转接,而且将转接目的地也设置为呼叫保持状态,然后通过在Refer-To头字段中的已转义Replaces头字段进行呼叫转接处理。这种转接方式也是当前PBX和Centrex用户期望支持的另外一种常见的服务。
除非对这个URL存疑或者已经知道URI无法在对话之外进行路由,呼叫转接方应该将转接目的地的Contact的URI作为一个Refer-To URI来使用。否则应该使用转接目标的记录地址(AOR)。换句话说,呼叫转接方应该使用同样的URL和呼叫转接目的地建立会话。万一已触发的INVITE被路由到了不同的用户代理,而不是转接目的地代理的话,则应该在已触发的INVITE中使用Require: replaces头字段。(这样做的目的是为了防止不正确的用户代理(不支持Replaces)忽略了Replaces,并且未进行dialog匹配而应答了INVITE请求。)
在SIP代理或者路由服务的流程中,可能出现已触发的INVITE请求抵达同样的用户代理地址;因此,为了防止已触发的INVITE请求到达相同的用户代理情况发生,需要设置一定的机制来应对这种情况。如果发生这种情况,触发的请求将以超时、403、404等错误失败结果进行响应。然后,被转接方可以通过Refer-To URI设置为Contact URI重试转接。
呼叫流程如下:
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31431
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=384i32lw3>
Content-Type: application/sdp
Content-Length: ...
F4 200 OK Transfer Target -> Transferor
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Content-Type: application/sdp
Content-Length: ...
F5 REFER Transferor -> Transferee
REFER sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Require: tdialog
<allOneLine>
Refer-To: <sips:482n4z24kdg@chicago.example.com;gr=8594958?
Replaces=592435881734450904%3Bto-tag%3D9m2n3wq%3Bfrom-tag3D763231>
</allOneLine>
Target-Dialog: 592435881734450904;local-tag=9m2n3wq
;remote-tag=763231
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F6 INVITE Transferee -> Transfer Target
INVITE sips:482n4z24kdg@chicago.example.com;gr=8594958 SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnaslu82
Max-Forwards: 70
To: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
From: <sips:transferee@biloxi.example.com>;tag=954
Call-ID: kmzwdle3dl3d08
CSeq: 41 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Replaces: 592435881734450904;to-tag=9m2n3wq;from-tag=763231
Content-Type: application/sdp
Content-Length: ...
一方不支持REFER时的恢复机制讨论
对于某些场景来说,如果不考虑保护转接目的地或暴露转接目的地这些问题的话,当只有呼叫转接方和另一方支持REFER时,可以通过询转的呼叫保持设置来完成呼叫转接。读者需要注意,可能会返回405 Method Not Allowed来替代,而不是501 Not Implemented的响应。
询转处理中Contact URI是一个未知无法路由的讨论
根据RFC3261的要求Contact URI必须是支持可全局路由的,甚至于在dialog之外的路由。但是,因为RFC2543用户代理定义局限性和一些架构(NAT/防火墙穿越、监控代理、应用层网关(ALGs)等设置),这一要求也可能无法满足。因此,如果Contact URL是已知的在dialog外部可路由的情况下,应该使用以上图例中的询转方式。
以下图例显示了一种使用场景,其中转接目的地的Conatct URI是在dialog之外的,是一个不可路由的URL,因此已触发的INVITE被发送到转接目的地的AOR地址。
F1 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bK76
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transfer Target -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transfertarget@client.chicago.example.com>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=a6c85cf
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314160 REFER
<allOneLine>
Refer-To: <sips:transfertarget@chicago.example.com?Replaces=
090459243588173445%3Bto-tag%3D9m2n3wq%3Bfrom-tag%3D763231
&Require=replaces>
<allOneLine>
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Length: 0
F4 INVITE Transferee -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnaslu82
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=954
Call-ID: 20482817324945934422930
CSeq: 42 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Replaces: 090459243588173445;to-tag=9m2n3wq;from-tag=763231
Require: replaces
Content-Type: application/sdp
Content-Length: ...
F5 NOTIFY Transferee -> Transferor
NOTIFY sips:transferor@pc33.atlanta.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:transferee@biloxi.example.com>;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 76 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer;id=98873867
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
以下图例显示了一个转接失败场景,其中AOR URI无法抵达呼叫转接目的地地址。因此,转接方使用Contact URI进行重试并且成功转接。
请注意,这里仍然不能保证会抵达正确的终端地址,并且第二个REFER的结果也可能是失败的。在这种情况下,转让方可以回退到无询转接状态或者完全放弃转接。因为,在一个dialog中发送了两个REFER,这样导致流程中创建了两个不同的订阅服务,转接接收方需要使用Event事件头字段中的id参数来区分这两个订阅的通知提示。
半询转呼叫处理
在前面的关于询转处理的流程中,转接方在会话创建之前可能决定尝试终止和转接目标的联系。通常情况下,这样的操作可以结束呼叫场景。但是,在某些情况下,转接方可能希望继续进行转接的操作。例如,转接方可能希望完成呼叫转接,并且知道被转接方最终会与转接目的地的语音信箱服务进行通信。一些PBX系统支持这个功能,有时称为”半询转”功能,它实际上是全询转和盲转的混合体。以下示例展示了一个半询转的呼叫流程。在这个流程中,转接方的用户代理在转接方挂断电话后仍然将转接视为询转流程。读者一定要请注意,必须在应答时向转接目的地目标播放媒体流,否则转接目的地目标可能会挂断电话,这样会导致转接操作的失败。
以下两个图例显示了另外两种可能发生的半询转方式的转接呼叫流程。然而,由于竞争条件存在,不推荐使用这些呼叫流程。在这两种流程中,当转接方挂机后,转接方试图通过向转接目的地发送CANCEL来恢复盲转移状态。这样的操作可能导致两种竞争条件出现。
一种是转接目的地在CANCEL之后仍然接听呼叫,导致盲转失败。这种竞争条件可以通过转接方设置为等待状态,等待发送REFER,直到获得从转接目的地方返回的487响应。如果返回的不是487响应而是200 OK的话,则说明转接目的地已经接听了询转。在这种情况下,必须按照以下第一个图例中的呼叫流程进行操作。在这个流程中,转接方必须向转接目的地目标播放一个媒体流来防止转接目的地挂机或者可能出现的转接失败。这也就是说,转接目的地的操作人员将听到一个静音,这个静音时长是从当操作人员应答呼叫(消息F1示例)直到转接流程完成(F3流程示例,并且操作人员与转接接收方通话除非按照(F2)播放了媒体)。
第二个竞争条件是发生在以下图例中,如果在收到CANCEL并返回487响应后,转接目的地目标终端进入“Off hook”。对盲转来说,这样的竞争条件可能导致一个486 Busy Here响应。因此,本文档中不推荐在半询转呼叫流程中使用CANCEL,以避免这些竞争条件的发生。
询转呼叫回退到基本转接流程的讨论
有时,可能尝试盲转会失败,这样的转接需要回退到基本转接状态中。以下流程显示了在INVITE中使用Require: replaces,这个INVITE是由转接方发送给转接目的地的一个INVITE请求来实现。
在以上处理流程中,呼叫流程显示了在转接方发送给转接目的地的INVITE中使用Require: replaces,其中转接方在发送INVITE给转接目的地时的意图已获知完成了一个询转接处理流程。因为转接目的地不支持Replaces,因此,INVITE被拒绝,并且返回420 Bad Extension响应,转接方立即从询转状态切换为基本转接流程状态。
以下图例中说明了使用OPTIONS的场景,显示了在转接方和转接接收方未明确指示支持REFER和在Allow和Supported头中的Replaces头字段时,并且当发送一个INVITE给转接目的地方时,转接方无意执行询转。
在dialog 1中,转接方通过使用OPTIONS确认了被转接方确实支持REFER和Replaces。因此,转接方开始执行抓接呼叫,执行方式是通过将被转接方设置为呼叫保持,并且呼叫转接目的地目标。在dialog 2中使用OPTIONS,转接方确定转接目的地既不支持REFER也不支持Replaces,因此无法进行呼叫转接流程。转接方通过发送BYE结束dialog 2,然后使用转接目的地的AOR URI对被转接方发送REFER。
通过Referred-By的转接呼叫处理
在我们以上的示例讨论中,转接目的地没有确定的转接方信息,甚至于在一些场景中,转接已经发生,但是转接目的地也没有确认的转接方信息。RFC3892对转接方提供了一种的Referred-By机制,通过这种机制,被转接方可以让转接目的地知道转接初始方的信息。
最简单安全的方式是在REFER中包含Referred-By头字段,然后拷贝到已触发的INVITE中。但是,更安全的机制是使用了Referred-By安全令牌,这个令牌是由转接方生成,签名的令牌,通过消息体传输给被转接方和转接目的地。在以下示例中显示了F5中的Referred-By和消息体,包括在了F6的已触发的INVITE中。这里没有显示 (S/MIME)。
作为即时会议的转接处理讨论
转接的形式中还包括一种作为即时会议的方式进行的转接。Bob为Alice和Carol执行了一个询转。为了让Alice和Carol确保双方是一个完全被通知的状态,维持一个转接操作,Bob这里执行了一个即时会议的focus-会议中心角色(RFC4579),并且支持这个即时会议,会议参与方包括了Bob,Alice和Carol。这里的Alice和Carol订阅了这个会议,他们都可以获知准确的会议状态,转接操作完成后,Bob删除这个会议。
多方转接处理流程讨论
有时,一些转接可能涉及到多个被转接方终端代理,经过多次处理才能实现最终转接。以下示例指示了Originator对Facilitator发起了一个呼叫,Facilitator再可以通过Screener,将呼叫发送到Recipient,Recipient的信息暴露给Originator对Facilitator。注意,这里仅提供了一个关于REFER的澄清的语义,不推荐在具体部署中使用。
总结
电话转接的处理一直是IPPBX的重要话题。本文档是一个关于呼叫转接的推荐规范,是一份关于SIP电话抓接的最佳实践类的分享资料。在本文章中,笔者首先讨论了呼叫转接的主要核心实体,呼叫转接实现的六个基本要求,然后介绍了关于REFER介绍,dialog的重用问题,基本转接流程,询转/半询转处理机制,转接失败的回退流程,和关于转接中的Referred-By使用,多方转接的说明概论。
文档的技术说明属于在应用中推荐的部署方式和应用细节,可能在很多的用户场景中不是非常重要,但是为读者提供了更多关于呼叫转接处理的视角,希望对关于呼叫转接处理比较关心的用户有所帮助。
另外,笔者这里没有涉及网关中关于呼叫转接的处理和其他的操作,也没有更多涉及到具体的IPPBX或者厂家产品的定义流程的说明,这些也涉及呼叫转接的流程,希望读者自己查阅实战学习。
参考资料:
https://www.rfc-editor.org/rfc/rfc5589.html
www.asterisk.org.cn
www.sip.org.cn
www.dinstar.cn
https://www.rfc-editor.org/rfc/rfc5057
https://www.rfc-editor.org/rfc/rfc5373
https://www.gminsights.com/industry-analysis/voice-over-internet-protocol-voip-market
作者:james.zhu
来源:SIP实验室
原文:https://mp.weixin.qq.com/s/j2ItyO39H5zsvW9Qnr_Ncg
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。