淺談WebRTC技術(shù)原理與應(yīng)用
一、技術(shù)背景
自2010年至今,WebRTC的出現(xiàn)和發(fā)展簡要背景
根據(jù) Cisco 預(yù)測指數(shù)顯示,到 2022 年,視頻將占所有 IP 流量的 82%,高于目前的 75%。在疫情背景下,線上實(shí)時(shí)音視頻交互已經(jīng)是當(dāng)下和未來重要的交互途徑之一了,比如在線視頻會議。


(線上實(shí)時(shí)音視頻交互)
WebRTC(Web Real-Time Communication),即網(wǎng)頁即時(shí)通信。 是一個(gè)支持網(wǎng)頁瀏覽器[1]進(jìn)行實(shí)時(shí)語音對話或視頻對話的技術(shù)方案。從前端技術(shù)開發(fā)的視角來看,是一組可調(diào)用的API標(biāo)準(zhǔn)。

在WebRTC發(fā)布之前,開發(fā)實(shí)時(shí)音視頻交互應(yīng)用的成本是非常昂貴,需要考慮的技術(shù)問題很多,如音視頻的編解碼問題,數(shù)據(jù)傳輸問題,延時(shí)、丟包、抖動、回音的處理和消除等,如果要兼容瀏覽器端的實(shí)時(shí)音視頻通信,還需要額外安裝插件。
2010年5月,Google以6820萬美元收購VoIP軟件開發(fā)商Global [2]IP[3] Solutions[4]的GIPS引擎,并改為名為“WebRTC”。旨在建立一個(gè)互聯(lián)網(wǎng)瀏覽器間的實(shí)時(shí)通信的平臺,讓 WebRTC技術(shù)成為 H5標(biāo)準(zhǔn)之一。
2012年1月,谷歌已經(jīng)把這款軟件集成到Chrome瀏覽器中,Opera初步集成WebRTC。
2013年6月,Mozilla Firefox[5]發(fā)布22.0版本正式集成及支持WebRTC。
2017 年 11 月 ,W3C WebRTC 1.0 草案正式定稿。
2021年 1 月,WebRTC 被 W3C 和 IETF 發(fā)布為正式標(biāo)準(zhǔn)(WebRTC 1.0: Real-Time Communication Between Browsers[6]

(圖引用自W3C重點(diǎn)報(bào)告,2021.10版[7])
根據(jù)全球領(lǐng)先的技術(shù)研究和咨詢公司——Technavio的關(guān)于“全球網(wǎng)絡(luò)實(shí)時(shí)通信(webrtc)市場”的研究報(bào)顯示,自2017-2021年期間,全球網(wǎng)絡(luò)實(shí)時(shí)通信(webrtc)市場,將以34.37%的年均復(fù)合增長率增長,可謂十分的迅速。
二、簡要特征
WebRTC內(nèi)容豐富,主要的技術(shù)特征包含以下幾點(diǎn):
1. 實(shí)時(shí)通訊
是一項(xiàng)實(shí)時(shí)通訊技術(shù),允許網(wǎng)絡(luò)應(yīng)用或者站點(diǎn),在不借助中間媒介的情況下,建立瀏覽器之間點(diǎn)對點(diǎn)(Peer-to-Peer)的連接,實(shí)現(xiàn)視頻流和(或)音頻流或者其他任意數(shù)據(jù)的傳輸。
2. 無依賴/插件
WebRTC包含的這些標(biāo)準(zhǔn)使用戶在無需安裝任何插件或者第三方的軟件的情況下,創(chuàng)建點(diǎn)對點(diǎn)(Peer-to-Peer)的數(shù)據(jù)分享和電話會議成為可能。
3. 協(xié)議棧 眾多
它并不是單一的協(xié)議,包含了媒體、加密、傳輸層等在內(nèi)的多個(gè)協(xié)議標(biāo)準(zhǔn)以及一套基于 JavaScript的 API,它包括了音視頻的采集、編解碼、網(wǎng)絡(luò)傳輸、顯示等功能。通過簡單易用的 JavaScript API ,在不安裝任何插件的情況下,讓瀏覽器擁有了 P2P音視頻和數(shù)據(jù)分享的能力。

(WebRTC依賴眾多協(xié)議棧圖)
| 相關(guān)協(xié)議 | 介紹與作用 |
|---|---|
| ICE、STUN、TURN | 用于內(nèi)網(wǎng)穿透, 解決了獲取與綁定公網(wǎng)映射地址 |
| DTLS | 用于對傳輸內(nèi)容進(jìn)行加密 |
| SRTP 、 SRTCP | 對媒體數(shù)據(jù)的封裝與傳輸控制協(xié)議 |
同時(shí)WebRTC 并不是一個(gè)孤立的協(xié)議,它擁有靈活的信令,可以便捷的對接現(xiàn)有的SIP 和電話網(wǎng)絡(luò)的系統(tǒng)。
三、兼容覆蓋
主流瀏覽器的兼容情況
目前大部分主流瀏覽器都正常兼容,如下圖

(瀏覽器兼容性覆蓋圖)
主流瀏覽器都支持 WebRTC 標(biāo)準(zhǔn) API ,因此也讓瀏覽器之間無插件化的音視頻互通成為可能, 大大降低了音視頻開發(fā)的門檻,開發(fā)者只需要調(diào)用 WebRTC API 即可快速構(gòu)建出音視頻應(yīng)用。
四、技術(shù)框架
結(jié)合技術(shù)框架圖來認(rèn)知和理解官方技術(shù)框架的基本內(nèi)容
如下圖的技術(shù)框架描述了WebRTC的核心內(nèi)容和面向不同開發(fā)者的API設(shè)計(jì)。

(技術(shù)框架圖)
從圖中可看到主要面向三類開發(fā)者的API設(shè)計(jì),包括:
a.對于Web開發(fā)者的API
框架包含了基于 ****JavaScript 、 經(jīng)過W3C認(rèn)證了的一套API標(biāo)準(zhǔn),使得web開發(fā)者可以基于這套API開發(fā)基于WebRTC的即時(shí)通訊應(yīng)用。
b.對于瀏覽器廠商的API
框架同樣包含了基于C++的底層WebRTC接口,對于瀏覽器廠商底層的接入十分友好。
c.瀏覽器廠商可自定義的部分
框架中還包含瀏覽器廠商可自定義的音視頻截取等擴(kuò)展部分。
五、核心內(nèi)容
從上述框架中看到,主要有音頻、視頻引擎和傳輸三部分主要內(nèi)容,其中又包含眾多的協(xié)議和方法等
WebRTC 主要組成:
Voice Engine(音頻引擎)
Voice Engine包含iSAC/iLBC Codec(音頻編解碼器,前者是針對寬帶和超寬帶,后者是針對窄帶) NetEQ for voice(處理網(wǎng)絡(luò)抖動和語音包丟失) Echo Canceler(回聲消除器)/ Noise Reduction(噪聲抑制)
Video Engine(視頻引擎)
VP8 Codec(視頻圖像編解碼器) Video jitter buffer(視頻抖動緩沖器,處理視頻抖動和視頻信息包丟失) Image enhancements(圖像質(zhì)量增強(qiáng))
Transport
六、實(shí)現(xiàn)原理
SRTP(安全的實(shí)時(shí)傳輸協(xié)議,用于音視頻流傳輸) Multiplexing(多路復(fù)用) P2P,STUN+TURN+ICE(用于NAT網(wǎng)絡(luò)和防火墻穿越的) 除此之外,安全傳輸可能還會用到DTLS(數(shù)據(jù)報(bào)安全傳輸),用于加密傳輸和密鑰協(xié)商 整個(gè)WebRTC通信是基于UDP的
不細(xì)致介紹音視頻采集、編碼和處理等內(nèi)容,僅介紹實(shí)時(shí)通訊的建立過程原理的核心內(nèi)容
1. 公網(wǎng)IP映射:明確網(wǎng)絡(luò)定位信息
WebRTC是建立瀏覽器端到端的連接(P2P),由于不需要服務(wù)器中轉(zhuǎn),所以獲取連接對象的網(wǎng)絡(luò)地址的方式,是借助于ICE、STUN、TURN等輔助內(nèi)網(wǎng)穿透技術(shù)(NAT)得到對應(yīng)主機(jī)的公網(wǎng)網(wǎng)絡(luò)地址和端口等網(wǎng)絡(luò)定位信息。明確網(wǎng)絡(luò)定位是建立端與端直接通訊的基礎(chǔ)。
(NAT原理圖)
(STUN服務(wù)器用于輔助內(nèi)網(wǎng)穿透得到對應(yīng)主機(jī)的公網(wǎng)網(wǎng)絡(luò)地址和端口信息圖)
2. 信令服務(wù)器:網(wǎng)絡(luò)協(xié)商與信息交換
信令服務(wù)器的作用是基于雙工通信來中轉(zhuǎn)信息。中轉(zhuǎn)信息包括公網(wǎng)IP映射后的網(wǎng)絡(luò)定位信息(公網(wǎng)IP、端口和媒體數(shù)據(jù)流等。

(概念圖)

(信令服務(wù)器信息交互過程圖)
3. 會話描述協(xié)議SDP:統(tǒng)一的媒體協(xié)商方式
不同端/瀏覽器對于媒體流數(shù)據(jù)的編碼格式各異,如VP8、VP9等,參與會話的各個(gè)成員的能力不對等、用戶環(huán)境與配置不一致等。
WebRTC 通訊還需要確定和交換本地和遠(yuǎn)程音頻和視頻媒體信息,例如分辨率和編解碼器功能。交換媒體配置信息的信令通過使用會話描述協(xié)議 (SDP) 交換Offer和Anwser來進(jìn)行。
SDP的交換一定是先于音視頻流交換的。其內(nèi)容包括會話基本信息、媒體信息描述等。
//SDP的結(jié)構(gòu)體
Session?description(會話級別描述)
?????????v=??(protocol?version)
?????????o=??(originator?and?session?identifier)
?????????s=??(session?name)
?????????c=*?(connection?information?--?not?required?if?included?in?all?media)
?????????One?or?more?Time?descriptions?("t="?and?"r="?lines;?see?below)
?????????a=*?(zero?or?more?session?attribute?lines)
?????????Zero?or?more?Media?descriptions
Time?description
?????????t=??(time?the?session?is?active)
Media?description(媒體級別描述),?if?present
?????????m=??(media?name?and?transport?address)
?????????c=*?(connection?information?--?optional?if?included?at?session?level)
?????????a=*?(zero?or?more?media?attribute?lines)
一個(gè)SDP例子如下
v=0?//代表版本,目前一般是`v=0`.
o=-?3883943731?1?IN?IP4?127.0.0.1
s=
t=0?0?//會話處于活動狀態(tài)的時(shí)間
a=group:BUNDLE?audio?video?//:描述服務(wù)質(zhì)量,傳輸層復(fù)用相關(guān)信息
m=audio?1?RTP/SAVPF?103?104?0?8?106?105?13?126?//?...?
a=ssrc:2223794119?label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh81
4.一對一連接建立過程
以建立一對一的Web RTC連接過程為

(一對一過程圖)
簡要過程

(簡要過程圖)
交換SDP,獲取各自媒體配置信息
STUN服務(wù)器交換網(wǎng)絡(luò)地址和端口等網(wǎng)絡(luò)信息
Turn中轉(zhuǎn)音視頻媒體流數(shù)據(jù)
工作流

(工作流程圖)
A和B雙方先調(diào)用 getUserMedia 打開本地?cái)z像頭,作為本地待輸出媒體流;
向信令服務(wù)器發(fā)送加入房間請求;
Peer B 接收到 Peer A 發(fā)送的 offer SDP 對象,并通過PeerConnection的SetLocalDescription方法保存 Answer SDP 對象并將它通過信令服務(wù)器發(fā)送給 Peer A。
在 SDP 信息的 offer/answer 流程中,Peer A 和 Peer B 已經(jīng)根據(jù) SDP 信息創(chuàng)建好相應(yīng)的音頻 Channel 和視頻 Channel,并開啟Candidate 數(shù)據(jù)的收集,Candidate數(shù)據(jù)(本地IP地址、公網(wǎng)IP地址、Relay服務(wù)端分配的地址)。
當(dāng) Peer A 收集到 Candidate 信息后通過信令服務(wù)器發(fā)送給 Peer B。同樣的過程 Peer B 對 Peer A 也會再發(fā)送一次。
6. 多對多的建立

(多對多建立點(diǎn)到點(diǎn)連接概念圖,以三個(gè)用戶點(diǎn)對點(diǎn)的連接為例)
7. JavaScript主要接口
getUserMedia()[8]:訪問數(shù)據(jù)流,例如來自用戶的相機(jī)和麥克風(fēng)
//請求媒體類型
const?constraints?=?{
??video:?true
??audio:true
};
const?video?=?document.querySelector('video');
//掛載流到相應(yīng)dom展示本地媒體流
function?handleSuccess(stream)?{
??video.srcObject?=?stream;
}
function?handleError(error)?{
??console.error('getUserMedia?error:?',?error);
}
//利用攝像頭捕獲多媒體流
navigator.mediaDevices.getUserMedia(constraints).
??then(handleSuccess).catch(handleError);
RTCPeerConnection[9]:通過加密和帶寬管理工具啟用音頻或視頻通話
//?允許 RTC 服務(wù)器配置。
const?server?=?{?
????"iceServers":?
????????????[{?"urls":?"stun:stun.stunprotocol.org"}]?
};
//?創(chuàng)建本地連接
const?localPeerConnection?=?new?RTCPeerConnection(servers);
//?收集Candidate?數(shù)據(jù)
localPeerConnection.onicecandidate=function(event){
????...
}
//?監(jiān)聽到媒體流接入時(shí)的操作
localPeerConnection.ontack=function(event){
????...
}
RTCDataChannel[10]:支持通用數(shù)據(jù)的點(diǎn)對點(diǎn)通信,常用于數(shù)據(jù)點(diǎn)到點(diǎn)的傳輸
const?pc?=?new?RTCPeerConnection();
const?dc?=?pc.createDataChannel("my?channel");
//接受數(shù)據(jù)
dc.onmessage?=?function?(event)?{
??console.log("received:?"?+?event.data);
};
//打開傳輸
dc.onopen?=?function?()?{
??console.log("datachannel?open");
};
//關(guān)閉傳輸
dc.onclose?=?function?()?{
??console.log("datachannel?close");
};
七、應(yīng)用案例
多人視頻案例為實(shí)踐應(yīng)用
1. 設(shè)計(jì)框架

2.關(guān)鍵代碼
1.1 媒體捕獲
獲取瀏覽器視頻權(quán)限,捕獲本地視頻媒體流,在Video元素中附加媒體流,顯示本地視頻結(jié)果。
//攝像頭兼容性處理
navigator.getUserMedia?=?(?navigator.getUserMedia?||
???????????????navigator.webkitGetUserMedia?||
???????????????navigator.mozGetUserMedia?||
???????????????navigator.msGetUserMedia);
//?獲取本地音頻和視頻流
navigator.mediaDevices.getUserMedia({
????????????????"audio":?false,
????????????????"video":?true
}).then(?(stream)=>?{
//顯示自己的輸出流,掛到頁面Video元素上
????document.getElementById("myVido").srcObject=stream
})

(捕獲本地視頻媒體流的顯示結(jié)果截圖)
為每個(gè)新的客戶端連接創(chuàng)建RTCPeerConnection對象
?//?stun和turn服務(wù)器??const?iceServer?=?{
????"iceServers":?[{
????????urls:"stun:stun.l.google.com:19302"
????}]
};
//為點(diǎn)到點(diǎn)的連接創(chuàng)建RTCPeerConnection
const?peerRTCConn=new?RTCPeerConnection(iceServer);
1.2 網(wǎng)絡(luò)協(xié)商
創(chuàng)建對等連接,收集ICE候選,等待媒體流接入時(shí)掛載到dom
交互式連通性建立(Interactive Connectivity Establishment — ICE)是一個(gè)允許實(shí)時(shí)對等端發(fā)現(xiàn)對方并且彼此連接的框架。此技術(shù)允許對等方發(fā)現(xiàn)有關(guān)彼此拓?fù)涞淖銐蛐畔?,從而有可能在彼此之間找到一條或多條通信路徑。ICE 代理負(fù)責(zé):收集本地IP,端口元組候選、在同級之間執(zhí)行連接檢查和發(fā)送連接保持活動
?//?發(fā)送ICE候選到其他客戶端?peerRTCConn.onicecandidate?=?function(event){
????if?(event.candidate)?{
????????//向信令服務(wù)器轉(zhuǎn)發(fā)收集到的ICE候選??????????socket.send(JSON.stringify({
????????????"event":?"relayICECandidate",
????????????"data":?{
????????????????'iceCandidate':?{
????????????????????'sdpMLineIndex':?event.candidate.sdpMLineIndex,
????????????????????'candidate':?event.candidate.candidate
????????????????}
????????????},
????????????"fromID":signalMsg['data']['peerId']
????????}));
????}
}
//有媒體流介入就掛載dom?peerRTCConn.ontrack=function(event){
????let?v=document.createElement("video")
????v.autoplay=true
????v.style="width:200px"
????
????document.getElementById("peer").appendChild(v)
????v.srcObject=event.streams[0]
}
1.3 媒體協(xié)商
發(fā)起時(shí)創(chuàng)建Offer。peer利用setLocalDescription方法將會話信息加到RTCPeerConnection(),并由信令服務(wù)器中轉(zhuǎn)。其他Peer會返回相應(yīng)的Answer。SDP過程。
?//新加入節(jié)點(diǎn)發(fā)起offer??if(canOffer){
????peerRTCConn.createOffer(
????????function?(localDescription)?{?
?????????????peerRTCConn.setLocalDescription(localDescription,
????????????????function()?{?
????????????????????//發(fā)送描述信息給信令服務(wù)器?????????????????????????socket.send(JSON.stringify({
????????????????????????"event":"relaySessionDescription",
????????????????????????"data":localDescription,
????????????????????????"fromID":peerId
????????????????????}))
?????????????????},
????????????????function()?{?alert("offer?failed");?}
????????????);
????????},
????????function?(error)?{
????????????console.log("error?sending?offer:?",?error);
????????}
????)
}
響應(yīng)時(shí)創(chuàng)建Answer。會話描述包括音視頻信息等內(nèi)容,當(dāng)發(fā)起者向響應(yīng)者發(fā)出offer類型的描述后,響應(yīng)者會返回answer類型的描述
//創(chuàng)建Answer會話
peer.createAnswer(
function(_remoteDescription)?{
?????peer.setLocalDescription(_remoteDescription,
????????function()?{?
???????????????//發(fā)送描述信息給信令服務(wù)器??????????????????socket.send(JSON.stringify({
????????????????????"event":"relaySessionDescription",
????????????????????"data":_remoteDescription,
????????????????????"callerID":signalMsg['fromId'],
????????????????????"fromID":signalMsg['fromId']
????????????????}))????????},
????????function()?{?alert("answer?failed");?}
????);
},
function(error)?{
????console.log("error?creating?answer:?",?error);
});
當(dāng)收到ICE候選共享后,會把ICE候選添加到遠(yuǎn)程對等點(diǎn)描述中
?//對應(yīng)的RTCPeerConnection
const?peer?=?peers[signalMsg["fromID"]];
//ICE候選添加到遠(yuǎn)程對等點(diǎn)描述
peer.addIceCandidate(new?RTCIceCandidate(signalMsg["data"].iceCandidate));
效果

(多人視頻結(jié)果截圖<本地模擬效果>)
1.4 信令中轉(zhuǎn)
信令服務(wù)部分關(guān)鍵代碼
wss.on('connection',?function?(ws)?{?
????ws.on('message',?function?(message)?{?
????????let?meeageObj=JSON.parse(message)
????????//交換ICE候選?????????if?(meeageObj['event']?=='relayICECandidate')?{?????????????wss.clients.forEach(function?(client)?{
????????????????console.log("send?iceCandidate")
????????????????????client.send(JSON.stringify({
????????????????????????"event":?"iceCandidate",
????????????????????????"data":?meeageObj['data'],
????????????????????????"fromID":?meeageObj['fromID']
????????????????????}));??????????
????????????});
????????}
????????//交換SDP?????????if?(meeageObj['event']?=='relaySessionDescription')?{
????????????console.log(meeageObj["fromID"],meeageObj["data"].type)?
????????????wss.clients.forEach(function?(client)?{
????????????????if?(client!=ws)?{
????????????????????client.send(JSON.stringify({
????????????????????????"event":?"sessionDescription",
????????????????????????"fromId":meeageObj["fromID"],
????????????????????????"data":?meeageObj["data"],
????????????????????}));
????????????????}
????????????});
????????}
????})
})
八、應(yīng)用場景
WebRTC在當(dāng)下和未來具有豐富的應(yīng)用場景,此文檔不再贅述,可見下面URL的內(nèi)容
https://webrtcforthecurious.com/zh/docs/08-applied-webrtc/
九、重要意義
WebRTC的出現(xiàn)、發(fā)展和被業(yè)內(nèi)標(biāo)準(zhǔn)(如W3C)等普遍認(rèn)可,對于當(dāng)下和未來大前端技術(shù)發(fā)展具有重要的意義
降低在web端的音視頻交互開發(fā)門檻
以往的音視頻交互開發(fā)對于Web開發(fā)者而言具有一定技術(shù)門檻, 現(xiàn)在借助于WebRTC,Web開發(fā)者通過調(diào)用JS接口,可快速的實(shí)現(xiàn)音視頻交互應(yīng)用。
避免依賴、插件造成的次生問題
以往的音視頻交互應(yīng)用構(gòu)建依賴于各種插件、軟件和服務(wù)器等 現(xiàn)在借助于主流瀏覽器即可形成端到端的音視頻交互
統(tǒng)一化和標(biāo)準(zhǔn)化對傳統(tǒng)音視頻交互環(huán)境差異性的規(guī)避
以往音視頻交互需要面對不同的 NAT 、防火墻對媒體 P2P 的建立帶來了很大的挑戰(zhàn) 現(xiàn)在WebRTC?中有P2P 打洞的開源項(xiàng)目 libjingle ,支持 STUN,TURN 等協(xié)議
更高效優(yōu)化的算法、技術(shù)對于音視頻交互性能的提升
WebRTC 通過NACK、FEC技術(shù),避免了經(jīng)過服務(wù)端路由中轉(zhuǎn),減少了延遲和帶寬消耗。還有 TCC + SVC + PACER + JitterBuffer 等技術(shù)對于音視頻流暢性進(jìn)行了優(yōu)化
十、參考
本文檔相關(guān)內(nèi)容參考自下面的眾多文章、項(xiàng)目Markdown和代碼等內(nèi)容,在此一一列出
https://github.com/Tinywan/WebRTC-tutorial
https://www.bookstack.cn/read/webrtc-book-cn/spilt.6.05_putting_it_all_together.md
https://www.html5rocks.com/en/tutorials/webrtc/basics/
https://zh.wikipedia.org/wiki/WebRTC
https://zhuanlan.zhihu.com/p/93107411
https://github.com/muaz-khan/WebRTC-Experiment
https://xie.infoq.cn/article/ddceaa09b2c3ec4b357bf0d26
https://juejin.cn/post/6969030139120189477
https://www.jianshu.com/p/24363820b3b2
https://zhuanlan.zhihu.com/p/79489847
https://www.researchandmarkets.com/reports/5116130/global-web-real-time-communication-webrtc
十一、QA
Q:是否有連接限制?
A:有看到在chrome會有限制256為最多連接,但更多取決于帶寬等 https://stackoverflow.com/questions/16015304/webrtc-peer-connections-limit
Q:商業(yè)應(yīng)用現(xiàn)狀?商業(yè)應(yīng)用時(shí)的安全性、數(shù)據(jù)傳輸?shù)慕鉀Q方案?
A:不太了解,目前成熟的商業(yè)應(yīng)用比較少,我猜想成熟的商業(yè)應(yīng)用會進(jìn)步一進(jìn)行包裝,以滿足商業(yè)應(yīng)用中的安全性、數(shù)據(jù)傳輸?shù)纫?/section> A:WebRTC對于一對一單聊比較適用,但對于超多人聊天還是有優(yōu)化空間https://toutiao.io/posts/489762/app_preview
Q:安卓應(yīng)用兼容性不好
A:這個(gè)我沒有經(jīng)驗(yàn),但現(xiàn)階段的確有兼容性問題,該技術(shù)還有待進(jìn)一步兼容性優(yōu)化和成熟應(yīng)用,我也去再了解了解。
參考資料
網(wǎng)頁瀏覽器: https://zh.wikipedia.org/wiki/%E7%B6%B2%E9%A0%81%E7%80%8F%E8%A6%BD%E5%99%A8
[2]Global : https://zh.wikipedia.org/wiki/Global_IP_Solutions
[3]IP: https://zh.wikipedia.org/wiki/Global_IP_Solutions
[4]Solutions: https://zh.wikipedia.org/wiki/Global_IP_Solutions
[5]Mozilla Firefox: https://zh.wikipedia.org/wiki/Mozilla_Firefox
[6]WebRTC 1.0: Real-Time Communication Between Browsers: https://www.w3.org/TR/2021/REC-webrtc-20210126/
[7]2021.10版: https://www.w3.org/2021/10/w3c-highlights/zh.Overview.html
[8]getUserMedia(): https://webrtc.github.io/samples/src/content/getusermedia/gum/
[9]RTCPeerConnection: https://webrtc.github.io/samples/src/content/peerconnection/pc1/
[10]RTCDataChannel: https://webrtc.github.io/samples/src/content/datachannel/basic/
???謝謝支持
以上便是本次分享的全部內(nèi)容,希望對你有所幫助^_^
喜歡的話別忘了?分享、點(diǎn)贊、收藏?三連哦~。
