首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RTCPeerConnection信令库

RTCPeerConnection信令库
EN

Code Review用户
提问于 2013-05-14 20:13:54
回答 1查看 810关注 0票数 2

我创建了一个库/npm模块来处理RTCPeerConnection的信令过程。还有很多工作需要完成(错误处理,在信令过程中处理断开连接的用户,等等),但目前我主要是在寻找关于总体架构的建议/想法。

这是Github回购

下面我包含了服务器端的模块和客户端的脚本。

服务器端:

代码语言:javascript
复制
var io = require('socket.io');
module.exports = function () {
  // Is used to give each peer a unique ID
  var peerIdCounter = 0;
  // create next ID and return it
  var incrementPeerIdCounter = function () {
    peerIdCounter++;
    return peerIdCounter;
  };
  //  //  //  //  /
  /////////////////
  // Peer Object //
  /*****************************************************************************/
  var createPeer = function (socket) {
    /////////////////////////////////////
    // Peer Object's Private Variables //
    //////////////////////////////////////////////////
    //                                              //
    var self;
    var id;
    // holds the peerConnect offer for this peer
    var offer;
    // list of peers that can connect
    var connectingPeers = {};
    // The Peer class

    function Peer(socket) {
      this.socket = socket;
      id = incrementPeerIdCounter();
      self = this;
      // listen for client sending offer
      self.socket.on('clientSendingOffer', receiveOfferFromClient);
      // detect receiving an answer from clietn
      self.socket.on('clientSendingAnswer', receiveAnswerFromClient);
      // listen for ice candidates
      self.socket.on('clientSendingIce', receiveIceCandidate);
    }
    //                                              //
    //////////////////////////////////////////////////
    //////////////////////////////////
    // Peer Object's Public Methods //
    //////////////////////////////////////////////////
    //                                              //
    // Initiates signaling process
    Peer.prototype.connectToPeer = function (peer, successCallback, failCallback) {
      // answering peer starts waiting for an offer
      peer.acceptOfferFrom(self);
      // This peer will make an offer
      this.makeOfferRequest(peer);
    };
    // Request a peerConnection offer from the current peer
    Peer.prototype.makeOfferRequest = function (peer) {
      // add peer to list of accepted requests
      connectingPeers[peer.getPeerId()] = peer;
      // ask client for an offer
      self.socket.emit('serverRequestingOffer', {
        peerId: peer.getPeerId()
      });
    };
    // Accept peerConnection offers from the specified peer
    Peer.prototype.acceptOfferFrom = function (peer) {
      // add peer to list of accepted requests
      connectingPeers[peer.getPeerId()] = peer;
    };
    // getter for the peer ID
    Peer.prototype.getPeerId = function () {
      return id;
    };
    //                                              //
    //////////////////////////////////////////////////
    ///////////////////////////////////
    // Peer Object's Private Methods //
    //////////////////////////////////////////////////
    //                                              //
    // Handle an offer sent from the client
    var receiveOfferFromClient = function (data) {
      offer = data.offer;
      sendOfferToClient(data.peerId);
    };
    // Send offer to the other peer
    var sendOfferToClient = function (peerId) {
      connectingPeers[peerId].socket.emit(
        'serverSendingOffer', {
        peerId: self.getPeerId(),
        offer: offer
      });
    };
    // Send answer to initiating peer
    var receiveAnswerFromClient = function (data) {
      var peerId = data.peerId;
      data.peerId = self.getPeerId();
      connectingPeers[peerId].socket.emit('serverSendingAnswer', data);
    };
    //Handle ICE candidates received
    var receiveIceCandidate = function (data) {
      var iceInfo = {
        peerId: self.getPeerId(),
        candidate: data.candidate
      };
      connectingPeers[data.peerId].socket.emit('serverSendingIce', iceInfo);
    };
    //                                              //
    //////////////////////////////////////////////////
    // Return an instance of the Peer class
    return new Peer(socket);
  };
  /*____________________________________________________________________________*/
  //  //  //  //  //  //  //  /
  /////////////////////////////
  // Module's Public Methods //
  /*****************************************************************************/
  // Initiates listening for signaling requests
  ///////////////////////////////////////////////
  var listen = function (port, successCallback, failCallback) {
    if(typeof port != 'number') {
      return false;
    }
    // Handle socket requests
    /////////////////////////////
    var server = io.listen(port);
    server.sockets.on('connection', function (socket) {
      var peer;
      try {
        peer = createPeer(socket);
      } catch(e) {
        failCallback(e);
      } finally {
        successCallback(peer);
      }
    });
    return server;
  };
  // Return the public methods
  return {
    listen: listen
  };
  /*____________________________________________________________________________*/
}();

客户端

代码语言:javascript
复制
(function () {
  var signalfire = function () {
    //  //  //  //  /
    /////////////////
    // Peer Object //
    /*****************************************************************************/
    var createPeer = function (socket, options) {
      /////////////////////////////////////
      // Peer Object's Private Variables //
      //////////////////////////////////////////////////
      //                                              //
      var self;
      //holds the ids of the peers that are connecting
      var connectingPeers = {};
      // holds function to call when server requests a connection offer
      // or provides a connection offer
      var makeRTCPeer = options.connector || function () {};
      // holds function to call when signaling process is complete
      var signalingComplete = options.onSignalingComplete || function () {};
      // The Peer class

      function Peer(socket) {
        this.socket = socket;
        self = this;
        // listen for server requesting offer
        self.socket.on('serverRequestingOffer', sendOfferToServer);
        // detect receiving an offer from server
        self.socket.on('serverSendingOffer', sendAnswerToServer);
        // listen for ice candidates
        self.socket.on('serverSendingAnswer', receiveAnswerFromServer);
        // listen for ice candidates
        self.socket.on('serverSendingIce', receiveIceCandidate);
      }
      //                                              //
      //////////////////////////////////////////////////
      ///////////////////////////////////
      // Peer Object's Private Methods //
      //////////////////////////////////////////////////
      //                                              //
      // Receive offer request and return an offer
      var sendOfferToServer = function (data) {
        // create RTCPeerConnection
        var rtcPeerConnection = makeRTCPeer();
        // initialize ice candidate listeners
        iceSetup(rtcPeerConnection, data);
        // Add connection to list of peers
        connectingPeers[data.peerId] = rtcPeerConnection;
        // create offer and send to server
        rtcPeerConnection.createOffer(function (offerResponse) {
          data.offer = offerResponse;
          rtcPeerConnection.setLocalDescription(offerResponse, function () {
            socket.emit('clientSendingOffer', data);
          });
        });
      };
      // Receive peer offer from server. Return an answer.
      var sendAnswerToServer = function (data) {
        // create RTCPeerConnection
        var rtcPeerConnection = makeRTCPeer();
        // initialize ice candidate listeners
        iceSetup(rtcPeerConnection, data);
        // Add connection to list of peers
        connectingPeers[data.peerId] = rtcPeerConnection;
        // Create description from offer received
        var offer = new RTCSessionDescription(data.offer);
        // Set Description, create answer, send answer to server
        rtcPeerConnection.setRemoteDescription(offer, function () {
          rtcPeerConnection.createAnswer(function (answer) {
            rtcPeerConnection.setLocalDescription(answer);
            var answerData = {
              peerId: data.peerId,
              answer: answer
            };
            socket.emit('clientSendingAnswer', answerData);
          });
        });
      };
      // Receive peer answer from server
      var receiveAnswerFromServer = function (data) {
        var peerConn = connectingPeers[data.peerId];
        var answer = new RTCSessionDescription(data.answer);
        peerConn.setRemoteDescription(answer, function () {});
      };
      // receive ice candidates from server
      var receiveIceCandidate = function (data) {
        if(data.candidate !== null) {
          connectingPeers[data.peerId].addIceCandidate(new RTCIceCandidate(data.candidate));
        }
      };
      // setup ice candidate handling
      var iceSetup = function (rtcPeerConnection, data) {
        // check if connection has been created
        rtcPeerConnection.onicechange = function (evt) {
          if(rtcPeerConnection.iceConnectionState === 'connected') {
            signalingComplete(rtcPeerConnection);
          }
        };
        // listen for ice candidates and send to server
        rtcPeerConnection.onicecandidate = function (iceData) {
          var sendingIceInfo = {
            peerId: data.peerId,
            candidate: iceData.candidate
          };
          socket.emit('clientSendingIce', sendingIceInfo);
        };
      };
      //                                              //
      //////////////////////////////////////////////////
      // Return an instance of the Peer class
      return new Peer(socket);
    };
    /*____________________________________________________________________________*/
    //  //  //  //  //  
    ////////////////////
    // Public Methods //
    /*****************************************************************************/
    var connect = function (options, successCallback, failCallback) {
      /*
        Options:
            "server" - The url + port of the server to connect to
            "connector" - A function that is called when the server requests
                        an RTC offer. Must return an RTCPeerConnction object.
        */
      if(typeof options != 'object') {
        return false;
      }
      var socket = io.connect(options.server, {
        'force new connection': true
      });
      socket.on('connect', function () {
        var peer;
        try {
          peer = createPeer(socket, options);
        } catch(e) {
          failCallback(e);
        } finally {
          successCallback(peer);
        }
      });
      socket.on('connect_error', function (e) {
        failCallback(e);
      });
      return socket;
    };
    return {
      connect: connect
    };
    /*____________________________________________________________________________*/
  };
  // set the signalfire global variable
  window.signalfire = signalfire();
}());
EN

回答 1

Code Review用户

发布于 2014-04-21 20:47:51

有趣的代码,

我有点惊讶于您将connectToPeer分配给Peer.prototype。在每次调用Peer时,都会创建一个不同的createPeer函数对象,这使得向prototype分配任何内容都是毫无意义的。这也意味着从内存的角度来看,每个连接的对等点都有自己的闭包,所有的代码都在createPeer中。我认为你这样做是因为你想要私人的功能,我不相信这是值得的。

此外,我感到惊讶的是,您在successCallback中调用了finally,这意味着在失败的情况下也会调用它,这是不直观的。

客户端和服务器之间显然有共同的代码,您应该提取该公共代码。

除此之外,您的代码有很好的注释,并且非常容易理解,而且JsHint没有什么可抱怨的。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/26178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档