sink.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. };
  11. SinkPeer.prototype.socketInit = function() {
  12. self = this;
  13. // Multiple sinks to one source.
  14. if (!!this._source) {
  15. this._socket.emit('sink', { source: this._source, isms: browserisms },
  16. function(data) {
  17. self._id = data.id;
  18. self._pc = new RTCPeerConnection(self._config);
  19. //FIREFOX
  20. self._pc.onaddstream = function(obj) {
  21. console.log('SINK: data stream get');
  22. };
  23. self._socket.on('offer', function(offer) {
  24. self._pc.setRemoteDescription(offer.sdp, function() {
  25. // If we also have to set up a stream on the sink end, do so.
  26. self.handleStream(false, offer.source, function() {
  27. self.maybeBrowserisms(false, offer.source);
  28. });
  29. }, function(err) {
  30. console.log('failed to setRemoteDescription with offer, ', err);
  31. });
  32. });
  33. });
  34. } else {
  35. // Otherwise, this sink is the originator to another sink and should wait
  36. // for an alert.
  37. this._socket.emit('source', function(data) {
  38. self._id = data.id;
  39. if (!!self._readyHandler) {
  40. self._readyHandler(self._id);
  41. }
  42. self._socket.on('sink-connected', function(data) {
  43. target = data.sink;
  44. self._pc = new RTCPeerConnection(self._config);
  45. self.handleStream(true, target, function() {
  46. self.maybeBrowserisms(true, target);
  47. });
  48. });
  49. self._socket.on('answer', function(data) {
  50. self._pc.setRemoteDescription(data.sdp, function() {
  51. // Firefoxism
  52. if (browserisms == 'Firefox') {
  53. self._pc.connectDataConnection(5000, 5001);
  54. }
  55. console.log('ORIGINATOR: PeerConnection success');
  56. }, function(err) {
  57. console.log('failed to setRemoteDescription, ', err);
  58. });
  59. });
  60. });
  61. }
  62. };
  63. SinkPeer.prototype.maybeBrowserisms = function(originator, target) {
  64. var self = this;
  65. if (browserisms == 'Firefox') {
  66. getUserMedia({ audio: true, fake: true }, function(s) {
  67. self._pc.addStream(s);
  68. if (originator) {
  69. self.makeOffer(target);
  70. } else {
  71. self.makeAnswer(target);
  72. }
  73. }, function(err) { console.log('crap'); });
  74. } else {
  75. if (originator) {
  76. this.makeOffer(target);
  77. } else {
  78. this.makeAnswer(target);
  79. }
  80. }
  81. }
  82. SinkPeer.prototype.makeAnswer = function(target) {
  83. var self = this;
  84. this._pc.createAnswer(function(answer) {
  85. self._pc.setLocalDescription(answer, function() {
  86. self._socket.emit('answer',
  87. { 'sink': self._id,
  88. 'sdp': answer,
  89. 'source': target });
  90. // Firefoxism
  91. if (browserisms && browserisms == 'Firefox') {
  92. self._pc.connectDataConnection(5001, 5000);
  93. }
  94. }, function(err) {
  95. console.log('failed to setLocalDescription, ', err)
  96. });
  97. }, function(err) {
  98. console.log('failed to create answer, ', err)
  99. });
  100. };
  101. SinkPeer.prototype.makeOffer = function(target) {
  102. var self = this;
  103. this._pc.createOffer(function(offer) {
  104. self._pc.setLocalDescription(offer, function() {
  105. self._socket.emit('offer',
  106. { 'sdp': offer,
  107. 'sink': target,
  108. 'source': self._id });
  109. }, function(err) {
  110. console.log('failed to setLocalDescription, ', err);
  111. });
  112. });
  113. };
  114. SinkPeer.prototype.handleStream = function(originator, target, cb) {
  115. this.setupDataChannel(originator, target, cb);
  116. }
  117. SinkPeer.prototype.setupDataChannel = function(originator, target, cb) {
  118. self = this;
  119. if (browserisms != 'Webkit') {
  120. if (originator) {
  121. /** ORIGINATOR SETUP */
  122. this._pc.onconnection = function() {
  123. console.log('ORIGINATOR: onconnection triggered');
  124. self._dc = self._pc.createDataChannel('StreamAPI', {}, target);
  125. self._dc.binaryType = 'arraybuffer';
  126. if (!!self._connectionHandler) {
  127. self._connectionHandler(target);
  128. }
  129. self._dc.onmessage = function(e) {
  130. self.handleDataMessage(e);
  131. };
  132. };
  133. } else {
  134. /** TARGET SETUP */
  135. this._pc.ondatachannel = function(dc) {
  136. console.log('SINK: ondatachannel triggered');
  137. self._dc = dc;
  138. self._dc.binaryType = 'arraybuffer';
  139. if (!!self._connectionHandler) {
  140. self._connectionHandler(target);
  141. }
  142. self._dc.onmessage = function(e) {
  143. self.handleDataMessage(e);
  144. };
  145. };
  146. this._pc.onconnection = function() {
  147. console.log('SINK: onconnection triggered');
  148. };
  149. }
  150. }
  151. this._pc.onclosedconnection = function() {
  152. // Remove socket handlers perhaps.
  153. };
  154. cb();
  155. };
  156. SinkPeer.prototype.send = function(data) {
  157. var ab = MsgPack.encode(data);
  158. this._dc.send(ab);
  159. }
  160. // Handles a DataChannel message.
  161. // TODO: have these extend Peer, which will impl these generic handlers.
  162. SinkPeer.prototype.handleDataMessage = function(e) {
  163. data = MsgPack.decode(e.data);
  164. if (!!this._dataHandler) {
  165. this._dataHandler(data);
  166. }
  167. }
  168. SinkPeer.prototype.on = function(code, cb) {
  169. if (code === 'stream') {
  170. this._streamHandler = cb;
  171. } else if (code === 'disconnect') {
  172. this._disconnectHandler = cb;
  173. } else if (code === 'data') {
  174. this._dataHandler = cb;
  175. } else if (code === 'ready') {
  176. this._readyHandler = cb;
  177. } else if (code === 'connection') {
  178. this._connectionHandler = cb;
  179. }
  180. }