websocket連通本地webrtc


  最近各大直播網站都比較火,想探究一下是怎么玩的。但是看了幾個大牛的回答,感覺有太多陌生的東西,嘗試起來成本略高。發現了有個東西叫webrtc,有人分析過他不適合做流量大,人數多的直播。但是我也只是玩一下,感受一下視頻連通的感覺。
  一開始在github上面看到了一個,比較全大部分的API都做了demo,還有canva 3d融合webrtc的例子。因為大部分例子都是沒有經過網絡的通訊,所以想用socket寫一個交換信令的demo。其中也找到過demo但是沒試通過...然后看一些博客和API自己寫一個小demo,幫助理解webrtc
  目錄結構就是這樣  只拉取了express socket.io
     


     前端代碼:
     html部分
  

        <script src="/socket.io/socket.io.js"></script>  
        Local: <br>
        <video id="localVideo" autoplay style="width:80px"></video><br>
        Remote: <br>
        <video id="remoteVideo" autoplay style="width:80px"></video>

 



  js部分

// 判斷發起端  
            var isCaller = window.location.href.split('#')[1];
            // 信令服務器的Socket連接
            var socket = io.connect('http://localhost:3000');
            // stun和turn服務器
            var iceServer = null;

            // iceServer在局域網下可以通訊
            var pc = new webkitRTCPeerConnection(iceServer);

            // 發送給的其他端通知
            pc.onicecandidate = function(event){
                if (event.candidate !== null) {
                    debugger
                    console.log('onicecandidate -----');
                    socket.emit('message',JSON.stringify({
                        "event": "_ice_candidate",
                        "data": {
                            "candidate": event.candidate
                        }
                    }));
                }
            };

            // 建立好p2p通道以后 會通過OnAddStream返回一個音視頻流的對象
            pc.onaddstream = function(event){
                document.getElementById('remoteVideo').src = URL.createObjectURL(event.stream);
            };

            // offer和answer 
            var sendOfferFn = function(desc){
                pc.setLocalDescription(desc);
                console.log('Offer -----');
                socket.emit('message',JSON.stringify(desc));
            },
            sendAnswerFn = function(desc){
                pc.setLocalDescription(desc);
                console.log('Answer -----');
                socket.emit('message',JSON.stringify(desc));
            };

            // 獲取本地音頻和視頻流
            navigator.webkitGetUserMedia({
                "audio": true,
                "video": true
            }, function(stream){
                //在localVideo輸出音視頻
                document.getElementById('localVideo').src = URL.createObjectURL(stream);
                //把本地的媒體流綁定到PeerConnection
                pc.addStream(stream);

                //發起端 發送offer
                if(isCaller){
                    pc.createOffer(sendOfferFn, function (error) {
                        console.log('Failure callback: ' + error);
                    });
                }
            }, function(error){
                console.log('getUserMedia error: ' + error);
            });


            socket.on('message',function(event){//處理socket請求
                
                if(event.type){
                    console.log('請求以返回--------'+event.type);
                }else{
                    console.log('--------')
                    console.log(event);
                }

                if(event.type=='offer' && !isCaller){
                    pc.setRemoteDescription(event)
                    pc.createAnswer(sendAnswerFn, function (error) {
                            console.log('Failure callback: ' + error);
                    });
                }
                if(event.type=='answer'  && isCaller){
                    pc.setRemoteDescription(event)
                }
                if(event.event=='_ice_candidate'){
                    pc.addIceCandidate(new RTCIceCandidate(event.data.candidate));
                }
            })

  node部分

var express = require('express');
var app = express()
var server = require('http').Server(app);
var io = require('socket.io')(server);

server.listen(3000);
app.use(express.static(__dirname + '/js'));
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
    socket.on('message',function(data){
        
        var message=JSON.parse(data);
        if(message.type){
            console.log(message.type);
        }else{
            console.log(message.event);
        }
        console.log('請求已經廣播出去--------');
        socket.broadcast.emit('message',message);            
    })
    

});

訪問localhost:3000開啟一個端  
然后訪問localhost:3000#true (開始進行對localhos:3000進行連接)

    下面具體流程轉載 煙雨任平生的

  • ClientA首先創建PeerConnection對象,然后打開本地音視頻設備,將音視頻數據封裝成MediaStream添加到PeerConnection中。
  • ClientA調用PeerConnection的CreateOffer方法創建一個用於offer的SDP對象,SDP對象中保存當前音視頻的相關參數。ClientA通過PeerConnection的SetLocalDescription方法將該SDP對象保存起來,並通過Signal服務器發送給ClientB。
  • ClientB接收到ClientA發送過的offer SDP對象,通過PeerConnection的SetRemoteDescription方法將其保存起來,並調用PeerConnection的CreateAnswer方法創建一個應答的SDP對象,通過PeerConnection的SetLocalDescription的方法保存該應答SDP對象並將它通過Signal服務器發送給ClientA。
  • ClientA接收到ClientB發送過來的應答SDP對象,將其通過PeerConnection的SetRemoteDescription方法保存起來。
  • 在SDP信息的offer/answer流程中,ClientA和ClientB已經根據SDP信息創建好相應的音頻Channel和視頻Channel並開啟Candidate數據的收集,Candidate數據可以簡單地理解成Client端的IP地址信息(本地IP地址、公網IP地址、Relay服務端分配的地址)。
  • 當ClientA收集到Candidate信息后,PeerConnection會通過OnIceCandidate接口給ClientA發送通知,ClientA將收到的Candidate信息通過Signal服務器發送給ClientB,ClientB通過PeerConnection的AddIceCandidate方法保存起來。同樣的操作ClientB對ClientA再來一次。
  • 這樣ClientA和ClientB就已經建立了音視頻傳輸的P2P通道,ClientB接收到ClientA傳送過來的音視頻流,會通過PeerConnection的OnAddStream回調接口返回一個標識ClientA端音視頻流的MediaStream對象,在ClientB端渲染出來即可。同樣操作也適應ClientB到ClientA的音視頻流的傳輸。


      具體流程可以參考:http://www.cnblogs.com/fangkm/p/4364553.html 他寫的比較細節,清新脫俗


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM