sink.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. function SinkPeer(options) {
  2. this._config = options.config || {};
  3. this._source = options.source || null;
  4. this._stream = options.stream || 'd';
  5. this._pc = null;
  6. this._id = null;
  7. this._dc = null;
  8. this._socket = io.connect('http://localhost');
  9. this.socketInit();
  10. this._handlers = {};
  11. // Testing firefox.
  12. // MULTICONNECTION doesn't work still.
  13. if (browserisms == 'Firefox' && !options.source) {
  14. if (!SinkPeer.usedPorts) {
  15. SinkPeer.usedPorts = [];
  16. }
  17. this.localPort = randomPort();
  18. while (SinkPeer.usedPorts.indexOf(this.localPort) != -1) {
  19. this.localPort = randomPort();
  20. }
  21. this.remotePort = randomPort();
  22. while (this.remotePort == this.localPort ||
  23. SinkPeer.usedPorts.indexOf(this.localPort) != -1) {
  24. this.remotePort = randomPort();
  25. }
  26. SinkPeer.usedPorts.push(this.remotePort);
  27. SinkPeer.usedPorts.push(this.localPort);
  28. }
  29. };
  30. function randomPort() {
  31. return Math.round(Math.random() * 60535) + 5000;
  32. };
  33. SinkPeer.prototype.socketInit = function() {
  34. var self = this;
  35. // Multiple sinks to one source.
  36. if (!!this._source) {
  37. this._socket.emit('sink', { source: this._source, isms: browserisms },
  38. function(data) {
  39. self._id = data.id;
  40. self._pc = new RTCPeerConnection(self._config);
  41. //FIREFOX
  42. self._pc.onaddstream = function(obj) {
  43. console.log('SINK: data stream get');
  44. };
  45. self._socket.on('offer', function(offer) {
  46. self._pc.setRemoteDescription(offer.sdp, function() {
  47. // If we also have to set up a stream on the sink end, do so.
  48. self.handleStream(false, offer.source, function() {
  49. self.maybeBrowserisms(false, offer.source);
  50. });
  51. }, function(err) {
  52. console.log('failed to setRemoteDescription with offer, ', err);
  53. });
  54. });
  55. });
  56. } else {
  57. // Otherwise, this sink is the originator to another sink and should wait
  58. // for an alert.
  59. this._socket.emit('source', function(data) {
  60. self._id = data.id;
  61. if (!!self._handlers['ready']) {
  62. self._handlers['ready'](self._id);
  63. }
  64. self._socket.on('sink-connected', function(data) {
  65. target = data.sink;
  66. self._pc = new RTCPeerConnection(self._config);
  67. self.handleStream(true, target, function() {
  68. self.maybeBrowserisms(true, target);
  69. });
  70. });
  71. self._socket.on('answer', function(data) {
  72. self._pc.setRemoteDescription(data.sdp, function() {
  73. // Firefoxism
  74. if (browserisms == 'Firefox') {
  75. self._pc.connectDataConnection(self.localPort, self.remotePort);
  76. //self._pc.connectDataConnection(5000, 5001);
  77. self._socket.emit('port', { sink: data.sink, remote: self.localPort, local: self.remotePort });
  78. }
  79. console.log('ORIGINATOR: PeerConnection success');
  80. }, function(err) {
  81. console.log('failed to setRemoteDescription, ', err);
  82. });
  83. });
  84. });
  85. }
  86. };
  87. SinkPeer.prototype.maybeBrowserisms = function(originator, target) {
  88. var self = this;
  89. if (browserisms == 'Firefox') {
  90. getUserMedia({ audio: true, fake: true }, function(s) {
  91. self._pc.addStream(s);
  92. if (originator) {
  93. self.makeOffer(target);
  94. } else {
  95. self.makeAnswer(target);
  96. }
  97. }, function(err) { console.log('crap'); });
  98. } else {
  99. if (originator) {
  100. this.makeOffer(target);
  101. } else {
  102. this.makeAnswer(target);
  103. }
  104. }
  105. }
  106. SinkPeer.prototype.makeAnswer = function(target) {
  107. var self = this;
  108. this._pc.createAnswer(function(answer) {
  109. self._pc.setLocalDescription(answer, function() {
  110. if (browserisms && browserisms == 'Firefox') {
  111. self._socket.on('port', function(data) {
  112. self._pc.connectDataConnection(data.local, data.remote);
  113. });
  114. }
  115. self._socket.emit('answer',
  116. { 'sink': self._id,
  117. 'sdp': answer,
  118. 'source': target });
  119. // Firefoxism
  120. //if (browserisms && browserisms == 'Firefox') {
  121. //self._pc.connectDataConnection(5001, 5000);
  122. //}
  123. }, function(err) {
  124. console.log('failed to setLocalDescription, ', err)
  125. });
  126. }, function(err) {
  127. console.log('failed to create answer, ', err)
  128. });
  129. };
  130. SinkPeer.prototype.makeOffer = function(target) {
  131. var self = this;
  132. this._pc.createOffer(function(offer) {
  133. self._pc.setLocalDescription(offer, function() {
  134. self._socket.emit('offer',
  135. { 'sdp': offer,
  136. 'sink': target,
  137. 'source': self._id });
  138. }, function(err) {
  139. console.log('failed to setLocalDescription, ', err);
  140. });
  141. });
  142. };
  143. SinkPeer.prototype.handleStream = function(originator, target, cb) {
  144. this.setupDataChannel(originator, target, cb);
  145. }
  146. SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
  147. var self = this;
  148. if (browserisms != 'Webkit') {
  149. if (originator) {
  150. /** ORIGINATOR SETUP */
  151. this._pc.onconnection = function() {
  152. console.log('ORIGINATOR: onconnection triggered');
  153. self._dc = self._pc.createDataChannel('StreamAPI', {}, target);
  154. self._dc.binaryType = 'blob';
  155. if (!!self._handlers['connection']) {
  156. self._handlers['connection'](target);
  157. }
  158. self._dc.onmessage = function(e) {
  159. self.handleDataMessage(e);
  160. };
  161. };
  162. } else {
  163. /** TARGET SETUP */
  164. this._pc.ondatachannel = function(dc) {
  165. console.log('SINK: ondatachannel triggered');
  166. self._dc = dc;
  167. self._dc.binaryType = 'blob';
  168. if (!!self._handlers['connection']) {
  169. self._handlers['connection'](target);
  170. }
  171. self._dc.onmessage = function(e) {
  172. self.handleDataMessage(e);
  173. };
  174. };
  175. this._pc.onconnection = function() {
  176. console.log('SINK: onconnection triggered');
  177. };
  178. }
  179. }
  180. this._pc.onclosedconnection = function() {
  181. // Remove socket handlers perhaps.
  182. };
  183. cb();
  184. };
  185. SinkPeer.prototype.send = function(data) {
  186. var ab = BinaryPack.pack(data);
  187. this._dc.send(ab);
  188. }
  189. // Handles a DataChannel message.
  190. // TODO: have these extend Peer, which will impl these generic handlers.
  191. SinkPeer.prototype.handleDataMessage = function(e) {
  192. var self = this;
  193. BinaryPack.unpack(e.data, function(msg) {
  194. if (!!self._handlers['data']) {
  195. self._handlers['data'](msg);
  196. }
  197. });
  198. }
  199. SinkPeer.prototype.on = function(code, cb) {
  200. this._handlers[code] = cb;
  201. }