不急不徐,持之以恒。

          http://blog.gopersist.com/

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            24 隨筆 :: 0 文章 :: 52 評論 :: 0 Trackbacks
          在學習WebRTC時,網上的示例大多代碼較多,以下是參考那些代碼簡化的一個WebRTC一對一的示例,在chrome 37下測試通過。其中iceServer可省略,沒有iceServer時在同一個局域網下仍可通訊。

          客戶端代碼:
          <html>
          <body>
              Local: <br>
              <video id="localVideo" autoplay></video><br>
              Remote: <br>
              <video id="remoteVideo" autoplay></video>

              <script>
                  
          // 僅僅用于控制哪一端的瀏覽器發起offer,#號后面有值的一方發起
                  var isCaller = window.location.href.split('#')[1];

                  
          // 與信令服務器的WebSocket連接
                  var socket = new WebSocket("ws://127.0.0.1:3000");

                  
          // stun和turn服務器
                  var iceServer = {
                      
          "iceServers": [{
                          
          "url""stun:stun.l.google.com:19302"
                      }, {
                          
          "url""turn:numb.viagenie.ca",
                          
          "username""webrtc@live.com",
                          
          "credential""muazkh"
                      }]
                  };

                  
          // 創建PeerConnection實例 (參數為null則沒有iceserver,即使沒有stunserver和turnserver,仍可在局域網下通訊)
                  var pc = new webkitRTCPeerConnection(iceServer);

                  
          // 發送ICE候選到其他客戶端
                  pc.onicecandidate = function(event){
                      
          if (event.candidate !== null) {
                          socket.send(JSON.stringify({
                              
          "event""_ice_candidate",
                              
          "data": {
                                  
          "candidate": event.candidate
                              }
                          }));
                      }
                  };

                  
          // 如果檢測到媒體流連接到本地,將其綁定到一個video標簽上輸出
                  pc.onaddstream = function(event){
                      document.getElementById('remoteVideo').src 
          = URL.createObjectURL(event.stream);
                  };

                  
          // 發送offer和answer的函數,發送本地session描述
                  var sendOfferFn = function(desc){
                      pc.setLocalDescription(desc);
                      socket.send(JSON.stringify({ 
                          
          "event""_offer",
                          
          "data": {
                              
          "sdp": desc
                          }
                      }));
                  },
                  sendAnswerFn 
          = function(desc){
                      pc.setLocalDescription(desc);
                      socket.send(JSON.stringify({ 
                          
          "event""_answer",
                          
          "data": {
                              
          "sdp": desc
                          }
                      }));
                  };

                  
          // 獲取本地音頻和視頻流
                  navigator.webkitGetUserMedia({
                      
          "audio"true,
                      
          "video"true
                  }, 
          function(stream){
                      
          //綁定本地媒體流到video標簽用于輸出
                      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.onmessage = function(event){
                      
          var json = JSON.parse(event.data);
                      console.log('onmessage: ', json);
                      
          //如果是一個ICE的候選,則將其加入到PeerConnection中,否則設定對方的session描述為傳遞過來的描述
                      if( json.event === "_ice_candidate" ){
                          pc.addIceCandidate(
          new RTCIceCandidate(json.data.candidate));
                      } 
          else {
                          pc.setRemoteDescription(
          new RTCSessionDescription(json.data.sdp));
                          
          // 如果是一個offer,那么需要回復一個answer
                          if(json.event === "_offer") {
                              pc.createAnswer(sendAnswerFn, 
          function (error) {
                                  console.log('Failure callback: ' 
          + error);
                              });
                          }
                      }
                  };
              
          </script>
          </body>
          </html>

          實現WebRTC時,信令服務器是必須的,它幫助客戶端之間進行溝通。
          這里使用Node.js的ws模塊來實現一個WebSocket服務作為信令服務器。另外使用express模塊讓它提供html頁面的訪問。
          server.js代碼如下:
          var express = require('express'),
          app = express(),
          server = require('http').createServer(app);

          server.listen(3000);

          app.get('/', function(req, res) {
              res.sendfile(__dirname + '/webrtc.html');
          });

          var WebSocketServer = require('ws').Server,
          wss = new WebSocketServer({server: server});

          // 存儲socket的數組,這里只能有2個socket,每次測試需要重啟,否則會出錯
          var wsc = [],
          index = 1;

          // 有socket連入
          wss.on('connection', function(ws) {
              console.log('connection');

              // 將socket存入數組
              wsc.push(ws);

              // 記下對方socket在數組中的下標,因為這個測試程序只允許2個socket
              // 所以第一個連入的socket存入0,第二個連入的就是存入1
              // otherIndex就反著來,第一個socket的otherIndex下標為1,第二個socket的otherIndex下標為0
              var otherIndex = index--,
              desc = null;

              if (otherIndex == 1) {
                  desc = 'first socket';
              } else {
                  desc = 'second socket';
              }

              // 轉發收到的消息
              ws.on('message', function(message) {
                  var json = JSON.parse(message);
                  console.log('received (' + desc + '): ', json);

                  wsc[otherIndex].send(message, function (error) {
                      if (error) {
                          console.log('Send message error (' + desc + '): ', error);
                      }
                  });
              });
          });

          使用npm安裝需要的模塊后使用node server.js啟動服務。
          測試時使用Chrome瀏覽器:
          第一個瀏覽器窗口訪問頁面:http://127.0.0.1:3000,在彈出的提示中允許使用攝像頭和麥克風。
          第二個瀏覽器窗口訪問頁面:http://127.0.0.1:3000#true,#true表示它是一個發起方,在彈出的提示中同樣允許使用攝像頭和麥克風。
          這時頁面中應當可以看到2個畫面,一個是本地的,一個是遠端的。

          將代碼中的IP稍做調整后部署到外網,即可在2個不同的地點訪問這個頁面進行實時通訊。


          微信訂閱號:
          源文地址:http://blog.gopersist.com/2014/10/21/webrtc-simple/
          posted on 2014-10-21 17:21 老林 閱讀(43356) 評論(6)  編輯  收藏 所屬分類: 即時通訊(IM)

          評論

          # re: 最簡單的WebRTC示例[未登錄] 2014-11-17 11:20 eric
          WebRTC需要stun,turn,ice服務器的支持。stun和turn是發現對方公網ip的方式,ice是一個統一的框架,將stun和turn的實現放在一起。但我在網上搜索ice server好像開源的幾乎沒有。希望多多交流:ericmmgg@126.com。  回復  更多評論
            

          # re: 最簡單的WebRTC示例 2014-11-24 18:36 xy.lin
          @eric
          stun用來發現公網IP,也要判斷路由器行為和防火墻。turn是在無法進行p2p時提供數據中轉服務。rfc5766-turn-server是一個開源項目,同時提供了上面的功能。  回復  更多評論
            

          # re: 最簡單的WebRTC示例[未登錄] 2015-05-14 14:08 danny
          請問樓主,當使用new webkitRTCPeerConnection建立connection后,candidate信息是connection主動去探測的么,如果探測有返回,就會調用onicecandidate()?  回復  更多評論
            

          # re: 最簡單的WebRTC示例[未登錄] 2015-11-18 13:39
          挺好的例子,不過我自己測試發現,在同一臺機器上顯示不了對端的視頻,兩臺機器上可以互通。  回復  更多評論
            

          # re: 最簡單的WebRTC示例 2016-05-26 11:27 keithwind
          是不是onicecandidate和onaddstream的代碼內容反調了,我沒測試,但是感覺流程執行不對  回復  更多評論
            

          # re: 最簡單的WebRTC示例 2016-05-26 17:43 keithwind
          if(json.event === "_offer")
          比較錯了,所以看不到,少一個下劃線  回復  更多評論
            

          主站蜘蛛池模板: 巴塘县| 社旗县| 尚志市| 阳高县| 娱乐| 政和县| 科技| 静宁县| 长海县| 沁水县| 宁城县| 宜黄县| 杭锦旗| 且末县| 梓潼县| 松江区| 汪清县| 潞西市| 洪泽县| 清镇市| 夏邑县| 陇川县| 淳安县| 武冈市| 富蕴县| 东辽县| 天柱县| 满洲里市| 宝应县| 元阳县| 桃园市| 尚志市| 宜城市| 楚雄市| 察隅县| 民勤县| 壤塘县| 施甸县| 宜城市| 孝感市| 葫芦岛市|