var defaultConfig = {'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]}; var util = { noop: function() {}, CLOUD_HOST: '0.peerjs.com', CLOUD_PORT: 9000, // Logging logic logLevel: 0, setLogLevel: function(level) { var debugLevel = parseInt(level, 10); if (!isNaN(parseInt(level, 10))) { util.logLevel = debugLevel; } else { // If they are using truthy/falsy values for debug util.logLevel = level ? 3 : 0; } util.log = util.warn = util.error = util.noop; if (util.logLevel > 0) { util.error = util._printWith('ERROR'); } if (util.logLevel > 1) { util.warn = util._printWith('WARNING'); } if (util.logLevel > 2) { util.log = util._print; } }, setLogFunction: function(fn) { if (fn.constructor !== Function) { util.warn('The log function you passed in is not a function. Defaulting to regular logs.'); } else { util._print = fn; } }, _printWith: function(prefix) { return function() { var copy = Array.prototype.slice.call(arguments); copy.unshift(prefix); util._print.apply(util, copy); }; }, _print: function () { var err = false; var copy = Array.prototype.slice.call(arguments); copy.unshift('PeerJS: '); for (var i = 0, l = copy.length; i < l; i++){ if (copy[i] instanceof Error) { copy[i] = '(' + copy[i].name + ') ' + copy[i].message; err = true; } } err ? console.error.apply(console, copy) : console.log.apply(console, copy); }, // // Returns browser-agnostic default config defaultConfig: defaultConfig, // // Returns the current browser. browser: (function() { if (window.mozRTCPeerConnection) { return 'Firefox'; } else if (window.webkitRTCPeerConnection) { return 'Chrome'; } else if (window.RTCPeerConnection) { return 'Supported'; } else { return 'Unsupported'; } })(), // // Lists which features are supported supports: (function() { if (typeof RTCPeerConnection === 'undefined') { return {}; } var data = true; var audioVideo = true; var binaryBlob = false; var sctp = false; var onnegotiationneeded = !!window.webkitRTCPeerConnection; var pc, dc; try { pc = new RTCPeerConnection(defaultConfig, {optional: [{RtpDataChannels: true}]}); } catch (e) { data = false; audioVideo = false; } if (data) { try { dc = pc.createDataChannel('_PEERJSTEST'); } catch (e) { data = false; } } if (data) { // Binary test try { dc.binaryType = 'blob'; binaryBlob = true; } catch (e) { } // Reliable test. // Unfortunately Chrome is a bit unreliable about whether or not they // support reliable. var reliablePC = new RTCPeerConnection(defaultConfig, {}); try { var reliableDC = reliablePC.createDataChannel('_PEERJSRELIABLETEST', {}); sctp = reliableDC.reliable; } catch (e) { } reliablePC.close(); } // FIXME: not really the best check... if (audioVideo) { audioVideo = !!pc.addStream; } // FIXME: this is not great because in theory it doesn't work for // av-only browsers (?). if (!onnegotiationneeded && data) { // sync default check. var negotiationPC = new RTCPeerConnection(defaultConfig, {optional: [{RtpDataChannels: true}]}); negotiationPC.onnegotiationneeded = function() { onnegotiationneeded = true; // async check. if (util && util.supports) { util.supports.onnegotiationneeded = true; } }; var negotiationDC = negotiationPC.createDataChannel('_PEERJSNEGOTIATIONTEST'); setTimeout(function() { negotiationPC.close(); }, 1000); } if (pc) { pc.close(); } return { audioVideo: audioVideo, data: data, binaryBlob: binaryBlob, binary: sctp, // deprecated; sctp implies binary support. reliable: sctp, // deprecated; sctp implies reliable data. sctp: sctp, onnegotiationneeded: onnegotiationneeded }; }()), // // Ensure alphanumeric ids validateId: function(id) { // Allow empty ids return !id || /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.exec(id); }, validateKey: function(key) { // Allow empty keys return !key || /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.exec(key); }, debug: false, inherits: function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }, extend: function(dest, source) { for(var key in source) { if(source.hasOwnProperty(key)) { dest[key] = source[key]; } } return dest; }, pack: BinaryPack.pack, unpack: BinaryPack.unpack, log: function () { if (util.debug) { var err = false; var copy = Array.prototype.slice.call(arguments); copy.unshift('PeerJS: '); for (var i = 0, l = copy.length; i < l; i++){ if (copy[i] instanceof Error) { copy[i] = '(' + copy[i].name + ') ' + copy[i].message; err = true; } } err ? console.error.apply(console, copy) : console.log.apply(console, copy); } }, setZeroTimeout: (function(global) { var timeouts = []; var messageName = 'zero-timeout-message'; // Like setTimeout, but only takes a function argument. There's // no time argument (always zero) and no arguments (you have to // use a closure). function setZeroTimeoutPostMessage(fn) { timeouts.push(fn); global.postMessage(messageName, '*'); } function handleMessage(event) { if (event.source == global && event.data == messageName) { if (event.stopPropagation) { event.stopPropagation(); } if (timeouts.length) { timeouts.shift()(); } } } if (global.addEventListener) { global.addEventListener('message', handleMessage, true); } else if (global.attachEvent) { global.attachEvent('onmessage', handleMessage); } return setZeroTimeoutPostMessage; }(this)), // Binary stuff blobToArrayBuffer: function(blob, cb){ var fr = new FileReader(); fr.onload = function(evt) { cb(evt.target.result); }; fr.readAsArrayBuffer(blob); }, blobToBinaryString: function(blob, cb){ var fr = new FileReader(); fr.onload = function(evt) { cb(evt.target.result); }; fr.readAsBinaryString(blob); }, binaryStringToArrayBuffer: function(binary) { var byteArray = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i++) { byteArray[i] = binary.charCodeAt(i) & 0xff; } return byteArray.buffer; }, randomToken: function () { return Math.random().toString(36).substr(2); }, // isSecure: function() { return location.protocol === 'https:'; } }; exports.util = util;