sink.js 5.0 KB

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