FreeSwitch编码协商

更新时间:2023-05-07 09:13:46 阅读: 评论:0

FreeSwitch编码协商
摘要
编码协商可能是⼀个令⼈困惑的主题。如果您不熟悉SDP(会话描述协议),那么这就增加了⼀层额外的神秘。如果你对这个话题感到陌⽣(或者只是对你所读过的和经历的东西感到困惑),那么希望通过这个简短的介绍,事情会变得更清楚⼀些。
⾸先,我们所说的“编解码协商”是什么意思?我们正在讨论是:每条腿将选择什么编码(codec)的处理过程。FreeSWITCH⽀持许多种编码。⼤部分的SIP终端也⽀持多种编码。⽽每条腿只能使⽤⼀种编码,因此,编码协商过程就是筛选过滤并确定最终选⽤编码的过程。这种“筛选过程”会引起混淆。这个过程是如何⼯作的?⼜如何修改它?本⽂将帮你回答这些问题。
FreeSWITCH的编码协商
FreeSWITCH⽀持两种基本的编解码协商模式:早期协商和晚期协商。早期协商意味着在FreeSWITCH和终端之间尽快协商编码,甚⾄在FreeSWITCH需要发送媒体(如铃声)或响应呼叫之前。这个过程甚⾄在来电到触发拨号计划之前就发⽣了。晚期协商意味着延迟编解码的选择处理,直到呼叫触发拨号计划之后,(能够)收集到更多的信息时才协商编码。这些附加信息可⽤于影响协商过程。我们接下来说明早期协商和晚期协商之间的区别。
考虑⼀下这个场景:
Alice有⼀台⽀持G722和PCMU的电话
Bob有⼀台⽀持PCMU和PCMA的电话
FreeSWITCH针对外呼的编码偏好列表是:G722,G722.1,PCMU,PCMA,G729
(FS的这个编码表将提供给所有的外呼通话)
观察以下两个呼叫流程,看你能否发现A腿编码协商处理的差异:
早期协商
Alice (A)拨打Bob (B)的号码
A呼叫FS并提供两种编码:G722和PCMU
FS检查A的编码表,并⽴即为A腿选择了G722编码
FS呼叫B并提供编码表:G722,G722.1,PCMU,PCMA,G729
B检视编码表,并选择PCMU
FS将A和B桥接在⼀起
FS执⾏G722和PCMU的编码转换
携带“继承编码”集的晚期协商
Alice (A)拨打Bob (B)的号码
A呼叫FS并提供两种编码:G722和PCMU
FS检视这两种编码,但没有马上选择其中的⼀种
FS呼叫B并提供可选编码G722和PCMU
B检视编码集并选择PCMU
此时FS为A腿选择PCMU编码
FS将A和B桥接到⼀块
A与B通过PCMU通信(不需要额外的编码转换)
注意A腿编码协商在时间上的差异。早期协商模式下,FreeSWITCH⽴刻选择⼀种编码(G722)。它并不等待和关⼼外呼(B腿)过程发⽣了什么,因此A腿直接选择722编码。在A腿决定编码后,FreeSWITCH通过拨号计划传递这个呼叫,最终通过⼀个bridge app呼
叫Bob的电话。为了初始化bridge,FreeSWITCH呼叫了B腿,并提供了⼀个相当⼤的编码表,这个表来源于FreeSWITCH的外呼编码偏好配置(这个表是可⾃定义的,详情后叙)。Bob的电话看到这个编码表,并从中选择第⼀个匹配的编码,在本例中就是PCMU。这时,双边的编码协商结束。
A 腿使⽤ G722
B 腿使⽤ PCMU
Bob的电话⼀回振铃信号,两条腿就被桥接在⼀起。FreeSWITCH必须将Alice的编解码器(G 722)转换为Bob的编解码器(PCMU),因为协商的结果是两种不同的编码。通常情况下,这是没问题的,但假设两部话机⽀持的编码集有交集,那你可能希望最终协商出相同的编码以减少CPU的消耗。这就是晚期协商起作⽤的地⽅。
如您所见,当FreeSWITCH为A腿选择⼀种编码⽽不知道B腿上设置了什么编码时,就很容易出现“编
码失配”。编码“不匹配”并不总是坏事,但很多时候,让两条腿共享相同的编码是件好事。使⽤晚期协商和⼀种名为“继承编码”的技术,我们可以强制A腿使⽤B腿上协商的编码。(这个过程稍后会详细描述,⽬前我们只考虑基本概念。)
在我们的第⼆个例⼦中,基本的呼叫流是FreeSWITCH创建A腿,但不是⽴即协商编解码。相反,FreeSWITCH在执⾏拨号计划之后才开始协商A腿的编码。在这种情况下,拨号计划执⾏结果是桥接Bob的电话。在桥接过程中,FreeSWITCH与Bob的电话协商了⼀种编码器即PCMU。⼀旦在B腿上选择了编码,FreeSWITCH就回到Alice的话机上,告诉它我们将在A腿上使⽤PCMU。现在呼叫的两条腿就使⽤相同的编码,这正是我们想要的。
这就是早期协商和晚期协商的区别所在。请记住:简单地启⽤晚期协商并不会⾃动强制A腿继承B腿的编码。它只是允许“继承编
码”作为协商编码的⼀种⽅式。晚期协商允许使⽤其他编码协商技巧。更多详情,请继续阅读。
早期协商
这是缺省的⾏为模式。
⼀般原则
当A腿呼叫FreeSWITCH时,它所提供的编码表将与相关SIP配置⽂件中的inbound-codec-prefs内容进⾏⽐较。⼀旦A提供的某个编码与FS允许的编码匹配,就会选择它为A腿的编码。如果A提供的编码中没有⼀个与允许的编码相匹配,则呼叫失败。
注:由于算法的原因,⼊局SDP中的编码顺序相对于inbound-codec-prefs配置的编码顺序具体优先权。
当FS呼叫B腿时,SIP配置项outbound-codec-prefs中的编码表被重新组织,⽅法是将上⾯A腿协商的编码推到表的顶部。显然,如果B不能接受编码表,结果就是呼叫失败。
例如:
A -------- GSM/PCMA/G729 --------> FS (allowing G729/PCMA/PCMU) -------- PCMA/G729/PCMU --------> B
发⽣了什么?
A向FS建议编码表GSM/PCMA/G729
FS根据其允许的编码表(inbound-codec-prefs中配置)按优先次序(SDP中的先后顺序)检查建议的编码表,并选择PCMA作为第⼀个授权编码,因此编解码表调整为:PCMA/G 729/PCMU
FS将调整后的编码表提交给B
早期协商参数
disable-transcoding
这是⼀个可以在出局SIP配置⽂件中设置的参数。
它将强制B腿(出局)使⽤A腿(⼊局)协商结果相同的编码。
若要设置此参数,请将以下⾏添加到所需的SIP配置⽂件中
<param name="disable-transcoding" value="true"/>
注意:通常误解的是,这个参数禁⽤FS中的编码转换能⼒。这是错误的。
这个参数只是更改出局编码以匹配⼊局端上的协商结果,从⽽达到不需转码的⽬的。
通过设置absolute_codec_string变量值为⼊局编码,也能达到相同的⽬的。
这个参数(仅在关闭晚期协商时适⽤)将从A腿获取协商后的编码,并将其作为在B腿的唯⼀选项(忽略任
何其他编码设置),如果B腿不能使⽤相同的编码,则呼叫失败。(笔者实测,实际上在晚期协商模式下也是⽣效的)
absolute_codec_string
这是⼀个通道变量,可以在拨号计划中设置,通常是在桥接前设置。
这个变量将强制B腿使⽤变量值指定的编码列表,⽽不⽤考虑其它任何因素。
例如:
<action application="export" data="nolocal:absolute_codec_string=PCMA,PCMU"/>
<action application="bridge" data="sofia/gateway/mygateway/mynumber"/>
或者
<action application="bridge" data="{absolute_codec_string='PCMA,PCMU'}sofia/gateway/mygateway/mynumber"/>
在后⼀种表达式中,请在编码表加上⼀对单引号,以保护参数解析的完整性,以逗号( ',' )为编码分割
符,⽐
如{var1=val1,var2=val2,absolute_codec_string='GSM,PCMU'}
注意:这个通道变量适⽤于disable-transcoding变量。换句话说,如果在出局SIP配置⽂件设置了disable-transcoding变量,并且在拨号计划中设置absolute_codec_string
为有别于⼊局编码的值,那么依然会产⽣转码开销。
codec_string
这是⼀个通道变量,可以在拨号计划中设置,通常是在桥接前设置。
The defined codec list will override the one t in the outbound-codec-prefs parameter of the outbound profile.
这个变量定义的编码列表将覆盖出局配置⽂件的 outbound-codec-prefs参数中设置的值。
以下是⼀个例⼦:
<action application="export" data="nolocal:codec_string=PCMA,PCMU"/>
<action application="bridge" data="sofia/gateway/mygateway/mynumber"/>
或者:
<action application="bridge" data="{codec_string='PCMA,PCMU'}sofia/gateway/mygateway/mynumber"/>
早期协商+禁⽤转码:
<param name="disable-transcoding" value="true"/>
如果sofia配置⽂件中设置了这个参数,那么所有呼出到B腿的信令中,将只携带A腿协商结果(只带⼀种编码,优先级最⾼的那个)
在任何⼀种情况下,A腿上的变量“codec_string”控制提供给B腿的编码集。
变量“absolute_codec_string”类似,但它暗⽰了隐式的编码列表,并将禁⽤⼀种默认⾏为--将A腿编码添加到列表中。
晚期协商(需要的参数)
inbound-late-negotiation
<param name="inbound-late-negotiation" value="true"/>
呼叫将直接执⾏拨号计划⽽不需要先查看编码。
协商将在A腿被应答后进⾏。
允许你将呼叫路由到⼀个脚本,检查SDP,并通过"codec_string"通道变量重写可接受的编码表。
<action application="t" data="inherit_codec=true"/>
inherit_codec=true (仅在启⽤晚期协商时才适⽤)将在B腿应答后触发编码协商,界时B腿的协商结果将会传递给A腿,以便两边使⽤相同的编码(如果A腿⽀持它);否则,它将从⾃⼰的列表中使⽤它所能使⽤的⼀切
只有在配置⽂件上启⽤晚期协商时,此变量才可⽤。它是⼀个可读字符串,包含主叫终端提取的所有编码。这可以很容易地从拨号计划中解析出来。
<action application="export" data="codec_string='${ep_codec_string}'"/>
代理媒体
如果启⽤代理媒体并且没有执⾏过answer app,那么将⽆法进⾏编码协商。
不相容宿端
如下所⽰,在需要混频/双腿编码不同、特别是激活media_mix_inbound_outbound_codecs变量的场景,媒体代理都不适⽤。
混频/双腿编码不同(需要转码)
如果您希望FreeSWITCH能够将两条腿与不同的编码匹配(在其中进⾏编码转换),那么需要设置⼏个变量才能使其成为可能。⾸先,您必须设置media_mix_inbound_outbound_codecs=true,既可以全局设置(通过l),也可以通过bridge变量单独设置(例如:<action application="bridge" data="{media_mix_inbound_outbound_codecs=true}sofia/gateway/....">)。
这个变量在V1.6及更⾼版本中是必须的,这是由于WebRTC⽀持,以及UDP承载SIP时SDP体量不断增长的原因。由于SDP的剪切尺⼨,使得从WebRTC到SIP转换成原始SDP变得越来越困难。基于UDP承载SIP时,⼀旦出现分包,就会破坏SIP数据包,因为UDP不会进⾏⾃动分包重组。当SIP包⼤于MTU值时,就会产⽣分包,唯⼀的解决⽅案就是减⼩包的⼤⼩。这意味着压缩报头、消除额外的报
头、或者删减不需要的编码描述以裁减SDP包体⼤⼩。
这意味着紧凑的头,消除额外的头,或只是不使⽤这么⼤的SDP消除编解码你不需要。对FS的影响是:如果没有
将media_mix_inbound_outbound_codecs设置为true,则只有A腿提供给FS的编码会被传递给B腿,这会减⼩SDP的体量,并⼤⼤减⼩了转码所带来的副作⽤。
其次,你可能希望关闭inbound-late-negotiation和inbound-zrtp-passthru(第⼆个强制第⼀个为true),或者希望在桥接之前预先应答A腿的呼叫。
最后,您应该确保这些变量,disable-transcoding、,inherit_codec、,bypass_media、proxy_media,统统设置为fal (因为这些都与我们想要实现的⽬标⽆关)。
警告
如果您的sdp包含具有不同ptime⾸选项的编码,并且ptime在sdp中指定,那么sofia将不会发送ptime属性
2010-10-18 11:47:52.234322 [WARNING] sofia_glue.c:213 Codec G723 payload 4 added to sdp wanting ptime 30 but it's already 20 (G729:18:20), disabling ptime.
说明实例
使⽤代理媒体模式时修改编码
下⾯是⼀个dialplan⽰例,它允许您更改编码⾸选顺序,同时仍然享受proxy_media模式的低cpu使⽤率。它类似
于openr/opensips/kamailio 的textops模块中的subst()。
<context>
<extension name="sdp_mangler">
<!-- Set some defaults for this call -->
<condition field="destination_number" expression="^(\d+)$" break="on-fal">
<action application="t" data="transfer_to=${destination_number} XML fail"/>
</condition>
<!-- Here we check for G729 if found we are going make sure we have it first in preference order -->
<condition field="${switch_r_sdp}" expression="/(.*)(m=audio \d+ RTP\/AVP)(?=[ \d]+18|18[ \d]+)([ \d]*)(.*)/s" break="never">
<action application="t" data="codec_mangle= 18"/>
<action application="t" data="transfer_to=${destination_number} XML public_proxy"/>
</condition>
<!-- Here we check for PCMU to add it back into the SDP if we want -->
<condition field="${switch_r_sdp}" expression="/(.*)(m=audio \d+ RTP\/AVP)(?=[ \d]+0|0[ \d]+)([ \d]*)(.*)/s" break="never">
<action application="t" data="codec_mangle=${codec_mangle} 0"/>
</condition>
<!-- Here we rebuild our SDP Moving G729 up front-->
<condition field="${switch_r_sdp}" expression="/(.*)(m=audio \d+ RTP\/AVP)([ \d]+)(.*)/s" break="nev
er">
<action application="t" data="switch_r_sdp=$1$2${codec_mangle} 101$4"/>
</condition>
<condition>
<action application="transfer" data="${transfer_to}"/>
</condition>
</extension>
</context>
重写SDP
switch_r_sdp:
<action application="t">
<![CDATA[switch_r_sdp=(sdp here)
]]>
</action>
出局禁⽤G.729b
<extension name="disable-annexB" continue="true">
<condition field="${switch_r_sdp}" expression="/(.*)(m=audio \d+ RTP\/AVP)(.*)( 18 )(.*)/s">
<action application="export" data="rtp_append_audio_sdp=a=fmtp:18 annexb=no"/>
</condition>
</extension>

本文发布于:2023-05-07 09:13:46,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/78/547062.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:编码   协商   呼叫   变量   拨号
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图