不急不徐,持之以恒。

          http://blog.gopersist.com/

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

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

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

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

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

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

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

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

                  
          // 發(fā)送offer和answer的函數(shù),發(fā)送本地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標(biāo)簽用于輸出
                      document.getElementById('localVideo').src = URL.createObjectURL(stream);
                      
          //向PeerConnection中加入需要發(fā)送的流
                      pc.addStream(stream);
                      
          //如果是發(fā)起方則發(fā)送一個offer信令
                      if(isCaller){
                          pc.createOffer(sendOfferFn, 
          function (error) {
                              console.log('Failure callback: ' 
          + error);
                          });
                      }
                  }, 
          function(error){
                      
          //處理媒體流創(chuàng)建失敗錯誤
                      console.log('getUserMedia error: ' + error);
                  });

                  
          //處理到來的信令
                  socket.onmessage = function(event){
                      
          var json = JSON.parse(event.data);
                      console.log('onmessage: ', json);
                      
          //如果是一個ICE的候選,則將其加入到PeerConnection中,否則設(shè)定對方的session描述為傳遞過來的描述
                      if( json.event === "_ice_candidate" ){
                          pc.addIceCandidate(
          new RTCIceCandidate(json.data.candidate));
                      } 
          else {
                          pc.setRemoteDescription(
          new RTCSessionDescription(json.data.sdp));
                          
          // 如果是一個offer,那么需要回復(fù)一個answer
                          if(json.event === "_offer") {
                              pc.createAnswer(sendAnswerFn, 
          function (error) {
                                  console.log('Failure callback: ' 
          + error);
                              });
                          }
                      }
                  };
              
          </script>
          </body>
          </html>

          實(shí)現(xiàn)WebRTC時,信令服務(wù)器是必須的,它幫助客戶端之間進(jìn)行溝通。
          這里使用Node.js的ws模塊來實(shí)現(xiàn)一個WebSocket服務(wù)作為信令服務(wù)器。另外使用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的數(shù)組,這里只能有2個socket,每次測試需要重啟,否則會出錯
          var wsc = [],
          index = 1;

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

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

              // 記下對方socket在數(shù)組中的下標(biāo),因?yàn)檫@個測試程序只允許2個socket
              // 所以第一個連入的socket存入0,第二個連入的就是存入1
              // otherIndex就反著來,第一個socket的otherIndex下標(biāo)為1,第二個socket的otherIndex下標(biāo)為0
              var otherIndex = index--,
              desc = null;

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

              // 轉(zhuǎn)發(fā)收到的消息
              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啟動服務(wù)。
          測試時使用Chrome瀏覽器:
          第一個瀏覽器窗口訪問頁面:http://127.0.0.1:3000,在彈出的提示中允許使用攝像頭和麥克風(fēng)。
          第二個瀏覽器窗口訪問頁面:http://127.0.0.1:3000#true,#true表示它是一個發(fā)起方,在彈出的提示中同樣允許使用攝像頭和麥克風(fēng)。
          這時頁面中應(yīng)當(dāng)可以看到2個畫面,一個是本地的,一個是遠(yuǎn)端的。

          將代碼中的IP稍做調(diào)整后部署到外網(wǎng),即可在2個不同的地點(diǎn)訪問這個頁面進(jìn)行實(shí)時通訊。


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

          評論

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

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

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

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

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

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

          主站蜘蛛池模板: 扎囊县| 噶尔县| 宿迁市| 多伦县| 卓尼县| 贡嘎县| 措美县| 惠安县| 洛宁县| 泊头市| 乌兰浩特市| 井冈山市| 桃江县| 富宁县| 五常市| 桃园县| 太仓市| 浮梁县| 左权县| 翁源县| 铁岭县| 呼图壁县| 和顺县| 林甸县| 黄龙县| 靖安县| 松溪县| 乌什县| 锦州市| 洪湖市| 刚察县| 黄山市| 建德市| 巢湖市| 西安市| 田东县| 萨迦县| 当阳市| 咸宁市| 乐昌市| 武汉市|