WebRTC 是一個支持網(wǎng)頁瀏覽器進行實時語音對話或視頻對話的技術(shù),谷歌 2010 年以 6820 萬美元收購 Global IP Solutions 公司而獲得的一項技術(shù)。2011 年 5 月開放了工程的源代碼,在行業(yè)內(nèi)得到了廣泛的支持和應用,成為下一代視頻通話的標準,該項目的最終目的主要是讓 Web 開發(fā)者能夠基于瀏覽器 (Chrome\FireFox\…)輕易快捷開發(fā)出豐富的實時多媒體應用,而無需下載安裝 任何插件,Web 開發(fā)者也無需關(guān) s 注多媒體的數(shù)字信號處理過程,只需編寫簡單 的 Javascript 程序即可實現(xiàn),W3C 等組織正在制定 Javascript 標準 API,目前是 WebRTC 1.0 版本,Draft 狀態(tài);另外,WebRTC 還希望能夠建立一個多互聯(lián)網(wǎng)瀏 覽器間健壯的實時通信的平臺,形成開發(fā)者與瀏覽器廠商良好的生態(tài)環(huán)境。同時, Google 也希望和致力于讓 WebRTC 的技術(shù)成為 HTML5 標準之一。
介紹完 webRTC 的歷史,那么我們?nèi)绾卧?HTML 頁面中建立一個 RTC 應用呢?
首先,向瀏覽器申請調(diào)用瀏覽器的權(quán)限,使用navigator.webkitGetUserMedia()或 MediaDevices.getUserMedia()。比較尷尬的一點是,javascript 接口由 Mozilla 社區(qū)開發(fā)的,所以火狐瀏覽器跟進的比較快,而谷歌還在沿用上一套接口,前者 在 Mozilla 社區(qū)已經(jīng)標記為不建議使用的接口,不過鑒于目前 webkit 內(nèi)核的瀏覽 器比較多,所以本文以前者的接口為主,并且 webkit 內(nèi)核版本要在 36 以上,但 在 webkit47 以上的版本調(diào)用媒體設(shè)備的時候必須用 https 協(xié)議,用來保證安全, 而 firefox 要求相對沒有那么嚴格,由于 firefox 瀏覽器在國內(nèi)是不需要翻墻更新 的,所以只需要更新到最新版本,那么支持就沒有什么問題。
navigator.webkitGetUserMedia()方法需要四個參數(shù),第一個參數(shù)直接傳入 navigator 對象,第二個參數(shù)為調(diào)用的硬件{audio: true,video:true},如果不需要調(diào)用 攝像頭,則 video 為 false,不寫則默認為 false。第三第四個為正確和錯誤回調(diào)函數(shù)。
如: getUserMedia.call(navigator, {audio: true,video:true}, resolve, reject);
第二個參數(shù)為成功回調(diào)函數(shù),第三個參數(shù)為失敗回調(diào)函數(shù)。失敗回調(diào)會傳入 一個參數(shù),為失敗信息。
成功回調(diào)函數(shù)會將一個媒體流作為參數(shù)傳入進來,此時創(chuàng)建一個 RTCPeerConnection 來存放流傳輸?shù)耐ǖ,?chuàng)建 RTCPeerConnection 時需要兩個參數(shù),一個是 iceServer,即視頻流傳輸?shù)刂,若沒有特殊的代理則設(shè)置為空就可以。 另一個為可選項數(shù)組,這里只需要一個 DtlsSrtpKeyAgreement:true,將這兩個參 數(shù)傳入到 RTCPeerConnection 中,即可得到一個 peerConnection 對象
var pc = new peerConnection({"iceServers": []}, {optional:[{DtlsSrtpKeyAgreemen t:true}]});
然后,需要一個來播放此媒體流,
如:document.getElementById("myVideo").src = windowUrl.createObjectURL(stre am);,用來看到自己的視頻,但同時還需要將媒體流通過 pc.addStrem(stream)傳 給 peerConnection 對象,然后用 pc.createOffer(callback,error)創(chuàng)建一個 offer,創(chuàng) 建成功后,觸發(fā)成功回調(diào),傳入一個 description(簡寫為 desc),將這個 desc 作 為參數(shù)設(shè)置為本地描述,此外這個 desc 還有一個作用,它有一個 sdp 對象,存 放的 sdp 串,需要將這個傳發(fā)送到接收方用以作為溝通的協(xié)議。
如:pc.setLocalDescription(desc,callback,error);
當 pc.iceGatheringState == "complete"時,設(shè)置成功,至此,發(fā)送方的已經(jīng)完成。
var pc = new peerConnection({"iceServers": []}, {optional:[{DtlsSrtpKeyAgreement:true}]}); getUserMedia.call(navigator,{audio: true,video:true},function(stream){pc.createOffer(function(desc){ pc.setLocalDescription(desc, function() {if(pc.iceGatheringState == "complete") {// 建立成功 }}, error);
}, error);},error);
接下來為應答方。
應答則是需要拿到對方使用的 SDP 串作為協(xié)議,設(shè)置遠程描述,也就是發(fā)送 方的信息,需要的參數(shù)則是 RTCSessionDescription 對象,RTCSessionDescription 對象需要一個對象參數(shù),對象包含 type 類型“offer”,另一個就是發(fā)送方發(fā)來的 sdp 串。
即:var sessionDescription = new RTCSessionDescription({type: "offer",sdp: receiveSdp} pc.setRemoteDescription(sessionDescription,callback,error); 設(shè)置完遠程描述后,需要將此消息告訴發(fā)送方,所以在成功回調(diào)中發(fā)送一個answer 請求,有些不同的是,pc.createAnswer 的前兩個參數(shù)都是回調(diào)函數(shù),第 三個才是參數(shù):{mandatory: {OfferToReceiveAudio: true,OfferToReceiveVideo: isVideo}};表示回復發(fā)送方,接受你的 audio 和 video 流。
即:var sessionDescription = new RTCSessionDescription({type: "offer",sdp: receiveSdp} pc.setRemoteDescription(sessionDescription,callback,error); 設(shè)置完遠程描述后,需要將此消息告訴發(fā)送方,所以在成功回調(diào)中發(fā)送一個answer 請求,有些不同的是,pc.createAnswer 的前兩個參數(shù)都是回調(diào)函數(shù),第 三個才是參數(shù):{mandatory: {OfferToReceiveAudio: true,OfferToReceiveVideo: isVideo}};表示回復發(fā)送方,接受你的 audio 和 video 流。
pc.setRemoteDescription(new sessionDescription({type: "offer",sdp: receiveSdp}), function() {
pc.createAnswer(function() {if(pc.iceGatheringState == "complete"){// 建立功}},error,constraints)}, remoteError)
至此,一次單程的 webrtc 就完成了,但是作為視頻應用,單方面接通是不行 的,雙方都看到對方的畫面的話,就讓被叫方也完成一次完整的視頻呼叫就可以 了。
最后關(guān)于瀏覽器的兼容性,我們看兩組數(shù)據(jù):
從市場占有率和技術(shù)成熟度來看,前兩名還是分屬 Chrome 和Firefox。因此,基于 H5 規(guī)范的的 RTC 應用目前重點還是以適配這 2 款瀏覽器為主。