轉自:http://www.myvoipapp.com/blogs/yxh/2015/01/23/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E6%9C%89%E9%80%89%E6%8B%A9sipml5/
有多種技術和實現方式可以將SIP與webRTC兩個世界連接起來,比如我們的miniWebPhone/miniSIPServer以及sipml5等。當然,最早出現的是sipml5以及與TA配套的webrtc網關。既然已經有了sipml5,為什么我們在設計和實現miniWebPhone(以下簡稱MWP)時,不采用現成的解決方案呢?
回答這個問題之前,請先粗略的看一下完成后的情況。sipml5的javascript文件大小超過2MB,而MWP的javascript文件是20KB。僅僅對比這兩個數據,我就認為我們的決定非常正確,sipml5實在是太臃腫了!
造成sipml5如此龐大的根本原因在於:TA的目標是在瀏覽器端用javascript來實現一個完整的SIP協議棧及呼叫處理過程。理想很豐滿,現實太骨感。
我想sipml5的設計者被HTTP與SIP之間的相似性給迷惑了。兩者的確都是基於文本格式,SIP甚至都基本遵循HTTP的消息定義,但是兩者卻有最根本的區別:HTTP本質上是無狀態、無層次的協議,而SIP是有嚴格的狀態,不僅有transaction的狀態,也有session和dialog狀態。同時SIP又是多層次的,包括transaction、session、UA等不同的層次。當你用一個無狀態、無差別的協議模式強行去套一個多狀態、多層次的模式,工作量無疑是巨大的。
而對javascript語言而言,其實並不擅長去解析或者分析類HTTP協議格式的文本。而SIP協議雖然采用HTTP協議的文本格式,但是在會話過程中,不僅僅要解析到header層面,還要進一步解析內部各種參數。這種情況就更加不是javascript擅長的。因此可以看到sipml5不得不耗費大量的處理過程去解析SIP協議的細節。javascript擅長處理什么文本格式呢?JSON!因此在miniWebPhone的設計和實現過程中,我們理所當然地采用JSON來重新定義消息格式。
讓我們再看看服務器端的設計。這又是另一個讓人很糾結的地方。由於瀏覽器不支持開UDP和TCP連接,只支持websocket連接(本質上其實還是個TCP連接),sipml5的設計者們不得不引入SIP over websocket(這個定義到現在還處於draft狀態)。而這要求客戶端和服務器兩端都必須修改才能支持。雖然websocket與TCP幾乎沒有區別,但是對SIP協議棧、SIP會話層面的處理來說,可不是僅僅重用TCP處理那么簡單,服務器端的工作量同樣巨大。
說到這里就稍微跑跑題,讓我們先吐槽一下瀏覽器的實現者們。當瀏覽器支持websocket的時候,實際上就已經支持了TCP,為什么不向應用層開放TCP連接能力?websocket本質上就是個TCP連接,只有開始的兩個握手消息是HTTP格式,后續跟HTTP一點關系都沒有。同樣,既然已經支持了webRTC,為什么不向應用層開放UDP連接能力?打開一個SRTP端口和打開一個UDP端口同樣一點區別都沒有。如果瀏覽器開放了TCP和UDP連接能力,哪怕僅僅開放UDP能力,sipml5的開發者也不用一邊哭一邊改設計,更不用搞出“SIP over websocket”這么個爺爺不疼、姥姥不愛的東西了。
讓我們回到原點。分析了這些困難和不足,既然服務器(或者網關)死活都要修改,那我們為什么不把工作量集中到一端,從而解放另外一端?因此我們放棄sipml5,重新思考:
客戶端無疑還是必須基於webRTC和javascript的。但是消息格式不再是HTTP或者SIP格式,而是JSON格式,這樣javascript就可以輕松處理。客戶端采用無狀態方式,呼叫的狀態由服務器端來維持。這就是MWP的javascript文件僅僅20KB就ok了的根本原因。
既然客戶端采用了JSON格式的消息,因此服務器端也要相應作出設計。主要工作無非就是轉碼成SIP消息格式並維持websocket連接,其他處理仍然可以沿用目前已有的SIP流程。而我們要做的,僅僅是在客戶端和SIP之間做個轉換層而已。