source.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. function SourcePeer(options) {
  2. // TODO: Allow passing in own ID.
  3. this._config = options.config || {};
  4. this._streams = options.streamType || 'd';
  5. this._name = options.name || 'StreamAPI';
  6. // PeerConnections open for this source. Client name => PC.
  7. this._pcs = {};
  8. this._id = null;
  9. // Same for DCs.
  10. this._dcs = {};
  11. this._socket = io.connect('http://localhost');
  12. this.socketInit();
  13. };
  14. SourcePeer.prototype.socketInit = function() {
  15. var self = this;
  16. this._socket.emit('source', function(data) {
  17. self._id = data.id;
  18. if (!!self._readyHandler) {
  19. self._readyHandler(self._id);
  20. }
  21. self._socket.on('sink-connected', function(data) {
  22. target = data.sink;
  23. var pc = new RTCPeerConnection(self._config);
  24. self._pcs[target] = pc;
  25. self.handleStream(pc, target, function(pc, target) {
  26. self.maybeBrowserisms(pc, target);
  27. });
  28. });
  29. self._socket.on('answer', function(data) {
  30. self._pcs[data.sink].setRemoteDescription(data.sdp, function() {
  31. // Firefoxism
  32. if (browserisms == 'Firefox') {
  33. self._pcs[data.sink].connectDataConnection(5000, 5001);
  34. }
  35. console.log('SOURCE: PeerConnection success');
  36. }, function(err) {
  37. console.log('failed to setRemoteDescription, ', err)
  38. });
  39. });
  40. });
  41. };
  42. // Stream Firefoxism... can be removed when DataChannel no longer requires
  43. // a stream.
  44. SourcePeer.prototype.maybeBrowserisms = function(pc, target) {
  45. var self = this;
  46. if (browserisms == 'Firefox') {
  47. getUserMedia({ audio: true, fake: true }, function(s) {
  48. pc.addStream(s);
  49. self.makeOffer(target);
  50. }, function(err) { console.log('crap'); });
  51. } else {
  52. this.makeOffer(target);
  53. }
  54. };
  55. // Make an offer.
  56. SourcePeer.prototype.makeOffer = function(target) {
  57. var pc = this._pcs[target];
  58. var self = this;
  59. pc.createOffer(function(offer) {
  60. pc.setLocalDescription(offer, function() {
  61. self._socket.emit('offer',
  62. { 'sdp': offer,
  63. 'sink': target,
  64. 'source': self._id });
  65. }, function(err) {
  66. console.log('failed to setLocalDescription, ', err);
  67. });
  68. });
  69. };
  70. // Based on stream type requested, sets up the stream for PC.
  71. SourcePeer.prototype.handleStream = function(pc, target, cb) {
  72. pc.onaddstream = function(obj) {
  73. console.log('SOURCE: data stream get');
  74. };
  75. /*if (this._streams === 'v') {
  76. } else if (this._streams === 'a') {
  77. } else if (this._streams === 'av') {
  78. } else if (this._streams === 'd') {*/
  79. this.setupDataChannel(pc, target, cb);
  80. /*} else if (this._streams === 'dav') {
  81. this.setupDataChannel(pc, target);
  82. } else if (this._streams === 'da') {
  83. this.setupDataChannel(pc, target);
  84. } else if (this._streams === 'dv') {
  85. this.setupDataChannel(pc, target);
  86. } else {
  87. //error
  88. }*/
  89. };
  90. SourcePeer.prototype.setupDataChannel = function(pc, target, cb) {
  91. var self = this;
  92. pc.onconnection = function() {
  93. console.log('SOURCE: onconnection triggered.');
  94. var dc = pc.createDataChannel(self._name, {}, target);
  95. self._dcs[target] = dc;
  96. dc.binaryType = 'arraybuffer';
  97. // User handler
  98. if (!!self._sinkHandler) {
  99. self._sinkHandler(target);
  100. }
  101. dc.onmessage = function(e) {
  102. self.handleDataMessage(e);
  103. };
  104. };
  105. pc.ondatachannel = function() {
  106. console.log('SOURCE: data channeled');
  107. };
  108. pc.onclosedconnection = function() {
  109. // ??
  110. };
  111. cb(pc, target);
  112. };
  113. SourcePeer.prototype.send = function(data, sink) {
  114. // TODO: try/catch
  115. var ab = MsgPack.encode(data);
  116. if (!!sink) {
  117. this._dcs[sink].send(ab);
  118. return;
  119. }
  120. for (var key in this._dcs) {
  121. if (this._dcs.hasOwnProperty(key)) {
  122. this._dcs[key].send(ab);
  123. }
  124. }
  125. }
  126. // Handles a DataChannel message.
  127. SourcePeer.prototype.handleDataMessage = function(e) {
  128. var data = MsgPack.decode(e.data);
  129. console.log(data);
  130. if (!!this._dataHandler) {
  131. this._dataHandler(data);
  132. }
  133. }
  134. SourcePeer.prototype.on = function(code, cb) {
  135. // For enduser.
  136. if (code === 'data') {
  137. this._dataHandler = cb;
  138. } else if (code === 'sink') {
  139. // SUCCESSFUL sink connection.
  140. this._sinkHandler = cb;
  141. } else if (code === 'stream') {
  142. this._streamHandler = cb;
  143. } else if (code === 'ready') {
  144. // Source has set up socket.
  145. this._readyHandler = cb;
  146. } else if (code == 'disconnect') {
  147. // A sink has disconnected.
  148. this._disconnectHandler = cb;
  149. }
  150. };