webrtc 一對一視頻服務搭建

WebRTC背景

WebRTC弊攘,名稱源自網(wǎng)頁即時通信(英語:Web Real-Time Communication)的縮寫匹层,是一個支持網(wǎng)頁瀏覽器進行實時語音對話或視頻對話的API芒澜。它于2011年6月1日開源并在Google宏悦、Mozilla募胃、Opera支持下被納入萬維網(wǎng)聯(lián)盟的W3C推薦標準溉贿。

客戶端

創(chuàng)建RTCPeerConnection實例->發(fā)送candidate->創(chuàng)建offer->交換offer->添加媒體流

客戶端主要工作簡單來看就是三個交換,交換ice豆拨、交換offer直奋、交換流。通過代碼來看:

  • 創(chuàng)建WebRTC實例

    去除瀏覽器前綴轉(zhuǎn)換通用變量

    const RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
    const IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
    const SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
    navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
    

    創(chuàng)建WebRTC peer實例,它接收一個配置選項configuration施禾,其中配置了用來創(chuàng)建連接的 ICE 服務器信息脚线。

    const configuration = {
        // 內(nèi)網(wǎng)穿透使用sturn和turn服務信息,下面的服務器國內(nèi)無法使用弥搞,需要自行搭建殉挽,??見后文
        iceServers: [
            {urls: "stun:23.21.150.121"},
            {urls: "stun:stun.l.google.com:19302"},
            {urls: "turn:numb.viagenie.ca", credential: "webrtcdemo", username: "louis%40mozilla.com"}
        ]
    }
    const pc = new RTCPeerConnection(configuration);
    // 當 ICE 框架找到可以使用 Peer 創(chuàng)建連接的 “候選者”,會立即觸發(fā)一個事件(onicecandidate)拓巧。ICE候選者信息通過信令服務器轉(zhuǎn)發(fā)
    pc.onicecandidate = function (e) {
        if (!e.candidate) return;
        // 通過信令服務器轉(zhuǎn)發(fā)candidate 接收方通過addIceCandidate方法添加
        send("icecandidate", JSON.stringify(e.candidate));
    };
    
    // ... 
    function addIce(candidate){
        // 信令服務器響應后 將遠端的candidate加入本地ice
        pc.addIceCandidate(new RTCIceCandidate(candidate));
    }
    
    
  • ICECandidate

    ICE全稱Interactive Connectivity Establishment:交互式連通建立方式斯碌。

    ICE參照RFC5245建議實現(xiàn),是一組基于offer/answer模式解決NAT穿越的協(xié)議集合肛度。
    它綜合利用現(xiàn)有的STUN傻唾,TURN等協(xié)議,以更有效的方式來建立會話承耿。

    客戶端側(cè)無需關心所處網(wǎng)絡的位置以及NAT類型冠骄,并且能夠動態(tài)的發(fā)現(xiàn)最優(yōu)的傳輸路徑。

    簡單來說 發(fā)起方創(chuàng)建RTCPeerConnection實例后要將自己的candidate發(fā)送給接收方加袋,雙方互換candidate才可建立鏈接凛辣。

    // 添加ice 
    pc.addIceCandidate(new RTCIceCandidate(candidate))
    

推薦博客 ICE

  • 交換offer SDP

    Offer SDP 是用來向另一端描述期望格式(視頻, 格式, 解編碼, 加密, 解析度, 尺寸 等等)的元數(shù)據(jù)。

    一次信息的交換需要從一端拿到 offer职烧,然后另外一端接受這個 offer 然后返回一個 answer扁誓。

    // 創(chuàng)建offer
    await pc.createOffer({
        // 是否接收音頻
        offerToReceiveAudio: true,
        // 是否接收視頻
        offerToReceiveVideo: true
    });
    // 添加至本地描述
    await pc.setLocalDescription(offer);
    
    // ... 將本地的offer通過信令服務器轉(zhuǎn)發(fā)給接收方
    
    // 接收方收到遠端的offer 創(chuàng)建自己answer 并發(fā)送給主叫 
    await recvPc.setRemoteDescription(offer);
    await recvPc.setLocalDescription(await recvPc.createAnswer());
    
    // ...將answer發(fā)送給主叫
    
    // ...接收到被叫方返回的answer信息添加到setRemoteDescription
    pc.setRemoteDescription(answer);
    
    
  • 添加流發(fā)送給對方

    在接收到offer時我們就可以獲取本地的媒體流防泵,并添加到RTCPeerConnection實例中

    //獲取媒體流 如果只想使用默認配置video直接賦值為true
    window.navigator.mediaDevices.getUserMedia({video: {
            // 幀數(shù) 
            frameRate: { ideal: 10, max: 15 },
            // 寬高 最大1280 最小800 ideal(應用最理想的)值時,這個值有著更高的權重蝗敢,意味著瀏覽器會先嘗試找到最接近指定的理想值的設定或者攝像頭(如果設備擁有不止一個攝像頭)捷泞。此外還要facingMode 前置或者后置攝像頭
            width: { max: 1280,ideal: 1024,min:800 },
            height: { max: 720,ideal: 960,min:600 }
        },audio:true})
    .then(mediaStream => {
        console.log('addStream');
        // 添加流到RTCPeerConnection實例中
        this.pc.addStream(mediaStream);
        // 把本地的流添加到video標簽中播放
        $('.my-video').srcObject = mediaStream;
    }); 
    
    // 監(jiān)聽onaddstream
    pc.onaddstream=function(e){
        // e.stream 
        $('.your-best-friend-video').srcObject = e.stream;
    }
    

推薦閱讀MDN教程

推薦博客 淺顯易懂

獲取媒體流 getUserMedia MDN教程

查看客戶端代碼

信令服務器

為客戶端交換offer交換ice的中轉(zhuǎn)站

使用nodejs創(chuàng)建一個簡單的WebSocket服務,如果想要在公網(wǎng)上必須要用wss,因為客戶端用的是https協(xié)議無法與ws協(xié)議連接寿谴,下面是如何創(chuàng)建wss:


const WebSocket = require('ws');
const https = require('https');
const options={
    key:fs.readFileSync('./ssl/privkey.key','utf8'),
    cert:fs.readFileSync('./ssl/cert.crt','utf8')
}
// 添加證書及私鑰 證書可以使用openSSL生成锁右,或者申請免費的
const options={
    key:fs.readFileSync('./ssl/privkey.key','utf8'),
    cert:fs.readFileSync('./ssl/cert.crt','utf8')
}
// 創(chuàng)建https服務
const httpsServer=https.createServer(options, function (req, res) {
    //要是單純的https連接的話就會返回這個東西
    res.writeHead(403);//403即可
    res.end("This is a  WebSockets server!\n");
}).listen(15065)
// 創(chuàng)建wss服務
const wsServer = new WebSocket.Server({
    server: httpsServer
});
wsServer.on('connection', (client, request) => {
    // 發(fā)送信息
    client.send('xxx')
    // 接收消息
    client.on('message', msg => {})
    // 關閉連接
    client.on('close', msg => {})
})

查看信令服務服務器代碼

STURN/TURN中繼服務器

客戶端在局域網(wǎng)環(huán)境下想要與外網(wǎng)的機器通訊,需要NAT網(wǎng)絡穿越讶泰。

  • coturn是谷歌開源的中繼服務器應用咏瑟,集合了sturn 和 turn。

  • NAT兩種類型痪署,對稱NAT與非對稱NAT:

    非對稱NAT码泞,每次請求對應的IP端口是不對應的(海王) 使用sturn就可以完成打洞穿越。
    
    對稱NAT惠桃,每次請求對應的IP端口是對應的(5201314)浦夷,打洞穿越難度大 需要使用turn服務器中繼辖试。
    
    通過一個場景解釋:客戶端向sturn服務器發(fā)請求辜王,獲得自己的對外ip和端口,此時客戶端是對稱NAT罐孝,這個對外暴露的端口只能給服務器使用呐馆,被叫客戶端無法使用主叫暴露的端口導致無法連接。如果是非對稱的莲兢,sturn服務器獲得主叫對外暴露的IP和端口汹来,告訴其他客戶端,其他客戶端就可以拿著這個ip和端口進行連接改艇。當然非對稱也有限制收班,具體分為三種,閱讀這篇文章[對稱與非對稱NAT](https://blog.csdn.net/yifuteli_kevin/article/details/8911261?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control)谒兄。
    
  • sturn和turn區(qū)別:

    sturn幫助客戶端尋址摔桦,客戶端請求sturn服務器,返回給客戶端對外暴露的ip和端口承疲,使客戶端可以相互尋址邻耕,并p2p連接
    
    turn 采用中繼的方式,占用資源大
    
  • 建議在客戶端strun和turn都要配置燕鸽。

  • 下載 安裝coturn

    下載libevent-2.0 里面有coturn依賴的庫

    wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
    tar zxvf libevent-2.0.21-stable.tar.gz
    cd libevent-2.0.21-stable && ./configure
    make && make install
    

    下載編譯coturn

    git clone https://github.com/coturn/coturn
    cd coturn 
    ./configure 
    make 
    make install
    
  • 配置

    coturn有多種配置方式:命令行兄世、conf文件,數(shù)據(jù)庫啊研。我們使用配置文件的方式御滩。進入/usr/local/etc/目錄下有turnserver.conf.default鸥拧,復制為turnserver.conf

    此外還需要OpenSSL

    yum install openssl 
    

    使用OpenSSL生成cert和key

    openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes 
    

    獲取網(wǎng)卡信息ifconfig,記下內(nèi)網(wǎng)地址

    進入配置文件并修改

    relay-device=eth0   #與前ifconfig查到的網(wǎng)卡名稱一致
    listening-ip=172.18.77.60    #內(nèi)網(wǎng)IP
    listening-port=3478
    external-ip=47.107.110.xxx    #公網(wǎng)IP
    relay-threads=50
    cert=/etc/turn_server_cert.pem
    pkey=/etc/turn_server_pkey.pem
    min-port=49152
    max-port=65535
    user=user:123456    #用戶名密碼艾恼,創(chuàng)建IceServer時用
    realm=xxxxxx
    

    啟動turnserver

     turnserver -o -a -f -user=user:123456 -r cwtlab
    
  • 測試

    可以使用自帶的工具進行測試也可以通谷歌提供的測試sturn/turn網(wǎng)站

    使用自動工具

    # 測試 STUN
    turnutils_stunclient 47.107.110.xxx
    # 測試 TURN
    turnutils_uclient -u user -w 123456 47.107.110.xxx
    
  • 進入源碼所根目錄查看相關文檔

    README.turnserver 查看turnserver相關指令及介紹

    README.turnadmin 查看turnadmin 相關指令及介紹

    README.turnutils 查看turnutils 測試

    相關程序位置bin目錄下

coturn 下載安裝 配置 博客

coturn 下載安裝 配置二

對稱與非對稱NAT

谷歌提供的測試sturn/turn網(wǎng)站

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末住涉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钠绍,更是在濱河造成了極大的恐慌舆声,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柳爽,死亡現(xiàn)場離奇詭異媳握,居然都是意外死亡,警方通過查閱死者的電腦和手機磷脯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門蛾找,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赵誓,你說我怎么就攤上這事打毛。” “怎么了俩功?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵幻枉,是天一觀的道長。 經(jīng)常有香客問我诡蜓,道長熬甫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任蔓罚,我火速辦了婚禮椿肩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豺谈。我一直安慰自己郑象,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布茬末。 她就那樣靜靜地躺著厂榛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪团南。 梳的紋絲不亂的頭發(fā)上噪沙,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音吐根,去河邊找鬼正歼。 笑死,一個胖子當著我的面吹牛拷橘,可吹牛的內(nèi)容都是我干的局义。 我是一名探鬼主播喜爷,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萄唇!你這毒婦竟也來了檩帐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤另萤,失蹤者是張志新(化名)和其女友劉穎湃密,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體四敞,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡泛源,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了忿危。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片达箍。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铺厨,靈堂內(nèi)的尸體忽然破棺而出缎玫,到底是詐尸還是另有隱情,我是刑警寧澤解滓,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布赃磨,位于F島的核電站,受9級特大地震影響伐蒂,放射性物質(zhì)發(fā)生泄漏煞躬。R本人自食惡果不足惜肛鹏,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一逸邦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧在扰,春花似錦缕减、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皱卓,卻和暖如春裹芝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背娜汁。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工嫂易, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掐禁。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓怜械,卻偏偏與公主長得像颅和,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缕允,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容