123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- function SourcePeer(options) {
- // TODO: Update for streams.
- // TODO: Allow passing in own ID.
- this._config = options.config || { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]};
- this._streams = options.streamType || 'd';
- this._name = options.name || 'StreamAPI';
- // PeerConnections open for this source. Client name => PC.
- this._pcs = {};
- this._id = null;
- // Same for DCs.
- this._dcs = {};
- this._socket = io.connect('http://localhost');
- this.socketInit();
- this._handlers = {};
- // Firefox
- if (browserisms == 'Firefox') {
- if (!SourcePeer.usedPorts) {
- SourcePeer.usedPorts = [];
- }
- this.localPort = randomPort();
- while (SourcePeer.usedPorts.indexOf(this.localPort) != -1) {
- this.localPort = randomPort();
- }
- this.remotePort = randomPort();
- while (this.remotePort == this.localPort ||
- SourcePeer.usedPorts.indexOf(this.remotePort) != -1) {
- this.remotePort = randomPort();
- }
- SourcePeer.usedPorts.push(this.remotePort);
- SourcePeer.usedPorts.push(this.localPort);
- }
- };
- function randomPort() {
- return Math.round(Math.random() * 60535) + 5000;
- };
- SourcePeer.prototype.socketInit = function() {
- var self = this;
- this._socket.emit('source', function(data) {
- self._id = data.id;
- if (!!self._handlers['ready']) {
- self._handlers['ready'](self._id);
- }
- self._socket.on('sink-connected', function(data) {
- target = data.sink;
- var pc = new RTCPeerConnection(self._config);
- self._pcs[target] = pc;
- self.handleStream(pc, target, function(pc, target) {
- self.maybeBrowserisms(pc, target);
- });
- });
- self._socket.on('answer', function(data) {
- self._pcs[data.sink].setRemoteDescription(new RTCSessionDescription(data.sdp),
- function() {
- // Firefoxism
- if (browserisms == 'Firefox') {
- self._pcs[data.sink].connectDataConnection(self.localPort, self.remotePort);
- self._socket.emit('port', { sink: data.sink, local: self.remotePort, remote: self.localPort });
- }
- console.log('SOURCE: PeerConnection success');
- }, function(err) {
- console.log('failed to setRemoteDescription, ', err)
- });
- });
- });
- };
- // Stream Firefoxism... can be removed when DataChannel no longer requires
- // a stream.
- SourcePeer.prototype.maybeBrowserisms = function(pc, target) {
- var self = this;
- if (browserisms == 'Firefox' && !this._video && !this._audio && !this._stream) {
- getUserMedia({ audio: true, fake: true }, function(s) {
- pc.addStream(s);
- self.makeOffer(target);
- }, function(err) { console.log('crap'); });
- } else {
- this.makeOffer(target);
- }
- };
- // Make an offer.
- SourcePeer.prototype.makeOffer = function(target) {
- var pc = this._pcs[target];
- var self = this;
- pc.createOffer(function(offer) {
- pc.setLocalDescription(offer, function() {
- self._socket.emit('offer',
- { 'sdp': offer,
- 'sink': target,
- 'source': self._id });
- }, function(err) {
- console.log('failed to setLocalDescription, ', err);
- });
- });
- };
- // Based on stream type requested, sets up the stream for PC.
- SourcePeer.prototype.handleStream = function(pc, target, cb) {
- pc.onaddstream = function(obj) {
- console.log('SOURCE: data stream get');
- };
- this.setupDataChannel(pc, target, cb);
- };
- SourcePeer.prototype.setupDataChannel = function(pc, target, cb) {
- var self = this;
- pc.onconnection = function() {
- console.log('SOURCE: onconnection triggered.');
- var dc = pc.createDataChannel(self._name, {}, target);
- self._dcs[target] = dc;
- dc.binaryType = 'blob';
- // User handler
- if (!!self._handlers['sink']) {
- self._handlers['sink'](target);
- }
- dc.onmessage = function(e) {
- self.handleDataMessage(e);
- };
- };
- pc.ondatachannel = function() {
- console.log('SOURCE: data channeled');
- };
- pc.onclosedconnection = function() {
- // ??
- };
- cb(pc, target);
- };
- SourcePeer.prototype.send = function(data, sink) {
- // TODO: try/catch
- var ab = BinaryPack.pack(data);
- if (!!sink) {
- this._dcs[sink].send(ab);
- return;
- }
- for (var key in this._dcs) {
- if (this._dcs.hasOwnProperty(key)) {
- this._dcs[key].send(ab);
- }
- }
- }
- // Handles a DataChannel message.
- SourcePeer.prototype.handleDataMessage = function(e) {
- var self = this;
- var fr = new FileReader();
- fr.onload = function(evt) {
- var ab = evt.target.result;
- var data = BinaryPack.unpack(ab);
- if (!!self._handlers['data']) {
- self._handlers['data'](data);
- }
- };
- fr.readAsArrayBuffer(e.data);
- }
- SourcePeer.prototype.on = function(code, cb) {
- // For enduser.
- // MAKE A HASH
- this._handlers[code] = cb;
- };
|