WebRTC 實(shí)現(xiàn)Android點(diǎn)到點(diǎn)互連(含Demo)

背景簡(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)端。

信令交換

  1. A向服務(wù)器發(fā)出init請(qǐng)求
  2. 服務(wù)器將A的init請(qǐng)求轉(zhuǎn)發(fā)給連接上服務(wù)器的其他端
  3. B收到init請(qǐng)求后,調(diào)用peerConnection.createOffer()方法創(chuàng)建一個(gè)包含SDP的offer信令
  4. offer信令創(chuàng)建成功后會(huì)調(diào)用SdpObserver監(jiān)聽中的onCreateSuccess()響應(yīng)函數(shù),在此處B通過peerConnection.setLocalDescription()方法將SDP賦予自己的PeerConnection對(duì)象,同時(shí)將offer信令發(fā)送給服務(wù)器
  5. 服務(wù)器將offer信令轉(zhuǎn)發(fā)給A端
  6. A收到offer信令后,調(diào)用peerConnection.setRemoteDescription()方法將B發(fā)過來的SDP賦予自己的PeerConnection對(duì)象,并調(diào)用peerConnection.createAnswer()方法創(chuàng)建一個(gè)answer信令
  7. answer信令創(chuàng)建成功后同樣會(huì)調(diào)用SdpObserver監(jiān)聽中的onCreateSuccess()響應(yīng)函數(shù),在此處A同樣通過peerConnection.setLocalDescription方法將SDP賦予自己的PeerConnection對(duì)象,同時(shí)將answer信令發(fā)送給服務(wù)器
  8. 服務(wù)器將answer信令轉(zhuǎn)發(fā)給B端
  9. B收到A的answer信令后,利用peerConnection.setRemoteDescription()方法將A發(fā)過來的SDP賦予自己的PeerConnection對(duì)象

設(shè)置Candidate

  1. PeerConnection.Observer監(jiān)聽會(huì)調(diào)用onIceCandidate()響應(yīng)函數(shù)并提供IceCandidate對(duì)象。然后將IceCandidate對(duì)象組成candidate信令發(fā)送給服務(wù)器
  2. 服務(wù)器將candidate信令轉(zhuǎn)發(fā)給連接上服務(wù)器的其他端
  3. 收到candidate信令后調(diào)用peerConnection.addIceCandidate()IceCandidate賦予自己的PeerConnection對(duì)象

至此Peer-to-Peer的連接已經(jīng)建立起來了

五、使用DataChannel收發(fā)信息

  1. 初始化DataChannel對(duì)象

        /*
        DataChannel.Init 可配參數(shù)說明:
        ordered:是否保證順序傳輸;
        maxRetransmitTimeMs:重傳允許的最長(zhǎng)時(shí)間;
        maxRetransmits:重傳允許的最大次數(shù);
         */
        DataChannel.Init init = new DataChannel.Init();
        dataChannel = peerConnection.createDataChannel("dataChannel", init);
    
  2. onDataChannel()回調(diào)中注冊(cè)消息回調(diào)

        dataChannel.registerObserver(this);
    
  3. 發(fā)送消息

        byte[] msg = message.getBytes();
        DataChannel.Buffer buffer = new DataChannel.Buffer(
                ByteBuffer.wrap(msg),
                false);
        dataChannel.send(buffer);
    
  4. 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)如下:

image.png

我們可以使用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)介

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容