Przeglądaj źródła

working in chrome

ericz 12 lat temu
rodzic
commit
91b5734593
9 zmienionych plików z 603 dodań i 478 usunięć
  1. 0 1
      demo/peer.js
  2. 3 2
      demo/static/peer.html
  3. 199 158
      demo/static/peer.js
  4. 3 1
      demo/static/peer1.html
  5. 199 158
      dist/peer.js
  6. 0 0
      dist/peer.min.js
  7. 157 128
      lib/connection.js
  8. 19 29
      lib/peer.js
  9. 23 1
      lib/util.js

+ 0 - 1
demo/peer.js

@@ -1081,7 +1081,6 @@ DataConnection.prototype._setupDataChannel = function(cb) {
     } else {
       this._pc.onconnection = function() {
         util.log('ORIGINATOR: onconnection triggered');
-
         self._startDataChannel();
       };
     }

+ 3 - 2
demo/static/peer.html

@@ -12,18 +12,19 @@
 <script>
 $(document).ready(function() {
   connections = {};
-  var REMOTE = 'ws://mixest.com:9382';
+  var REMOTE = 'ws://localhost:9000';
   originator = new Peer({ ws: REMOTE, debug: true });
   originator.on('ready', function(id) {
     console.log(id);
   });
   originator.on('connection', function(connection) {
+    x = connection;
     console.log('connection');
     connection.on('data', function(data) {
       console.log(data);
     });
     connection.send('What is going on?');
-    connections[connection.metadata.username] = connection;
+    //connections[connection.metadata.username] = connection;
   });
 });
 

+ 199 - 158
demo/static/peer.js

@@ -791,7 +791,29 @@ var util = {
       global.attachEvent('onmessage', handleMessage);
     }
     return setZeroTimeoutPostMessage;
-  }(this))
+  }(this)),
+  
+  blobToArrayBuffer: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsArrayBuffer(blob);
+  },
+  blobToBinaryString: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsBinaryString(blob);
+  },
+  binaryStringToArrayBuffer: function(binary) {
+    var byteArray = new Uint8Array(binary.length);
+    for (var i = 0; i < binary.length; i++) {
+      byteArray[i] = binary.charCodeAt(i) & 0xff;
+    }
+    return byteArray.buffer;
+  }
 };
 var RTCPeerConnection = null;
 var getUserMedia = null;
@@ -830,35 +852,30 @@ function Peer(options) {
 
   options = util.extend({
     debug: false,
-    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
-    ws: 'ws://localhost'
+    peer: 'ws://localhost'
   }, options);
+  this.options = options;
   util.debug = options.debug;
 
   this._id = null;
 
+  this._socket = new WebSocket(options.ws);
+  this._socketInit();
+  
+  
   // Connections
   this.connections = {};
-  this._socket = new WebSocket(options.ws);
-
-  // Init socket msg handlers
-  var self = this;
-  this._socket.onopen = function() {
-    self.socketInit();
-  };
 };
 
 util.inherits(Peer, EventEmitter);
 
 /** Start up websocket communications. */
-Peer.prototype.socketInit = function() {
+Peer.prototype._socketInit = function() {
   var self = this;
-
   this._socket.onmessage = function(event) {
     var message = JSON.parse(event.data);
     var peer = message.src;
     var connection = self.connections[peer];
-
     switch (message.type) {
       case 'ID':
         self._id = message.id;
@@ -867,20 +884,17 @@ Peer.prototype.socketInit = function() {
       case 'OFFER':
         var options = {
           metadata: message.metadata,
-          peer: peer,
-          id: self._id,
-          originator: false,
           sdp: message.sdp
         };
-        var connection = new DataConnection(options, self._socket, function(err, connection) {
+        var connection = new DataConnection(self._id, peer, self._socket, function(err, connection) {
           if (!err) {
             self.emit('connection', connection);
           }
-        });
+        }, options);
         self.connections[peer] = connection;
         break;
       case 'ANSWER':
-        if (connection) connection.handleAnswer(message);
+        if (connection) connection.handleSDP(message);
         break;
       case 'CANDIDATE':
         if (connection) connection.handleCandidate(message);
@@ -889,7 +903,7 @@ Peer.prototype.socketInit = function() {
         if (connection) connection.handleLeave(message);
         break;
       case 'PORT':
-        if (browserisms && browserisms == 'Firefox') {
+        if (browserisms == 'Firefox') {
           connection.handlePort(message);
           break;
         }
@@ -898,11 +912,12 @@ Peer.prototype.socketInit = function() {
         break;
     }
   };
-  // Announce as a PEER to receive an ID.
-  this._socket.send(JSON.stringify({
-    type: 'PEER'
-  }));
-
+  this._socket.onopen = function() {
+    // Announce as a PEER to receive an ID.
+    self._socket.send(JSON.stringify({
+      type: 'PEER'
+    }));
+  };
 };
 
 
@@ -910,29 +925,32 @@ Peer.prototype.connect = function(peer, metadata, cb) {
   if (typeof metadata === 'function' && !cb) cb = metadata; metadata = false;
 
   var options = {
-    metadata: metadata,
-    id: this._id,
-    peer: peer,
-    originator: true
+    metadata: metadata
   };
-  var connection = new DataConnection(options, this._socket, cb);
+  var connection = new DataConnection(this._id, peer, this._socket, cb, options);
   this.connections[peer] = connection;
 };
 
 
 exports.Peer = Peer;
 
-function DataConnection(options, socket, cb) {
+function DataConnection(id, peer, socket, cb, options) {
   if (!(this instanceof DataConnection)) return new DataConnection(options);
   EventEmitter.call(this);
 
+  options = util.extend({
+    debug: false,
+    ice: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] }
+  }, options);
+  this.options = options;
+  
   // Is this the originator?
-  this._originator = options.originator || false;
+  
+  this._id = id;
+  this._peer = peer;
+  this._originator = (options.sdp == undefined);
   this._cb = cb;
-  this._peer = options.peer;
-  this._id = options.id;
-
-  var sdp = options.sdp;
+ 
   this.metadata = options.metadata;
 
   // Set up socket handlers.
@@ -940,60 +958,73 @@ function DataConnection(options, socket, cb) {
 
   // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox') {
-    if (!DataConnection.usedPorts) {
-      DataConnection.usedPorts = [];
-    }
-    this.localPort = util.randomPort();
-    while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.localPort = util.randomPort();
-    }
-    this.remotePort = util.randomPort();
-    while (this.remotePort == this.localPort ||
-        DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.remotePort = util.randomPort();
-    }
-    DataConnection.usedPorts.push(this.remotePort);
-    DataConnection.usedPorts.push(this.localPort);
+    this._firefoxPortSetup();
   }
-
+  //
+  
   // Set up PeerConnection.
   this._startPeerConnection();
+  
+  // Listen for ICE candidates
+  this._setupIce();
+  
+  // Listen for negotiation needed
+  this._setupOffer();
+  
+  // Listen or create a data channel
+  this._setupDataChannel();
+  
   var self = this;
-  if (this._originator) {
-    this._setupDataChannel();
-    this._maybeBrowserisms();
-  } else if (sdp) {
-    try {
-      sdp = new RTCSessionDescription(sdp);
-    } catch(e) {
-      util.log('Firefox');
+  
+  if (options.sdp) {
+    this.handleSDP({type: 'OFFER', sdp: options.sdp});
+    if (browserisms !== 'Firefox') { 
+      this._makeAnswer();
     }
-    this._pc.setRemoteDescription(sdp, function() {
-      util.log('setRemoteDescription: offer');
-      self._setupDataChannel();
-      self._maybeBrowserisms();
-
-    }, function(err) {
-      this._cb('failed to setRemoteDescription');
-      util.log('failed to setRemoteDescription with offer, ', err);
-    });
+  }
+  
+  if (browserisms == 'Firefox') {
+    this._firefoxAdditional();
   }
 };
 
 util.inherits(DataConnection, EventEmitter);
 
-DataConnection.prototype.handleAnswer = function(message) {
+DataConnection.prototype._setupOffer = function() {
+  var self = this;
+  util.log('Listening for `negotiationneeded`');
+  this._pc.onnegotiationneeded = function() {
+    util.log('`negotiationneeded` triggered');
+    self._makeOffer();
+  };
+}
+
+DataConnection.prototype._setupDataChannel = function() {
+  var self = this;
+  if (this._originator) {
+    util.log('Creating data channel');
+    this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
+    this._configureDataChannel();
+  } else {
+    util.log('Listening for data channel');
+    this._pc.ondatachannel = function(evt) {
+      util.log('Received data channel');
+      self._dc = evt.channel;
+      self._configureDataChannel();
+    };
+  }
+};
+
+DataConnection.prototype.handleSDP = function(message) {
   var sdp = message.sdp;
-  try {
-    sdp = new RTCSessionDescription(message.sdp);
-  } catch(e) {
-    util.log('Firefox');
+  if (browserisms != 'Firefox') {
+    sdp = new RTCSessionDescription(sdp);
   }
   var self = this;
   this._pc.setRemoteDescription(sdp, function() {
-    util.log('setRemoteDescription: answer');
+    util.log('Set remoteDescription: ' + message.type);
     // Firefoxism
-    if (browserisms == 'Firefox') {
+    if (message.type == 'ANSWER' && browserisms == 'Firefox') {
       self._pc.connectDataConnection(self.localPort, self.remotePort);
       self._socket.send(JSON.stringify({
         type: 'PORT',
@@ -1003,23 +1034,21 @@ DataConnection.prototype.handleAnswer = function(message) {
         local: self.remotePort
       }));
     }
-    util.log('ORIGINATOR: PeerConnection success');
   }, function(err) {
-    this._cb('failed to setRemoteDescription');
-    util.log('failed to setRemoteDescription, ', err);
+    this._cb('Failed to setRemoteDescription');
+    util.log('Failed to setRemoteDescription, ', err);
   });
 };
 
 
 DataConnection.prototype.handleCandidate = function(message) {
-  util.log(message.candidate);
   var candidate = new RTCIceCandidate(message.candidate);
   this._pc.addIceCandidate(candidate);
 };
 
 
 DataConnection.prototype.handleLeave = function(message) {
-  util.log('counterpart disconnected');
+  util.log('Peer ' + this._peer + ' disconnected');
   if (!!this._pc && this._pc.readyState != 'closed') {
     this._pc.close();
     this._pc = null;
@@ -1043,42 +1072,41 @@ DataConnection.prototype.handlePort = function(message) {
 
 /** Starts a PeerConnection and sets up handlers. */
 DataConnection.prototype._startPeerConnection = function() {
-  this._pc = new RTCPeerConnection(this._config, { optional:[ { RtpDataChannels: true } ]});
-  this._setupIce();
+  util.log('Creating RTCPeerConnection: ', this.options.ice);
+  this._pc = new RTCPeerConnection(this.options.ice, { optional:[ { RtpDataChannels: true } ]});
 };
 
 
 /** Takes care of ice handlers. */
 DataConnection.prototype._setupIce = function() {
+  util.log('Listening for ICE candidates');
   var self = this;
-  this._pc.onicecandidate = function(event) {
-    util.log('candidates received');
-    if (event.candidate) {
+  this._pc.onicecandidate = function(evt) {
+    if (evt.candidate) {
+      util.log('Received ICE candidates');
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
-        candidate: event.candidate,
+        candidate: evt.candidate,
         dst: self._peer,
         src: self._id
       }));
-    } else {
-      util.log("End of candidates.");
     }
   };
 };
 
 
-/** Sets up DataChannel handlers. */
+/** Sets up DataChannel handlers. 
 DataConnection.prototype._setupDataChannel = function() {
   var self = this;
   if (this._originator) {
-    /** ORIGINATOR SETUP */
+    
     if (browserisms == 'Webkit') {
 
       // TODO: figure out the right thing to do with this.
       this._pc.onstatechange = function() {
         util.log('State Change: ', self._pc.readyState);
       }
-
+      
     } else {
       this._pc.onconnection = function() {
         util.log('ORIGINATOR: onconnection triggered');
@@ -1087,17 +1115,7 @@ DataConnection.prototype._setupDataChannel = function() {
       };
     }
   } else {
-    /** TARGET SETUP */
-    this._pc.ondatachannel = function(dc) {
-      util.log('SINK: ondatachannel triggered');
-      self._dc = dc;
-      self._dc.binaryType = 'blob';
-      self._dc.onmessage = function(e) {
-        self._handleDataMessage(e);
-      };
-
-      self._cb(null, self);
-    };
+    
 
     this._pc.onconnection = function() {
       util.log('SINK: onconnection triggered');
@@ -1109,51 +1127,81 @@ DataConnection.prototype._setupDataChannel = function() {
     self.emit('close', self._peer);
   };
 };
+*/
 
+DataConnection.prototype._firefoxPortSetup = function() {
+  if (!DataConnection.usedPorts) {
+    DataConnection.usedPorts = [];
+  }
+  this.localPort = util.randomPort();
+  while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.localPort = util.randomPort();
+  }
+  this.remotePort = util.randomPort();
+  while (this.remotePort == this.localPort ||
+      DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.remotePort = util.randomPort();
+  }
+  DataConnection.usedPorts.push(this.remotePort);
+  DataConnection.usedPorts.push(this.localPort);
+}
 
-DataConnection.prototype._startDataChannel = function() {
+DataConnection.prototype._configureDataChannel = function() {
   var self = this;
-  this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
-  this._dc.binaryType = 'blob';
+  
+  if (browserisms == 'Firefox') {
+    this._dc.binaryType = 'blob';
+  }
+  this._dc.onopen = function() {
+    util.log('Data channel connection success');
+    self._cb(null, self);
+  };
   this._dc.onmessage = function(e) {
     self._handleDataMessage(e);
   };
-
-  this._cb(null, self);
 };
 
 
 /** Decide whether to handle Firefoxisms. */
-DataConnection.prototype._maybeBrowserisms = function() {
+DataConnection.prototype._firefoxAdditional = function() {
   var self = this;
-  if (browserisms == 'Firefox') {
-    getUserMedia({ audio: true, fake: true }, function(s) {
-      self._pc.addStream(s);
-
-      if (self._originator) {
-        self._makeOffer();
-      } else {
-        self._makeAnswer();
-      }
-
-    }, function(err) { util.log('crap'); });
-  } else {
+  getUserMedia({ audio: true, fake: true }, function(s) {
+    self._pc.addStream(s);
     if (self._originator) {
-      this._makeOffer();
+      self._makeOffer();
     } else {
-      this._makeAnswer();
+      self._makeAnswer();
     }
-  }
+  }, function(err) { util.log('Could not getUserMedia'); });
 }
 
+DataConnection.prototype._makeOffer = function() {
+  var self = this;
+  this._pc.createOffer(function(offer) {
+    util.log('Created offer');
+    self._pc.setLocalDescription(offer, function() {
+      util.log('Set localDescription to offer');
+      self._socket.send(JSON.stringify({
+        type: 'OFFER',
+        sdp: offer,
+        dst: self._peer,
+        src: self._id,
+        metadata: self._metadata
+      }));
+    }, function(err) {
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err);
+    });
+  });
+};
 
 /** Create an answer for PC. */
 DataConnection.prototype._makeAnswer = function() {
   var self = this;
-
   this._pc.createAnswer(function(answer) {
+    util.log('Created answer');
     self._pc.setLocalDescription(answer, function() {
-      util.log('setLocalDescription: answer');
+      util.log('Set localDescription to answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -1161,56 +1209,49 @@ DataConnection.prototype._makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err)
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    self._cb('failed to create answer');
-    util.log('failed to create answer, ', err)
+    self._cb('Failed to create answer');
+    util.log('Failed to create answer, ', err)
   });
 };
 
 
-/** Create an offer for PC. */
-DataConnection.prototype._makeOffer = function() {
-  var self = this;
 
-  this._pc.createOffer(function(offer) {
-    self._pc.setLocalDescription(offer, function() {
-      util.log('setLocalDescription: offer');
-      self._socket.send(JSON.stringify({
-        type: 'OFFER',
-        sdp: offer,
-        dst: self._peer,
-        src: self._id,
-        metadata: self._metadata
-      }));
-    }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err);
-    });
-  });
-};
 
 
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
-  var ab = BinaryPack.pack(data);
-  this._dc.send(ab);
+  var self = this;
+  var blob = BinaryPack.pack(data);
+  if (browserisms == 'Webkit') {
+    util.blobToBinaryString(blob, function(str){
+      self._dc.send(str);
+    });
+  } else {
+    this._dc.send(blob);
+  }
 };
 
 
 // Handles a DataChannel message.
 DataConnection.prototype._handleDataMessage = function(e) {
   var self = this;
-  var fr = new FileReader();
-  fr.onload = function(evt) {
-    var ab = evt.target.result;
-    var data = BinaryPack.unpack(ab);
-
-    self.emit('data', data);
-  };
-  fr.readAsArrayBuffer(e.data);
+  if (e.data.constructor == Blob) {
+    util.blobToArrayBuffer(e.data, function(ab) {
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+    });
+  } else if (e.data.constructor == ArrayBuffer) {
+      var data = BinaryPack.unpack(e.data);
+      self.emit('data', data);
+  } else if (e.data.constructor == String) {
+      var ab = util.binaryStringToArrayBuffer(e.data);
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+  }
 };
 
 })(this);

+ 3 - 1
demo/static/peer1.html

@@ -15,9 +15,11 @@ $(document).ready(function() {
   $('#connect').click(function() {
     var source = $('#source').val();
 
-    sink = new Peer({ ws: 'ws://mixest.com:9382', debug: true });
+    sink = new Peer({ ws: 'ws://localhost:9000', debug: true });
     sink.on('ready', function() {
       sink.connect(source, { username: 'michelle' }, function(err, connection) {
+        x = connection;
+        console.log('got connection');
         console.log(connection);
 
         connection.on('data', function(data) {

+ 199 - 158
dist/peer.js

@@ -791,7 +791,29 @@ var util = {
       global.attachEvent('onmessage', handleMessage);
     }
     return setZeroTimeoutPostMessage;
-  }(this))
+  }(this)),
+  
+  blobToArrayBuffer: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsArrayBuffer(blob);
+  },
+  blobToBinaryString: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsBinaryString(blob);
+  },
+  binaryStringToArrayBuffer: function(binary) {
+    var byteArray = new Uint8Array(binary.length);
+    for (var i = 0; i < binary.length; i++) {
+      byteArray[i] = binary.charCodeAt(i) & 0xff;
+    }
+    return byteArray.buffer;
+  }
 };
 var RTCPeerConnection = null;
 var getUserMedia = null;
@@ -830,35 +852,30 @@ function Peer(options) {
 
   options = util.extend({
     debug: false,
-    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
-    ws: 'ws://localhost'
+    peer: 'ws://localhost'
   }, options);
+  this.options = options;
   util.debug = options.debug;
 
   this._id = null;
 
+  this._socket = new WebSocket(options.ws);
+  this._socketInit();
+  
+  
   // Connections
   this.connections = {};
-  this._socket = new WebSocket(options.ws);
-
-  // Init socket msg handlers
-  var self = this;
-  this._socket.onopen = function() {
-    self.socketInit();
-  };
 };
 
 util.inherits(Peer, EventEmitter);
 
 /** Start up websocket communications. */
-Peer.prototype.socketInit = function() {
+Peer.prototype._socketInit = function() {
   var self = this;
-
   this._socket.onmessage = function(event) {
     var message = JSON.parse(event.data);
     var peer = message.src;
     var connection = self.connections[peer];
-
     switch (message.type) {
       case 'ID':
         self._id = message.id;
@@ -867,20 +884,17 @@ Peer.prototype.socketInit = function() {
       case 'OFFER':
         var options = {
           metadata: message.metadata,
-          peer: peer,
-          id: self._id,
-          originator: false,
           sdp: message.sdp
         };
-        var connection = new DataConnection(options, self._socket, function(err, connection) {
+        var connection = new DataConnection(self._id, peer, self._socket, function(err, connection) {
           if (!err) {
             self.emit('connection', connection);
           }
-        });
+        }, options);
         self.connections[peer] = connection;
         break;
       case 'ANSWER':
-        if (connection) connection.handleAnswer(message);
+        if (connection) connection.handleSDP(message);
         break;
       case 'CANDIDATE':
         if (connection) connection.handleCandidate(message);
@@ -889,7 +903,7 @@ Peer.prototype.socketInit = function() {
         if (connection) connection.handleLeave(message);
         break;
       case 'PORT':
-        if (browserisms && browserisms == 'Firefox') {
+        if (browserisms == 'Firefox') {
           connection.handlePort(message);
           break;
         }
@@ -898,11 +912,12 @@ Peer.prototype.socketInit = function() {
         break;
     }
   };
-  // Announce as a PEER to receive an ID.
-  this._socket.send(JSON.stringify({
-    type: 'PEER'
-  }));
-
+  this._socket.onopen = function() {
+    // Announce as a PEER to receive an ID.
+    self._socket.send(JSON.stringify({
+      type: 'PEER'
+    }));
+  };
 };
 
 
@@ -910,29 +925,32 @@ Peer.prototype.connect = function(peer, metadata, cb) {
   if (typeof metadata === 'function' && !cb) cb = metadata; metadata = false;
 
   var options = {
-    metadata: metadata,
-    id: this._id,
-    peer: peer,
-    originator: true
+    metadata: metadata
   };
-  var connection = new DataConnection(options, this._socket, cb);
+  var connection = new DataConnection(this._id, peer, this._socket, cb, options);
   this.connections[peer] = connection;
 };
 
 
 exports.Peer = Peer;
 
-function DataConnection(options, socket, cb) {
+function DataConnection(id, peer, socket, cb, options) {
   if (!(this instanceof DataConnection)) return new DataConnection(options);
   EventEmitter.call(this);
 
+  options = util.extend({
+    debug: false,
+    ice: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] }
+  }, options);
+  this.options = options;
+  
   // Is this the originator?
-  this._originator = options.originator || false;
+  
+  this._id = id;
+  this._peer = peer;
+  this._originator = (options.sdp == undefined);
   this._cb = cb;
-  this._peer = options.peer;
-  this._id = options.id;
-
-  var sdp = options.sdp;
+ 
   this.metadata = options.metadata;
 
   // Set up socket handlers.
@@ -940,60 +958,73 @@ function DataConnection(options, socket, cb) {
 
   // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox') {
-    if (!DataConnection.usedPorts) {
-      DataConnection.usedPorts = [];
-    }
-    this.localPort = util.randomPort();
-    while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.localPort = util.randomPort();
-    }
-    this.remotePort = util.randomPort();
-    while (this.remotePort == this.localPort ||
-        DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.remotePort = util.randomPort();
-    }
-    DataConnection.usedPorts.push(this.remotePort);
-    DataConnection.usedPorts.push(this.localPort);
+    this._firefoxPortSetup();
   }
-
+  //
+  
   // Set up PeerConnection.
   this._startPeerConnection();
+  
+  // Listen for ICE candidates
+  this._setupIce();
+  
+  // Listen for negotiation needed
+  this._setupOffer();
+  
+  // Listen or create a data channel
+  this._setupDataChannel();
+  
   var self = this;
-  if (this._originator) {
-    this._setupDataChannel();
-    this._maybeBrowserisms();
-  } else if (sdp) {
-    try {
-      sdp = new RTCSessionDescription(sdp);
-    } catch(e) {
-      util.log('Firefox');
+  
+  if (options.sdp) {
+    this.handleSDP({type: 'OFFER', sdp: options.sdp});
+    if (browserisms !== 'Firefox') { 
+      this._makeAnswer();
     }
-    this._pc.setRemoteDescription(sdp, function() {
-      util.log('setRemoteDescription: offer');
-      self._setupDataChannel();
-      self._maybeBrowserisms();
-
-    }, function(err) {
-      this._cb('failed to setRemoteDescription');
-      util.log('failed to setRemoteDescription with offer, ', err);
-    });
+  }
+  
+  if (browserisms == 'Firefox') {
+    this._firefoxAdditional();
   }
 };
 
 util.inherits(DataConnection, EventEmitter);
 
-DataConnection.prototype.handleAnswer = function(message) {
+DataConnection.prototype._setupOffer = function() {
+  var self = this;
+  util.log('Listening for `negotiationneeded`');
+  this._pc.onnegotiationneeded = function() {
+    util.log('`negotiationneeded` triggered');
+    self._makeOffer();
+  };
+}
+
+DataConnection.prototype._setupDataChannel = function() {
+  var self = this;
+  if (this._originator) {
+    util.log('Creating data channel');
+    this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
+    this._configureDataChannel();
+  } else {
+    util.log('Listening for data channel');
+    this._pc.ondatachannel = function(evt) {
+      util.log('Received data channel');
+      self._dc = evt.channel;
+      self._configureDataChannel();
+    };
+  }
+};
+
+DataConnection.prototype.handleSDP = function(message) {
   var sdp = message.sdp;
-  try {
-    sdp = new RTCSessionDescription(message.sdp);
-  } catch(e) {
-    util.log('Firefox');
+  if (browserisms != 'Firefox') {
+    sdp = new RTCSessionDescription(sdp);
   }
   var self = this;
   this._pc.setRemoteDescription(sdp, function() {
-    util.log('setRemoteDescription: answer');
+    util.log('Set remoteDescription: ' + message.type);
     // Firefoxism
-    if (browserisms == 'Firefox') {
+    if (message.type == 'ANSWER' && browserisms == 'Firefox') {
       self._pc.connectDataConnection(self.localPort, self.remotePort);
       self._socket.send(JSON.stringify({
         type: 'PORT',
@@ -1003,23 +1034,21 @@ DataConnection.prototype.handleAnswer = function(message) {
         local: self.remotePort
       }));
     }
-    util.log('ORIGINATOR: PeerConnection success');
   }, function(err) {
-    this._cb('failed to setRemoteDescription');
-    util.log('failed to setRemoteDescription, ', err);
+    this._cb('Failed to setRemoteDescription');
+    util.log('Failed to setRemoteDescription, ', err);
   });
 };
 
 
 DataConnection.prototype.handleCandidate = function(message) {
-  util.log(message.candidate);
   var candidate = new RTCIceCandidate(message.candidate);
   this._pc.addIceCandidate(candidate);
 };
 
 
 DataConnection.prototype.handleLeave = function(message) {
-  util.log('counterpart disconnected');
+  util.log('Peer ' + this._peer + ' disconnected');
   if (!!this._pc && this._pc.readyState != 'closed') {
     this._pc.close();
     this._pc = null;
@@ -1043,42 +1072,41 @@ DataConnection.prototype.handlePort = function(message) {
 
 /** Starts a PeerConnection and sets up handlers. */
 DataConnection.prototype._startPeerConnection = function() {
-  this._pc = new RTCPeerConnection(this._config, { optional:[ { RtpDataChannels: true } ]});
-  this._setupIce();
+  util.log('Creating RTCPeerConnection: ', this.options.ice);
+  this._pc = new RTCPeerConnection(this.options.ice, { optional:[ { RtpDataChannels: true } ]});
 };
 
 
 /** Takes care of ice handlers. */
 DataConnection.prototype._setupIce = function() {
+  util.log('Listening for ICE candidates');
   var self = this;
-  this._pc.onicecandidate = function(event) {
-    util.log('candidates received');
-    if (event.candidate) {
+  this._pc.onicecandidate = function(evt) {
+    if (evt.candidate) {
+      util.log('Received ICE candidates');
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
-        candidate: event.candidate,
+        candidate: evt.candidate,
         dst: self._peer,
         src: self._id
       }));
-    } else {
-      util.log("End of candidates.");
     }
   };
 };
 
 
-/** Sets up DataChannel handlers. */
+/** Sets up DataChannel handlers. 
 DataConnection.prototype._setupDataChannel = function() {
   var self = this;
   if (this._originator) {
-    /** ORIGINATOR SETUP */
+    
     if (browserisms == 'Webkit') {
 
       // TODO: figure out the right thing to do with this.
       this._pc.onstatechange = function() {
         util.log('State Change: ', self._pc.readyState);
       }
-
+      
     } else {
       this._pc.onconnection = function() {
         util.log('ORIGINATOR: onconnection triggered');
@@ -1087,17 +1115,7 @@ DataConnection.prototype._setupDataChannel = function() {
       };
     }
   } else {
-    /** TARGET SETUP */
-    this._pc.ondatachannel = function(dc) {
-      util.log('SINK: ondatachannel triggered');
-      self._dc = dc;
-      self._dc.binaryType = 'blob';
-      self._dc.onmessage = function(e) {
-        self._handleDataMessage(e);
-      };
-
-      self._cb(null, self);
-    };
+    
 
     this._pc.onconnection = function() {
       util.log('SINK: onconnection triggered');
@@ -1109,51 +1127,81 @@ DataConnection.prototype._setupDataChannel = function() {
     self.emit('close', self._peer);
   };
 };
+*/
 
+DataConnection.prototype._firefoxPortSetup = function() {
+  if (!DataConnection.usedPorts) {
+    DataConnection.usedPorts = [];
+  }
+  this.localPort = util.randomPort();
+  while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.localPort = util.randomPort();
+  }
+  this.remotePort = util.randomPort();
+  while (this.remotePort == this.localPort ||
+      DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.remotePort = util.randomPort();
+  }
+  DataConnection.usedPorts.push(this.remotePort);
+  DataConnection.usedPorts.push(this.localPort);
+}
 
-DataConnection.prototype._startDataChannel = function() {
+DataConnection.prototype._configureDataChannel = function() {
   var self = this;
-  this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
-  this._dc.binaryType = 'blob';
+  
+  if (browserisms == 'Firefox') {
+    this._dc.binaryType = 'blob';
+  }
+  this._dc.onopen = function() {
+    util.log('Data channel connection success');
+    self._cb(null, self);
+  };
   this._dc.onmessage = function(e) {
     self._handleDataMessage(e);
   };
-
-  this._cb(null, self);
 };
 
 
 /** Decide whether to handle Firefoxisms. */
-DataConnection.prototype._maybeBrowserisms = function() {
+DataConnection.prototype._firefoxAdditional = function() {
   var self = this;
-  if (browserisms == 'Firefox') {
-    getUserMedia({ audio: true, fake: true }, function(s) {
-      self._pc.addStream(s);
-
-      if (self._originator) {
-        self._makeOffer();
-      } else {
-        self._makeAnswer();
-      }
-
-    }, function(err) { util.log('crap'); });
-  } else {
+  getUserMedia({ audio: true, fake: true }, function(s) {
+    self._pc.addStream(s);
     if (self._originator) {
-      this._makeOffer();
+      self._makeOffer();
     } else {
-      this._makeAnswer();
+      self._makeAnswer();
     }
-  }
+  }, function(err) { util.log('Could not getUserMedia'); });
 }
 
+DataConnection.prototype._makeOffer = function() {
+  var self = this;
+  this._pc.createOffer(function(offer) {
+    util.log('Created offer');
+    self._pc.setLocalDescription(offer, function() {
+      util.log('Set localDescription to offer');
+      self._socket.send(JSON.stringify({
+        type: 'OFFER',
+        sdp: offer,
+        dst: self._peer,
+        src: self._id,
+        metadata: self._metadata
+      }));
+    }, function(err) {
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err);
+    });
+  });
+};
 
 /** Create an answer for PC. */
 DataConnection.prototype._makeAnswer = function() {
   var self = this;
-
   this._pc.createAnswer(function(answer) {
+    util.log('Created answer');
     self._pc.setLocalDescription(answer, function() {
-      util.log('setLocalDescription: answer');
+      util.log('Set localDescription to answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -1161,56 +1209,49 @@ DataConnection.prototype._makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err)
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    self._cb('failed to create answer');
-    util.log('failed to create answer, ', err)
+    self._cb('Failed to create answer');
+    util.log('Failed to create answer, ', err)
   });
 };
 
 
-/** Create an offer for PC. */
-DataConnection.prototype._makeOffer = function() {
-  var self = this;
 
-  this._pc.createOffer(function(offer) {
-    self._pc.setLocalDescription(offer, function() {
-      util.log('setLocalDescription: offer');
-      self._socket.send(JSON.stringify({
-        type: 'OFFER',
-        sdp: offer,
-        dst: self._peer,
-        src: self._id,
-        metadata: self._metadata
-      }));
-    }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err);
-    });
-  });
-};
 
 
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
-  var ab = BinaryPack.pack(data);
-  this._dc.send(ab);
+  var self = this;
+  var blob = BinaryPack.pack(data);
+  if (browserisms == 'Webkit') {
+    util.blobToBinaryString(blob, function(str){
+      self._dc.send(str);
+    });
+  } else {
+    this._dc.send(blob);
+  }
 };
 
 
 // Handles a DataChannel message.
 DataConnection.prototype._handleDataMessage = function(e) {
   var self = this;
-  var fr = new FileReader();
-  fr.onload = function(evt) {
-    var ab = evt.target.result;
-    var data = BinaryPack.unpack(ab);
-
-    self.emit('data', data);
-  };
-  fr.readAsArrayBuffer(e.data);
+  if (e.data.constructor == Blob) {
+    util.blobToArrayBuffer(e.data, function(ab) {
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+    });
+  } else if (e.data.constructor == ArrayBuffer) {
+      var data = BinaryPack.unpack(e.data);
+      self.emit('data', data);
+  } else if (e.data.constructor == String) {
+      var ab = util.binaryStringToArrayBuffer(e.data);
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+  }
 };
 
 })(this);

Plik diff jest za duży
+ 0 - 0
dist/peer.min.js


+ 157 - 128
lib/connection.js

@@ -1,14 +1,20 @@
-function DataConnection(options, socket, cb) {
+function DataConnection(id, peer, socket, cb, options) {
   if (!(this instanceof DataConnection)) return new DataConnection(options);
   EventEmitter.call(this);
 
+  options = util.extend({
+    debug: false,
+    ice: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] }
+  }, options);
+  this.options = options;
+  
   // Is this the originator?
-  this._originator = options.originator || false;
+  
+  this._id = id;
+  this._peer = peer;
+  this._originator = (options.sdp == undefined);
   this._cb = cb;
-  this._peer = options.peer;
-  this._id = options.id;
-
-  var sdp = options.sdp;
+ 
   this.metadata = options.metadata;
 
   // Set up socket handlers.
@@ -16,60 +22,73 @@ function DataConnection(options, socket, cb) {
 
   // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox') {
-    if (!DataConnection.usedPorts) {
-      DataConnection.usedPorts = [];
-    }
-    this.localPort = util.randomPort();
-    while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.localPort = util.randomPort();
-    }
-    this.remotePort = util.randomPort();
-    while (this.remotePort == this.localPort ||
-        DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-      this.remotePort = util.randomPort();
-    }
-    DataConnection.usedPorts.push(this.remotePort);
-    DataConnection.usedPorts.push(this.localPort);
+    this._firefoxPortSetup();
   }
-
+  //
+  
   // Set up PeerConnection.
   this._startPeerConnection();
+  
+  // Listen for ICE candidates
+  this._setupIce();
+  
+  // Listen for negotiation needed
+  this._setupOffer();
+  
+  // Listen or create a data channel
+  this._setupDataChannel();
+  
   var self = this;
-  if (this._originator) {
-    this._setupDataChannel();
-    this._maybeBrowserisms();
-  } else if (sdp) {
-    try {
-      sdp = new RTCSessionDescription(sdp);
-    } catch(e) {
-      util.log('Firefox');
+  
+  if (options.sdp) {
+    this.handleSDP({type: 'OFFER', sdp: options.sdp});
+    if (browserisms !== 'Firefox') { 
+      this._makeAnswer();
     }
-    this._pc.setRemoteDescription(sdp, function() {
-      util.log('setRemoteDescription: offer');
-      self._setupDataChannel();
-      self._maybeBrowserisms();
-
-    }, function(err) {
-      this._cb('failed to setRemoteDescription');
-      util.log('failed to setRemoteDescription with offer, ', err);
-    });
+  }
+  
+  if (browserisms == 'Firefox') {
+    this._firefoxAdditional();
   }
 };
 
 util.inherits(DataConnection, EventEmitter);
 
-DataConnection.prototype.handleAnswer = function(message) {
+DataConnection.prototype._setupOffer = function() {
+  var self = this;
+  util.log('Listening for `negotiationneeded`');
+  this._pc.onnegotiationneeded = function() {
+    util.log('`negotiationneeded` triggered');
+    self._makeOffer();
+  };
+}
+
+DataConnection.prototype._setupDataChannel = function() {
+  var self = this;
+  if (this._originator) {
+    util.log('Creating data channel');
+    this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
+    this._configureDataChannel();
+  } else {
+    util.log('Listening for data channel');
+    this._pc.ondatachannel = function(evt) {
+      util.log('Received data channel');
+      self._dc = evt.channel;
+      self._configureDataChannel();
+    };
+  }
+};
+
+DataConnection.prototype.handleSDP = function(message) {
   var sdp = message.sdp;
-  try {
-    sdp = new RTCSessionDescription(message.sdp);
-  } catch(e) {
-    util.log('Firefox');
+  if (browserisms != 'Firefox') {
+    sdp = new RTCSessionDescription(sdp);
   }
   var self = this;
   this._pc.setRemoteDescription(sdp, function() {
-    util.log('setRemoteDescription: answer');
+    util.log('Set remoteDescription: ' + message.type);
     // Firefoxism
-    if (browserisms == 'Firefox') {
+    if (message.type == 'ANSWER' && browserisms == 'Firefox') {
       self._pc.connectDataConnection(self.localPort, self.remotePort);
       self._socket.send(JSON.stringify({
         type: 'PORT',
@@ -79,23 +98,21 @@ DataConnection.prototype.handleAnswer = function(message) {
         local: self.remotePort
       }));
     }
-    util.log('ORIGINATOR: PeerConnection success');
   }, function(err) {
-    this._cb('failed to setRemoteDescription');
-    util.log('failed to setRemoteDescription, ', err);
+    this._cb('Failed to setRemoteDescription');
+    util.log('Failed to setRemoteDescription, ', err);
   });
 };
 
 
 DataConnection.prototype.handleCandidate = function(message) {
-  util.log(message.candidate);
   var candidate = new RTCIceCandidate(message.candidate);
   this._pc.addIceCandidate(candidate);
 };
 
 
 DataConnection.prototype.handleLeave = function(message) {
-  util.log('counterpart disconnected');
+  util.log('Peer ' + this._peer + ' disconnected');
   if (!!this._pc && this._pc.readyState != 'closed') {
     this._pc.close();
     this._pc = null;
@@ -119,42 +136,41 @@ DataConnection.prototype.handlePort = function(message) {
 
 /** Starts a PeerConnection and sets up handlers. */
 DataConnection.prototype._startPeerConnection = function() {
-  this._pc = new RTCPeerConnection(this._config, { optional:[ { RtpDataChannels: true } ]});
-  this._setupIce();
+  util.log('Creating RTCPeerConnection: ', this.options.ice);
+  this._pc = new RTCPeerConnection(this.options.ice, { optional:[ { RtpDataChannels: true } ]});
 };
 
 
 /** Takes care of ice handlers. */
 DataConnection.prototype._setupIce = function() {
+  util.log('Listening for ICE candidates');
   var self = this;
-  this._pc.onicecandidate = function(event) {
-    util.log('candidates received');
-    if (event.candidate) {
+  this._pc.onicecandidate = function(evt) {
+    if (evt.candidate) {
+      util.log('Received ICE candidates');
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
-        candidate: event.candidate,
+        candidate: evt.candidate,
         dst: self._peer,
         src: self._id
       }));
-    } else {
-      util.log("End of candidates.");
     }
   };
 };
 
 
-/** Sets up DataChannel handlers. */
+/** Sets up DataChannel handlers. 
 DataConnection.prototype._setupDataChannel = function() {
   var self = this;
   if (this._originator) {
-    /** ORIGINATOR SETUP */
+    
     if (browserisms == 'Webkit') {
 
       // TODO: figure out the right thing to do with this.
       this._pc.onstatechange = function() {
         util.log('State Change: ', self._pc.readyState);
       }
-
+      
     } else {
       this._pc.onconnection = function() {
         util.log('ORIGINATOR: onconnection triggered');
@@ -163,17 +179,7 @@ DataConnection.prototype._setupDataChannel = function() {
       };
     }
   } else {
-    /** TARGET SETUP */
-    this._pc.ondatachannel = function(dc) {
-      util.log('SINK: ondatachannel triggered');
-      self._dc = dc;
-      self._dc.binaryType = 'blob';
-      self._dc.onmessage = function(e) {
-        self._handleDataMessage(e);
-      };
-
-      self._cb(null, self);
-    };
+    
 
     this._pc.onconnection = function() {
       util.log('SINK: onconnection triggered');
@@ -185,51 +191,81 @@ DataConnection.prototype._setupDataChannel = function() {
     self.emit('close', self._peer);
   };
 };
+*/
 
+DataConnection.prototype._firefoxPortSetup = function() {
+  if (!DataConnection.usedPorts) {
+    DataConnection.usedPorts = [];
+  }
+  this.localPort = util.randomPort();
+  while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.localPort = util.randomPort();
+  }
+  this.remotePort = util.randomPort();
+  while (this.remotePort == this.localPort ||
+      DataConnection.usedPorts.indexOf(this.localPort) != -1) {
+    this.remotePort = util.randomPort();
+  }
+  DataConnection.usedPorts.push(this.remotePort);
+  DataConnection.usedPorts.push(this.localPort);
+}
 
-DataConnection.prototype._startDataChannel = function() {
+DataConnection.prototype._configureDataChannel = function() {
   var self = this;
-  this._dc = this._pc.createDataChannel(this._peer, { reliable: false });
-  this._dc.binaryType = 'blob';
+  
+  if (browserisms == 'Firefox') {
+    this._dc.binaryType = 'blob';
+  }
+  this._dc.onopen = function() {
+    util.log('Data channel connection success');
+    self._cb(null, self);
+  };
   this._dc.onmessage = function(e) {
     self._handleDataMessage(e);
   };
-
-  this._cb(null, self);
 };
 
 
 /** Decide whether to handle Firefoxisms. */
-DataConnection.prototype._maybeBrowserisms = function() {
+DataConnection.prototype._firefoxAdditional = function() {
   var self = this;
-  if (browserisms == 'Firefox') {
-    getUserMedia({ audio: true, fake: true }, function(s) {
-      self._pc.addStream(s);
-
-      if (self._originator) {
-        self._makeOffer();
-      } else {
-        self._makeAnswer();
-      }
-
-    }, function(err) { util.log('crap'); });
-  } else {
+  getUserMedia({ audio: true, fake: true }, function(s) {
+    self._pc.addStream(s);
     if (self._originator) {
-      this._makeOffer();
+      self._makeOffer();
     } else {
-      this._makeAnswer();
+      self._makeAnswer();
     }
-  }
+  }, function(err) { util.log('Could not getUserMedia'); });
 }
 
+DataConnection.prototype._makeOffer = function() {
+  var self = this;
+  this._pc.createOffer(function(offer) {
+    util.log('Created offer');
+    self._pc.setLocalDescription(offer, function() {
+      util.log('Set localDescription to offer');
+      self._socket.send(JSON.stringify({
+        type: 'OFFER',
+        sdp: offer,
+        dst: self._peer,
+        src: self._id,
+        metadata: self._metadata
+      }));
+    }, function(err) {
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err);
+    });
+  });
+};
 
 /** Create an answer for PC. */
 DataConnection.prototype._makeAnswer = function() {
   var self = this;
-
   this._pc.createAnswer(function(answer) {
+    util.log('Created answer');
     self._pc.setLocalDescription(answer, function() {
-      util.log('setLocalDescription: answer');
+      util.log('Set localDescription to answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -237,54 +273,47 @@ DataConnection.prototype._makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err)
+      self._cb('Failed to setLocalDescription');
+      util.log('Failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    self._cb('failed to create answer');
-    util.log('failed to create answer, ', err)
+    self._cb('Failed to create answer');
+    util.log('Failed to create answer, ', err)
   });
 };
 
 
-/** Create an offer for PC. */
-DataConnection.prototype._makeOffer = function() {
-  var self = this;
 
-  this._pc.createOffer(function(offer) {
-    self._pc.setLocalDescription(offer, function() {
-      util.log('setLocalDescription: offer');
-      self._socket.send(JSON.stringify({
-        type: 'OFFER',
-        sdp: offer,
-        dst: self._peer,
-        src: self._id,
-        metadata: self._metadata
-      }));
-    }, function(err) {
-      self._cb('failed to setLocalDescription');
-      util.log('failed to setLocalDescription, ', err);
-    });
-  });
-};
 
 
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
-  var ab = BinaryPack.pack(data);
-  this._dc.send(ab);
+  var self = this;
+  var blob = BinaryPack.pack(data);
+  if (browserisms == 'Webkit') {
+    util.blobToBinaryString(blob, function(str){
+      self._dc.send(str);
+    });
+  } else {
+    this._dc.send(blob);
+  }
 };
 
 
 // Handles a DataChannel message.
 DataConnection.prototype._handleDataMessage = function(e) {
   var self = this;
-  var fr = new FileReader();
-  fr.onload = function(evt) {
-    var ab = evt.target.result;
-    var data = BinaryPack.unpack(ab);
-
-    self.emit('data', data);
-  };
-  fr.readAsArrayBuffer(e.data);
+  if (e.data.constructor == Blob) {
+    util.blobToArrayBuffer(e.data, function(ab) {
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+    });
+  } else if (e.data.constructor == ArrayBuffer) {
+      var data = BinaryPack.unpack(e.data);
+      self.emit('data', data);
+  } else if (e.data.constructor == String) {
+      var ab = util.binaryStringToArrayBuffer(e.data);
+      var data = BinaryPack.unpack(ab);
+      self.emit('data', data);
+  }
 };

+ 19 - 29
lib/peer.js

@@ -4,35 +4,30 @@ function Peer(options) {
 
   options = util.extend({
     debug: false,
-    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
-    ws: 'ws://localhost'
+    peer: 'ws://localhost'
   }, options);
+  this.options = options;
   util.debug = options.debug;
 
   this._id = null;
 
+  this._socket = new WebSocket(options.ws);
+  this._socketInit();
+  
+  
   // Connections
   this.connections = {};
-  this._socket = new WebSocket(options.ws);
-
-  // Init socket msg handlers
-  var self = this;
-  this._socket.onopen = function() {
-    self.socketInit();
-  };
 };
 
 util.inherits(Peer, EventEmitter);
 
 /** Start up websocket communications. */
-Peer.prototype.socketInit = function() {
+Peer.prototype._socketInit = function() {
   var self = this;
-
   this._socket.onmessage = function(event) {
     var message = JSON.parse(event.data);
     var peer = message.src;
     var connection = self.connections[peer];
-
     switch (message.type) {
       case 'ID':
         self._id = message.id;
@@ -41,20 +36,17 @@ Peer.prototype.socketInit = function() {
       case 'OFFER':
         var options = {
           metadata: message.metadata,
-          peer: peer,
-          id: self._id,
-          originator: false,
           sdp: message.sdp
         };
-        var connection = new DataConnection(options, self._socket, function(err, connection) {
+        var connection = new DataConnection(self._id, peer, self._socket, function(err, connection) {
           if (!err) {
             self.emit('connection', connection);
           }
-        });
+        }, options);
         self.connections[peer] = connection;
         break;
       case 'ANSWER':
-        if (connection) connection.handleAnswer(message);
+        if (connection) connection.handleSDP(message);
         break;
       case 'CANDIDATE':
         if (connection) connection.handleCandidate(message);
@@ -63,7 +55,7 @@ Peer.prototype.socketInit = function() {
         if (connection) connection.handleLeave(message);
         break;
       case 'PORT':
-        if (browserisms && browserisms == 'Firefox') {
+        if (browserisms == 'Firefox') {
           connection.handlePort(message);
           break;
         }
@@ -72,11 +64,12 @@ Peer.prototype.socketInit = function() {
         break;
     }
   };
-  // Announce as a PEER to receive an ID.
-  this._socket.send(JSON.stringify({
-    type: 'PEER'
-  }));
-
+  this._socket.onopen = function() {
+    // Announce as a PEER to receive an ID.
+    self._socket.send(JSON.stringify({
+      type: 'PEER'
+    }));
+  };
 };
 
 
@@ -84,12 +77,9 @@ Peer.prototype.connect = function(peer, metadata, cb) {
   if (typeof metadata === 'function' && !cb) cb = metadata; metadata = false;
 
   var options = {
-    metadata: metadata,
-    id: this._id,
-    peer: peer,
-    originator: true
+    metadata: metadata
   };
-  var connection = new DataConnection(options, this._socket, cb);
+  var connection = new DataConnection(this._id, peer, this._socket, cb, options);
   this.connections[peer] = connection;
 };
 

+ 23 - 1
lib/util.js

@@ -63,5 +63,27 @@ var util = {
       global.attachEvent('onmessage', handleMessage);
     }
     return setZeroTimeoutPostMessage;
-  }(this))
+  }(this)),
+  
+  blobToArrayBuffer: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsArrayBuffer(blob);
+  },
+  blobToBinaryString: function(blob, cb){
+    var fr = new FileReader();
+    fr.onload = function(evt) {
+      cb(evt.target.result);
+    };
+    fr.readAsBinaryString(blob);
+  },
+  binaryStringToArrayBuffer: function(binary) {
+    var byteArray = new Uint8Array(binary.length);
+    for (var i = 0; i < binary.length; i++) {
+      byteArray[i] = binary.charCodeAt(i) & 0xff;
+    }
+    return byteArray.buffer;
+  }
 };

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików