浏览代码

started ice stuff, added _peer, fixed RTCSessionDescription for Firefox

Michelle Bu 12 年之前
父节点
当前提交
b810cace14
共有 2 个文件被更改,包括 103 次插入39 次删除
  1. 97 37
      public/js/sink.js
  2. 6 2
      server.js

+ 97 - 37
public/js/sink.js

@@ -1,13 +1,13 @@
 function SinkPeer(options) {
   this._config = options.config || { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]};
-  this._source = options.source || null;
+  this._peer = options.source || null;
   this._video = options.video;
   this._data = options.data != undefined ? options.data : true;
   this._audio = options.audio;
   this._pc = null;
   this._id = null;
   this._dc = null;
-  this._socket = io.connect('http://localhost');
+  this._socket = io.connect('http://192.168.0.14:8000');
   this.socketInit();
   this._handlers = {};
 
@@ -29,6 +29,13 @@ function SinkPeer(options) {
     SinkPeer.usedPorts.push(this.remotePort);
     SinkPeer.usedPorts.push(this.localPort);
   }
+
+  // Makes sure things clean up neatly.
+  window.onbeforeunload = function() {
+    if (!!this._socket) {
+      this._socket.emit('leave');
+    }
+  }
 };
 
 
@@ -37,28 +44,40 @@ function randomPort() {
 };
 
 
+/** Start up websocket communications. */
 SinkPeer.prototype.socketInit = function() {
   var self = this;
   // Multiple sinks to one source.
-  if (!!this._source) {
-    this._socket.emit('sink', { source: this._source, isms: browserisms },
+  if (!!this._peer) {
+    this._socket.emit('sink', { source: this._peer, isms: browserisms },
         function(data) {
       self._id = data.id;
-      self._pc = new RTCPeerConnection(self._config);
-      self.setupAudioVideo();
+      self.startPeerConnection();
 
       self._socket.on('offer', function(offer) {
-        self._pc.setRemoteDescription(new RTCSessionDescription(offer.sdp),
-            function() {
+        var sdp = offer.sdp;
+        try {
+          sdp = new RTCSessionDescription(offer.sdp);
+        } catch(e) {
+          console.log('Firefox');
+        }
+        self._pc.setRemoteDescription(sdp, function() {
 
           // If we also have to set up a stream on the sink end, do so.
-          self.handleStream(false, offer.source, function() {
-            self.maybeBrowserisms(false, offer.source);
+          self.handleStream(false, function() {
+            self.maybeBrowserisms(false);
           });
         }, function(err) {
           console.log('failed to setRemoteDescription with offer, ', err);
         });
       });
+
+      /*self._socket.on('candidate', function(data) {
+        console.log('SINK: Ice Candidate');
+        var candidate = new RTCIceCandidate({ sdpMLineIndex: data.label,
+                                              candidate: data.candidate });
+        self._pc.addIceCandidate(candidate);
+      });*/
     });
   } else {
     // Otherwise, this sink is the originator to another sink and should wait
@@ -71,17 +90,21 @@ SinkPeer.prototype.socketInit = function() {
       }
 
       self._socket.on('sink-connected', function(data) {
-        target = data.sink;
-        self._pc = new RTCPeerConnection(self._config);
-        self.setupAudioVideo();
-        self.handleStream(true, target, function() {
-          self.maybeBrowserisms(true, target);
+        self._peer = data.sink;
+        self.startPeerConnection();
+        self.handleStream(true, function() {
+          self.maybeBrowserisms(true);
         });
       });
 
       self._socket.on('answer', function(data) {
-        self._pc.setRemoteDescription(new RTCSessionDescription(data.sdp),
-            function() {
+        var sdp = data.sdp;
+        try {
+          sdp = new RTCSessionDescription(data.sdp);
+        } catch(e) {
+          console.log('Firefox');
+        }
+        self._pc.setRemoteDescription(sdp, function() {
           // Firefoxism
           if (browserisms == 'Firefox') {
             self._pc.connectDataConnection(self.localPort, self.remotePort);
@@ -92,36 +115,66 @@ SinkPeer.prototype.socketInit = function() {
           console.log('failed to setRemoteDescription, ', err);
         });
       });
+
+      self._socket.on('candidate', function(data) {
+        console.log('ORIGINATOR: Ice Candidate');
+        var candidate = new RTCIceCandidate({ sdpMLineIndex: data.label,
+                                              candidate: data.candidate });
+        self._pc.addIceCandidate(candidate);
+      });
     });
   }
 };
 
 
-SinkPeer.prototype.maybeBrowserisms = function(originator, target) {
-  console.log('maybeBrowserisms');
+/** Takes care of ice handlers. */
+SinkPeer.prototype.setupIce = function() {
+  this._pc.onicecandidate = function(event) {
+    if (event.candidate) {
+      this._socket.emit('candidate', { label: event.candidate.sdpMLineIndex,
+                                       id: event.candidate.sdpMid,
+                                       candidate: event.candidate.candidate });
+    } else {
+      console.log("End of candidates.");
+    }
+  };
+};
+
+
+/** Starts a PeerConnection and sets up handlers. */
+SinkPeer.prototype.startPeerConnection = function() {
+  this._pc = new RTCPeerConnection(this._config);
+  //this.setupIce();
+  this.setupAudioVideo();
+};
+
+
+/** Decide whether to handle Firefoxisms. */
+SinkPeer.prototype.maybeBrowserisms = function(originator) {
   var self = this;
   if (browserisms == 'Firefox' && !this._video && !this._audio && !this._stream) {
     getUserMedia({ audio: true, fake: true }, function(s) {
       self._pc.addStream(s);
 
       if (originator) {
-        self.makeOffer(target);
+        self.makeOffer();
       } else {
-        self.makeAnswer(target);
+        self.makeAnswer();
       }
 
     }, function(err) { console.log('crap'); });
   } else {
     if (originator) {
-      this.makeOffer(target);
+      this.makeOffer();
     } else {
-      this.makeAnswer(target);
+      this.makeAnswer();
     }
   }
 }
 
 
-SinkPeer.prototype.makeAnswer = function(target) {
+/** Create an answer for PC. */
+SinkPeer.prototype.makeAnswer = function() {
   var self = this;
 
   this._pc.createAnswer(function(answer) {
@@ -134,7 +187,7 @@ SinkPeer.prototype.makeAnswer = function(target) {
       self._socket.emit('answer',
           { 'sink': self._id,
             'sdp': answer,
-            'source': target });
+            'source': self._peer });
     }, function(err) {
       console.log('failed to setLocalDescription, ', err)
     });
@@ -144,14 +197,15 @@ SinkPeer.prototype.makeAnswer = function(target) {
 };
 
 
-SinkPeer.prototype.makeOffer = function(target) {
+/** Create an offer for PC. */
+SinkPeer.prototype.makeOffer = function() {
   var self = this;
 
   this._pc.createOffer(function(offer) {
     self._pc.setLocalDescription(offer, function() {
       self._socket.emit('offer',
         { 'sdp': offer,
-          'sink': target,
+          'sink': self._peer,
           'source': self._id });
     }, function(err) {
       console.log('failed to setLocalDescription, ', err);
@@ -160,6 +214,7 @@ SinkPeer.prototype.makeOffer = function(target) {
 };
 
 
+/** Sets up A/V stream handler. */
 SinkPeer.prototype.setupAudioVideo = function() {
   var self = this;
   this._pc.onaddstream = function(obj) {
@@ -171,9 +226,10 @@ SinkPeer.prototype.setupAudioVideo = function() {
 };
 
 
-SinkPeer.prototype.handleStream = function(originator, target, cb) {
+/** Handle the different types of streams requested by user. */
+SinkPeer.prototype.handleStream = function(originator, cb) {
   if (this._data) {
-    this.setupDataChannel(originator, target);
+    this.setupDataChannel(originator);
   } else {
     cb();
   }
@@ -181,6 +237,7 @@ SinkPeer.prototype.handleStream = function(originator, target, cb) {
 };
 
 
+/** Get A/V streams. */
 SinkPeer.prototype.getAudioVideo = function(originator, cb) {
   var self = this;
   if (this._video) {
@@ -189,8 +246,8 @@ SinkPeer.prototype.getAudioVideo = function(originator, cb) {
 
       if (originator && !!self._handlers['localstream']) {
         self._handlers['localstream']('video', vstream);
-      } else if (!originator && !self.handlers['remotestream']) {
-        self.handlers['remotestream']('video', vstream);
+      } else if (!originator && !self._handlers['remotestream']) {
+        self._handlers['remotestream']('video', vstream);
       }
 
       if (self._audio) {
@@ -199,8 +256,8 @@ SinkPeer.prototype.getAudioVideo = function(originator, cb) {
 
           if (originator && !!self._handlers['localstream']) {
             self._handlers['localstream']('audio', astream);
-          } else if (!originator && !self.handlers['remotestream']) {
-            self.handlers['remotestream']('audio', astream);
+          } else if (!originator && !self._handlers['remotestream']) {
+            self._handlers['remotestream']('audio', astream);
           }
 
           cb();
@@ -228,7 +285,8 @@ SinkPeer.prototype.getAudioVideo = function(originator, cb) {
 };
 
 
-SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
+/** Sets up DataChannel handlers. */
+SinkPeer.prototype.setupDataChannel = function(originator, cb) {
   var self = this;
   if (browserisms != 'Webkit') {
     if (originator) {
@@ -236,11 +294,11 @@ SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
       this._pc.onconnection = function() {
         console.log('ORIGINATOR: onconnection triggered');
 
-        self._dc = self._pc.createDataChannel('StreamAPI', {}, target);
+        self._dc = self._pc.createDataChannel('StreamAPI', {}, self._peer);
         self._dc.binaryType = 'blob';
 
         if (!!self._handlers['connection']) {
-          self._handlers['connection'](target);
+          self._handlers['connection'](self._peer);
         }
 
         self._dc.onmessage = function(e) {
@@ -255,7 +313,7 @@ SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
         self._dc.binaryType = 'blob';
 
         if (!!self._handlers['connection']) {
-          self._handlers['connection'](target);
+          self._handlers['connection'](self._peer);
         }
 
         self._dc.onmessage = function(e) {
@@ -274,6 +332,8 @@ SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
   };
 };
 
+
+/** Allows user to send data. */
 SinkPeer.prototype.send = function(data) {
   var ab = BinaryPack.pack(data);
   this._dc.send(ab);

+ 6 - 2
server.js

@@ -36,8 +36,12 @@ io.sockets.on('connection', function(socket) {
     var source_id = msg.source;
     var sink_id = socket.id;
     var source = clients[source_id];
-    source.emit('sink-connected', { 'sink': sink_id });
-    fn({ 'id': sink_id });
+    if (!!source) {
+      source.emit('sink-connected', { 'sink': sink_id });
+      fn({ 'id': sink_id });
+    } else {
+      fn({ 'error': 'Source ID not found.' });
+    };
   });
 
   // Offer from src to dest.