ericz 12 yıl önce
ebeveyn
işleme
92bfa60bbb
7 değiştirilmiş dosya ile 401 ekleme ve 143 silme
  1. 114 47
      demo/static/peer.js
  2. 2 1
      demo/static/sink.html
  3. 1 1
      demo/static/sinkoriginator.html
  4. 114 47
      dist/peer.js
  5. 0 0
      dist/peer.min.js
  6. 105 47
      lib/sink.js
  7. 65 0
      lib/util.js

+ 114 - 47
demo/static/peer.js

@@ -752,6 +752,15 @@ var util = {
   randomPort: function() {
     return Math.round(Math.random() * 60535) + 5000;
   },
+  
+  log: function () {
+    if (debug) {
+      for (var i = 0; i < arguments.length; i++) {
+        console.log('*', i, '-- ', arguments[i]);
+      }
+    }
+  },
+
   setZeroTimeout: (function(global) {
     var timeouts = [];
     var messageName = 'zero-timeout-message';
@@ -818,23 +827,40 @@ function Peer(options) {
   
   EventEmitter.call(this);
   
+  options = util.extend({
+    // Defaults
+  }, options);
+  
+  
   this._config = options.config || { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] };
+  this._id = null;
+  // User handlers.
+  this._handlers = {};
+
+  // Source to connect to; null if waiting for a connection.
   this._peer = options.source || null;
+
+  // Booleans to determine what streams to allow.
   this._video = options.video;
   this._data = options.data != undefined ? options.data : true;
   this._audio = options.audio;
+
+  // Connections
   this._pc = null;
-  this._id = null;
   this._dc = null;
   this._socket = new WebSocket(options.ws || 'ws://localhost');
+
+  // Local streams for multiple use.
+  this._localVideo = options.localVideo || null;
+  this._localAudio = options.localAudio || null;
+
+  // Init socket msg handlers
   var self = this;
   this._socket.onopen = function() {
     self.socketInit();
   };
-  
 
-  // Testing firefox.
-  // MULTICONNECTION doesn't work still.
+  // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox' && !options.source) {
     if (!Peer.usedPorts) {
       Peer.usedPorts = [];
@@ -856,11 +882,12 @@ function Peer(options) {
 
 util.inherits(Peer, EventEmitter);
 
+
 /** Start up websocket communications. */
 Peer.prototype.socketInit = function() {
   var self = this;
-  // Multiple sinks to one source.
   if (!!this._peer) {
+    // Announce as a sink if initiated with a source.
     this._socket.send(JSON.stringify({
       type: 'SINK',
       source: this._peer,
@@ -881,24 +908,36 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: offer');
+            util.log('setRemoteDescription: offer');
 
             // If we also have to set up a stream on the sink end, do so.
             self.handleStream(false, function() {
               self.maybeBrowserisms(false);
             });
           }, function(err) {
-            console.log('failed to setRemoteDescription with offer, ', err);
+            util.log('failed to setRemoteDescription with offer, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'PORT':
           if (browserisms && browserisms == 'Firefox') {
             if (!Peer.usedPorts) {
@@ -910,14 +949,14 @@ Peer.prototype.socketInit = function() {
             break;
           }
         case 'DEFAULT':
-          console.log('SINK: unrecognized message ', message.type);
+          util.log('SINK: unrecognized message ', message.type);
           break;
       }
     };
 
   } else {
     // Otherwise, this sink is the originator to another sink and should wait
-    // for an alert.
+    // for an alert to begin the PC process.
     this._socket.send(JSON.stringify({
       type: 'SOURCE',
       isms: browserisms
@@ -943,10 +982,10 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: answer');
+            util.log('setRemoteDescription: answer');
             // Firefoxism
             if (browserisms == 'Firefox') {
               self._pc.connectDataConnection(self.localPort, self.remotePort);
@@ -957,29 +996,42 @@ Peer.prototype.socketInit = function() {
                 local: self.remotePort
               }));
             }
-            console.log('ORIGINATOR: PeerConnection success');
+            util.log('ORIGINATOR: PeerConnection success');
           }, function(err) {
-            console.log('failed to setRemoteDescription, ', err);
+            util.log('failed to setRemoteDescription, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'DEFAULT':
-          console.log('ORIGINATOR: message not recognized ', message.type);
+          util.log('ORIGINATOR: message not recognized ', message.type);
       }
     };
   }
-  // Makes sure things clean up neatly.
+
+  // Makes sure things clean up neatly when window is closed.
   window.onbeforeunload = function() {
-    if (!!self._pc) {
+    if (!!self._pc && self._pc.readyState != 'closed') {
       self._pc.close();
     }
     if (!!self._socket && !!self._peer) {
       self._socket.send(JSON.stringify({ type: 'LEAVE', dst: self._peer }));
-      if (!!self._dc) {
+      if (!!self._dc && self._dc.readyState != 'closed') {
         self._dc.close();
       }
     }
@@ -991,7 +1043,7 @@ Peer.prototype.socketInit = function() {
 Peer.prototype.setupIce = function() {
   var self = this;
   this._pc.onicecandidate = function(event) {
-    console.log('candidates received');
+    util.log('candidates received');
     if (event.candidate) {
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
@@ -999,7 +1051,7 @@ Peer.prototype.setupIce = function() {
         dst: self._peer
       }));
     } else {
-      console.log("End of candidates.");
+      util.log("End of candidates.");
     }
   };
 };
@@ -1016,7 +1068,7 @@ Peer.prototype.startPeerConnection = function() {
 /** Decide whether to handle Firefoxisms. */
 Peer.prototype.maybeBrowserisms = function(originator) {
   var self = this;
-  if (browserisms == 'Firefox' && !this._video && !this._audio && !this._stream) {
+  if (browserisms == 'Firefox' && !this._video && !this._audio/* && !this._stream*/) {
     getUserMedia({ audio: true, fake: true }, function(s) {
       self._pc.addStream(s);
 
@@ -1026,7 +1078,7 @@ Peer.prototype.maybeBrowserisms = function(originator) {
         self.makeAnswer();
       }
 
-    }, function(err) { console.log('crap'); });
+    }, function(err) { util.log('crap'); });
   } else {
     if (originator) {
       this.makeOffer();
@@ -1042,9 +1094,9 @@ Peer.prototype.makeAnswer = function() {
   var self = this;
 
   this._pc.createAnswer(function(answer) {
-    console.log('createAnswer');
+    util.log('createAnswer');
     self._pc.setLocalDescription(answer, function() {
-      console.log('setLocalDescription: answer');
+      util.log('setLocalDescription: answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -1052,10 +1104,10 @@ Peer.prototype.makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err)
+      util.log('failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    console.log('failed to create answer, ', err)
+    util.log('failed to create answer, ', err)
   });
 };
 
@@ -1065,9 +1117,9 @@ Peer.prototype.makeOffer = function() {
   var self = this;
 
   this._pc.createOffer(function(offer) {
-    console.log('createOffer')
+    util.log('createOffer')
     self._pc.setLocalDescription(offer, function() {
-      console.log('setLocalDescription: offer');
+      util.log('setLocalDescription: offer');
       self._socket.send(JSON.stringify({
         type: 'OFFER',
         sdp: offer,
@@ -1075,7 +1127,7 @@ Peer.prototype.makeOffer = function() {
         src: self._id
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err);
+      util.log('failed to setLocalDescription, ', err);
     });
   });
 };
@@ -1084,10 +1136,10 @@ Peer.prototype.makeOffer = function() {
 /** Sets up A/V stream handler. */
 Peer.prototype.setupAudioVideo = function() {
   var self = this;
-  console.log('onaddstream handler added');
+  util.log('onaddstream handler added');
   this._pc.onaddstream = function(obj) {
-    console.log('Remote stream added');
-    this._stream = true;
+    util.log('Remote stream added');
+    //    this._stream = true;
     self.emit('remotestream', obj.type, obj.stream);
   };
 };
@@ -1105,35 +1157,49 @@ Peer.prototype.handleStream = function(originator, cb) {
 /** Get A/V streams. */
 Peer.prototype.getAudioVideo = function(originator, cb) {
   var self = this;
-  if (this._video) {
+  if (this._video && !this._localVideo) {
     getUserMedia({ video: true }, function(vstream) {
       self._pc.addStream(vstream);
-      console.log('Local video stream added');
+      self._localVideo = vstream;
+      util.log('Local video stream added');
 
       self.emit('localstream', 'video', vstream);
       
-      if (self._audio) {
+      if (self._audio && !self._localAudio) {
         getUserMedia({ audio: true }, function(astream) {
           self._pc.addStream(astream);
-          console.log('Local audio stream added');
+          self._localAudio = astream;
+          util.log('Local audio stream added');
 
           self.emit('localstream', 'audio', astream);
 
           cb();
-        }, function(err) { console.log('Audio cannot start'); cb(); });
+        }, function(err) { util.log('Audio cannot start'); cb(); });
       } else {
+        if (self._audio) {
+          self._pc.addStream(self._localAudio);
+        }
         cb();
       }
-    }, function(err) { console.log('Video cannot start', err); cb(); });
-  } else if (this._audio) {
+    }, function(err) { util.log('Video cannot start', err); cb(); });
+  } else if (this._audio && !this._localAudio) {
     getUserMedia({ audio: true }, function(astream) {
       self._pc.addStream(astream);
+      self._localAudio = astream;
+      util.log('Local audio stream added');
 
       self.emit('localstream', 'audio', astream);
       
       cb();
-    }, function(err) { console.log('Audio cannot start'); cb(); });
+    }, function(err) { util.log('Audio cannot start'); cb(); });
   } else {
+    if (this._audio) {
+      this._pc.addStream(this._localAudio);
+    }
+    if (this._video) {
+      this._pc.addStream(this._localVideo);
+    }
+    util.log('no audio/video streams initiated');
     cb();
   }
 
@@ -1148,9 +1214,9 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     if (browserisms == 'Webkit') {
 
       this._pc.onstatechange = function() {
-        console.log('State Change: ', self._pc.readyState);
+        util.log('State Change: ', self._pc.readyState);
         /*if (self._pc.readyState == 'active') {
-          console.log('ORIGINATOR: active state detected');
+          util.log('ORIGINATOR: active state detected');
 
           self._dc = self._pc.createDataChannel('StreamAPI', { reliable: false });
           self._dc.binaryType = 'blob';
@@ -1167,7 +1233,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
 
     } else {
       this._pc.onconnection = function() {
-        console.log('ORIGINATOR: onconnection triggered');
+        util.log('ORIGINATOR: onconnection triggered');
 
         self.startDataChannel();
       };
@@ -1175,7 +1241,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
   } else {
     /** TARGET SETUP */
     this._pc.ondatachannel = function(dc) {
-      console.log('SINK: ondatachannel triggered');
+      util.log('SINK: ondatachannel triggered');
       self._dc = dc;
       self._dc.binaryType = 'blob';
 
@@ -1187,7 +1253,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     };
 
     this._pc.onconnection = function() {
-      console.log('SINK: onconnection triggered');
+      util.log('SINK: onconnection triggered');
     };
   }
 
@@ -1235,4 +1301,5 @@ Peer.prototype.handleDataMessage = function(e) {
 
 exports.Peer = Peer;
 
+
 })(this);

+ 2 - 1
demo/static/sink.html

@@ -13,8 +13,9 @@
 $(document).ready(function() {
   $('#connect').click(function() {
     var source = $('#source').val();
+
     sink = new Peer({ ws: 'ws://localhost:9382', source: source, audio: true,
-      video: true });
+      video: true, debug: true });
     sink.on('data', function(data) {
       console.log(data);
       sink.send('I am so scared.');

+ 1 - 1
demo/static/sinkoriginator.html

@@ -11,7 +11,7 @@
 <script type="text/javascript" src="/peer.js"></script>
 <script>
 $(document).ready(function() {
-  originator = new Peer({ ws: 'ws://localhost:9382', video: true, audio: true });
+  originator = new Peer({ ws: 'ws://localhost:9382', video: true, audio: true, debug: true });
   originator.on('ready', function(id) {
     console.log(id);
   });

+ 114 - 47
dist/peer.js

@@ -752,6 +752,15 @@ var util = {
   randomPort: function() {
     return Math.round(Math.random() * 60535) + 5000;
   },
+  
+  log: function () {
+    if (debug) {
+      for (var i = 0; i < arguments.length; i++) {
+        console.log('*', i, '-- ', arguments[i]);
+      }
+    }
+  },
+
   setZeroTimeout: (function(global) {
     var timeouts = [];
     var messageName = 'zero-timeout-message';
@@ -818,23 +827,40 @@ function Peer(options) {
   
   EventEmitter.call(this);
   
+  options = util.extend({
+    // Defaults
+  }, options);
+  
+  
   this._config = options.config || { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] };
+  this._id = null;
+  // User handlers.
+  this._handlers = {};
+
+  // Source to connect to; null if waiting for a connection.
   this._peer = options.source || null;
+
+  // Booleans to determine what streams to allow.
   this._video = options.video;
   this._data = options.data != undefined ? options.data : true;
   this._audio = options.audio;
+
+  // Connections
   this._pc = null;
-  this._id = null;
   this._dc = null;
   this._socket = new WebSocket(options.ws || 'ws://localhost');
+
+  // Local streams for multiple use.
+  this._localVideo = options.localVideo || null;
+  this._localAudio = options.localAudio || null;
+
+  // Init socket msg handlers
   var self = this;
   this._socket.onopen = function() {
     self.socketInit();
   };
-  
 
-  // Testing firefox.
-  // MULTICONNECTION doesn't work still.
+  // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox' && !options.source) {
     if (!Peer.usedPorts) {
       Peer.usedPorts = [];
@@ -856,11 +882,12 @@ function Peer(options) {
 
 util.inherits(Peer, EventEmitter);
 
+
 /** Start up websocket communications. */
 Peer.prototype.socketInit = function() {
   var self = this;
-  // Multiple sinks to one source.
   if (!!this._peer) {
+    // Announce as a sink if initiated with a source.
     this._socket.send(JSON.stringify({
       type: 'SINK',
       source: this._peer,
@@ -881,24 +908,36 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: offer');
+            util.log('setRemoteDescription: offer');
 
             // If we also have to set up a stream on the sink end, do so.
             self.handleStream(false, function() {
               self.maybeBrowserisms(false);
             });
           }, function(err) {
-            console.log('failed to setRemoteDescription with offer, ', err);
+            util.log('failed to setRemoteDescription with offer, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'PORT':
           if (browserisms && browserisms == 'Firefox') {
             if (!Peer.usedPorts) {
@@ -910,14 +949,14 @@ Peer.prototype.socketInit = function() {
             break;
           }
         case 'DEFAULT':
-          console.log('SINK: unrecognized message ', message.type);
+          util.log('SINK: unrecognized message ', message.type);
           break;
       }
     };
 
   } else {
     // Otherwise, this sink is the originator to another sink and should wait
-    // for an alert.
+    // for an alert to begin the PC process.
     this._socket.send(JSON.stringify({
       type: 'SOURCE',
       isms: browserisms
@@ -943,10 +982,10 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: answer');
+            util.log('setRemoteDescription: answer');
             // Firefoxism
             if (browserisms == 'Firefox') {
               self._pc.connectDataConnection(self.localPort, self.remotePort);
@@ -957,29 +996,42 @@ Peer.prototype.socketInit = function() {
                 local: self.remotePort
               }));
             }
-            console.log('ORIGINATOR: PeerConnection success');
+            util.log('ORIGINATOR: PeerConnection success');
           }, function(err) {
-            console.log('failed to setRemoteDescription, ', err);
+            util.log('failed to setRemoteDescription, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'DEFAULT':
-          console.log('ORIGINATOR: message not recognized ', message.type);
+          util.log('ORIGINATOR: message not recognized ', message.type);
       }
     };
   }
-  // Makes sure things clean up neatly.
+
+  // Makes sure things clean up neatly when window is closed.
   window.onbeforeunload = function() {
-    if (!!self._pc) {
+    if (!!self._pc && self._pc.readyState != 'closed') {
       self._pc.close();
     }
     if (!!self._socket && !!self._peer) {
       self._socket.send(JSON.stringify({ type: 'LEAVE', dst: self._peer }));
-      if (!!self._dc) {
+      if (!!self._dc && self._dc.readyState != 'closed') {
         self._dc.close();
       }
     }
@@ -991,7 +1043,7 @@ Peer.prototype.socketInit = function() {
 Peer.prototype.setupIce = function() {
   var self = this;
   this._pc.onicecandidate = function(event) {
-    console.log('candidates received');
+    util.log('candidates received');
     if (event.candidate) {
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
@@ -999,7 +1051,7 @@ Peer.prototype.setupIce = function() {
         dst: self._peer
       }));
     } else {
-      console.log("End of candidates.");
+      util.log("End of candidates.");
     }
   };
 };
@@ -1016,7 +1068,7 @@ Peer.prototype.startPeerConnection = function() {
 /** Decide whether to handle Firefoxisms. */
 Peer.prototype.maybeBrowserisms = function(originator) {
   var self = this;
-  if (browserisms == 'Firefox' && !this._video && !this._audio && !this._stream) {
+  if (browserisms == 'Firefox' && !this._video && !this._audio/* && !this._stream*/) {
     getUserMedia({ audio: true, fake: true }, function(s) {
       self._pc.addStream(s);
 
@@ -1026,7 +1078,7 @@ Peer.prototype.maybeBrowserisms = function(originator) {
         self.makeAnswer();
       }
 
-    }, function(err) { console.log('crap'); });
+    }, function(err) { util.log('crap'); });
   } else {
     if (originator) {
       this.makeOffer();
@@ -1042,9 +1094,9 @@ Peer.prototype.makeAnswer = function() {
   var self = this;
 
   this._pc.createAnswer(function(answer) {
-    console.log('createAnswer');
+    util.log('createAnswer');
     self._pc.setLocalDescription(answer, function() {
-      console.log('setLocalDescription: answer');
+      util.log('setLocalDescription: answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -1052,10 +1104,10 @@ Peer.prototype.makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err)
+      util.log('failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    console.log('failed to create answer, ', err)
+    util.log('failed to create answer, ', err)
   });
 };
 
@@ -1065,9 +1117,9 @@ Peer.prototype.makeOffer = function() {
   var self = this;
 
   this._pc.createOffer(function(offer) {
-    console.log('createOffer')
+    util.log('createOffer')
     self._pc.setLocalDescription(offer, function() {
-      console.log('setLocalDescription: offer');
+      util.log('setLocalDescription: offer');
       self._socket.send(JSON.stringify({
         type: 'OFFER',
         sdp: offer,
@@ -1075,7 +1127,7 @@ Peer.prototype.makeOffer = function() {
         src: self._id
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err);
+      util.log('failed to setLocalDescription, ', err);
     });
   });
 };
@@ -1084,10 +1136,10 @@ Peer.prototype.makeOffer = function() {
 /** Sets up A/V stream handler. */
 Peer.prototype.setupAudioVideo = function() {
   var self = this;
-  console.log('onaddstream handler added');
+  util.log('onaddstream handler added');
   this._pc.onaddstream = function(obj) {
-    console.log('Remote stream added');
-    this._stream = true;
+    util.log('Remote stream added');
+    //    this._stream = true;
     self.emit('remotestream', obj.type, obj.stream);
   };
 };
@@ -1105,35 +1157,49 @@ Peer.prototype.handleStream = function(originator, cb) {
 /** Get A/V streams. */
 Peer.prototype.getAudioVideo = function(originator, cb) {
   var self = this;
-  if (this._video) {
+  if (this._video && !this._localVideo) {
     getUserMedia({ video: true }, function(vstream) {
       self._pc.addStream(vstream);
-      console.log('Local video stream added');
+      self._localVideo = vstream;
+      util.log('Local video stream added');
 
       self.emit('localstream', 'video', vstream);
       
-      if (self._audio) {
+      if (self._audio && !self._localAudio) {
         getUserMedia({ audio: true }, function(astream) {
           self._pc.addStream(astream);
-          console.log('Local audio stream added');
+          self._localAudio = astream;
+          util.log('Local audio stream added');
 
           self.emit('localstream', 'audio', astream);
 
           cb();
-        }, function(err) { console.log('Audio cannot start'); cb(); });
+        }, function(err) { util.log('Audio cannot start'); cb(); });
       } else {
+        if (self._audio) {
+          self._pc.addStream(self._localAudio);
+        }
         cb();
       }
-    }, function(err) { console.log('Video cannot start', err); cb(); });
-  } else if (this._audio) {
+    }, function(err) { util.log('Video cannot start', err); cb(); });
+  } else if (this._audio && !this._localAudio) {
     getUserMedia({ audio: true }, function(astream) {
       self._pc.addStream(astream);
+      self._localAudio = astream;
+      util.log('Local audio stream added');
 
       self.emit('localstream', 'audio', astream);
       
       cb();
-    }, function(err) { console.log('Audio cannot start'); cb(); });
+    }, function(err) { util.log('Audio cannot start'); cb(); });
   } else {
+    if (this._audio) {
+      this._pc.addStream(this._localAudio);
+    }
+    if (this._video) {
+      this._pc.addStream(this._localVideo);
+    }
+    util.log('no audio/video streams initiated');
     cb();
   }
 
@@ -1148,9 +1214,9 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     if (browserisms == 'Webkit') {
 
       this._pc.onstatechange = function() {
-        console.log('State Change: ', self._pc.readyState);
+        util.log('State Change: ', self._pc.readyState);
         /*if (self._pc.readyState == 'active') {
-          console.log('ORIGINATOR: active state detected');
+          util.log('ORIGINATOR: active state detected');
 
           self._dc = self._pc.createDataChannel('StreamAPI', { reliable: false });
           self._dc.binaryType = 'blob';
@@ -1167,7 +1233,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
 
     } else {
       this._pc.onconnection = function() {
-        console.log('ORIGINATOR: onconnection triggered');
+        util.log('ORIGINATOR: onconnection triggered');
 
         self.startDataChannel();
       };
@@ -1175,7 +1241,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
   } else {
     /** TARGET SETUP */
     this._pc.ondatachannel = function(dc) {
-      console.log('SINK: ondatachannel triggered');
+      util.log('SINK: ondatachannel triggered');
       self._dc = dc;
       self._dc.binaryType = 'blob';
 
@@ -1187,7 +1253,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     };
 
     this._pc.onconnection = function() {
-      console.log('SINK: onconnection triggered');
+      util.log('SINK: onconnection triggered');
     };
   }
 
@@ -1235,4 +1301,5 @@ Peer.prototype.handleDataMessage = function(e) {
 
 exports.Peer = Peer;
 
+
 })(this);

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
dist/peer.min.js


+ 105 - 47
lib/sink.js

@@ -3,23 +3,40 @@ function Peer(options) {
   
   EventEmitter.call(this);
   
+  options = util.extend({
+    // Defaults
+  }, options);
+  
+  
   this._config = options.config || { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] };
+  this._id = null;
+  // User handlers.
+  this._handlers = {};
+
+  // Source to connect to; null if waiting for a connection.
   this._peer = options.source || null;
+
+  // Booleans to determine what streams to allow.
   this._video = options.video;
   this._data = options.data != undefined ? options.data : true;
   this._audio = options.audio;
+
+  // Connections
   this._pc = null;
-  this._id = null;
   this._dc = null;
   this._socket = new WebSocket(options.ws || 'ws://localhost');
+
+  // Local streams for multiple use.
+  this._localVideo = options.localVideo || null;
+  this._localAudio = options.localAudio || null;
+
+  // Init socket msg handlers
   var self = this;
   this._socket.onopen = function() {
     self.socketInit();
   };
-  
 
-  // Testing firefox.
-  // MULTICONNECTION doesn't work still.
+  // Firefoxism: connectDataConnection ports.
   if (browserisms == 'Firefox' && !options.source) {
     if (!Peer.usedPorts) {
       Peer.usedPorts = [];
@@ -41,11 +58,12 @@ function Peer(options) {
 
 util.inherits(Peer, EventEmitter);
 
+
 /** Start up websocket communications. */
 Peer.prototype.socketInit = function() {
   var self = this;
-  // Multiple sinks to one source.
   if (!!this._peer) {
+    // Announce as a sink if initiated with a source.
     this._socket.send(JSON.stringify({
       type: 'SINK',
       source: this._peer,
@@ -66,24 +84,36 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: offer');
+            util.log('setRemoteDescription: offer');
 
             // If we also have to set up a stream on the sink end, do so.
             self.handleStream(false, function() {
               self.maybeBrowserisms(false);
             });
           }, function(err) {
-            console.log('failed to setRemoteDescription with offer, ', err);
+            util.log('failed to setRemoteDescription with offer, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'PORT':
           if (browserisms && browserisms == 'Firefox') {
             if (!Peer.usedPorts) {
@@ -95,14 +125,14 @@ Peer.prototype.socketInit = function() {
             break;
           }
         case 'DEFAULT':
-          console.log('SINK: unrecognized message ', message.type);
+          util.log('SINK: unrecognized message ', message.type);
           break;
       }
     };
 
   } else {
     // Otherwise, this sink is the originator to another sink and should wait
-    // for an alert.
+    // for an alert to begin the PC process.
     this._socket.send(JSON.stringify({
       type: 'SOURCE',
       isms: browserisms
@@ -128,10 +158,10 @@ Peer.prototype.socketInit = function() {
           try {
             sdp = new RTCSessionDescription(message.sdp);
           } catch(e) {
-            console.log('Firefox');
+            util.log('Firefox');
           }
           self._pc.setRemoteDescription(sdp, function() {
-            console.log('setRemoteDescription: answer');
+            util.log('setRemoteDescription: answer');
             // Firefoxism
             if (browserisms == 'Firefox') {
               self._pc.connectDataConnection(self.localPort, self.remotePort);
@@ -142,29 +172,42 @@ Peer.prototype.socketInit = function() {
                 local: self.remotePort
               }));
             }
-            console.log('ORIGINATOR: PeerConnection success');
+            util.log('ORIGINATOR: PeerConnection success');
           }, function(err) {
-            console.log('failed to setRemoteDescription, ', err);
+            util.log('failed to setRemoteDescription, ', err);
           });
           break;
         case 'CANDIDATE':
-          console.log(message.candidate);
+          util.log(message.candidate);
           var candidate = new RTCIceCandidate(message.candidate);
           self._pc.addIceCandidate(candidate);
           break;
+        case 'LEAVE':
+          util.log('counterpart disconnected');
+          if (!!self._pc && self._pc.readyState != 'closed') {
+            self._pc.close();
+            self._pc = null;
+            self._peer = null;
+          }
+          if (!!self._dc && self._dc.readyState != 'closed') {
+            self._dc.close();
+            self._dc = null;
+          }
+          break;
         case 'DEFAULT':
-          console.log('ORIGINATOR: message not recognized ', message.type);
+          util.log('ORIGINATOR: message not recognized ', message.type);
       }
     };
   }
-  // Makes sure things clean up neatly.
+
+  // Makes sure things clean up neatly when window is closed.
   window.onbeforeunload = function() {
-    if (!!self._pc) {
+    if (!!self._pc && self._pc.readyState != 'closed') {
       self._pc.close();
     }
     if (!!self._socket && !!self._peer) {
       self._socket.send(JSON.stringify({ type: 'LEAVE', dst: self._peer }));
-      if (!!self._dc) {
+      if (!!self._dc && self._dc.readyState != 'closed') {
         self._dc.close();
       }
     }
@@ -176,7 +219,7 @@ Peer.prototype.socketInit = function() {
 Peer.prototype.setupIce = function() {
   var self = this;
   this._pc.onicecandidate = function(event) {
-    console.log('candidates received');
+    util.log('candidates received');
     if (event.candidate) {
       self._socket.send(JSON.stringify({
         type: 'CANDIDATE',
@@ -184,7 +227,7 @@ Peer.prototype.setupIce = function() {
         dst: self._peer
       }));
     } else {
-      console.log("End of candidates.");
+      util.log("End of candidates.");
     }
   };
 };
@@ -201,7 +244,7 @@ Peer.prototype.startPeerConnection = function() {
 /** Decide whether to handle Firefoxisms. */
 Peer.prototype.maybeBrowserisms = function(originator) {
   var self = this;
-  if (browserisms == 'Firefox' && !this._video && !this._audio && !this._stream) {
+  if (browserisms == 'Firefox' && !this._video && !this._audio/* && !this._stream*/) {
     getUserMedia({ audio: true, fake: true }, function(s) {
       self._pc.addStream(s);
 
@@ -211,7 +254,7 @@ Peer.prototype.maybeBrowserisms = function(originator) {
         self.makeAnswer();
       }
 
-    }, function(err) { console.log('crap'); });
+    }, function(err) { util.log('crap'); });
   } else {
     if (originator) {
       this.makeOffer();
@@ -227,9 +270,9 @@ Peer.prototype.makeAnswer = function() {
   var self = this;
 
   this._pc.createAnswer(function(answer) {
-    console.log('createAnswer');
+    util.log('createAnswer');
     self._pc.setLocalDescription(answer, function() {
-      console.log('setLocalDescription: answer');
+      util.log('setLocalDescription: answer');
       self._socket.send(JSON.stringify({
         type: 'ANSWER',
         src: self._id,
@@ -237,10 +280,10 @@ Peer.prototype.makeAnswer = function() {
         dst: self._peer
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err)
+      util.log('failed to setLocalDescription, ', err)
     });
   }, function(err) {
-    console.log('failed to create answer, ', err)
+    util.log('failed to create answer, ', err)
   });
 };
 
@@ -250,9 +293,9 @@ Peer.prototype.makeOffer = function() {
   var self = this;
 
   this._pc.createOffer(function(offer) {
-    console.log('createOffer')
+    util.log('createOffer')
     self._pc.setLocalDescription(offer, function() {
-      console.log('setLocalDescription: offer');
+      util.log('setLocalDescription: offer');
       self._socket.send(JSON.stringify({
         type: 'OFFER',
         sdp: offer,
@@ -260,7 +303,7 @@ Peer.prototype.makeOffer = function() {
         src: self._id
       }));
     }, function(err) {
-      console.log('failed to setLocalDescription, ', err);
+      util.log('failed to setLocalDescription, ', err);
     });
   });
 };
@@ -269,10 +312,10 @@ Peer.prototype.makeOffer = function() {
 /** Sets up A/V stream handler. */
 Peer.prototype.setupAudioVideo = function() {
   var self = this;
-  console.log('onaddstream handler added');
+  util.log('onaddstream handler added');
   this._pc.onaddstream = function(obj) {
-    console.log('Remote stream added');
-    this._stream = true;
+    util.log('Remote stream added');
+    //    this._stream = true;
     self.emit('remotestream', obj.type, obj.stream);
   };
 };
@@ -290,35 +333,49 @@ Peer.prototype.handleStream = function(originator, cb) {
 /** Get A/V streams. */
 Peer.prototype.getAudioVideo = function(originator, cb) {
   var self = this;
-  if (this._video) {
+  if (this._video && !this._localVideo) {
     getUserMedia({ video: true }, function(vstream) {
       self._pc.addStream(vstream);
-      console.log('Local video stream added');
+      self._localVideo = vstream;
+      util.log('Local video stream added');
 
       self.emit('localstream', 'video', vstream);
       
-      if (self._audio) {
+      if (self._audio && !self._localAudio) {
         getUserMedia({ audio: true }, function(astream) {
           self._pc.addStream(astream);
-          console.log('Local audio stream added');
+          self._localAudio = astream;
+          util.log('Local audio stream added');
 
           self.emit('localstream', 'audio', astream);
 
           cb();
-        }, function(err) { console.log('Audio cannot start'); cb(); });
+        }, function(err) { util.log('Audio cannot start'); cb(); });
       } else {
+        if (self._audio) {
+          self._pc.addStream(self._localAudio);
+        }
         cb();
       }
-    }, function(err) { console.log('Video cannot start', err); cb(); });
-  } else if (this._audio) {
+    }, function(err) { util.log('Video cannot start', err); cb(); });
+  } else if (this._audio && !this._localAudio) {
     getUserMedia({ audio: true }, function(astream) {
       self._pc.addStream(astream);
+      self._localAudio = astream;
+      util.log('Local audio stream added');
 
       self.emit('localstream', 'audio', astream);
       
       cb();
-    }, function(err) { console.log('Audio cannot start'); cb(); });
+    }, function(err) { util.log('Audio cannot start'); cb(); });
   } else {
+    if (this._audio) {
+      this._pc.addStream(this._localAudio);
+    }
+    if (this._video) {
+      this._pc.addStream(this._localVideo);
+    }
+    util.log('no audio/video streams initiated');
     cb();
   }
 
@@ -333,9 +390,9 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     if (browserisms == 'Webkit') {
 
       this._pc.onstatechange = function() {
-        console.log('State Change: ', self._pc.readyState);
+        util.log('State Change: ', self._pc.readyState);
         /*if (self._pc.readyState == 'active') {
-          console.log('ORIGINATOR: active state detected');
+          util.log('ORIGINATOR: active state detected');
 
           self._dc = self._pc.createDataChannel('StreamAPI', { reliable: false });
           self._dc.binaryType = 'blob';
@@ -352,7 +409,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
 
     } else {
       this._pc.onconnection = function() {
-        console.log('ORIGINATOR: onconnection triggered');
+        util.log('ORIGINATOR: onconnection triggered');
 
         self.startDataChannel();
       };
@@ -360,7 +417,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
   } else {
     /** TARGET SETUP */
     this._pc.ondatachannel = function(dc) {
-      console.log('SINK: ondatachannel triggered');
+      util.log('SINK: ondatachannel triggered');
       self._dc = dc;
       self._dc.binaryType = 'blob';
 
@@ -372,7 +429,7 @@ Peer.prototype.setupDataChannel = function(originator, cb) {
     };
 
     this._pc.onconnection = function() {
-      console.log('SINK: onconnection triggered');
+      util.log('SINK: onconnection triggered');
     };
   }
 
@@ -419,3 +476,4 @@ Peer.prototype.handleDataMessage = function(e) {
 }
 
 exports.Peer = Peer;
+

+ 65 - 0
lib/util.js

@@ -0,0 +1,65 @@
+
+var util = {
+  inherits: function(ctor, superCtor) {
+    ctor.super_ = superCtor;
+    ctor.prototype = Object.create(superCtor.prototype, {
+      constructor: {
+        value: ctor,
+        enumerable: false,
+        writable: true,
+        configurable: true
+      }
+    });
+  },
+  extend: function(dest, source) {
+    for(var key in source) {
+      if(source.hasOwnProperty(key)) {
+        dest[key] = source[key];
+      }
+    }
+    return dest;
+  },
+  pack: BinaryPack.pack,
+  unpack: BinaryPack.unpack,
+  randomPort: function() {
+    return Math.round(Math.random() * 60535) + 5000;
+  },
+  
+  log: function () {
+    if (debug) {
+      for (var i = 0; i < arguments.length; i++) {
+        console.log('*', i, '-- ', arguments[i]);
+      }
+    }
+  },
+
+  setZeroTimeout: (function(global) {
+    var timeouts = [];
+    var messageName = 'zero-timeout-message';
+
+    // Like setTimeout, but only takes a function argument.	 There's
+    // no time argument (always zero) and no arguments (you have to
+    // use a closure).
+    function setZeroTimeoutPostMessage(fn) {
+      timeouts.push(fn);
+      global.postMessage(messageName, '*');
+    }		
+
+    function handleMessage(event) {
+      if (event.source == global && event.data == messageName) {
+        if (event.stopPropagation) {
+          event.stopPropagation();
+        }
+        if (timeouts.length) {
+          timeouts.shift()();
+        }
+      }
+    }
+    if (global.addEventListener) {
+      global.addEventListener('message', handleMessage, true);
+    } else if (global.attachEvent) {
+      global.attachEvent('onmessage', handleMessage);
+    }
+    return setZeroTimeoutPostMessage;
+  }(this))
+};

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor