ericz 11 年之前
父节点
当前提交
457ece1937
共有 10 个文件被更改,包括 105 次插入94 次删除
  1. 9 2
      changelog.md
  2. 1 1
      deps/reliable
  3. 31 35
      dist/peer.js
  4. 0 0
      dist/peer.min.js
  5. 27 16
      examples/chat.html
  6. 6 5
      examples/helloworldv.html
  7. 11 15
      lib/dataconnection.js
  8. 15 15
      lib/negotiator.js
  9. 4 4
      lib/socket.js
  10. 1 1
      lib/util.js

+ 9 - 2
changelog.md

@@ -1,12 +1,19 @@
 # PeerJS Changelog
 # PeerJS Changelog
 
 
 ## Version 0.3.0 (TBA)
 ## Version 0.3.0 (TBA)
+
+### Highlights
+* **Interoperable DataChannels and video/audio streams.**
 * Support for WebRTC video and audio streams.
 * Support for WebRTC video and audio streams.
-* **Deprecate the ability to assign labels to DataConnections.** They will
-  instead have a randomly-generated ID.
 * Add `util.supports.[FEATURE]` flags, which represent the WebRTC features
 * Add `util.supports.[FEATURE]` flags, which represent the WebRTC features
   supported by your browser.
   supported by your browser.
+
+### Other changes
+* **Deprecate current Peer#connections format.** Connections will no longer be
+  keyed by label and will instead be in a list.
 * Additional logging levels (warnings, errors, all).
 * Additional logging levels (warnings, errors, all).
+* Additional logging functionality (`logFunction`).
+* SSL option now in config rather than automatic.
 
 
 ## Version 0.2.8 (1 July 2013)
 ## Version 0.2.8 (1 July 2013)
 * Fix bug, no error on Firefox 24 due to missing error callback.
 * Fix bug, no error on Firefox 24 due to missing error callback.

+ 1 - 1
deps/reliable

@@ -1 +1 @@
-Subproject commit 856406373194f62fe68407eb680caa289a202a99
+Subproject commit 0bbaf986efa550ea261b33ae20e17d85fb5b5bfa

+ 31 - 35
dist/peer.js

@@ -781,7 +781,7 @@ var util = {
       audioVideo: true,
       audioVideo: true,
       data: true,
       data: true,
       binary: false,
       binary: false,
-      reliable: true,
+      reliable: false,
       onnegotiationneeded: true
       onnegotiationneeded: true
     };
     };
   }()),
   }()),
@@ -1639,7 +1639,7 @@ function DataConnection(peer, provider, options) {
   this.id = this.options.connectionId || DataConnection._idPrefix + util.randomToken();
   this.id = this.options.connectionId || DataConnection._idPrefix + util.randomToken();
 
 
   this.label = this.options.label || this.id;
   this.label = this.options.label || this.id;
-  this.metadata = this.options.metadata; // TODO: metadata could also be a part of the paylod.
+  this.metadata = this.options.metadata;
   this.serialization = this.options.serialization;
   this.serialization = this.options.serialization;
   this.reliable = this.options.reliable;
   this.reliable = this.options.reliable;
 
 
@@ -1667,7 +1667,6 @@ DataConnection.prototype.initialize = function(dc) {
 
 
 DataConnection.prototype._configureDataChannel = function() {
 DataConnection.prototype._configureDataChannel = function() {
   var self = this;
   var self = this;
-  // TODO: util.supports.binary
   if (util.supports.binary) {
   if (util.supports.binary) {
     // Webkit doesn't support binary yet
     // Webkit doesn't support binary yet
     this._dc.binaryType = 'arraybuffer';
     this._dc.binaryType = 'arraybuffer';
@@ -1679,7 +1678,6 @@ DataConnection.prototype._configureDataChannel = function() {
   }
   }
 
 
   // Use the Reliable shim for non Firefox browsers
   // Use the Reliable shim for non Firefox browsers
-  // TODO: util.supports.reliable
   if (!util.supports.reliable) {
   if (!util.supports.reliable) {
     this._reliable = new Reliable(this._dc, util.debug);
     this._reliable = new Reliable(this._dc, util.debug);
   }
   }
@@ -1695,19 +1693,20 @@ DataConnection.prototype._configureDataChannel = function() {
   }
   }
   this._dc.onclose = function(e) {
   this._dc.onclose = function(e) {
     util.log('DataChannel closed for:', self.peer);
     util.log('DataChannel closed for:', self.peer);
-    // TODO: remove connection from Peer as well!!
     self.close();
     self.close();
   };
   };
 }
 }
 
 
 DataConnection.prototype._cleanup = function() {
 DataConnection.prototype._cleanup = function() {
-  if (this._dc && this._dc.readyState !== 'closed') {
-    this._dc.close();
-    this._dc = null;
+  // readyState is deprecated but still exists in older versions.
+  if (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed') {
+    this.pc.close();
+    this.open = false;
+    Negotiator.cleanup(this);
+    this.emit('close');
+  } else {
+    this.emit('error', new Error('The connection has already been closed'));
   }
   }
-  this.open = false;
-  Negotiator.cleanup(this);
-  this.emit('close');
 }
 }
 
 
 // Handles a DataChannel message.
 // Handles a DataChannel message.
@@ -1746,7 +1745,7 @@ DataConnection.prototype.close = function() {
     return;
     return;
   }
   }
   this._cleanup();
   this._cleanup();
-};
+}
 
 
 /** Allows user to send data. */
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
 DataConnection.prototype.send = function(data) {
@@ -1776,20 +1775,17 @@ DataConnection.prototype.send = function(data) {
       this._dc.send(blob);
       this._dc.send(blob);
     }
     }
   }
   }
-};
+}
 
 
 DataConnection.prototype.handleMessage = function(message) {
 DataConnection.prototype.handleMessage = function(message) {
   var payload = message.payload;
   var payload = message.payload;
 
 
   switch (message.type) {
   switch (message.type) {
     case 'ANSWER':
     case 'ANSWER':
-      // TODO: assert sdp exists.
-      // Should we pass `this`?
       // Forward to negotiator
       // Forward to negotiator
       Negotiator.handleSDP(message.type, this, payload.sdp);
       Negotiator.handleSDP(message.type, this, payload.sdp);
       break;
       break;
     case 'CANDIDATE':
     case 'CANDIDATE':
-      // TODO
       Negotiator.handleCandidate(this, payload.candidate);
       Negotiator.handleCandidate(this, payload.candidate);
       break;
       break;
     default:
     default:
@@ -1884,8 +1880,6 @@ MediaConnection.prototype.close = function() {
 /**
 /**
  * Manages all negotiations between Peers.
  * Manages all negotiations between Peers.
  */
  */
-// TODO: LOCKS.
-// TODO: FIREFOX new PC after offer made for DC.
 var Negotiator = {
 var Negotiator = {
   pcs: {
   pcs: {
     data: {},
     data: {},
@@ -1898,9 +1892,7 @@ var Negotiator = {
 Negotiator._idPrefix = 'pc_';
 Negotiator._idPrefix = 'pc_';
 
 
 /** Returns a PeerConnection object set up correctly (for data, media). */
 /** Returns a PeerConnection object set up correctly (for data, media). */
-// Options preceeded with _ are ones we add artificially.
 Negotiator.startConnection = function(connection, options) {
 Negotiator.startConnection = function(connection, options) {
-  //Negotiator._addProvider(provider);
   var pc = Negotiator._getPeerConnection(connection, options);
   var pc = Negotiator._getPeerConnection(connection, options);
 
 
   if (connection.type === 'media' && options._stream) {
   if (connection.type === 'media' && options._stream) {
@@ -1937,9 +1929,8 @@ Negotiator._getPeerConnection = function(connection, options) {
   var peerConnections = Negotiator.pcs[connection.type][connection.peer];
   var peerConnections = Negotiator.pcs[connection.type][connection.peer];
 
 
   var pc;
   var pc;
-  if (options.multiplex) {
-    // TODO: this doesn't work right now because we don't have PC ids.
-    // Find an existing PC to use.
+  // Not multiplexing while FF and Chrome have not-great support for it.
+  /*if (options.multiplex) {
     ids = Object.keys(peerConnections);
     ids = Object.keys(peerConnections);
     for (var i = 0, ii = ids.length; i < ii; i += 1) {
     for (var i = 0, ii = ids.length; i < ii; i += 1) {
       pc = peerConnections[ids[i]];
       pc = peerConnections[ids[i]];
@@ -1947,7 +1938,8 @@ Negotiator._getPeerConnection = function(connection, options) {
         break; // We can go ahead and use this PC.
         break; // We can go ahead and use this PC.
       }
       }
     }
     }
-  } else if (options.pc) { // Simplest case: PC id already provided for us.
+  } else */
+  if (options.pc) { // Simplest case: PC id already provided for us.
     pc = Negotiator.pcs[connection.type][connection.peer][options.pc];
     pc = Negotiator.pcs[connection.type][connection.peer][options.pc];
   }
   }
 
 
@@ -1975,7 +1967,12 @@ Negotiator._startPeerConnection = function(connection) {
   util.log('Creating RTCPeerConnection.');
   util.log('Creating RTCPeerConnection.');
 
 
   var id = Negotiator._idPrefix + util.randomToken();
   var id = Negotiator._idPrefix + util.randomToken();
-  pc = new RTCPeerConnection(connection.provider.options.config, {optional: [{RtpDataChannels: true}]});
+  pc = new RTCPeerConnection(connection.provider.options.config, {
+    optional: [{
+      RtpDataChannels: true,
+      DtlsSrtpKeyAgreement: true /* Firefox interop */
+    }]
+  });
   Negotiator.pcs[connection.type][connection.peer][id] = pc;
   Negotiator.pcs[connection.type][connection.peer][id] = pc;
 
 
   Negotiator._setupListeners(connection, pc, id);
   Negotiator._setupListeners(connection, pc, id);
@@ -2008,6 +2005,7 @@ Negotiator._setupListeners = function(connection, pc, pc_id) {
 
 
   pc.oniceconnectionstatechange = function() {
   pc.oniceconnectionstatechange = function() {
     switch (pc.iceConnectionState) {
     switch (pc.iceConnectionState) {
+      case 'disconnected':
       case 'failed':
       case 'failed':
         util.log('iceConnectionState is disconnected, closing connections to ' + peerId);
         util.log('iceConnectionState is disconnected, closing connections to ' + peerId);
         Negotiator.cleanup(connection);
         Negotiator.cleanup(connection);
@@ -2054,7 +2052,6 @@ Negotiator._setupListeners = function(connection, pc, pc_id) {
 
 
 Negotiator.cleanup = function(connection) {
 Negotiator.cleanup = function(connection) {
   connection.close(); // Will fail safely if connection is already closed.
   connection.close(); // Will fail safely if connection is already closed.
-  // TODO: close PeerConnection when all connections are closed.
   util.log('Cleanup PeerConnection for ' + connection.peer);
   util.log('Cleanup PeerConnection for ' + connection.peer);
   /*if (!!this.pc && (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed')) {
   /*if (!!this.pc && (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed')) {
     this.pc.close();
     this.pc.close();
@@ -2073,8 +2070,8 @@ Negotiator._makeOffer = function(connection) {
   pc.createOffer(function(offer) {
   pc.createOffer(function(offer) {
     util.log('Created offer.');
     util.log('Created offer.');
 
 
-    if (!util.supports.reliable) {
-      //offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
+    if (!util.supports.reliable && connection.type === 'data') {
+      offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
     }
     }
 
 
     pc.setLocalDescription(offer, function() {
     pc.setLocalDescription(offer, function() {
@@ -2108,9 +2105,8 @@ Negotiator._makeAnswer = function(connection) {
   pc.createAnswer(function(answer) {
   pc.createAnswer(function(answer) {
     util.log('Created answer.');
     util.log('Created answer.');
 
 
-    if (!util.supports.reliable) {
-      // TODO
-      //answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
+    if (!util.supports.reliable && connection.type === 'data') {
+      answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
     }
     }
 
 
     pc.setLocalDescription(answer, function() {
     pc.setLocalDescription(answer, function() {
@@ -2200,7 +2196,7 @@ Socket.prototype.start = function(id) {
 
 
   this._startXhrStream();
   this._startXhrStream();
   this._startWebSocket();
   this._startWebSocket();
-};
+}
 
 
 
 
 /** Start up websocket communications. */
 /** Start up websocket communications. */
@@ -2237,7 +2233,7 @@ Socket.prototype._startWebSocket = function(id) {
     self._sendQueuedMessages();
     self._sendQueuedMessages();
     util.log('Socket open');
     util.log('Socket open');
   };
   };
-};
+}
 
 
 /** Start XHR streaming. */
 /** Start XHR streaming. */
 Socket.prototype._startXhrStream = function(n) {
 Socket.prototype._startXhrStream = function(n) {
@@ -2261,7 +2257,7 @@ Socket.prototype._startXhrStream = function(n) {
   } catch(e) {
   } catch(e) {
     util.log('XMLHttpRequest not available; defaulting to WebSockets');
     util.log('XMLHttpRequest not available; defaulting to WebSockets');
   }
   }
-};
+}
 
 
 
 
 /** Handles onreadystatechange response as a stream. */
 /** Handles onreadystatechange response as a stream. */
@@ -2367,6 +2363,6 @@ Socket.prototype.close = function() {
     this._socket.close();
     this._socket.close();
     this.disconnected = true;
     this.disconnected = true;
   }
   }
-};
+}
 
 
 })(this);
 })(this);

文件差异内容过多而无法显示
+ 0 - 0
dist/peer.min.js


+ 27 - 16
examples/chat.html

@@ -21,6 +21,7 @@
 <script>
 <script>
 // Connect to PeerJS, have server assign an ID instead of providing one
 // Connect to PeerJS, have server assign an ID instead of providing one
 var peer = new Peer({key: 'lwjd5qra8257b9', debug: 3});
 var peer = new Peer({key: 'lwjd5qra8257b9', debug: 3});
+var connectedPeers = {};
 
 
 // Show this peer's ID.
 // Show this peer's ID.
 peer.on('open', function(id){
 peer.on('open', function(id){
@@ -61,6 +62,7 @@ function connect(c) {
           if ($('.connection').length === 0) {
           if ($('.connection').length === 0) {
             $('.filler').show();
             $('.filler').show();
           }
           }
+          delete connectedPeers[c.peer];
         });
         });
   } else if (c.label === 'file') {
   } else if (c.label === 'file') {
     c.on('data', function(data) {
     c.on('data', function(data) {
@@ -98,17 +100,21 @@ $(document).ready(function() {
 
 
   // Connect to a peer
   // Connect to a peer
   $('#connect').click(function() {
   $('#connect').click(function() {
-    // Create 2 connections, one labelled chat and another labelled file.
-    var c = peer.connect($('#rid').val(), { label: 'chat' });
-    c.on('open', function() {
-      connect(c);
-    });
-    c.on('error', function(err) { alert(err); });
-    var f = peer.connect($('#rid').val(), { reliable: true, label: 'file' });
-    f.on('open', function() {
-      connect(f);
-    });
-    f.on('error', function(err) { alert(err); });
+    requestedPeer = $('#rid').val();
+    if (!connectedPeers[requestedPeer]) {
+      // Create 2 connections, one labelled chat and another labelled file.
+      var c = peer.connect(requestedPeer, { label: 'chat' });
+      c.on('open', function() {
+        connect(c);
+      });
+      c.on('error', function(err) { alert(err); });
+      var f = peer.connect(requestedPeer, { reliable: true, label: 'file' });
+      f.on('open', function() {
+        connect(f);
+      });
+      f.on('error', function(err) { alert(err); });
+    }
+    connectedPeers[requestedPeer] = 1;
   });
   });
 
 
   // Close a connection.
   // Close a connection.
@@ -137,14 +143,19 @@ $(document).ready(function() {
   // Goes through each active peer and calls FN on its connections.
   // Goes through each active peer and calls FN on its connections.
   function eachActiveConnection(fn) {
   function eachActiveConnection(fn) {
     var actives = $('.active');
     var actives = $('.active');
+    var checkedIds = {};
     actives.each(function() {
     actives.each(function() {
       var peerId = $(this).attr('id');
       var peerId = $(this).attr('id');
-      var conns = peer.connections[peerId];
-      var labels = Object.keys(conns);
-      for (var i = 0, ii = labels.length; i < ii; i += 1) {
-        var conn = conns[labels[i]];
-        fn(conn, $(this));
+
+      if (!checkedIds[peerId]) {
+        var conns = peer.connections[peerId];
+        for (var i = 0, ii = conns.length; i < ii; i += 1) {
+          var conn = conns[i];
+          fn(conn, $(this));
+        }
       }
       }
+
+      checkedIds[peerId] = 1;
     });
     });
   }
   }
 
 

+ 6 - 5
examples/helloworldv.html

@@ -9,9 +9,9 @@
   // Just for demo.
   // Just for demo.
   console._log = console.log;
   console._log = console.log;
   console.error = console.log = function() {
   console.error = console.log = function() {
-    var copy = Array.prototype.slice.call(arguments).join(' ');
-    $('.log').append(copy + '<br>');
-    console._log(copy);
+    var copy = Array.prototype.slice.call(arguments);
+    $('.log').append(copy.join(' ') + '<br>');
+    console._log.apply(console, copy);
   };
   };
 </script>
 </script>
 
 
@@ -26,8 +26,9 @@
       window.ls = s;
       window.ls = s;
       // Create a new Peer with our demo API key, with debug set to true so we can
       // Create a new Peer with our demo API key, with debug set to true so we can
       // see what's going on.
       // see what's going on.
-      peer1 = new Peer(window.location.hash.substr(1), { key: 'lwjd5qra8257b9', debug: true });
-      
+      peer1 = new Peer(window.location.hash.substr(1), { key: 'lwjd5qra8257b9', debug: 3});
+      peer1.on('error', console.log);
+      peer1.on('close', console.log);
       peer1.on('call', function(c){
       peer1.on('call', function(c){
         c.answer(s);
         c.answer(s);
         c.on('stream', function(s){
         c.on('stream', function(s){

+ 11 - 15
lib/dataconnection.js

@@ -19,7 +19,7 @@ function DataConnection(peer, provider, options) {
   this.id = this.options.connectionId || DataConnection._idPrefix + util.randomToken();
   this.id = this.options.connectionId || DataConnection._idPrefix + util.randomToken();
 
 
   this.label = this.options.label || this.id;
   this.label = this.options.label || this.id;
-  this.metadata = this.options.metadata; // TODO: metadata could also be a part of the paylod.
+  this.metadata = this.options.metadata;
   this.serialization = this.options.serialization;
   this.serialization = this.options.serialization;
   this.reliable = this.options.reliable;
   this.reliable = this.options.reliable;
 
 
@@ -47,7 +47,6 @@ DataConnection.prototype.initialize = function(dc) {
 
 
 DataConnection.prototype._configureDataChannel = function() {
 DataConnection.prototype._configureDataChannel = function() {
   var self = this;
   var self = this;
-  // TODO: util.supports.binary
   if (util.supports.binary) {
   if (util.supports.binary) {
     // Webkit doesn't support binary yet
     // Webkit doesn't support binary yet
     this._dc.binaryType = 'arraybuffer';
     this._dc.binaryType = 'arraybuffer';
@@ -59,7 +58,6 @@ DataConnection.prototype._configureDataChannel = function() {
   }
   }
 
 
   // Use the Reliable shim for non Firefox browsers
   // Use the Reliable shim for non Firefox browsers
-  // TODO: util.supports.reliable
   if (!util.supports.reliable) {
   if (!util.supports.reliable) {
     this._reliable = new Reliable(this._dc, util.debug);
     this._reliable = new Reliable(this._dc, util.debug);
   }
   }
@@ -75,19 +73,20 @@ DataConnection.prototype._configureDataChannel = function() {
   }
   }
   this._dc.onclose = function(e) {
   this._dc.onclose = function(e) {
     util.log('DataChannel closed for:', self.peer);
     util.log('DataChannel closed for:', self.peer);
-    // TODO: remove connection from Peer as well!!
     self.close();
     self.close();
   };
   };
 }
 }
 
 
 DataConnection.prototype._cleanup = function() {
 DataConnection.prototype._cleanup = function() {
-  if (this._dc && this._dc.readyState !== 'closed') {
-    this._dc.close();
-    this._dc = null;
+  // readyState is deprecated but still exists in older versions.
+  if (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed') {
+    this.pc.close();
+    this.open = false;
+    Negotiator.cleanup(this);
+    this.emit('close');
+  } else {
+    this.emit('error', new Error('The connection has already been closed'));
   }
   }
-  this.open = false;
-  Negotiator.cleanup(this);
-  this.emit('close');
 }
 }
 
 
 // Handles a DataChannel message.
 // Handles a DataChannel message.
@@ -126,7 +125,7 @@ DataConnection.prototype.close = function() {
     return;
     return;
   }
   }
   this._cleanup();
   this._cleanup();
-};
+}
 
 
 /** Allows user to send data. */
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
 DataConnection.prototype.send = function(data) {
@@ -156,20 +155,17 @@ DataConnection.prototype.send = function(data) {
       this._dc.send(blob);
       this._dc.send(blob);
     }
     }
   }
   }
-};
+}
 
 
 DataConnection.prototype.handleMessage = function(message) {
 DataConnection.prototype.handleMessage = function(message) {
   var payload = message.payload;
   var payload = message.payload;
 
 
   switch (message.type) {
   switch (message.type) {
     case 'ANSWER':
     case 'ANSWER':
-      // TODO: assert sdp exists.
-      // Should we pass `this`?
       // Forward to negotiator
       // Forward to negotiator
       Negotiator.handleSDP(message.type, this, payload.sdp);
       Negotiator.handleSDP(message.type, this, payload.sdp);
       break;
       break;
     case 'CANDIDATE':
     case 'CANDIDATE':
-      // TODO
       Negotiator.handleCandidate(this, payload.candidate);
       Negotiator.handleCandidate(this, payload.candidate);
       break;
       break;
     default:
     default:

+ 15 - 15
lib/negotiator.js

@@ -1,8 +1,6 @@
 /**
 /**
  * Manages all negotiations between Peers.
  * Manages all negotiations between Peers.
  */
  */
-// TODO: LOCKS.
-// TODO: FIREFOX new PC after offer made for DC.
 var Negotiator = {
 var Negotiator = {
   pcs: {
   pcs: {
     data: {},
     data: {},
@@ -15,9 +13,7 @@ var Negotiator = {
 Negotiator._idPrefix = 'pc_';
 Negotiator._idPrefix = 'pc_';
 
 
 /** Returns a PeerConnection object set up correctly (for data, media). */
 /** Returns a PeerConnection object set up correctly (for data, media). */
-// Options preceeded with _ are ones we add artificially.
 Negotiator.startConnection = function(connection, options) {
 Negotiator.startConnection = function(connection, options) {
-  //Negotiator._addProvider(provider);
   var pc = Negotiator._getPeerConnection(connection, options);
   var pc = Negotiator._getPeerConnection(connection, options);
 
 
   if (connection.type === 'media' && options._stream) {
   if (connection.type === 'media' && options._stream) {
@@ -54,9 +50,8 @@ Negotiator._getPeerConnection = function(connection, options) {
   var peerConnections = Negotiator.pcs[connection.type][connection.peer];
   var peerConnections = Negotiator.pcs[connection.type][connection.peer];
 
 
   var pc;
   var pc;
-  if (options.multiplex) {
-    // TODO: this doesn't work right now because we don't have PC ids.
-    // Find an existing PC to use.
+  // Not multiplexing while FF and Chrome have not-great support for it.
+  /*if (options.multiplex) {
     ids = Object.keys(peerConnections);
     ids = Object.keys(peerConnections);
     for (var i = 0, ii = ids.length; i < ii; i += 1) {
     for (var i = 0, ii = ids.length; i < ii; i += 1) {
       pc = peerConnections[ids[i]];
       pc = peerConnections[ids[i]];
@@ -64,7 +59,8 @@ Negotiator._getPeerConnection = function(connection, options) {
         break; // We can go ahead and use this PC.
         break; // We can go ahead and use this PC.
       }
       }
     }
     }
-  } else if (options.pc) { // Simplest case: PC id already provided for us.
+  } else */
+  if (options.pc) { // Simplest case: PC id already provided for us.
     pc = Negotiator.pcs[connection.type][connection.peer][options.pc];
     pc = Negotiator.pcs[connection.type][connection.peer][options.pc];
   }
   }
 
 
@@ -92,7 +88,12 @@ Negotiator._startPeerConnection = function(connection) {
   util.log('Creating RTCPeerConnection.');
   util.log('Creating RTCPeerConnection.');
 
 
   var id = Negotiator._idPrefix + util.randomToken();
   var id = Negotiator._idPrefix + util.randomToken();
-  pc = new RTCPeerConnection(connection.provider.options.config, {optional: [{RtpDataChannels: true}]});
+  pc = new RTCPeerConnection(connection.provider.options.config, {
+    optional: [{
+      RtpDataChannels: true,
+      DtlsSrtpKeyAgreement: true /* Firefox interop */
+    }]
+  });
   Negotiator.pcs[connection.type][connection.peer][id] = pc;
   Negotiator.pcs[connection.type][connection.peer][id] = pc;
 
 
   Negotiator._setupListeners(connection, pc, id);
   Negotiator._setupListeners(connection, pc, id);
@@ -125,6 +126,7 @@ Negotiator._setupListeners = function(connection, pc, pc_id) {
 
 
   pc.oniceconnectionstatechange = function() {
   pc.oniceconnectionstatechange = function() {
     switch (pc.iceConnectionState) {
     switch (pc.iceConnectionState) {
+      case 'disconnected':
       case 'failed':
       case 'failed':
         util.log('iceConnectionState is disconnected, closing connections to ' + peerId);
         util.log('iceConnectionState is disconnected, closing connections to ' + peerId);
         Negotiator.cleanup(connection);
         Negotiator.cleanup(connection);
@@ -171,7 +173,6 @@ Negotiator._setupListeners = function(connection, pc, pc_id) {
 
 
 Negotiator.cleanup = function(connection) {
 Negotiator.cleanup = function(connection) {
   connection.close(); // Will fail safely if connection is already closed.
   connection.close(); // Will fail safely if connection is already closed.
-  // TODO: close PeerConnection when all connections are closed.
   util.log('Cleanup PeerConnection for ' + connection.peer);
   util.log('Cleanup PeerConnection for ' + connection.peer);
   /*if (!!this.pc && (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed')) {
   /*if (!!this.pc && (this.pc.readyState !== 'closed' || this.pc.signalingState !== 'closed')) {
     this.pc.close();
     this.pc.close();
@@ -190,8 +191,8 @@ Negotiator._makeOffer = function(connection) {
   pc.createOffer(function(offer) {
   pc.createOffer(function(offer) {
     util.log('Created offer.');
     util.log('Created offer.');
 
 
-    if (!util.supports.reliable) {
-      //offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
+    if (!util.supports.reliable && connection.type === 'data') {
+      offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
     }
     }
 
 
     pc.setLocalDescription(offer, function() {
     pc.setLocalDescription(offer, function() {
@@ -225,9 +226,8 @@ Negotiator._makeAnswer = function(connection) {
   pc.createAnswer(function(answer) {
   pc.createAnswer(function(answer) {
     util.log('Created answer.');
     util.log('Created answer.');
 
 
-    if (!util.supports.reliable) {
-      // TODO
-      //answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
+    if (!util.supports.reliable && connection.type === 'data') {
+      answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
     }
     }
 
 
     pc.setLocalDescription(answer, function() {
     pc.setLocalDescription(answer, function() {

+ 4 - 4
lib/socket.js

@@ -30,7 +30,7 @@ Socket.prototype.start = function(id) {
 
 
   this._startXhrStream();
   this._startXhrStream();
   this._startWebSocket();
   this._startWebSocket();
-};
+}
 
 
 
 
 /** Start up websocket communications. */
 /** Start up websocket communications. */
@@ -67,7 +67,7 @@ Socket.prototype._startWebSocket = function(id) {
     self._sendQueuedMessages();
     self._sendQueuedMessages();
     util.log('Socket open');
     util.log('Socket open');
   };
   };
-};
+}
 
 
 /** Start XHR streaming. */
 /** Start XHR streaming. */
 Socket.prototype._startXhrStream = function(n) {
 Socket.prototype._startXhrStream = function(n) {
@@ -91,7 +91,7 @@ Socket.prototype._startXhrStream = function(n) {
   } catch(e) {
   } catch(e) {
     util.log('XMLHttpRequest not available; defaulting to WebSockets');
     util.log('XMLHttpRequest not available; defaulting to WebSockets');
   }
   }
-};
+}
 
 
 
 
 /** Handles onreadystatechange response as a stream. */
 /** Handles onreadystatechange response as a stream. */
@@ -197,4 +197,4 @@ Socket.prototype.close = function() {
     this._socket.close();
     this._socket.close();
     this.disconnected = true;
     this.disconnected = true;
   }
   }
-};
+}

+ 1 - 1
lib/util.js

@@ -61,7 +61,7 @@ var util = {
       audioVideo: true,
       audioVideo: true,
       data: true,
       data: true,
       binary: false,
       binary: false,
-      reliable: true,
+      reliable: false,
       onnegotiationneeded: true
       onnegotiationneeded: true
     };
     };
   }()),
   }()),

部分文件因为文件数量过多而无法显示