180还是183?

在FreeSWITCH中怎么配置回180还是183,是一个经常被问到的问题。然而,答案却远没有你想象中的那么简单。

要明白怎么配置,首先你需要明白180和183的来龙去脉。另外,你自己还要知道你要干什么。

“什么?我提的问题我当然知道我要干什么!” 也许你会这样咆哮,也许你真的知道你要干什么,但是,我不知道。所以,在你得到有效的回答之前,你得先学会让我知道。

好了,先不争论这个,我们来说说什么是180和183。

在SIP通信中,所有1开头的响应叫临时响应,常见的有100,180和183。这些响应一般是对INVITE请求的响应。使用场景是这样的:主叫用户(A)在发起一个呼叫时,会向被叫用户(B)发起一个INVITE请求,被叫用户在收到这个请求后,会给主叫用户一个响应,一般的响应流程是回100,紧接着回180,或(和)183。

INVITE

A <-----------> B

180/183

其中,100主要是信令层的,它的作用是B告诉A它收到了A的INVITE请求。关于它的作用实际也可以讲一讲的,但那就到信令的底层了,大家一般可以不用关注。

180/183的作用是B告诉A,你可以听回铃音了。

什么是回铃音?这要从更早的模拟电话时代讲起。A给B打电话,B的话机会振铃,同时A的话机回放回铃音(嘟嘟声),这样,A就知道B的话机振铃了。

所以,回铃音是模拟电话时代的事情,它的作用就是给A一个提示,对方的电话正在振铃,这样,A就可以放心地等待B接电话。当然,随着技术的进步和时代的发展,回铃音也在进步,典型地,除了嘟嘟声以外,电信运营商也会利用这段等待的时间给用户放一些音乐,甚至是广告,反正闲着也是闲着。这些音乐或广告就称为彩铃,这些是在A与B正式通话前播放的,因此不对A收费。但是由于彩铃也是资源,因此运营商可能会对B收费(B放音乐提高自己的逼格,或者放广告提升自己的形象甚至获取商业利益,收费也是有道理的)。

到了SIP时代,就需要在SIP中描述这些回铃音或彩铃,这些回铃音或彩铃是真正的声音数据,称为媒体(Media)。但为了将它与真正的媒体(即A与B真正的通话数据)相区别,将其为早期媒体,即Early Media。

SIP的全称是(Session Initiation Protocol,即会话初始协议),它仅仅是完成会话的协商,但是实际的媒体如何传输却需要另外一个协议来协商,负责描述媒体的协议称为SDP(Session Description Protocol),即会话描述协议。不过,SDP寄生在SIP中,典型地,它寄生在INVITE消息和183消息中。当A向B发起呼叫时,它需要把自己的SDP放到INVITE消息中发给B,同时,B在183消息中放入自己的SDP,回送给A。当双方都知道对方的SDP后,真正的媒体数据就可以传输了,这时,A才听到B的Early Media。

为了帮助大家理解SDP,我们再进一步。假设B接听了电话,B会响应200 OK消息,该消息也带了SDP(可能跟183中的相同也可能不同),用于建立A与B真正的通话,毕竟A给B打电话是为了跟B通话,而不是为了听Early Media中的音乐或广告。

所以,不管是183中的SDP,还是200 OK中的SDP,都是为了建立媒体服务的。区别只是一个叫Early Media,另一个叫Media。其实Early Media和Media差别除了一个是广告一个是真正的B的声音外,差别也不大,非要说差别的话,那就是运营商的收费方面有差别,因为Early Media是不收费的。

也许有人开始嫌我罗嗦了,但是,我确信,有些人真的不是从根本上理解我上面说的这些,包括一些开始嫌我罗嗦的人。不信,耐心点接着往下看。

好吧,183和200好像有点懂了,那180和183又有什么区别呢?

180和183之间就差个3。

你说我开玩笑?好吧,这些狗屎都是RFC定义的,RFC就没定义他们的区别!

不过,RFC划出道来大家就要走啊,因此,大家就都按照自己的理解实现了180和183。

现在最流行的实现方式是:180不带SDP,183带SDP。FreeSWITCH也遵守这种约定。

所以,180与183的区别不是3,也不是其它的,关键是看它们带不带SDP,即180也可以带SDP,183也可以不带SDP。为了防止思维混乱,我们下面认为180不带SDP,而183带SDP。如上面所说,这些符合绝大多数人的思维。

那么,带SDP的183我们上面讲过了,180不带SDP有什么用呢?

我们上面不是说到时代进步了吗?SIP终端属于智能终端,比以前的模拟电话可先进多了。其中的一点就是它能区别180和183。如果A的SIP终端收到183,它就协商媒体,将B端发过来的Early Media在自己的扬声器里放出来;但如果收到的是180,没有SDP就没法协商媒体,因此,B就没法给A发Early Media了。怎么办,总不能让主叫用户干等着啊,所以,A的话机在这种情况下能自己产生一个回铃音,或任何用户在A话机上设置的音乐。

好吧,到这里,不管你有没有理解,反正我把该说的都说了。

那么,言归正传,如何在FreeSWITCH中配置回180还是183呢?

FreeSWITCH是一个多功能的SIP服务器,在此,为了简单起见,我们先把它当成一个普通的SIP UA。比方说,它就是B。

在FreeSWITCH内部,FreeSWITCH的行为靠一些称为Application的功能函数控制的。当一个呼叫到来时,FreeSWITCH会查找拨号计划(Dialplan)来决定执行哪些Application。如,下面的Dialplan,当一个呼叫到来时,它首先执行Answer,给对方回200 OK,然后执行playback给对方放一段声音(从声音文件中读取),然后挂机。

<action application="answer"/>

<action application="playback" data="/tmp/hello.wav"/>

<action application="hangup"/>

如果你自己测试这段Dialplan,就会发现,FreeSWITCH不会回180也不会回183,而是直接回200。这里,answer想当于B摘机应答,在SIP中就直接回200。

当然,“纸上得来终觉浅,绝知此事要躬行。” 至于真是是不是这样你还自己自己去试,学习SIP最好的办法不是看RFC,而是照着我说的这些(以及《FreeSWITCH权威指南上的例子》)自己抓包去看。如果试着不对的话,也不要怪我,也许是你的Dialplan里边东西太多,在这几个Application前执行了你不知道的其它的Application。

好吧,那怎么让它回183呢?

在上面的Dialplan中把answer那一行去掉,就回183了。

为什么呢?

因为playback的作用是向A播放一段声音,但,在B向A发送声音前要建立媒体通道。如果有answer,FreeSWITCH会发送200 OK,带SDP建立媒体通道。如果没有answer,那么FreeSWITCH就会发送183,带SDP建立媒体通道,而这时,hello.wav的媒体内容就成了Early Media。

所以,送不送183就看你在answer前还是answer后执行playback。

那么180呢?也很简单,那就是在发送180前执行一个 ring_ready,即:

<action application="ring_ready"/>

<action application="answer"/>

<action application="playback" data="/tmp/hello.wav"/>

<action application="hangup"/>

在上面的例子中,如果你抓包,就可以看到180,但你很可能听不到回铃音。原因很简单,answer执行的太快了。尝试在ring_ready和answer之间停顿一下,就可以听到回铃音了。下面例子中的sleep可以在发送完180后暂停2秒钟(2000毫秒)再发送200 OK:

<action application="ring_ready"/>

<action application="sleep" data="2000"/>

<action application="answer"/>

我们已经知道怎么让FreeSWITCH发180还是183了,问题解决了吗?

显然没有,我知道你在实际应用中没这么简单。我们在这里把FreeSWITCH当成了B,但实际你希望FreeSWITCH是FreeSWITCH,B是B。什么意思呢?FreeSWITCH实际上是一个B2BUA,它是一个中间人,你希望的拓扑结构是这样的:

A <--------> FreeSWITCH <---------> B

哎呀呀,你看你看,我第一句话说中了吧,针对你提的问题,答案远没你想象的简单。现在,我们需要列出(猜出)你想要的各种情况了。

好吧,就算这回我猜中了,继续往下说。

中间人也是不好当的,因为,他可以有N种不同的策略。至于使用哪种策略,看B的心情,也要看FreeSWITCH的心情。啊,说白了,又是没有标准答案。所以你还是要把你想要的告诉我。如果你不告诉我,我就得猜,或者把所有N种可能的情况都告诉你。

首先,我们先看一种熟悉的情况。FreeSWITCH可以假装它就是B,这样,配置方法跟上面讲的基本一样,只是它在假装后还要假戏真做,要用bridge这个Application再去呼叫B,并把电话接通。

<action application="ring_ready"/>

<action application="sleep" data="2000"/>

<action application="answer"/>

<action application="playback" data="/tmp/hello.wav"/>

<action application="bridge" data="user/B"/>

所以在上面的配置中,至于是回180还是183,配置方式跟上面讲的一模一样,就没必要多说了。

其次,FreeSWITCH心情好,想听听B的意见。如果它即不执行ring_ready,也不执行answer,而是直接用bridge去呼叫B。

<action application="bridge" data="user/B"/>

这种情况其实也简单,那就是,如果B向FreeSWITCH回复180,FreeSWITCH就向A回180;如果B回183,FreeSWITCH就向A回183。这种情况其实就相当于FreeSWITCH不存在,所有消息都是透明的。(不过,要记住:FreeSWITCH是一个B2BUA,即它是一个中间人,它不会直接拿B回给它的180或183消息“转”给A,而是自己新产生了一个180或183消息回给A。当然,也许你不关心这个,但你说得越不清楚,我越累啊,要不然人家还会说我的回答不严谨呢。或者,万一我猜错的你问的意思呢?)

再次,FreeSWITCH跟B这两天不大对付,什么事情都拧把。B回180,FreeSWITCH就回183,B回183,FreeSWITCH就回180。

好吧,看起来是越来越复杂了。又是两种情况。

先看B回180的情况。FreeSWITCH要想给A回一个183,由于B的180中不带媒体,FreeSWITCH就要“造”一个媒体出来,因此,它想了这种一种办法,在bridge之前造一个媒体:

<action application="set" data="ringback=/tmp/ring.wav"/>

<action application="bridge" data="user/B"/>

由于在执行bridge之前还没有B,因此FreeSWITCH不知道什么时候B回180还是183。通过在bridge之前使用set设置一个变量(ringback),实际上相当于FreeSWITCH给bridge下了一个套,到了bridge阶段,不管你什么时候B回180,FreeSWITCH都会向A播放事先“造”好的回铃音ring.wav。当然,FreeSWITCH要向A发送媒体前要先用183建立媒体通道,这就完成了180到183的转换。

所以,这也是FreeSWITCH设计精巧之处——同是一个bridge,通过一个ringback变量改变了它的行为。

再看183变180的情况。

如果B向FreeSWITCH回了183,FreeSWITCH要向A回180,那就不能把媒体信息送给A。所以,实现也很简单,还是一个简单的bridge,只是,把B送来的Early Media忽略掉就行了:

<action application="ring_ready"/>

<action application="bridge" data="{ignore_early_media=true}user/B"/>

跟set不同。set是一个Application,它作用于当前的Channel,即A那一个Channel(那时候还没有B)。而{ignore_early_media=true}这种语法,在建立B端的Channel的同时,将ignore_early_media作用于B。再强调一次,FreeSWITCH是一个B2BUA,因此A跟B间的通话要产生两个Channel,即所谓的a-leg和b-leg。

在建立B通道的时候,ignore_early_media也是给bridge下了一个套。即不管什么时候B回了183,忽略它。由于我们选择了忽略,因此,为了让A仍能听到回铃音,我们用ring_ready在bridge前送一个180。严格来说,它不是183变180,因为FreeSWITCH以收到183前就已经送出了180,但是,如果你不趴在FreeSWITCH内部看,谁知道什么时候变得呢?

N种情况讲了N种了,永远都会有N+1。既然FreeSWITCH位于中间,那它能不能把B发过来的广告(彩铃)换成它自己的广告呢?能是能,但我不教你怎么做。不过,不幸的是,如果你不是特别笨的话,我上面已经教会你了……

读到这里,你认为这个问题好答吗?

时间: 2024-08-07 00:18:36

180还是183?的相关文章

IP地址、子网掩码、网络号、主机号、网络地址、主机地址

对于192.168.0.0到192.168.0.255这个网络来说,以下说法中正确的是____. 正确答案: D   你的答案: D (正确) 网段内可用来作为主机IP的范围是:192.168.0.0到192.168.0.255 Network IP是192.168.0.255 Broadcast IP是192.168.0.0 网段内的主机可以通过网卡对网卡传递数据 192.168.0.1和192.168.0.2的主机需要使用Router传递数据包 是class B等级 添加笔记 求解答(4)

中国地图 xaml Canvas

<Canvas x:Name="LayoutRoot"  Height="560" Width="700" Background="Transparent">       <Canvas  x:Name="CanvasPolygon">         <Polygon Fill="#FFE9800B" IsHitTestVisible="True

中国海域系统源代码

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="inin1(),init(),initCollections(),startTimer(),complete(),success(),inin()"  layout="ab

一款纯html5实现的人跑步动画

今天给大家分享一款纯html5实现的人跑步动画.这款动画中实现了人跑步的动画,且上面有三个按钮,分别是选择让这个跑步的拿什么武器,第一个是拿了一把剑,第二个是拿了一把斧头,第三个是不拿任保东西.效果图如下: 在线预览   源码下载 实面的代码. html代码: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink&

ascii码所有字符对照表(包含汉字和外国文字)

http://www.0xaa55.com/thread-398-1-1.html看到了0xaa55的这个帖子,想起了2年前我在51cto发的一个帖子http://down.51cto.com/data/293635 [C] 纯文本查看 复制代码 01 #include <stdio.h>  02 void main( void ) 03 { 04     FILE *stream; 05     int i,j; 06     stream=fopen("ascii.txt&quo

图像滤镜艺术---(Instagram)1977滤镜

图像特效---(Instagram)1977滤镜 本文介绍1977这个滤镜的具体实现,这个滤镜最早是Instagram中使用的 ,由于Instagram滤镜备受欢迎,因此,美图秀秀中也使用了这个滤镜,只是名字不是1977,而是1970. 原理不多说了,直接给出代码最实在,这个代码是经过优化过的,复杂的算法都已经写成了一个映射表,这样做可以大大提高效率,代码如下: private Bitmap FilterProcess(Bitmap a) { Bitmap srcBitmap = new Bit

IP段对应表

  IP总数 子网掩码 C段个数 /30 4 255.255.255.252 1/64 /29 8 255.255.255.248 1/32 /28 16 255.255.255.240 1/16 /27 32 255.255.255.224 1/8 /26 64 255.255.255.192 1/4 /24 256 255.255.255.0 1 /23 512 255.255.254.0 2 /22 1024 255.255.252.0 4 /21 2048 255.255.248.0 8

Java 8 Stream API具体解释

Java 8 Stream API具体解释 一.Stream API介绍 Java 8引入了全新的Stream API,此Stream与Java I/O包里的InputStream和OutputStream是全然不同的概念,它不同于StAX对XML解析的Stream,也不同于Amazon Kinesis对大数据实时处理的Stream.Stream API更像具有Iterable的集合类,但行为和集合类又有所不同,它是对集合对象功能的增强.专注于对集合对象进行各种非常便捷.高效的聚合操作或大批量数

Mono源代码学习笔记:Console类(六)

Unix 终端的基础知识 许多 Unix 系统使用终端.但是在今天的许多情况下,终端也许是一个运行终端程序的 PC 机.从历史上来说,不同的生产商提供了大量的硬件终端.Linux 操作系统包含一个环境变量 TERM,用来表示我们正在使用的终端的类型,如下所示: [email protected]:~$ w 16:35:13 up 6 days, 7:36, 2 users, load average: 0.62, 0.34, 0.25 USER TTY FROM [email protected