Advertisement
Chukwu

XSockets.WebRTC.latest.js

Aug 21st, 2014
3,013
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. String.prototype.capitalize = function () {
  2.     return this.replace(/(^|\s)([a-z])/g, function (m, p1, p2) {
  3.         return p1 + p2.toUpperCase();
  4.     });
  5. };
  6.  
  7. var RTCPeerConnection = null;
  8. var getUserMedia = null;
  9. var attachMediaStream = null;
  10. var reattachMediaStream = null;
  11. var webrtcDetectedBrowser = null;
  12. var webrtcDetectedVersion = null;
  13.  
  14. function trace(text) {
  15.     // This function is used for logging.
  16.     if (text[text.length - 1] == '\n') {
  17.         text = text.substring(0, text.length - 1);
  18.     }
  19.     console.log((performance.now() / 1000).toFixed(3) + ": " + text);
  20. }
  21.  
  22. if (navigator.mozGetUserMedia) {
  23.     console.log("This appears to be Firefox");
  24.  
  25.     webrtcDetectedBrowser = "firefox";
  26.  
  27.     webrtcDetectedVersion =
  28.              parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
  29.  
  30.     // The RTCPeerConnection object.
  31.     RTCPeerConnection = mozRTCPeerConnection;
  32.  
  33.     // The RTCSessionDescription object.
  34.     RTCSessionDescription = mozRTCSessionDescription;
  35.  
  36.     // The RTCIceCandidate object.
  37.     RTCIceCandidate = mozRTCIceCandidate;
  38.  
  39.     // Get UserMedia (only difference is the prefix).
  40.     // Code from Adam Barth.
  41.     getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  42.  
  43.     // Creates iceServer from the url for FF.
  44.     createIceServer = function (url, username, password) {
  45.         var iceServer = null;
  46.         var url_parts = url.split(':');
  47.         if (url_parts[0].indexOf('stun') === 0) {
  48.             // Create iceServer with stun url.
  49.             iceServer = { 'url': url };
  50.         } else if (url_parts[0].indexOf('turn') === 0) {
  51.             if (webrtcDetectedVersion < 27) {
  52.                 // Create iceServer with turn url.
  53.                 // Ignore the transport parameter from TURN url for FF version <=27.
  54.                 var turn_url_parts = url.split("?");
  55.                 // Return null for createIceServer if transport=tcp.
  56.                 if (turn_url_parts[1].indexOf('transport=udp') === 0) {
  57.                     iceServer = {
  58.                         'url': turn_url_parts[0],
  59.                         'credential': password,
  60.                         'username': username
  61.                     };
  62.                 }
  63.             } else {
  64.                 // FF 27 and above supports transport parameters in TURN url,
  65.                 // So passing in the full url to create iceServer.
  66.                 iceServer = {
  67.                     'url': url,
  68.                     'credential': password,
  69.                     'username': username
  70.                 };
  71.             }
  72.         }
  73.         return iceServer;
  74.     };
  75.  
  76.     // Attach a media stream to an element.
  77.     attachMediaStream = function (element, stream) {
  78.         console.log("Attaching media stream");
  79.         element.mozSrcObject = stream;
  80.         element.play();
  81.     };
  82.  
  83.     reattachMediaStream = function (to, from) {
  84.         console.log("Reattaching media stream");
  85.         to.mozSrcObject = from.mozSrcObject;
  86.         to.play();
  87.     };
  88.  
  89.     // Fake get{Video,Audio}Tracks
  90.     MediaStream.prototype.getVideoTracks = function () {
  91.         return [];
  92.     };
  93.  
  94.     MediaStream.prototype.getAudioTracks = function () {
  95.         return [];
  96.     };
  97. } else if (navigator.webkitGetUserMedia) {
  98.     console.log("This appears to be Chrome");
  99.  
  100.     webrtcDetectedBrowser = "chrome";
  101.     webrtcDetectedVersion =
  102.            parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10);
  103.  
  104.     // Creates iceServer from the url for Chrome.
  105.     createIceServer = function (url, username, password) {
  106.         var iceServer = null;
  107.         var url_parts = url.split(':');
  108.         if (url_parts[0].indexOf('stun') === 0) {
  109.             // Create iceServer with stun url.
  110.             iceServer = { 'url': url };
  111.         } else if (url_parts[0].indexOf('turn') === 0) {
  112.             // Chrome M28 & above uses below TURN format.
  113.             iceServer = {
  114.                 'url': url,
  115.                 'credential': password,
  116.                 'username': username
  117.             };
  118.         }
  119.         return iceServer;
  120.     };
  121.  
  122.     // The RTCPeerConnection object.
  123.     RTCPeerConnection = webkitRTCPeerConnection;
  124.  
  125.     // Get UserMedia (only difference is the prefix).
  126.     // Code from Adam Barth.
  127.     getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  128.  
  129.     // Attach a media stream to an element.
  130.     attachMediaStream = function (element, stream) {
  131.         if (typeof element.srcObject !== 'undefined') {
  132.             element.srcObject = stream;
  133.         } else if (typeof element.mozSrcObject !== 'undefined') {
  134.             element.mozSrcObject = stream;
  135.         } else if (typeof element.src !== 'undefined') {
  136.             element.src = URL.createObjectURL(stream);
  137.         } else {
  138.             console.log('Error attaching stream to element.');
  139.         }
  140.     };
  141.  
  142.     reattachMediaStream = function (to, from) {
  143.         to.src = from.src;
  144.     };
  145. } else {
  146.     console.log("Browser does not appear to be WebRTC-capable");
  147. }
  148.  
  149. window.requestAnimFrame = (function () {
  150.     return window.requestAnimationFrame ||
  151.             window.webkitRequestAnimationFrame ||
  152.             window.mozRequestAnimationFrame ||
  153.             function (callback) {
  154.                 window.setTimeout(callback, 1000 / 60);
  155.             };
  156. })();
  157.  
  158. XSockets.PeerContext = function (guid, context) {
  159.     this.PeerId = guid;
  160.     this.Context = context;
  161. };
  162.  
  163.  
  164. XSockets.AudioAnalyser = (function () {
  165.     function AudioAnalyser(stream, interval, cb) {
  166.         var self = this;
  167.         var buflen = 2048;
  168.         var buf = new Uint8Array(buflen);
  169.         function autoCorrelate(buf, sampleRate) {
  170.             var minSamples = 4;
  171.             var maxSamples = 1000;
  172.             var size = 1000;
  173.             var bestOffset = -1;
  174.             var bestCorrelation = 0;
  175.             var rms = 0;
  176.             var currentPitch = 0;
  177.             if (buf.length < (size + maxSamples - minSamples))
  178.                 return;  // Not enough data
  179.             for (var i = 0; i < size; i++) {
  180.                 var val = (buf[i] - 128) / 128;
  181.                 rms += val * val;
  182.             }
  183.             rms = Math.sqrt(rms / size);
  184.             for (var offset = minSamples; offset <= maxSamples; offset++) {
  185.                 var correlation = 0;
  186.                 for (var i = 0; i < size; i++) {
  187.                     correlation += Math.abs(((buf[i] - 128) / 128) - ((buf[i + offset] - 128) / 128));
  188.                 }
  189.                 correlation = 1 - (correlation / size);
  190.                 if (correlation > bestCorrelation) {
  191.                     bestCorrelation = correlation;
  192.                     bestOffset = offset;
  193.                 }
  194.             }
  195.             if ((rms > 0.01) && (bestCorrelation > 0.01)) {
  196.                 currentPitch = sampleRate / bestOffset;
  197.                 var result = {
  198.                     Confidence: bestCorrelation,
  199.                     CurrentPitch: currentPitch,
  200.                     Fequency: sampleRate / bestOffset,
  201.                     RMS: rms,
  202.                     TimeStamp: new Date()
  203.                 };
  204.                 if (self.onResult)
  205.                     self.onResult(result);
  206.                 self.analyzerResult.unshift(result);
  207.             }
  208.         }
  209.         function pitcher() {
  210.             self.analyser.getByteTimeDomainData(buf);
  211.             autoCorrelate(buf, self.audioContext.sampleRate);
  212.         }
  213.         this.analyzerResult = [];
  214.         this.isSpeaking = false;
  215.         this.onResult = undefined;
  216.         this.onAnalysis = undefined;
  217.         this.audioContext = new AudioContext();
  218.         var mediaStreamSource = this.audioContext.createMediaStreamSource(stream);
  219.         this.analyser = this.audioContext.createAnalyser();
  220.  
  221.         mediaStreamSource.connect(this.analyser);
  222.         this.analyser.smoothingTimeConstant = 0.8;
  223.         this.analyser.fftSize = 2048;
  224.  
  225.         window.setInterval(function () {
  226.             pitcher();
  227.         }, (interval || 1000) / 10);
  228.  
  229.         setInterval(function () {
  230.             if (self.analyzerResult.length > 5) {
  231.                 // How old is the latest confident audio analyze?
  232.                 var now = new Date();
  233.                 var result = self.analyzerResult[0];
  234.                 var lastKnown = new Date(self.analyzerResult[0].TimeStamp.getTime());
  235.                 if ((now - lastKnown) > 1000) {
  236.                     if (self.isSpeaking) {
  237.                         result.IsSpeaking = false;
  238.                         if (self.onAnalysis) self.onAnalysis(result);
  239.                         self.analyzerResult = [];
  240.                     }
  241.                     self.isSpeaking = false;
  242.                 } else {
  243.                     if (!self.isSpeaking) {
  244.                         result.IsSpeaking = true;
  245.                         if (self.onAnalysis) self.onAnalysis(result);
  246.                     }
  247.                     self.isSpeaking = true;
  248.                 }
  249.             }
  250.         }, 250);
  251.         if (cb) cb();
  252.     }
  253.     return AudioAnalyser;
  254.  
  255. })();
  256.  
  257. XSockets.WebRTC = function (ws, settings) {
  258.     var isAudioMuted = false;
  259.     var self = this;
  260.     var localStreams = [];
  261.     var subscriptions = new XSockets.Subscriptions();
  262.     this.PeerConnections = {};
  263.     this.DataChannels = undefined;
  264.     var defaults = {
  265.         iceServers: [{
  266.             "url": "stun:stun.l.google.com:19302"
  267.         }]
  268.         ,
  269.         sdpConstraints: {
  270.             optional: [],
  271.             mandatory: {
  272.                 OfferToReceiveAudio: true,
  273.                 OfferToReceiveVideo: true
  274.             }
  275.         },
  276.         streamConstraints: {
  277.             mandatory: {},
  278.             optional: []
  279.         },
  280.         sdpExpressions: []
  281.     };
  282.  
  283.  
  284.  
  285.  
  286.     var options = XSockets.Utils.extend(defaults, settings); ;
  287.  
  288.  
  289.     this.bind = function (event, fn, opts, callback) {
  290.         subscriptions.add(event, fn);
  291.         if (callback && typeof (callback) === "function") {
  292.             callback();
  293.         }
  294.         return this;
  295.     };
  296.     this.unbind = function (event, callback) {
  297.         subscriptions.REMove(event);
  298.         if (callback && typeof (callback) === "function") {
  299.             callback();
  300.         }
  301.         return this;
  302.     };
  303.     this.dispatch = function (eventName, message, obj) {
  304.         var _eventName = "on" + eventName;
  305.  
  306.         if (this.hasOwnProperty(_eventName)) {
  307.             self[_eventName](message);
  308.         }
  309.         if (subscriptions.get(eventName) === null) {
  310.             return;
  311.         }
  312.         if (typeof message === "string") {
  313.             message = JSON.parse(message);
  314.         }
  315.         subscriptions.fire(eventName, message, function () { });
  316.     };
  317.  
  318.  
  319.  
  320.     this.muteAudio = function (cb) {
  321.         /// <summary>Toggle mute on all local streams</summary>
  322.         /// <param name="cb" type="Object">function to be invoked when toggled</param>
  323.         localStreams.forEach(function (a, b) {
  324.             var audioTracks = a.getAudioTracks();
  325.  
  326.             if (audioTracks.length === 0) {
  327.                 return;
  328.             }
  329.             if (isAudioMuted) {
  330.                 for (i = 0; i < audioTracks.length; i++) {
  331.                     audioTracks[i].enabled = true;
  332.                 }
  333.             } else {
  334.                 for (i = 0; i < audioTracks.length; i++) {
  335.                     audioTracks[i].enabled = false;
  336.                 }
  337.             }
  338.         });
  339.         isAudioMuted = !isAudioMuted;
  340.         if (cb) cb(isAudioMuted);
  341.     };
  342.  
  343.     this.hasStream = function () {
  344.         /// <summary>Determin of there is media streams attach to the local peer</summary>
  345.         return localStreams.length > 0;
  346.     };
  347.  
  348.  
  349.     this.leaveContext = function () {
  350.         /// <summary>Leave the current context (hang up on all )</summary>
  351.         ws.publish("leaveContext", {
  352.  
  353.         });
  354.         return this;
  355.     };
  356.     this.changeContext = function (contextGuid) {
  357.         /// <summary>Change context on broker</summary>
  358.         /// <param name="contextGuid" type="Object">Unique identifer of the context to 'join'</param>
  359.         ws.publish("changecontext", {
  360.             context: contextGuid
  361.         });
  362.         return this;
  363.     };
  364.  
  365.  
  366.  
  367.  
  368.     this.getLocalStreams = function () {
  369.         /// <summary>Get local streams</summary>
  370.         return localStreams;
  371.     };
  372.     this.REMoveStream = function (id, fn) {
  373.         /// <summary>Remove the specified local stream</summary>
  374.         /// <param name="id" type="Object">Id of the media stream</param>
  375.         /// <param name="fn" type="Object">callback function invoked when remote peers notified and stream removed.</param>
  376.         localStreams.forEach(function (stream, index) {
  377.             if (stream.id === id) {
  378.  
  379.                 localStreams[index].stop();
  380.                 localStreams.splice(index, 1);
  381.                 for (var peer in self.PeerConnections) {
  382.                     //  self.PeerConnections[peer].Connection.REMoveStream(_stream);
  383.                     //createOffer({
  384.                     //    PeerId: peer
  385.                     //});
  386.                     ws.publish("removestream", {
  387.                         recipient: peer,
  388.                         streamId: id
  389.                     });
  390.                     if (fn) fn(id);
  391.                 }
  392.             }
  393.         });
  394.     };
  395.  
  396.     this.userMediaConstraints = {
  397.         qvga: function (audio) {
  398.             return {
  399.                 video: {
  400.                     mandatory: {
  401.                         maxWidth: 320,
  402.                         maxHeight: 180
  403.                     }
  404.                 },
  405.                 audio: typeof (audio) !== "boolean" ? false : audio
  406.             };
  407.         },
  408.         vga: function (audio) {
  409.             return {
  410.                 video: {
  411.                     mandatory: {
  412.                         maxWidth: 640,
  413.                         maxHeight: 360
  414.                     }
  415.                 },
  416.                 audio: typeof (audio) !== "boolean" ? false : audio
  417.             };
  418.         },
  419.         hd: function (audio) {
  420.  
  421.             return {
  422.                 video: {
  423.                     mandatory: {
  424.                         minWidth: 1280,
  425.                         minHeight: 720
  426.                     }
  427.                 },
  428.                 audio: typeof (audio) !== "boolean" ? false : audio
  429.             };
  430.         },
  431.         create: function (w, h, audio) {
  432.             return {
  433.                 video: {
  434.                     mandatory: {
  435.                         minWidth: w,
  436.                         minHeight: h
  437.                     }
  438.                 },
  439.                 audio: typeof (audio) !== "boolean" ? false : audio
  440.             };
  441.         },
  442.         screenSharing: function () {
  443.             return {
  444.                 video: {
  445.                     mandatory: {
  446.                         chromeMediaSource: 'screen'
  447.                     }
  448.                 }
  449.             };
  450.         }
  451.     };
  452.  
  453.     this.getREMotePeers = function () {
  454.         /// <summary>Returns a list of remotePeers (list of id's)</summary>
  455.         var ids = [];
  456.         for (var peer in self.PeerConnections)
  457.             ids.push(peer);
  458.         return ids;
  459.  
  460.     };
  461.  
  462.     this.refreshStreams = function (id, fn) {
  463.         /// <summary>Reattach streams and renegotiate</summary>
  464.         /// <param name="id" type="Object">PeerConnection id</param>
  465.         /// <param name="fn" type="Object">callback that will be invoked when completed.</param>
  466.         localStreams.forEach(function (stream, index) {
  467.             self.PeerConnections[id].Connection.REMoveStream(localStreams[index]);
  468.         });
  469.         createOffer({
  470.             PeerId: id
  471.         });
  472.  
  473.         if (fn) fn(id);
  474.     };
  475.  
  476.     this.addLocalStream = function (stream, cb) {
  477.         var index = localStreams.push(stream);
  478.         // Check it there is PeerConnections
  479.         ws.trigger("AddStream", {
  480.             streamId: stream.id,
  481.             description: ""
  482.         });
  483.         self.dispatch(XSockets.WebRTC.Events.onlocalStream, stream);
  484.         if (cb) cb(stream, index);
  485.         return this;
  486.     };
  487.  
  488.     this.REMovePeerConnection = function (id, fn) {
  489.         /// <summary>Remove the specified Peerconnection</summary>
  490.         /// <param name="id" type="guid">Id of the PeerConnection. Id is the PeerId of the actual PeerConnection</param>
  491.         /// <param name="fn" type="function">callback function invoked when the PeerConnection is removed</param>
  492.         //ws.publish("peerconnectiondisconnect", {
  493.         //    Recipient: id,
  494.         //    Sender: self.CurrentContext.PeerId
  495.         //});
  496.         if (self.PeerConnections[id] !== undefined) {
  497.             try {
  498.                 self.PeerConnections[id].Connection.close();
  499.                 self.dispatch(XSockets.WebRTC.Events.onPeerConnectionLost, {
  500.                     PeerId: id
  501.                 });
  502.             } catch (err) {
  503.  
  504.             }
  505.  
  506.         };
  507.         delete self.PeerConnections[id];
  508.         if (fn) fn();
  509.     };
  510.  
  511.     this.getUserMedia = function (constraints, success, error) {
  512.  
  513.         /// <summary>get a media stream</summary>
  514.         /// <param name="userMediaSettings" type="Object">connstraints. i.e .usersdpConstraints.hd()</param>
  515.         /// <param name="success" type="Object">callback function invoked when media stream captured</param>
  516.         /// <param name="error" type="Object">callback function invoked on faild to get the media stream </param>
  517.         function push_freshstream(stream) {
  518.             localStreams.push(stream);
  519.             ws.trigger("AddStream", {
  520.                 streamId: stream.id,
  521.                 description: ""
  522.             });
  523.             self.dispatch(XSockets.WebRTC.Events.onlocalStream, stream);
  524.             if (success && typeof (success) === "function") success(self.CurrentContext);
  525.         }
  526.         window.getUserMedia(constraints, function (stream) {
  527.             push_freshstream(stream);
  528.  
  529.         }, function (err) {
  530.             if (constraints.video == null || constraints.video == false) {
  531.                 constraints.audio = true;constraints.video = false;
  532.             }else if(constraints.audio == null || constraints.audio == false){
  533.                 constraints.video = true;constraints.audio = false;
  534.             }else{
  535.                 constraints.video = true;constraints.audio = true;
  536.             }
  537.             window.getUserMedia(constraints, function (stream) {
  538.                 console.log('default constraint fails due to possible microphone hardware deprecation. default Fallback activated', err);
  539.                 push_freshstream(stream);
  540.  
  541.             }, function (err) {
  542.                 if (error && typeof (error) === "function") error(err);
  543.             });
  544.         });
  545.         return this;
  546.     };
  547.  
  548.     // DataChannels
  549.  
  550.     this.addDataChannel = function (dc) {
  551.         /// <summary>Add a XSockets.WebRTC.DataChannel. Channel will be offered to REMote peers</summary>
  552.         /// <param name="dc" type="Object">XSockets.WebRTC.DataChannel to add</param>
  553.         /// <param name="success" type="Object">callback function invoked when added.</param>
  554.         this.DataChannels = this.DataChannels || {};
  555.         if (!this.DataChannels.hasOwnProperty(dc.name)) {
  556.             this.DataChannels[dc.name] = dc;
  557.         } else {
  558.             throw "A RTCDataChannel named '" + dc.Name + "' already exists and cannot be created.";
  559.         }
  560.  
  561.  
  562.  
  563.     };
  564.     this.REMoveDataChannel = function (name, cb) {
  565.         /// <summary>Remove a Sockets.WebRTC.DataChannel </summary>
  566.         /// <param name="name" type="Object">name of the XSockets.WebRTC.DataChannel to remove from offers</param>
  567.         /// <param name="success" type="Object">callback function invoked when removed</param>
  568.  
  569.         if (this.DataChannels.hasOwnProperty(name)) {
  570.             delete this.DataChannels[name];
  571.             // REMove delegates from peers..
  572.             for (var pc in this.PeerConnections) {
  573.                 this.PeerConnections[pc].RTCDataChannels[name].close();
  574.                 delete this.PeerConnections[pc].RTCDataChannels[name];
  575.             }
  576.         } else {
  577.             throw "A RTCDataChannel named '" + name + "' does not exists.";
  578.         }
  579.     };
  580.  
  581.  
  582.     // Private methods
  583.     var rtcPeerConnection = function (configuration, peerId) {
  584.  
  585.         var that = this;
  586.         this.PeerId = peerId;
  587.         this.RTCDataChannels = {};
  588.         if (typeof (self.DataChannels) === "object" && configuration.sdpConstraints.optional.filter(function (option) { return option.RtpDataChannels; }).length === 0) {
  589.             configuration.sdpConstraints.optional.push({ RtpDataChannels: true });
  590.         }
  591.         this.Connection = new RTCPeerConnection({ iceServers: configuration.iceServers }, configuration.sdpConstraints);
  592.         this.Connection.oniceconnectionstatechange = function (data) {
  593.             //   console.log("oniceconnectionstatechange", data);
  594.         };
  595.         this.Connection.onnegotiationneeded = function (data) {
  596.             // console.log("onnegotiationneeded", data);
  597.         };
  598.         this.Connection.onREMovestream = function (data) {
  599.             //console.log("onremovestream", data);
  600.         };
  601.         this.Connection.onsignalingstatechange = function (data) {
  602.             //console.log("onsignalingstatechange", data);
  603.         };
  604.         // If there is dataChannels attach, offer em
  605.         for (var dc in self.DataChannels) {
  606.             var dataChannel = self.DataChannels[dc];
  607.             this.RTCDataChannels[dataChannel.name] = this.Connection.createDataChannel(dataChannel.name, { reliable: false });
  608.             this.RTCDataChannels[dataChannel.name].onmessage = function (data) {
  609.                 var obj = JSON.parse(data.data).JSON;
  610.                 dataChannel.subscriptions.fire(obj.event, { peerId: that.PeerId, message: JSON.parse(obj.data) }, function () { });
  611.             };
  612.             this.RTCDataChannels[dataChannel.name].onopen = function (event) {
  613.                 //console.log("dataChannel open ", dataChannel.name, data);
  614.                 if (dataChannel.onopen) dataChannel.onopen(that.PeerId, event);
  615.             };
  616.             this.RTCDataChannels[dataChannel.name].closed = function (event) {
  617.                 if (dataChannel.onclose) dataChannel.onclose(that.PeerId, event);
  618.             };
  619.             dataChannel.onpublish = function (topic, data) {
  620.                 var message = new XSockets.Message(topic, data);
  621.                 for (var p in self.PeerConnections) {
  622.                     self.PeerConnections[p].RTCDataChannels[dataChannel.name].send(JSON.stringify(message));
  623.                 }
  624.             };
  625.             dataChannel.onpublishTo = function (peerId, topic, data) {
  626.                 var message = new XSockets.Message(topic, data);
  627.                 if (self.PeerConnections[peerId])
  628.                     self.PeerConnections[peerId].RTCDataChannels[dataChannel.name].send(JSON.stringify(message));
  629.             };
  630.         }
  631.         this.Connection.onaddstream = function (event) {
  632.             self.dispatch(XSockets.WebRTC.Events.onREMoteStream, {
  633.                 PeerId: that.PeerId,
  634.                 stream: event.stream
  635.             });
  636.         };
  637.         this.Connection.onicecandidate = function (event) {
  638.             if (event.candidate) {
  639.                 var candidate = {
  640.                     type: 'candidate',
  641.                     label: event.candidate.sdpMLineIndex,
  642.                     id: event.candidate.sdpMid,
  643.                     candidate: event.candidate.candidate
  644.                 };
  645.                 ws.publish("contextsignal", {
  646.                     sender: self.CurrentContext.PeerId,
  647.                     recipient: that.PeerId,
  648.                     message: JSON.stringify(candidate)
  649.                 });
  650.             }
  651.         };
  652.         self.dispatch(XSockets.WebRTC.Events.onPeerConnectionCreated, { PeerId: that.PeerId });
  653.     };
  654.     var createOffer = function (peer) {
  655.         if (!peer) return;
  656.  
  657.         //if (self.PeerConnections[peer.PeerId]) {
  658.         self.PeerConnections[peer.PeerId] = new rtcPeerConnection(options, peer.PeerId);
  659.         localStreams.forEach(function (a, b) {
  660.  
  661.             self.PeerConnections[peer.PeerId].Connection.addStream(a, options.streamConstraints);
  662.         });
  663.         self.PeerConnections[peer.PeerId].Connection.createOffer(function (localDescription) {
  664.             options.sdpExpressions.forEach(function (expr, b) {
  665.                 localDescription.sdp = expr(localDescription.sdp);
  666.             }, function (failue) {
  667.                 console.log(failue);
  668.             });
  669.             self.PeerConnections[peer.PeerId].Connection.setLocalDescription(localDescription);
  670.             ws.publish("contextsignal", {
  671.                 Sender: self.CurrentContext.PeerId,
  672.                 Recipient: peer.PeerId,
  673.                 Message: JSON.stringify(localDescription)
  674.             });
  675.         }, null, options.sdpConstraints);
  676.         //}
  677.     };
  678.     self.bind("connect", function (peer) {
  679.         createOffer(peer);
  680.     });
  681.     self.bind("candidate", function (event) {
  682.         var candidate = JSON.parse(event.Message);
  683.         if (!self.PeerConnections[event.Sender]) return;
  684.         self.PeerConnections[event.Sender].Connection.addIceCandidate(new RTCIceCandidate({
  685.             sdpMLineIndex: candidate.label,
  686.             candidate: candidate.candidate
  687.         }));
  688.     });
  689.     self.bind("answer", function (event) {
  690.         self.dispatch(XSockets.WebRTC.Events.onAnswer, {
  691.             PeerId: event.Sender
  692.         });
  693.         self.PeerConnections[event.Sender].Connection.setREMoteDescription(new RTCSessionDescription(JSON.parse(event.Message)));
  694.     });
  695.     self.bind("offer", function (event) {
  696.         self.dispatch(XSockets.WebRTC.Events.onOffer, {
  697.             PeerId: event.Sender
  698.         });
  699.         self.PeerConnections[event.Sender] = new rtcPeerConnection(options, event.Sender);
  700.         self.PeerConnections[event.Sender].Connection.setREMoteDescription(new RTCSessionDescription(JSON.parse(event.Message)));
  701.  
  702.  
  703.  
  704.         localStreams.forEach(function (a, b) {
  705.             self.PeerConnections[event.Sender].Connection.addStream(a, options.streamConstraints);
  706.         });
  707.  
  708.         self.PeerConnections[event.Sender].Connection.createAnswer(function (description) {
  709.  
  710.             self.PeerConnections[event.Sender].Connection.setLocalDescription(description);
  711.             options.sdpExpressions.forEach(function (expr, b) {
  712.  
  713.                 description.sdp = expr(description.sdp);
  714.             }, function (failure) {
  715.                 // dispatch the error
  716.             });
  717.             var answer = {
  718.                 Sender: self.CurrentContext.PeerId,
  719.                 Recipient: event.Sender,
  720.                 Message: JSON.stringify(description)
  721.             };
  722.             ws.publish("contextsignal", answer);
  723.         }, null, options.sdpConstraints);
  724.  
  725.     });
  726.     ws.subscribe("contextcreated", function (context) {
  727.         self.CurrentContext = new XSockets.PeerContext(context.PeerId, context.Context);
  728.         self.dispatch(XSockets.WebRTC.Events.onContextCreated, context);
  729.     }, function () {
  730.         ws.publish('GetContext');
  731.     });
  732.     ws.subscribe("contextsignal", function (signal) {
  733.         var msg = JSON.parse(signal.Message);
  734.         self.dispatch(msg.type, signal);
  735.     });
  736.     ws.subscribe("contextchanged", function (change) {
  737.         self.dispatch(XSockets.WebRTC.Events.onContextChange, change);
  738.     });
  739.     ws.subscribe("contextconnect", function (peers) {
  740.         peers.forEach(function (peer) {
  741.             self.dispatch("connect", peer);
  742.             self.dispatch(XSockets.WebRTC.Events.onPeerConnectionStarted, peer);
  743.         });
  744.     });
  745.     ws.subscribe("peerconnectiondisconnect", function (peer) {
  746.         if (self.PeerConnections[peer.Sender] !== undefined) {
  747.             self.PeerConnections[peer.Sender].Connection.close();
  748.             self.dispatch(XSockets.WebRTC.Events.onPeerConnectionLost, {
  749.                 PeerId: peer.Sender
  750.             });
  751.             delete self.PeerConnections[peer.Sender];
  752.         }
  753.     });
  754.     ws.subscribe("streamadded", function (event) {
  755.         self.dispatch(XSockets.WebRTC.Events.onLocalStreamCreated, event);
  756.     });
  757.     ws.subscribe("streamremoved", function (event) {
  758.         self.dispatch(XSockets.WebRTC.Events.onREMoteStreamLost, {
  759.             PeerId: event.Sender,
  760.             StreamId: event.StreamId
  761.         });
  762.     });
  763.     ws.subscribe("peerconnectionlost", function (peer) {
  764.  
  765.         self.dispatch(XSockets.WebRTC.Events.onPeerConnectionLost, {
  766.             PeerId: peer.PeerId
  767.         });
  768.         if (self.PeerConnections[peer.PeerId] !== undefined) {
  769.             self.PeerConnections[peer.PeerId].Connection.close();
  770.             delete self.PeerConnections[peer.PeerId];
  771.         };
  772.  
  773.  
  774.     });
  775.  
  776.  
  777.  
  778.  
  779.  
  780. };
  781.  
  782.  
  783. XSockets.WebRTC.DataChannel = (function () {
  784.     function DataChannel(name) {
  785.         var self = this;
  786.         this.subscriptions = new XSockets.Subscriptions();
  787.         this.name = name;
  788.         this.subscribe = function (topic, cb) {
  789.             self.subscriptions.add(topic, cb);
  790.         };
  791.         this.publish = function (topic, data, cb) {
  792.             if (!self.onpublish) return;
  793.             self.onpublish(topic, data);
  794.             if (cb) cb(data);
  795.         };
  796.         this.publishTo = function(peerId,topic, data, cb) {
  797.  
  798.         };
  799.         this.unsubscribe = function (topic, cb) {
  800.             self.subscriptions.REMove(topic);
  801.             if (cb) cb();
  802.         };
  803.         this.onbinary = undefined;
  804.         this.onpublish = undefined;
  805.         this.onclose = undefined;
  806.         this.onopen = undefined;
  807.     }
  808.     return DataChannel;
  809. })();
  810.  
  811.  
  812. XSockets.WebRTC.CallManager = function (ws, settings) {
  813.     var events = settings.events;
  814.     this.call = function (recipient) {
  815.         ws.trigger("offercontext", {
  816.             PeerId: recipient.PeerId
  817.         });
  818.     };
  819.  
  820.     this.acceptCall = function (call) {
  821.         events.onAcceptCall(call);
  822.     };
  823.     this.denyCall = function (recipient) {
  824.         ws.trigger("denycontext", {
  825.             PeerId: recipient.PeerId
  826.         });
  827.     };
  828.     this.endCall = function () {
  829.         ws.trigger("leavecontext", {});
  830.     };
  831.     ws.subscribe("contextoffer", events.onCall);
  832.     ws.subscribe("contextdeny", events.onDenyCall);
  833. };
  834.  
  835. XSockets.WebRTC.Events = {
  836.     onlocalStream: "localstream",
  837.     onREMoteStream: "remotestream",
  838.     onRemoteStreamLost: "removestream",
  839.     onLocalStreamCreated: "streamadded",
  840.     onContextChange: "contextchanged", // Fires when the current context changes
  841.     onContextCreated: "contextcreated", // Fires when a client recives a new context
  842.     onPeerConnectionStarted: "peerconnectionstarted", // Fires when a new RTCPeerConnection is initialized
  843.     onPeerConnectionCreated: "peerconnectioncreated", // Fires when a new RTCPeerConnection is created
  844.     onPeerConnectionLost: "peerconnectionlost", // Fires when a RTCPeerConnection is lost
  845.     onDataChannelOpen: "datachannelopen", // Fires when a datachannel is open
  846.     onDataChannelClose: "datachannelclose", // Fires when a datachannes is closed
  847.     onOffer: 'sdoffer',
  848.     onAnswer: 'sdanswer'
  849.  
  850. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement