背景簡(jiǎn)介
WebRTC被譽(yù)為是web長(zhǎng)期開源開發(fā)的一個(gè)新啟元,是近年來web開發(fā)的最重要?jiǎng)?chuàng)新。WebRTC允許Web開發(fā)者在其web應(yīng)用中添加視頻聊天或者點(diǎn)對(duì)點(diǎn)數(shù)據(jù)傳輸,不需要復(fù)雜的代碼或者昂貴的配置。目前支持Chrome、Firefox和Opera,后續(xù)會(huì)支持更多的瀏覽器,它有能力達(dá)到數(shù)十億的設(shè)備。
然而,WebRTC一直被誤解為僅適合于瀏覽器。事實(shí)上,WebRTC最重要的一個(gè)特征是允許本地和web應(yīng)用間的互操作,很少有人使用到這個(gè)特性。
所以自然Android應(yīng)用也可以植入WebRTC。好處是什么?簡(jiǎn)單來說就是你可以用很簡(jiǎn)潔的代碼,在手機(jī)上實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)的視頻聊天或者數(shù)據(jù)傳輸,點(diǎn)對(duì)點(diǎn)!點(diǎn)對(duì)點(diǎn)!點(diǎn)對(duì)點(diǎn)!重要的事情說三遍。
項(xiàng)目準(zhǔn)備
信令服務(wù)器代碼:https://github.com/matthewYang92/WebRtcServer(代碼改自ProjectRTC)
- 安裝Node.js
- 進(jìn)入項(xiàng)目根目錄,命令行:npm install
- 命令行:node app.js
- 打開瀏覽器輸入127.0.0.1:3000,見到WebRtcServer標(biāo)題,服務(wù)器ready
客戶端代碼:https://github.com/matthewYang92/WebRtcAndroidClient(代碼參考AndroidRTC項(xiàng)目)
- 下載后直接AndroidStudio打開
- 將
WebRtcClient.java類中的mSocketAddress變量改成你服務(wù)器的ip端口3000 - 安裝后啟動(dòng)App,如果服務(wù)器log顯示-- xxxxx joined --證明客戶端已連上服務(wù)器
- 至少兩個(gè)客戶端連接到服務(wù)器之后,其中一端點(diǎn)擊init開始連接
如果你已經(jīng)成功跑通了Demo,那么恭喜你已經(jīng)成功了一半,接下來我們分析下實(shí)現(xiàn)流程。
實(shí)現(xiàn)流程
一、添加WebRTC庫(kù)依賴
compile 'org.webrtc:google-webrtc:1.0.+'
二、初始化核心類PeerConnectionFactory
PeerConnectionFactory.initialize(PeerConnectionFactory
.InitializationOptions
.builder(this)
.createInitializationOptions());
三、創(chuàng)建PeerConnection對(duì)象
peerConnection = factory.createPeerConnection(
iceServers, //ICE服務(wù)器列表
constraints, //MediaConstraints
this); //Context
四、建立P2P連接通道
WebRTC是基于P2P的,但在端與端之間的連接通道還沒建立起來之前,我們需要通過一個(gè)信令服務(wù)器為端與端之間傳遞信令建立通道。信令服務(wù)器要做的東西很簡(jiǎn)單,就是將一端的信息透?jìng)鹘o另一端,步驟如下(以Demo為例):我們啟動(dòng)A端與B端,通過SocketIO連接到信令服務(wù)器,我們以A作為發(fā)送端,B為響應(yīng)端。
信令交換
- A向服務(wù)器發(fā)出init請(qǐng)求
- 服務(wù)器將A的init請(qǐng)求轉(zhuǎn)發(fā)給連接上服務(wù)器的其他端
- B收到init請(qǐng)求后,調(diào)用
peerConnection.createOffer()方法創(chuàng)建一個(gè)包含SDP的offer信令 - offer信令創(chuàng)建成功后會(huì)調(diào)用
SdpObserver監(jiān)聽中的onCreateSuccess()響應(yīng)函數(shù),在此處B通過peerConnection.setLocalDescription()方法將SDP賦予自己的PeerConnection對(duì)象,同時(shí)將offer信令發(fā)送給服務(wù)器 - 服務(wù)器將offer信令轉(zhuǎn)發(fā)給A端
- A收到offer信令后,調(diào)用
peerConnection.setRemoteDescription()方法將B發(fā)過來的SDP賦予自己的PeerConnection對(duì)象,并調(diào)用peerConnection.createAnswer()方法創(chuàng)建一個(gè)answer信令 - answer信令創(chuàng)建成功后同樣會(huì)調(diào)用
SdpObserver監(jiān)聽中的onCreateSuccess()響應(yīng)函數(shù),在此處A同樣通過peerConnection.setLocalDescription方法將SDP賦予自己的PeerConnection對(duì)象,同時(shí)將answer信令發(fā)送給服務(wù)器 - 服務(wù)器將answer信令轉(zhuǎn)發(fā)給B端
- B收到A的answer信令后,利用
peerConnection.setRemoteDescription()方法將A發(fā)過來的SDP賦予自己的PeerConnection對(duì)象
設(shè)置Candidate
-
PeerConnection.Observer監(jiān)聽會(huì)調(diào)用onIceCandidate()響應(yīng)函數(shù)并提供IceCandidate對(duì)象。然后將IceCandidate對(duì)象組成candidate信令發(fā)送給服務(wù)器 - 服務(wù)器將candidate信令轉(zhuǎn)發(fā)給連接上服務(wù)器的其他端
- 收到candidate信令后調(diào)用
peerConnection.addIceCandidate()將IceCandidate賦予自己的PeerConnection對(duì)象
至此Peer-to-Peer的連接已經(jīng)建立起來了
五、使用DataChannel收發(fā)信息
-
初始化DataChannel對(duì)象
/* DataChannel.Init 可配參數(shù)說明: ordered:是否保證順序傳輸; maxRetransmitTimeMs:重傳允許的最長(zhǎng)時(shí)間; maxRetransmits:重傳允許的最大次數(shù); */ DataChannel.Init init = new DataChannel.Init(); dataChannel = peerConnection.createDataChannel("dataChannel", init); -
在
onDataChannel()回調(diào)中注冊(cè)消息回調(diào)dataChannel.registerObserver(this); -
發(fā)送消息
byte[] msg = message.getBytes(); DataChannel.Buffer buffer = new DataChannel.Buffer( ByteBuffer.wrap(msg), false); dataChannel.send(buffer); -
onMessage()回調(diào)收消息ByteBuffer data = buffer.data; byte[] bytes = new byte[data.capacity()]; data.get(bytes); String msg = new String(bytes);
六、關(guān)于ICE服務(wù)
(以下內(nèi)容引用自http://blog.csdn.net/youmingyu/article/details/53192714,博主的文章對(duì)我?guī)椭级?,非常感謝)
如果在局域網(wǎng)內(nèi),信令交換后就已經(jīng)可以傳遞媒體流了,但如果雙方不在同一個(gè)局域網(wǎng),就需要進(jìn)行NAT/防火墻穿透(我是在局域網(wǎng)下測(cè)試的,沒有穿透,但還是把這方面內(nèi)容介紹下)。
WebRTC使用ICE框架來保證穿透。ICE全名叫交互式連接建立(Interactive Connectivity Establishment),一種綜合性的NAT/FW穿越技術(shù),它是一種框架,可以整合各種NAT/FW穿越技術(shù)如STUN、TURN(Traversal Using Relay NAT 中繼NAT實(shí)現(xiàn)的穿透)。ICE會(huì)先使用STUN,嘗試建立一個(gè)基于UDP的連接,如果失敗了,就會(huì)去TCP(先嘗試HTTP,然后嘗試HTTPS),如果依舊失敗ICE就會(huì)使用一個(gè)中繼的TURN服務(wù)器。使用STUN服務(wù)器穿透的結(jié)構(gòu)如下:

我們可以使用Google的stun服務(wù)器:stun:stun.l.google.com:19302(Google嘛,翻墻你懂得,當(dāng)然如果有精力可以自己搭建一個(gè)stun服務(wù)器),那么我們?cè)趺窗堰@個(gè)地址告訴WebRTC呢,還記得之前的iceServers嗎,就是在創(chuàng)建PeerConnection對(duì)象的時(shí)候需要的參數(shù),iceServers里面存放的就是進(jìn)行穿透地址變換的服務(wù)器地址,添加方法如下(保險(xiǎn)起見可以多添加幾個(gè)服務(wù)器地址,如果有的話):
iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));
參考
官網(wǎng)
Android之WebRTC介紹
WebRTC的Android2Android實(shí)現(xiàn)
NAT- STUN和TURN簡(jiǎn)介