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發過來的廣告(彩鈴)換成它自己的廣告呢?能是能,但我不教你怎么做。不過,不幸的是,如果你不是特別笨的話,我上面已經教會你了……

 

 

讀到這里,你認為這個問題好答嗎?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM