diff --git a/public/js/simplewebrtc.bundle.js b/public/js/simplewebrtc.bundle.js index 9e707b9..1141605 100644 --- a/public/js/simplewebrtc.bundle.js +++ b/public/js/simplewebrtc.bundle.js @@ -463,7 +463,59 @@ SimpleWebRTC.prototype.sendFile = function () { module.exports = SimpleWebRTC; -},{"./socketioconnection":3,"./webrtc":2,"attachmediastream":7,"mockconsole":6,"webrtcsupport":5,"wildemitter":4}],4:[function(require,module,exports){ +},{"./socketioconnection":3,"./webrtc":2,"attachmediastream":7,"mockconsole":6,"webrtcsupport":5,"wildemitter":4}],5:[function(require,module,exports){ +// created by @HenrikJoreteg +var prefix; +var version; + +if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) { + prefix = 'moz'; + version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); +} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) { + prefix = 'webkit'; + version = navigator.userAgent.match(/Chrom(e|ium)/) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); +} + +var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; +var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; +var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; +var MediaStream = window.webkitMediaStream || window.MediaStream; +var screenSharing = window.location.protocol === 'https:' && + ((prefix === 'webkit' && version >= 26) || + (prefix === 'moz' && version >= 33)) +var AudioContext = window.AudioContext || window.webkitAudioContext; +var videoEl = document.createElement('video'); +var supportVp8 = videoEl && videoEl.canPlayType && videoEl.canPlayType('video/webm; codecs="vp8", vorbis') === "probably"; +var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia; + +// export support flags and constructors.prototype && PC +module.exports = { + prefix: prefix, + browserVersion: version, + support: !!PC && supportVp8 && !!getUserMedia, + // new support style + supportRTCPeerConnection: !!PC, + supportVp8: supportVp8, + supportGetUserMedia: !!getUserMedia, + supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), + supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), + supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), + supportScreenSharing: !!screenSharing, + // old deprecated style. Dont use this anymore + dataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), + webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), + mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), + screenSharing: !!screenSharing, + // constructors + AudioContext: AudioContext, + PeerConnection: PC, + SessionDescription: SessionDescription, + IceCandidate: IceCandidate, + MediaStream: MediaStream, + getUserMedia: getUserMedia +}; + +},{}],4:[function(require,module,exports){ /* WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based on @visionmedia's Emitter from UI Kit. @@ -608,58 +660,6 @@ WildEmitter.prototype.getWildcardCallbacks = function (eventName) { return result; }; -},{}],5:[function(require,module,exports){ -// created by @HenrikJoreteg -var prefix; -var version; - -if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) { - prefix = 'moz'; - version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); -} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) { - prefix = 'webkit'; - version = navigator.userAgent.match(/Chrom(e|ium)/) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); -} - -var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; -var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; -var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; -var MediaStream = window.webkitMediaStream || window.MediaStream; -var screenSharing = window.location.protocol === 'https:' && - ((prefix === 'webkit' && version >= 26) || - (prefix === 'moz' && version >= 33)) -var AudioContext = window.AudioContext || window.webkitAudioContext; -var videoEl = document.createElement('video'); -var supportVp8 = videoEl && videoEl.canPlayType && videoEl.canPlayType('video/webm; codecs="vp8", vorbis') === "probably"; -var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia; - -// export support flags and constructors.prototype && PC -module.exports = { - prefix: prefix, - browserVersion: version, - support: !!PC && supportVp8 && !!getUserMedia, - // new support style - supportRTCPeerConnection: !!PC, - supportVp8: supportVp8, - supportGetUserMedia: !!getUserMedia, - supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), - supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), - supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), - supportScreenSharing: !!screenSharing, - // old deprecated style. Dont use this anymore - dataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), - webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), - mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), - screenSharing: !!screenSharing, - // constructors - AudioContext: AudioContext, - PeerConnection: PC, - SessionDescription: SessionDescription, - IceCandidate: IceCandidate, - MediaStream: MediaStream, - getUserMedia: getUserMedia -}; - },{}],6:[function(require,module,exports){ var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","); var l = methods.length; @@ -5389,9 +5389,6 @@ var INBAND_FILETRANSFER_V1 = 'https://simplewebrtc.com/protocol/filetransfer#inb function Peer(options) { var self = this; - // call emitter constructor - WildEmitter.call(this); - this.id = options.id; this.parent = options.parent; this.type = options.type || 'video'; @@ -5451,6 +5448,9 @@ function Peer(options) { }); } + // call emitter constructor + WildEmitter.call(this); + this.on('channelOpen', function (channel) { if (channel.protocol === INBAND_FILETRANSFER_V1) { channel.onmessage = function (event) { @@ -5506,7 +5506,7 @@ Peer.prototype.handleMessage = function (message) { this.parent.emit('mute', {id: message.from, name: message.payload.name}); } else if (message.type === 'unmute') { this.parent.emit('unmute', {id: message.from, name: message.payload.name}); - } else { + } else { this.parent.emit(message.type, {id: message.from, payload: message.payload, roomType: message.roomType}); } }; @@ -5656,7 +5656,91 @@ Peer.prototype.sendFile = function (file) { module.exports = Peer; -},{"filetransfer":15,"rtcpeerconnection":14,"util":8,"webrtcsupport":5,"wildemitter":4}],10:[function(require,module,exports){ +},{"filetransfer":15,"rtcpeerconnection":14,"util":8,"webrtcsupport":5,"wildemitter":4}],16:[function(require,module,exports){ +// getUserMedia helper by @HenrikJoreteg +var func = (window.navigator.getUserMedia || + window.navigator.webkitGetUserMedia || + window.navigator.mozGetUserMedia || + window.navigator.msGetUserMedia); + + +module.exports = function (constraints, cb) { + var options, error; + var haveOpts = arguments.length === 2; + var defaultOpts = {video: true, audio: true}; + + var denied = 'PermissionDeniedError'; + var altDenied = 'PERMISSION_DENIED'; + var notSatisfied = 'ConstraintNotSatisfiedError'; + + // make constraints optional + if (!haveOpts) { + cb = constraints; + constraints = defaultOpts; + } + + // treat lack of browser support like an error + if (!func) { + // throw proper error per spec + error = new Error('MediaStreamError'); + error.name = 'NotSupportedError'; + + // keep all callbacks async + return window.setTimeout(function () { + cb(error); + }, 0); + } + + // normalize error handling when no media types are requested + if (!constraints.audio && !constraints.video) { + error = new Error('MediaStreamError'); + error.name = 'NoMediaRequestedError'; + + // keep all callbacks async + return window.setTimeout(function () { + cb(error); + }, 0); + } + + if (localStorage && localStorage.useFirefoxFakeDevice === "true") { + constraints.fake = true; + } + + func.call(window.navigator, constraints, function (stream) { + cb(null, stream); + }, function (err) { + var error; + // coerce into an error object since FF gives us a string + // there are only two valid names according to the spec + // we coerce all non-denied to "constraint not satisfied". + if (typeof err === 'string') { + error = new Error('MediaStreamError'); + if (err === denied || err === altDenied) { + error.name = denied; + } else { + error.name = notSatisfied; + } + } else { + // if we get an error object make sure '.name' property is set + // according to spec: http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermediaerror-and-navigatorusermediaerrorcallback + error = err; + if (!error.name) { + // this is likely chrome which + // sets a property called "ERROR_DENIED" on the error object + // if so we make sure to set a name + if (error[denied]) { + err.name = denied; + } else { + err.name = notSatisfied; + } + } + } + + cb(error); + }); +}; + +},{}],10:[function(require,module,exports){ var util = require('util'); var hark = require('hark'); var webrtc = require('webrtcsupport'); @@ -5673,7 +5757,6 @@ function LocalMedia(opts) { var config = this.config = { autoAdjustMic: false, detectSpeakingEvents: true, - audioFallback: false, media: { audio: true, video: true @@ -5708,7 +5791,6 @@ LocalMedia.prototype.start = function (mediaConstraints, cb) { var constraints = mediaConstraints || this.config.media; getUserMedia(constraints, function (err, stream) { - if (!err) { if (constraints.audio && self.config.detectSpeakingEvents) { self.setupAudioMonitor(stream, self.config.harkOptions); @@ -5734,13 +5816,6 @@ LocalMedia.prototype.start = function (mediaConstraints, cb) { }; self.emit('localStream', stream); - } else { - // Fallback for users without a camera - if (self.config.audioFallback && err.name === 'DevicesNotFoundError' && constraints.video !== false) { - constraints.video = false; - self.start(constraints, cb); - return; - } } if (cb) { return cb(err, stream); @@ -5752,35 +5827,23 @@ LocalMedia.prototype.stop = function (stream) { var self = this; // FIXME: duplicates cleanup code until fixed in FF if (stream) { - stream.getTracks().forEach(function (track) { track.stop(); }); + stream.stop(); + self.emit('localStreamStopped', stream); var idx = self.localStreams.indexOf(stream); if (idx > -1) { - self.emit('localStreamStopped', stream); self.localStreams = self.localStreams.splice(idx, 1); - } else { - idx = self.localScreens.indexOf(stream); - if (idx > -1) { - self.emit('localScreenStopped', stream); - self.localScreens = self.localScreens.splce(idx, 1); - } } } else { - this.stopStreams(); - this.stopScreenShare(); - } -}; - -LocalMedia.prototype.stopStreams = function () { - var self = this; - if (this.audioMonitor) { - this.audioMonitor.stop(); - delete this.audioMonitor; + if (this.audioMonitor) { + this.audioMonitor.stop(); + delete this.audioMonitor; + } + this.localStreams.forEach(function (stream) { + stream.stop(); + self.emit('localStreamStopped', stream); + }); + this.localStreams = []; } - this.localStreams.forEach(function (stream) { - stream.getTracks().forEach(function (track) { track.stop(); }); - self.emit('localStreamStopped', stream); - }); - this.localStreams = []; }; LocalMedia.prototype.startScreenShare = function (cb) { @@ -5810,14 +5873,11 @@ LocalMedia.prototype.startScreenShare = function (cb) { }; LocalMedia.prototype.stopScreenShare = function (stream) { - var self = this; if (stream) { - stream.getTracks().forEach(function (track) { track.stop(); }); - this.emit('localScreenStopped', stream); + stream.stop(); } else { this.localScreens.forEach(function (stream) { - stream.getTracks().forEach(function (track) { track.stop(); }); - self.emit('localScreenStopped', stream); + stream.stop(); }); this.localScreens = []; } @@ -5958,667 +6018,42 @@ Object.defineProperty(LocalMedia.prototype, 'localScreen', { module.exports = LocalMedia; -},{"getscreenmedia":17,"getusermedia":16,"hark":18,"mediastream-gain":19,"mockconsole":6,"util":8,"webrtcsupport":5,"wildemitter":4}],20:[function(require,module,exports){ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - -/* More information about these options at jshint.com/docs/options */ -/* jshint browser: true, camelcase: true, curly: true, devel: true, - eqeqeq: true, forin: false, globalstrict: true, node: true, - quotmark: single, undef: true, unused: strict */ -/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise, -mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */ -/* exported trace,requestUserMedia */ - -'use strict'; - -var getUserMedia = null; -var attachMediaStream = null; -var reattachMediaStream = null; -var webrtcDetectedBrowser = null; -var webrtcDetectedVersion = null; -var webrtcMinimumVersion = null; -var webrtcUtils = { - log: function() { - // suppress console.log output when being included as a module. - if (typeof module !== 'undefined' || - typeof require === 'function' && typeof define === 'function') { - return; - } - console.log.apply(console, arguments); - } -}; +},{"getscreenmedia":18,"getusermedia":16,"hark":17,"mediastream-gain":19,"mockconsole":6,"util":8,"webrtcsupport":5,"wildemitter":4}],14:[function(require,module,exports){ +var util = require('util'); +var each = require('lodash.foreach'); +var pluck = require('lodash.pluck'); +var webrtc = require('webrtcsupport'); +var SJJ = require('sdp-jingle-json'); +var WildEmitter = require('wildemitter'); +var peerconn = require('traceablepeerconnection'); -function trace(text) { - // This function is used for logging. - if (text[text.length - 1] === '\n') { - text = text.substring(0, text.length - 1); - } - if (window.performance) { - var now = (window.performance.now() / 1000).toFixed(3); - webrtcUtils.log(now + ': ' + text); - } else { - webrtcUtils.log(text); - } -} -if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - // If prefixed srcObject property exists, return it. - // Otherwise use the shimmed property, _srcObject - return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject; - }, - set: function(stream) { - if ('mozSrcObject' in this) { - this.mozSrcObject = stream; - } else { - // Use _srcObject as a private property for this shim - this._srcObject = stream; - // TODO: revokeObjectUrl(this.src) when !stream to release resources? - this.src = URL.createObjectURL(stream); - } - } - }); - } - // Proxy existing globals - getUserMedia = window.navigator && window.navigator.getUserMedia; -} - -// Attach a media stream to an element. -attachMediaStream = function(element, stream) { - element.srcObject = stream; -}; - -reattachMediaStream = function(to, from) { - to.srcObject = from.srcObject; -}; - -if (typeof window === 'undefined' || !window.navigator) { - webrtcUtils.log('This does not appear to be a browser'); - webrtcDetectedBrowser = 'not a browser'; -} else if (navigator.mozGetUserMedia && window.mozRTCPeerConnection) { - webrtcUtils.log('This appears to be Firefox'); - - webrtcDetectedBrowser = 'firefox'; - - // the detected firefox version. - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); - - // the minimum firefox version still supported by adapter. - webrtcMinimumVersion = 31; - - // The RTCPeerConnection object. - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (webrtcDetectedVersion < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new mozRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors - }; +function PeerConnection(config, constraints) { + var self = this; + var item; + WildEmitter.call(this); - // The RTCSessionDescription object. - window.RTCSessionDescription = mozRTCSessionDescription; + config = config || {}; + config.iceServers = config.iceServers || []; - // The RTCIceCandidate object. - window.RTCIceCandidate = mozRTCIceCandidate; - - // getUserMedia constraints shim. - getUserMedia = function(constraints, onSuccess, onError) { - var constraintsToFF37 = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r.min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - if (webrtcDetectedVersion < 38) { - webrtcUtils.log('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37(constraints.video); - } - webrtcUtils.log('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, onError); - }; - - navigator.getUserMedia = getUserMedia; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: requestUserMedia, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (webrtcDetectedVersion < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().catch(function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } -} else if (navigator.webkitGetUserMedia && !!window.chrome) { - webrtcUtils.log('This appears to be Chrome'); - - webrtcDetectedBrowser = 'chrome'; - - // the detected chrome version. - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); - - // the minimum chrome version still supported by adapter. - webrtcMinimumVersion = 38; - - // The RTCPeerConnection object. - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors - var origGetStats = pc.getStats.bind(pc); - pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line - var self = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats(selector, successCallback); - } - - var fixChromeStats = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - if (arguments.length >= 2) { - var successCallbackWrapper = function(response) { - args[1](fixChromeStats(response)); - }; - - return origGetStats.apply(this, [successCallbackWrapper, arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - if (args.length === 1 && selector === null) { - origGetStats.apply(self, [ - function(response) { - resolve.apply(null, [fixChromeStats(response)]); - }, reject]); - } else { - origGetStats.apply(self, [resolve, reject]); - } - }); - }; - - return pc; - }; - - // add promise support - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - var self = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof(arguments[0]) === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(self, [resolve, reject, opts]); - }); - } else { - return nativeMethod.apply(this, arguments); - } - }; - }); - - ['setLocalDescription', 'setRemoteDescription', - 'addIceCandidate'].forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - var args = arguments; - var self = this; - return new Promise(function(resolve, reject) { - nativeMethod.apply(self, [args[0], - function() { - resolve(); - if (args.length >= 2) { - args[1].apply(null, []); - } - }, - function(err) { - reject(err); - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }] - ); - }); - }; - }); - - // getUserMedia constraints shim. - var constraintsToChrome = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - getUserMedia = function(constraints, onSuccess, onError) { - if (constraints.audio) { - constraints.audio = constraintsToChrome(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToChrome(constraints.video); - } - webrtcUtils.log('chrome: ' + JSON.stringify(constraints)); - return navigator.webkitGetUserMedia(constraints, onSuccess, onError); - }; - navigator.getUserMedia = getUserMedia; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: requestUserMedia, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }}; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return requestUserMedia(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - webrtcUtils.log('spec: ' + JSON.stringify(c)); // whitespace for alignment - c.audio = constraintsToChrome(c.audio); - c.video = constraintsToChrome(c.video); - webrtcUtils.log('chrome: ' + JSON.stringify(c)); - return origGetUserMedia(c); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - webrtcUtils.log('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - webrtcUtils.log('Dummy mediaDevices.removeEventListener called.'); - }; - } - - // Attach a media stream to an element. - attachMediaStream = function(element, stream) { - if (webrtcDetectedVersion >= 43) { - element.srcObject = stream; - } else if (typeof element.src !== 'undefined') { - element.src = URL.createObjectURL(stream); - } else { - webrtcUtils.log('Error attaching stream to element.'); - } - }; - reattachMediaStream = function(to, from) { - if (webrtcDetectedVersion >= 43) { - to.srcObject = from.srcObject; - } else { - to.src = from.src; - } - }; - -} else if (navigator.mediaDevices && navigator.userAgent.match( - /Edge\/(\d+).(\d+)$/)) { - webrtcUtils.log('This appears to be Edge'); - webrtcDetectedBrowser = 'edge'; - - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10); - - // the minimum version still supported by adapter. - webrtcMinimumVersion = 12; -} else { - webrtcUtils.log('Browser does not appear to be WebRTC-capable'); -} - -// Returns the result of getUserMedia as a Promise. -function requestUserMedia(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia(constraints, resolve, reject); - }); -} - -var webrtcTesting = {}; -Object.defineProperty(webrtcTesting, 'version', { - set: function(version) { - webrtcDetectedVersion = version; - } -}); - -if (typeof module !== 'undefined') { - var RTCPeerConnection; - if (typeof window !== 'undefined') { - RTCPeerConnection = window.RTCPeerConnection; - } - module.exports = { - RTCPeerConnection: RTCPeerConnection, - getUserMedia: getUserMedia, - attachMediaStream: attachMediaStream, - reattachMediaStream: reattachMediaStream, - webrtcDetectedBrowser: webrtcDetectedBrowser, - webrtcDetectedVersion: webrtcDetectedVersion, - webrtcMinimumVersion: webrtcMinimumVersion, - webrtcTesting: webrtcTesting - //requestUserMedia: not exposed on purpose. - //trace: not exposed on purpose. - }; -} else if ((typeof require === 'function') && (typeof define === 'function')) { - // Expose objects and functions when RequireJS is doing the loading. - define([], function() { - return { - RTCPeerConnection: window.RTCPeerConnection, - getUserMedia: getUserMedia, - attachMediaStream: attachMediaStream, - reattachMediaStream: reattachMediaStream, - webrtcDetectedBrowser: webrtcDetectedBrowser, - webrtcDetectedVersion: webrtcDetectedVersion, - webrtcMinimumVersion: webrtcMinimumVersion, - webrtcTesting: webrtcTesting - //requestUserMedia: not exposed on purpose. - //trace: not exposed on purpose. - }; - }); -} - -},{}],15:[function(require,module,exports){ -var WildEmitter = require('wildemitter'); -var util = require('util'); - -function Sender(opts) { - WildEmitter.call(this); - var options = opts || {}; - this.config = { - chunksize: 16384, - pacing: 0 - }; - // set our config from options - var item; - for (item in options) { - this.config[item] = options[item]; - } - - this.file = null; - this.channel = null; -} -util.inherits(Sender, WildEmitter); - -Sender.prototype.send = function (file, channel) { - var self = this; - this.file = file; - this.channel = channel; - var sliceFile = function(offset) { - var reader = new window.FileReader(); - reader.onload = (function() { - return function(e) { - self.channel.send(e.target.result); - self.emit('progress', offset, file.size, e.target.result); - if (file.size > offset + e.target.result.byteLength) { - window.setTimeout(sliceFile, self.config.pacing, offset + self.config.chunksize); - } else { - self.emit('progress', file.size, file.size, null); - self.emit('sentFile'); - } - }; - })(file); - var slice = file.slice(offset, offset + self.config.chunksize); - reader.readAsArrayBuffer(slice); - }; - window.setTimeout(sliceFile, 0, 0); -}; - -function Receiver() { - WildEmitter.call(this); - - this.receiveBuffer = []; - this.received = 0; - this.metadata = {}; - this.channel = null; -} -util.inherits(Receiver, WildEmitter); - -Receiver.prototype.receive = function (metadata, channel) { - var self = this; - - if (metadata) { - this.metadata = metadata; - } - this.channel = channel; - // chrome only supports arraybuffers and those make it easier to calc the hash - channel.binaryType = 'arraybuffer'; - this.channel.onmessage = function (event) { - var len = event.data.byteLength; - self.received += len; - self.receiveBuffer.push(event.data); - - self.emit('progress', self.received, self.metadata.size, event.data); - if (self.received === self.metadata.size) { - self.emit('receivedFile', new window.Blob(self.receiveBuffer), self.metadata); - self.receiveBuffer = []; // discard receivebuffer - } else if (self.received > self.metadata.size) { - // FIXME - console.error('received more than expected, discarding...'); - self.receiveBuffer = []; // just discard... - - } - }; -}; - -module.exports = {}; -module.exports.support = typeof window !== 'undefined' && window && window.File && window.FileReader && window.Blob; -module.exports.Sender = Sender; -module.exports.Receiver = Receiver; - -},{"util":8,"wildemitter":4}],14:[function(require,module,exports){ -var util = require('util'); -var each = require('lodash.foreach'); -var pluck = require('lodash.pluck'); -var SJJ = require('sdp-jingle-json'); -var WildEmitter = require('wildemitter'); -var peerconn = require('traceablepeerconnection'); -var adapter = require('webrtc-adapter-test'); - -function PeerConnection(config, constraints) { - var self = this; - var item; - WildEmitter.call(this); - - config = config || {}; - config.iceServers = config.iceServers || []; - - // make sure this only gets enabled in Google Chrome - // EXPERIMENTAL FLAG, might get removed without notice - this.enableChromeNativeSimulcast = false; - if (constraints && constraints.optional && - adapter.webrtcDetectedBrowser === 'chrome' && - navigator.appVersion.match(/Chromium\//) === null) { - constraints.optional.forEach(function (constraint) { - if (constraint.enableChromeNativeSimulcast) { - self.enableChromeNativeSimulcast = true; - } - }); - } + // make sure this only gets enabled in Google Chrome + // EXPERIMENTAL FLAG, might get removed without notice + this.enableChromeNativeSimulcast = false; + if (constraints && constraints.optional && + webrtc.prefix === 'webkit' && + navigator.appVersion.match(/Chromium\//) === null) { + constraints.optional.forEach(function (constraint, idx) { + if (constraint.enableChromeNativeSimulcast) { + self.enableChromeNativeSimulcast = true; + } + }); + } // EXPERIMENTAL FLAG, might get removed without notice this.enableMultiStreamHacks = false; if (constraints && constraints.optional && - adapter.webrtcDetectedBrowser === 'chrome') { - constraints.optional.forEach(function (constraint) { + webrtc.prefix === 'webkit') { + constraints.optional.forEach(function (constraint, idx) { if (constraint.enableMultiStreamHacks) { self.enableMultiStreamHacks = true; } @@ -6627,7 +6062,7 @@ function PeerConnection(config, constraints) { // EXPERIMENTAL FLAG, might get removed without notice this.restrictBandwidth = 0; if (constraints && constraints.optional) { - constraints.optional.forEach(function (constraint) { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetRestrictBandwidth) { self.restrictBandwidth = constraint.andyetRestrictBandwidth; } @@ -6640,7 +6075,7 @@ function PeerConnection(config, constraints) { // ~20ms seems good this.batchIceCandidates = 0; if (constraints && constraints.optional) { - constraints.optional.forEach(function (constraint) { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetBatchIce) { self.batchIceCandidates = constraint.andyetBatchIce; } @@ -6652,8 +6087,8 @@ function PeerConnection(config, constraints) { // this attemps to strip out candidates with an already known foundation // and type -- i.e. those which are gathered via the same TURN server // but different transports (TURN udp, tcp and tls respectively) - if (constraints && constraints.optional && adapter.webrtcDetectedBrowser === 'chrome') { - constraints.optional.forEach(function (constraint) { + if (constraints && constraints.optional && webrtc.prefix === 'webkit') { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetFasterICE) { self.eliminateDuplicateCandidates = constraint.andyetFasterICE; } @@ -6663,7 +6098,7 @@ function PeerConnection(config, constraints) { // when using a server such as the jitsi videobridge we don't need to signal // our candidates if (constraints && constraints.optional) { - constraints.optional.forEach(function (constraint) { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetDontSignalCandidates) { self.dontSignalCandidates = constraint.andyetDontSignalCandidates; } @@ -6674,7 +6109,7 @@ function PeerConnection(config, constraints) { // EXPERIMENTAL FLAG, might get removed without notice this.assumeSetLocalSuccess = false; if (constraints && constraints.optional) { - constraints.optional.forEach(function (constraint) { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetAssumeSetLocalSuccess) { self.assumeSetLocalSuccess = constraint.andyetAssumeSetLocalSuccess; } @@ -6684,10 +6119,10 @@ function PeerConnection(config, constraints) { // EXPERIMENTAL FLAG, might get removed without notice // working around https://bugzilla.mozilla.org/show_bug.cgi?id=1087551 // pass in a timeout for this - if (adapter.webrtcDetectedBrowser === 'firefox') { + if (webrtc.prefix === 'moz') { if (constraints && constraints.optional) { this.wtFirefox = 0; - constraints.optional.forEach(function (constraint) { + constraints.optional.forEach(function (constraint, idx) { if (constraint.andyetFirefoxMakesMeSad) { self.wtFirefox = constraint.andyetFirefoxMakesMeSad; if (self.wtFirefox > 0) { @@ -6744,7 +6179,7 @@ function PeerConnection(config, constraints) { } if (this.config.debug) { - this.on('*', function () { + this.on('*', function (eventName, event) { var logger = config.logger || console; logger.log('PeerConnection event:', arguments); }); @@ -6844,7 +6279,7 @@ PeerConnection.prototype.processIce = function (update, cb) { function (candidate) { var iceCandidate = SJJ.toCandidateSDP(candidate) + '\r\n'; self.pc.addIceCandidate( - new RTCIceCandidate({ + new webrtc.IceCandidate({ candidate: iceCandidate, sdpMLineIndex: mline, sdpMid: mid @@ -6873,7 +6308,7 @@ PeerConnection.prototype.processIce = function (update, cb) { } self.pc.addIceCandidate( - new RTCIceCandidate(update.candidate), + new webrtc.IceCandidate(update.candidate), function () { }, function (err) { self.emit('error', err); @@ -7027,7 +6462,7 @@ PeerConnection.prototype.handleOffer = function (offer, cb) { self._checkRemoteCandidate(line); } }); - self.pc.setRemoteDescription(new RTCSessionDescription(offer), + self.pc.setRemoteDescription(new webrtc.SessionDescription(offer), function () { cb(); }, @@ -7059,6 +6494,7 @@ PeerConnection.prototype.answerBroadcastOnly = function (cb) { // Answer an offer with given constraints default is audio/video PeerConnection.prototype.answer = function (constraints, cb) { + var self = this; var hasConstraints = arguments.length === 2; var callback = hasConstraints ? cb : constraints; var mediaConstraints = hasConstraints && constraints ? constraints : { @@ -7089,14 +6525,14 @@ PeerConnection.prototype.handleAnswer = function (answer, cb) { } }); self.pc.setRemoteDescription( - new RTCSessionDescription(answer), + new webrtc.SessionDescription(answer), function () { if (self.wtFirefox) { window.setTimeout(function () { self.firefoxcandidatebuffer.forEach(function (candidate) { // add candidates later self.pc.addIceCandidate( - new RTCIceCandidate(candidate), + new webrtc.IceCandidate(candidate), function () { }, function (err) { self.emit('error', err); @@ -7137,6 +6573,7 @@ PeerConnection.prototype._answer = function (constraints, cb) { self.pc.createAnswer( function (answer) { var sim = []; + var rtx = []; if (self.enableChromeNativeSimulcast) { // native simulcast part 1: add another SSRC answer.jingle = SJJ.toSessionJSON(answer.sdp, { @@ -7144,6 +6581,7 @@ PeerConnection.prototype._answer = function (constraints, cb) { direction: 'outgoing' }); if (answer.jingle.contents.length >= 2 && answer.jingle.contents[1].name === 'video') { + var hasSimgroup = false; var groups = answer.jingle.contents[1].description.sourceGroups || []; var hasSim = false; groups.forEach(function (group) { @@ -7211,6 +6649,7 @@ PeerConnection.prototype._answer = function (constraints, cb) { direction: 'outgoing' }); } + var groups = expandedAnswer.jingle.contents[1].description.sourceGroups || []; expandedAnswer.jingle.contents[1].description.sources.forEach(function (source, idx) { // the floor idx/2 is a hack that relies on a particular order // of groups, alternating between sim and rtx @@ -7401,9 +6840,8 @@ PeerConnection.prototype.createDataChannel = function (name, opts) { }; // a wrapper around getStats which hides the differences (where possible) -// TODO: remove in favor of adapter.js shim PeerConnection.prototype.getStats = function (cb) { - if (adapter.webrtcDetectedBrowser === 'firefox') { + if (webrtc.prefix === 'moz') { this.pc.getStats( function (res) { var items = []; @@ -7436,88 +6874,95 @@ PeerConnection.prototype.getStats = function (cb) { module.exports = PeerConnection; -},{"lodash.foreach":23,"lodash.pluck":24,"sdp-jingle-json":21,"traceablepeerconnection":22,"util":8,"webrtc-adapter-test":20,"wildemitter":4}],16:[function(require,module,exports){ -// getUserMedia helper by @HenrikJoreteg -var adapter = require('webrtc-adapter-test'); +},{"lodash.foreach":22,"lodash.pluck":23,"sdp-jingle-json":20,"traceablepeerconnection":21,"util":8,"webrtcsupport":5,"wildemitter":4}],15:[function(require,module,exports){ +var WildEmitter = require('wildemitter'); +var util = require('util'); -module.exports = function (constraints, cb) { - var options, error; - var haveOpts = arguments.length === 2; - var defaultOpts = {video: true, audio: true}; +function Sender(opts) { + WildEmitter.call(this); + var options = opts || {}; + this.config = { + chunksize: 16384, + pacing: 0 + }; + // set our config from options + var item; + for (item in options) { + this.config[item] = options[item]; + } - var denied = 'PermissionDeniedError'; - var altDenied = 'PERMISSION_DENIED'; - var notSatisfied = 'ConstraintNotSatisfiedError'; + this.file = null; + this.channel = null; +} +util.inherits(Sender, WildEmitter); - // make constraints optional - if (!haveOpts) { - cb = constraints; - constraints = defaultOpts; - } +Sender.prototype.send = function (file, channel) { + var self = this; + this.file = file; + this.channel = channel; + var sliceFile = function(offset) { + var reader = new window.FileReader(); + reader.onload = (function() { + return function(e) { + self.channel.send(e.target.result); + self.emit('progress', offset, file.size, e.target.result); + if (file.size > offset + e.target.result.byteLength) { + window.setTimeout(sliceFile, self.config.pacing, offset + self.config.chunksize); + } else { + self.emit('progress', file.size, file.size, null); + self.emit('sentFile'); + } + }; + })(file); + var slice = file.slice(offset, offset + self.config.chunksize); + reader.readAsArrayBuffer(slice); + }; + window.setTimeout(sliceFile, 0, 0); +}; - // treat lack of browser support like an error - if (!navigator.getUserMedia) { - // throw proper error per spec - error = new Error('MediaStreamError'); - error.name = 'NotSupportedError'; +function Receiver() { + WildEmitter.call(this); - // keep all callbacks async - return window.setTimeout(function () { - cb(error); - }, 0); - } + this.receiveBuffer = []; + this.received = 0; + this.metadata = {}; + this.channel = null; +} +util.inherits(Receiver, WildEmitter); - // normalize error handling when no media types are requested - if (!constraints.audio && !constraints.video) { - error = new Error('MediaStreamError'); - error.name = 'NoMediaRequestedError'; +Receiver.prototype.receive = function (metadata, channel) { + var self = this; - // keep all callbacks async - return window.setTimeout(function () { - cb(error); - }, 0); + if (metadata) { + this.metadata = metadata; } + this.channel = channel; + // chrome only supports arraybuffers and those make it easier to calc the hash + channel.binaryType = 'arraybuffer'; + this.channel.onmessage = function (event) { + var len = event.data.byteLength; + self.received += len; + self.receiveBuffer.push(event.data); - // testing support - if (localStorage && localStorage.useFirefoxFakeDevice === "true") { - constraints.fake = true; - } + self.emit('progress', self.received, self.metadata.size, event.data); + if (self.received === self.metadata.size) { + self.emit('receivedFile', new window.Blob(self.receiveBuffer), self.metadata); + self.receiveBuffer = []; // discard receivebuffer + } else if (self.received > self.metadata.size) { + // FIXME + console.error('received more than expected, discarding...'); + self.receiveBuffer = []; // just discard... - navigator.getUserMedia(constraints, function (stream) { - cb(null, stream); - }, function (err) { - var error; - // coerce into an error object since FF gives us a string - // there are only two valid names according to the spec - // we coerce all non-denied to "constraint not satisfied". - if (typeof err === 'string') { - error = new Error('MediaStreamError'); - if (err === denied || err === altDenied) { - error.name = denied; - } else { - error.name = notSatisfied; - } - } else { - // if we get an error object make sure '.name' property is set - // according to spec: http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermediaerror-and-navigatorusermediaerrorcallback - error = err; - if (!error.name) { - // this is likely chrome which - // sets a property called "ERROR_DENIED" on the error object - // if so we make sure to set a name - if (error[denied]) { - err.name = denied; - } else { - err.name = notSatisfied; - } - } } - - cb(error); - }); + }; }; -},{"webrtc-adapter-test":25}],18:[function(require,module,exports){ +module.exports = {}; +module.exports.support = window && window.File && window.FileReader && window.Blob; +module.exports.Sender = Sender; +module.exports.Receiver = Receiver; + +},{"util":8,"wildemitter":4}],17:[function(require,module,exports){ var WildEmitter = require('wildemitter'); function getMaxVolume (analyser, fftBins) { @@ -7647,545 +7092,129 @@ module.exports = function(stream, options) { return harker; } -},{"wildemitter":26}],25:[function(require,module,exports){ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - -/* More information about these options at jshint.com/docs/options */ -/* jshint browser: true, camelcase: true, curly: true, devel: true, - eqeqeq: true, forin: false, globalstrict: true, node: true, - quotmark: single, undef: true, unused: strict */ -/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise, -mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */ -/* exported trace,requestUserMedia */ - -'use strict'; - -var getUserMedia = null; -var attachMediaStream = null; -var reattachMediaStream = null; -var webrtcDetectedBrowser = null; -var webrtcDetectedVersion = null; -var webrtcMinimumVersion = null; -var webrtcUtils = { - log: function() { - // suppress console.log output when being included as a module. - if (typeof module !== 'undefined' || - typeof require === 'function' && typeof define === 'function') { - return; - } - console.log.apply(console, arguments); - } -}; - -function trace(text) { - // This function is used for logging. - if (text[text.length - 1] === '\n') { - text = text.substring(0, text.length - 1); - } - if (window.performance) { - var now = (window.performance.now() / 1000).toFixed(3); - webrtcUtils.log(now + ': ' + text); - } else { - webrtcUtils.log(text); - } -} - -if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - // If prefixed srcObject property exists, return it. - // Otherwise use the shimmed property, _srcObject - return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject; - }, - set: function(stream) { - if ('mozSrcObject' in this) { - this.mozSrcObject = stream; - } else { - // Use _srcObject as a private property for this shim - this._srcObject = stream; - // TODO: revokeObjectUrl(this.src) when !stream to release resources? - this.src = URL.createObjectURL(stream); - } - } - }); - } - // Proxy existing globals - getUserMedia = window.navigator && window.navigator.getUserMedia; -} - -// Attach a media stream to an element. -attachMediaStream = function(element, stream) { - element.srcObject = stream; -}; - -reattachMediaStream = function(to, from) { - to.srcObject = from.srcObject; -}; - -if (typeof window === 'undefined' || !window.navigator) { - webrtcUtils.log('This does not appear to be a browser'); - webrtcDetectedBrowser = 'not a browser'; -} else if (navigator.mozGetUserMedia && window.mozRTCPeerConnection) { - webrtcUtils.log('This appears to be Firefox'); - - webrtcDetectedBrowser = 'firefox'; - - // the detected firefox version. - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); - - // the minimum firefox version still supported by adapter. - webrtcMinimumVersion = 31; - - // The RTCPeerConnection object. - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (webrtcDetectedVersion < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new mozRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors - }; - - // The RTCSessionDescription object. - window.RTCSessionDescription = mozRTCSessionDescription; - - // The RTCIceCandidate object. - window.RTCIceCandidate = mozRTCIceCandidate; +},{"wildemitter":24}],20:[function(require,module,exports){ +var toSDP = require('./lib/tosdp'); +var toJSON = require('./lib/tojson'); - // getUserMedia constraints shim. - getUserMedia = function(constraints, onSuccess, onError) { - var constraintsToFF37 = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r.min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - if (webrtcDetectedVersion < 38) { - webrtcUtils.log('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37(constraints.video); - } - webrtcUtils.log('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, onError); - }; - navigator.getUserMedia = getUserMedia; +// Converstion from JSON to SDP - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: requestUserMedia, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); +exports.toIncomingSDPOffer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'responder', + direction: 'incoming' }); - }; - - if (webrtcDetectedVersion < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().catch(function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } -} else if (navigator.webkitGetUserMedia && !!window.chrome) { - webrtcUtils.log('This appears to be Chrome'); - - webrtcDetectedBrowser = 'chrome'; - - // the detected chrome version. - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); - - // the minimum chrome version still supported by adapter. - webrtcMinimumVersion = 38; - - // The RTCPeerConnection object. - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors - var origGetStats = pc.getStats.bind(pc); - pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line - var self = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats(selector, successCallback); - } - - var fixChromeStats = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - if (arguments.length >= 2) { - var successCallbackWrapper = function(response) { - args[1](fixChromeStats(response)); - }; - - return origGetStats.apply(this, [successCallbackWrapper, arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - if (args.length === 1 && selector === null) { - origGetStats.apply(self, [ - function(response) { - resolve.apply(null, [fixChromeStats(response)]); - }, reject]); - } else { - origGetStats.apply(self, [resolve, reject]); - } - }); - }; +}; +exports.toOutgoingSDPOffer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'initiator', + direction: 'outgoing' + }); +}; +exports.toIncomingSDPAnswer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'initiator', + direction: 'incoming' + }); +}; +exports.toOutgoingSDPAnswer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'responder', + direction: 'outgoing' + }); +}; +exports.toIncomingMediaSDPOffer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'responder', + direction: 'incoming' + }); +}; +exports.toOutgoingMediaSDPOffer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'initiator', + direction: 'outgoing' + }); +}; +exports.toIncomingMediaSDPAnswer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'initiator', + direction: 'incoming' + }); +}; +exports.toOutgoingMediaSDPAnswer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'responder', + direction: 'outgoing' + }); +}; +exports.toCandidateSDP = toSDP.toCandidateSDP; +exports.toMediaSDP = toSDP.toMediaSDP; +exports.toSessionSDP = toSDP.toSessionSDP; - return pc; - }; - // add promise support - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - var self = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof(arguments[0]) === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(self, [resolve, reject, opts]); - }); - } else { - return nativeMethod.apply(this, arguments); - } - }; - }); +// Conversion from SDP to JSON - ['setLocalDescription', 'setRemoteDescription', - 'addIceCandidate'].forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - var args = arguments; - var self = this; - return new Promise(function(resolve, reject) { - nativeMethod.apply(self, [args[0], - function() { - resolve(); - if (args.length >= 2) { - args[1].apply(null, []); - } - }, - function(err) { - reject(err); - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }] - ); - }); - }; - }); - - // getUserMedia constraints shim. - var constraintsToChrome = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname(mix, key)] = r[mix]; - } - }); - } +exports.toIncomingJSONOffer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'responder', + direction: 'incoming', + creators: creators }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - getUserMedia = function(constraints, onSuccess, onError) { - if (constraints.audio) { - constraints.audio = constraintsToChrome(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToChrome(constraints.video); - } - webrtcUtils.log('chrome: ' + JSON.stringify(constraints)); - return navigator.webkitGetUserMedia(constraints, onSuccess, onError); - }; - navigator.getUserMedia = getUserMedia; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: requestUserMedia, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }}; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return requestUserMedia(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - webrtcUtils.log('spec: ' + JSON.stringify(c)); // whitespace for alignment - c.audio = constraintsToChrome(c.audio); - c.video = constraintsToChrome(c.video); - webrtcUtils.log('chrome: ' + JSON.stringify(c)); - return origGetUserMedia(c); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - webrtcUtils.log('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - webrtcUtils.log('Dummy mediaDevices.removeEventListener called.'); - }; - } - - // Attach a media stream to an element. - attachMediaStream = function(element, stream) { - if (webrtcDetectedVersion >= 43) { - element.srcObject = stream; - } else if (typeof element.src !== 'undefined') { - element.src = URL.createObjectURL(stream); - } else { - webrtcUtils.log('Error attaching stream to element.'); - } - }; - reattachMediaStream = function(to, from) { - if (webrtcDetectedVersion >= 43) { - to.srcObject = from.srcObject; - } else { - to.src = from.src; - } - }; - -} else if (navigator.mediaDevices && navigator.userAgent.match( - /Edge\/(\d+).(\d+)$/)) { - webrtcUtils.log('This appears to be Edge'); - webrtcDetectedBrowser = 'edge'; - - webrtcDetectedVersion = - parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10); - - // the minimum version still supported by adapter. - webrtcMinimumVersion = 12; -} else { - webrtcUtils.log('Browser does not appear to be WebRTC-capable'); -} - -// Returns the result of getUserMedia as a Promise. -function requestUserMedia(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia(constraints, resolve, reject); - }); -} - -var webrtcTesting = {}; -Object.defineProperty(webrtcTesting, 'version', { - set: function(version) { - webrtcDetectedVersion = version; - } -}); - -if (typeof module !== 'undefined') { - var RTCPeerConnection; - if (typeof window !== 'undefined') { - RTCPeerConnection = window.RTCPeerConnection; - } - module.exports = { - RTCPeerConnection: RTCPeerConnection, - getUserMedia: getUserMedia, - attachMediaStream: attachMediaStream, - reattachMediaStream: reattachMediaStream, - webrtcDetectedBrowser: webrtcDetectedBrowser, - webrtcDetectedVersion: webrtcDetectedVersion, - webrtcMinimumVersion: webrtcMinimumVersion, - webrtcTesting: webrtcTesting - //requestUserMedia: not exposed on purpose. - //trace: not exposed on purpose. - }; -} else if ((typeof require === 'function') && (typeof define === 'function')) { - // Expose objects and functions when RequireJS is doing the loading. - define([], function() { - return { - RTCPeerConnection: window.RTCPeerConnection, - getUserMedia: getUserMedia, - attachMediaStream: attachMediaStream, - reattachMediaStream: reattachMediaStream, - webrtcDetectedBrowser: webrtcDetectedBrowser, - webrtcDetectedVersion: webrtcDetectedVersion, - webrtcMinimumVersion: webrtcMinimumVersion, - webrtcTesting: webrtcTesting - //requestUserMedia: not exposed on purpose. - //trace: not exposed on purpose. - }; - }); -} +}; +exports.toOutgoingJSONOffer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'initiator', + direction: 'outgoing', + creators: creators + }); +}; +exports.toIncomingJSONAnswer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'initiator', + direction: 'incoming', + creators: creators + }); +}; +exports.toOutgoingJSONAnswer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'responder', + direction: 'outgoing', + creators: creators + }); +}; +exports.toIncomingMediaJSONOffer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'responder', + direction: 'incoming', + creator: creator + }); +}; +exports.toOutgoingMediaJSONOffer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'initiator', + direction: 'outgoing', + creator: creator + }); +}; +exports.toIncomingMediaJSONAnswer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'initiator', + direction: 'incoming', + creator: creator + }); +}; +exports.toOutgoingMediaJSONAnswer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'responder', + direction: 'outgoing', + creator: creator + }); +}; +exports.toCandidateJSON = toJSON.toCandidateJSON; +exports.toMediaJSON = toJSON.toMediaJSON; +exports.toSessionJSON = toJSON.toSessionJSON; -},{}],26:[function(require,module,exports){ +},{"./lib/tojson":26,"./lib/tosdp":25}],24:[function(require,module,exports){ /* WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based on @visionmedia's Emitter from UI Kit. @@ -8329,129 +7358,7 @@ WildEmitter.prototype.getWildcardCallbacks = function (eventName) { return result; }; -},{}],21:[function(require,module,exports){ -var toSDP = require('./lib/tosdp'); -var toJSON = require('./lib/tojson'); - - -// Converstion from JSON to SDP - -exports.toIncomingSDPOffer = function (session) { - return toSDP.toSessionSDP(session, { - role: 'responder', - direction: 'incoming' - }); -}; -exports.toOutgoingSDPOffer = function (session) { - return toSDP.toSessionSDP(session, { - role: 'initiator', - direction: 'outgoing' - }); -}; -exports.toIncomingSDPAnswer = function (session) { - return toSDP.toSessionSDP(session, { - role: 'initiator', - direction: 'incoming' - }); -}; -exports.toOutgoingSDPAnswer = function (session) { - return toSDP.toSessionSDP(session, { - role: 'responder', - direction: 'outgoing' - }); -}; -exports.toIncomingMediaSDPOffer = function (media) { - return toSDP.toMediaSDP(media, { - role: 'responder', - direction: 'incoming' - }); -}; -exports.toOutgoingMediaSDPOffer = function (media) { - return toSDP.toMediaSDP(media, { - role: 'initiator', - direction: 'outgoing' - }); -}; -exports.toIncomingMediaSDPAnswer = function (media) { - return toSDP.toMediaSDP(media, { - role: 'initiator', - direction: 'incoming' - }); -}; -exports.toOutgoingMediaSDPAnswer = function (media) { - return toSDP.toMediaSDP(media, { - role: 'responder', - direction: 'outgoing' - }); -}; -exports.toCandidateSDP = toSDP.toCandidateSDP; -exports.toMediaSDP = toSDP.toMediaSDP; -exports.toSessionSDP = toSDP.toSessionSDP; - - -// Conversion from SDP to JSON - -exports.toIncomingJSONOffer = function (sdp, creators) { - return toJSON.toSessionJSON(sdp, { - role: 'responder', - direction: 'incoming', - creators: creators - }); -}; -exports.toOutgoingJSONOffer = function (sdp, creators) { - return toJSON.toSessionJSON(sdp, { - role: 'initiator', - direction: 'outgoing', - creators: creators - }); -}; -exports.toIncomingJSONAnswer = function (sdp, creators) { - return toJSON.toSessionJSON(sdp, { - role: 'initiator', - direction: 'incoming', - creators: creators - }); -}; -exports.toOutgoingJSONAnswer = function (sdp, creators) { - return toJSON.toSessionJSON(sdp, { - role: 'responder', - direction: 'outgoing', - creators: creators - }); -}; -exports.toIncomingMediaJSONOffer = function (sdp, creator) { - return toJSON.toMediaJSON(sdp, { - role: 'responder', - direction: 'incoming', - creator: creator - }); -}; -exports.toOutgoingMediaJSONOffer = function (sdp, creator) { - return toJSON.toMediaJSON(sdp, { - role: 'initiator', - direction: 'outgoing', - creator: creator - }); -}; -exports.toIncomingMediaJSONAnswer = function (sdp, creator) { - return toJSON.toMediaJSON(sdp, { - role: 'initiator', - direction: 'incoming', - creator: creator - }); -}; -exports.toOutgoingMediaJSONAnswer = function (sdp, creator) { - return toJSON.toMediaJSON(sdp, { - role: 'responder', - direction: 'outgoing', - creator: creator - }); -}; -exports.toCandidateJSON = toJSON.toCandidateJSON; -exports.toMediaJSON = toJSON.toMediaJSON; -exports.toSessionJSON = toJSON.toSessionJSON; - -},{"./lib/tojson":28,"./lib/tosdp":27}],17:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ // getScreenMedia helper by @HenrikJoreteg var getUserMedia = require('getusermedia'); @@ -8476,7 +7383,7 @@ module.exports = function (constraints, cb) { // "known" crash in chrome 34 and 35 on linux if (window.navigator.userAgent.match('Linux')) maxver = 35; - // check that the extension is installed by looking for a + // check that the extension is installed by looking for a // sessionStorage variable that contains the extension id // this has to be set after installation unless the contest // script does that @@ -8489,7 +7396,7 @@ module.exports = function (constraints, cb) { error.name = 'PERMISSION_DENIED'; callback(error); } else { - constraints = (hasConstraints && constraints) || {audio: false, video: { + var constraints = constraints || {audio: false, video: { mandatory: { chromeMediaSource: 'desktop', maxWidth: window.screen.width, @@ -8506,30 +7413,6 @@ module.exports = function (constraints, cb) { } } ); - } else if (window.cefGetScreenMedia) { - //window.cefGetScreenMedia is experimental - may be removed without notice - window.cefGetScreenMedia(function(sourceId) { - if (!sourceId) { - var error = new Error('cefGetScreenMediaError'); - error.name = 'CEF_GETSCREENMEDIA_CANCELED'; - callback(error); - } else { - constraints = (hasConstraints && constraints) || {audio: false, video: { - mandatory: { - chromeMediaSource: 'desktop', - maxWidth: window.screen.width, - maxHeight: window.screen.height, - maxFrameRate: 3 - }, - optional: [ - {googLeakyBucket: true}, - {googTemporalLayeredScreencast: true} - ] - }}; - constraints.video.mandatory.chromeMediaSourceId = sourceId; - getUserMedia(constraints, callback); - } - }); } else if (isCef || (chromever >= 26 && chromever <= maxver)) { // chrome 26 - chrome 33 way to do it -- requires bad chrome://flags // note: this is basically in maintenance mode and will go away soon @@ -8623,54 +7506,7 @@ window.addEventListener('message', function (event) { } }); -},{"getusermedia":16}],19:[function(require,module,exports){ -var support = require('webrtcsupport'); - - -function GainController(stream) { - this.support = support.webAudio && support.mediaStream; - - // set our starting value - this.gain = 1; - - if (this.support) { - var context = this.context = new support.AudioContext(); - this.microphone = context.createMediaStreamSource(stream); - this.gainFilter = context.createGain(); - this.destination = context.createMediaStreamDestination(); - this.outputStream = this.destination.stream; - this.microphone.connect(this.gainFilter); - this.gainFilter.connect(this.destination); - stream.addTrack(this.outputStream.getAudioTracks()[0]); - stream.removeTrack(stream.getAudioTracks()[0]); - } - this.stream = stream; -} - -// setting -GainController.prototype.setGain = function (val) { - // check for support - if (!this.support) return; - this.gainFilter.gain.value = val; - this.gain = val; -}; - -GainController.prototype.getGain = function () { - return this.gain; -}; - -GainController.prototype.off = function () { - return this.setGain(0); -}; - -GainController.prototype.on = function () { - this.setGain(1); -}; - - -module.exports = GainController; - -},{"webrtcsupport":5}],23:[function(require,module,exports){ +},{"getusermedia":16}],22:[function(require,module,exports){ /** * lodash 3.0.3 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -8734,7 +7570,54 @@ var forEach = createForEach(arrayEach, baseEach); module.exports = forEach; -},{"lodash._arrayeach":29,"lodash._baseeach":30,"lodash._bindcallback":31,"lodash.isarray":32}],24:[function(require,module,exports){ +},{"lodash._arrayeach":30,"lodash._baseeach":28,"lodash._bindcallback":29,"lodash.isarray":27}],19:[function(require,module,exports){ +var support = require('webrtcsupport'); + + +function GainController(stream) { + this.support = support.webAudio && support.mediaStream; + + // set our starting value + this.gain = 1; + + if (this.support) { + var context = this.context = new support.AudioContext(); + this.microphone = context.createMediaStreamSource(stream); + this.gainFilter = context.createGain(); + this.destination = context.createMediaStreamDestination(); + this.outputStream = this.destination.stream; + this.microphone.connect(this.gainFilter); + this.gainFilter.connect(this.destination); + stream.addTrack(this.outputStream.getAudioTracks()[0]); + stream.removeTrack(stream.getAudioTracks()[0]); + } + this.stream = stream; +} + +// setting +GainController.prototype.setGain = function (val) { + // check for support + if (!this.support) return; + this.gainFilter.gain.value = val; + this.gain = val; +}; + +GainController.prototype.getGain = function () { + return this.gain; +}; + +GainController.prototype.off = function () { + return this.setGain(0); +}; + +GainController.prototype.on = function () { + this.setGain(1); +}; + + +module.exports = GainController; + +},{"webrtcsupport":5}],23:[function(require,module,exports){ /** * lodash 3.1.2 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -8893,456 +7776,359 @@ function property(path) { module.exports = pluck; -},{"lodash._baseget":33,"lodash._topath":34,"lodash.isarray":35,"lodash.map":36}],27:[function(require,module,exports){ -var SENDERS = require('./senders'); - - -exports.toSessionSDP = function (session, opts) { - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; - var sid = opts.sid || session.sid || Date.now(); - var time = opts.time || Date.now(); - - var sdp = [ - 'v=0', - 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0', - 's=-', - 't=0 0', - 'a=msid-semantic: WMS *' - ]; +},{"lodash._baseget":33,"lodash._topath":34,"lodash.isarray":31,"lodash.map":32}],31:[function(require,module,exports){ +/** + * lodash 3.0.3 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ - var groups = session.groups || []; - groups.forEach(function (group) { - sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' ')); - }); +/** `Object#toString` result references. */ +var arrayTag = '[object Array]', + funcTag = '[object Function]'; - var contents = session.contents || []; - contents.forEach(function (content) { - sdp.push(exports.toMediaSDP(content, opts)); - }); +/** + * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). + * In addition to special characters the forward slash is escaped to allow for + * easier `eval` use and `Function` compilation. + */ +var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); - return sdp.join('\r\n') + '\r\n'; -}; +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; -exports.toMediaSDP = function (content, opts) { - var sdp = []; +/** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} - var desc = content.description; - var transport = content.transport; - var payloads = desc.payloads || []; - var fingerprints = (transport && transport.fingerprints) || []; +/** Used for native method references. */ +var objectProto = Object.prototype; - var mline = []; - if (desc.descType == 'datachannel') { - mline.push('application'); - mline.push('1'); - mline.push('DTLS/SCTP'); - if (transport.sctp) { - transport.sctp.forEach(function (map) { - mline.push(map.number); - }); - } - } else { - mline.push(desc.media); - mline.push('1'); - if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) { - mline.push('RTP/SAVPF'); - } else { - mline.push('RTP/AVPF'); - } - payloads.forEach(function (payload) { - mline.push(payload.id); - }); - } +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - sdp.push('m=' + mline.join(' ')); +/** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; - sdp.push('c=IN IP4 0.0.0.0'); - if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) { - sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth); - } - if (desc.descType == 'rtp') { - sdp.push('a=rtcp:1 IN IP4 0.0.0.0'); - } +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + escapeRegExp(fnToString.call(hasOwnProperty)) + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); - if (transport) { - if (transport.ufrag) { - sdp.push('a=ice-ufrag:' + transport.ufrag); - } - if (transport.pwd) { - sdp.push('a=ice-pwd:' + transport.pwd); - } +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsArray = getNative(Array, 'isArray'); - var pushedSetup = false; - fingerprints.forEach(function (fingerprint) { - sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value); - if (fingerprint.setup && !pushedSetup) { - sdp.push('a=setup:' + fingerprint.setup); - } - }); +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; - if (transport.sctp) { - transport.sctp.forEach(function (map) { - sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams); - }); - } - } +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; +} - if (desc.descType == 'rtp') { - sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv')); - } - sdp.push('a=mid:' + content.name); +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} - if (desc.sources && desc.sources.length) { - (desc.sources[0].parameters || []).forEach(function (param) { - if (param.key === 'msid') { - sdp.push('a=msid:' + param.value); - } - }); - } - - if (desc.mux) { - sdp.push('a=rtcp-mux'); - } - - var encryption = desc.encryption || []; - encryption.forEach(function (crypto) { - sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : '')); - }); - if (desc.googConferenceFlag) { - sdp.push('a=x-google-flag:conference'); - } - - payloads.forEach(function (payload) { - var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate; - if (payload.channels && payload.channels != '1') { - rtpmap += '/' + payload.channels; - } - sdp.push(rtpmap); +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ +var isArray = nativeIsArray || function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; +}; - if (payload.parameters && payload.parameters.length) { - var fmtp = ['a=fmtp:' + payload.id]; - var parameters = []; - payload.parameters.forEach(function (param) { - parameters.push((param.key ? param.key + '=' : '') + param.value); - }); - fmtp.push(parameters.join(';')); - sdp.push(fmtp.join(' ')); - } +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); +} - if (payload.feedback) { - payload.feedback.forEach(function (fb) { - if (fb.type === 'trr-int') { - sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0')); - } else { - sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); - } - }); - } - }); +/** + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' + */ +function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; +} - if (desc.feedback) { - desc.feedback.forEach(function (fb) { - if (fb.type === 'trr-int') { - sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0')); - } else { - sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); - } - }); - } +module.exports = isArray; - var hdrExts = desc.headerExtensions || []; - hdrExts.forEach(function (hdr) { - sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri); - }); +},{}],27:[function(require,module,exports){ +/** + * lodash 3.0.3 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ - var ssrcGroups = desc.sourceGroups || []; - ssrcGroups.forEach(function (ssrcGroup) { - sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' ')); - }); +/** `Object#toString` result references. */ +var arrayTag = '[object Array]', + funcTag = '[object Function]'; - var ssrcs = desc.sources || []; - ssrcs.forEach(function (ssrc) { - for (var i = 0; i < ssrc.parameters.length; i++) { - var param = ssrc.parameters[i]; - sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : '')); - } - }); +/** + * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). + * In addition to special characters the forward slash is escaped to allow for + * easier `eval` use and `Function` compilation. + */ +var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); - var candidates = transport.candidates || []; - candidates.forEach(function (candidate) { - sdp.push(exports.toCandidateSDP(candidate)); - }); +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; - return sdp.join('\r\n'); -}; +/** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} -exports.toCandidateSDP = function (candidate) { - var sdp = []; +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); +/** Used for native method references. */ +var objectProto = Object.prototype; - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type === 'srflx' || type === 'prflx' || type === 'relay') { - if (candidate.relAddr && candidate.relPort) { - sdp.push('raddr'); - sdp.push(candidate.relAddr); - sdp.push('rport'); - sdp.push(candidate.relPort); - } - } - if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; - sdp.push('generation'); - sdp.push(candidate.generation || '0'); +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - // FIXME: apparently this is wrong per spec - // but then, we need this when actually putting this into - // SDP so it's going to stay. - // decision needs to be revisited when browsers dont - // accept this any longer - return 'a=candidate:' + sdp.join(' '); -}; +/** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; -},{"./senders":37}],28:[function(require,module,exports){ -var SENDERS = require('./senders'); -var parsers = require('./parsers'); -var idCounter = Math.random(); +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + escapeRegExp(fnToString.call(hasOwnProperty)) + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsArray = getNative(Array, 'isArray'); -exports._setIdCounter = function (counter) { - idCounter = counter; -}; +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; -exports.toSessionJSON = function (sdp, opts) { - var i; - var creators = opts.creators || []; - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; +} +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} - // Divide the SDP into session and media sections. - var media = sdp.split('\r\nm='); - for (i = 1; i < media.length; i++) { - media[i] = 'm=' + media[i]; - if (i !== media.length - 1) { - media[i] += '\r\n'; - } - } - var session = media.shift() + '\r\n'; - var sessionLines = parsers.lines(session); - var parsed = {}; - - var contents = []; - for (i = 0; i < media.length; i++) { - contents.push(exports.toMediaJSON(media[i], session, { - role: role, - direction: direction, - creator: creators[i] || 'initiator' - })); - } - parsed.contents = contents; - - var groupLines = parsers.findLines('a=group:', sessionLines); - if (groupLines.length) { - parsed.groups = parsers.groups(groupLines); - } - - return parsed; +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ +var isArray = nativeIsArray || function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; }; -exports.toMediaJSON = function (media, session, opts) { - var creator = opts.creator || 'initiator'; - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; - - var lines = parsers.lines(media); - var sessionLines = parsers.lines(session); - var mline = parsers.mline(lines[0]); - - var content = { - creator: creator, - name: mline.media, - description: { - descType: 'rtp', - media: mline.media, - payloads: [], - encryption: [], - feedback: [], - headerExtensions: [] - }, - transport: { - transType: 'iceUdp', - candidates: [], - fingerprints: [] - } - }; - if (mline.media == 'application') { - // FIXME: the description is most likely to be independent - // of the SDP and should be processed by other parts of the library - content.description = { - descType: 'datachannel' - }; - content.transport.sctp = []; - } - var desc = content.description; - var trans = content.transport; - - // If we have a mid, use that for the content name instead. - var mid = parsers.findLine('a=mid:', lines); - if (mid) { - content.name = mid.substr(6); - } - - if (parsers.findLine('a=sendrecv', lines, sessionLines)) { - content.senders = 'both'; - } else if (parsers.findLine('a=sendonly', lines, sessionLines)) { - content.senders = SENDERS[role][direction].sendonly; - } else if (parsers.findLine('a=recvonly', lines, sessionLines)) { - content.senders = SENDERS[role][direction].recvonly; - } else if (parsers.findLine('a=inactive', lines, sessionLines)) { - content.senders = 'none'; - } - - if (desc.descType == 'rtp') { - var bandwidth = parsers.findLine('b=', lines); - if (bandwidth) { - desc.bandwidth = parsers.bandwidth(bandwidth); - } - - var ssrc = parsers.findLine('a=ssrc:', lines); - if (ssrc) { - desc.ssrc = ssrc.substr(7).split(' ')[0]; - } - - var rtpmapLines = parsers.findLines('a=rtpmap:', lines); - rtpmapLines.forEach(function (line) { - var payload = parsers.rtpmap(line); - payload.parameters = []; - payload.feedback = []; - - var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines); - // There should only be one fmtp line per payload - fmtpLines.forEach(function (line) { - payload.parameters = parsers.fmtp(line); - }); - - var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines); - fbLines.forEach(function (line) { - payload.feedback.push(parsers.rtcpfb(line)); - }); - - desc.payloads.push(payload); - }); - - var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines); - cryptoLines.forEach(function (line) { - desc.encryption.push(parsers.crypto(line)); - }); - - if (parsers.findLine('a=rtcp-mux', lines)) { - desc.mux = true; - } - - var fbLines = parsers.findLines('a=rtcp-fb:*', lines); - fbLines.forEach(function (line) { - desc.feedback.push(parsers.rtcpfb(line)); - }); - - var extLines = parsers.findLines('a=extmap:', lines); - extLines.forEach(function (line) { - var ext = parsers.extmap(line); - - ext.senders = SENDERS[role][direction][ext.senders]; - - desc.headerExtensions.push(ext); - }); - - var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines); - desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []); - - var ssrcLines = parsers.findLines('a=ssrc:', lines); - var sources = desc.sources = parsers.sources(ssrcLines || []); - - var msidLine = parsers.findLine('a=msid:', lines); - if (msidLine) { - var msid = parsers.msid(msidLine); - ['msid', 'mslabel', 'label'].forEach(function (key) { - for (var i = 0; i < sources.length; i++) { - var found = false; - for (var j = 0; j < sources[i].parameters.length; j++) { - if (sources[i].parameters[j].key === key) { - found = true; - } - } - if (!found) { - sources[i].parameters.push({ key: key, value: msid[key] }); - } - } - }); - } - - if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) { - desc.googConferenceFlag = true; - } - } - - // transport specific attributes - var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines); - var setup = parsers.findLine('a=setup:', lines, sessionLines); - fingerprintLines.forEach(function (line) { - var fp = parsers.fingerprint(line); - if (setup) { - fp.setup = setup.substr(8); - } - trans.fingerprints.push(fp); - }); - - var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines); - var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines); - if (ufragLine && pwdLine) { - trans.ufrag = ufragLine.substr(12); - trans.pwd = pwdLine.substr(10); - trans.candidates = []; - - var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines); - candidateLines.forEach(function (line) { - trans.candidates.push(exports.toCandidateJSON(line)); - }); - } - - if (desc.descType == 'datachannel') { - var sctpmapLines = parsers.findLines('a=sctpmap:', lines); - sctpmapLines.forEach(function (line) { - var sctp = parsers.sctpmap(line); - trans.sctp.push(sctp); - }); - } +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); +} - return content; -}; +/** + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' + */ +function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; +} -exports.toCandidateJSON = function (line) { - var candidate = parsers.candidate(line.split('\r\n')[0]); - candidate.id = (idCounter++).toString(36).substr(0, 12); - return candidate; -}; +module.exports = isArray; -},{"./parsers":38,"./senders":37}],29:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ /** * lodash 3.0.0 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -9375,7 +8161,7 @@ function arrayEach(array, iteratee) { module.exports = arrayEach; -},{}],31:[function(require,module,exports){ +},{}],29:[function(require,module,exports){ /** * lodash 3.0.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -9442,447 +8228,790 @@ function identity(value) { module.exports = bindCallback; -},{}],32:[function(require,module,exports){ -/** - * lodash 3.0.4 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ +},{}],25:[function(require,module,exports){ +var SENDERS = require('./senders'); -/** `Object#toString` result references. */ -var arrayTag = '[object Array]', - funcTag = '[object Function]'; -/** Used to detect host constructors (Safari > 5). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; +exports.toSessionSDP = function (session, opts) { + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + var sid = opts.sid || session.sid || Date.now(); + var time = opts.time || Date.now(); -/** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} - -/** Used for native method references. */ -var objectProto = Object.prototype; + var sdp = [ + 'v=0', + 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0', + 's=-', + 't=0 0' + ]; -/** Used to resolve the decompiled source of functions. */ -var fnToString = Function.prototype.toString; + var groups = session.groups || []; + groups.forEach(function (group) { + sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' ')); + }); -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; + var contents = session.contents || []; + contents.forEach(function (content) { + sdp.push(exports.toMediaSDP(content, opts)); + }); -/** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ -var objToString = objectProto.toString; + return sdp.join('\r\n') + '\r\n'; +}; -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); +exports.toMediaSDP = function (content, opts) { + var sdp = []; -/* Native method references for those with the same name as other `lodash` methods. */ -var nativeIsArray = getNative(Array, 'isArray'); + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; -/** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; + var desc = content.description; + var transport = content.transport; + var payloads = desc.payloads || []; + var fingerprints = (transport && transport.fingerprints) || []; -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; -} + var mline = []; + if (desc.descType == 'datachannel') { + mline.push('application'); + mline.push('1'); + mline.push('DTLS/SCTP'); + if (transport.sctp) { + transport.sctp.forEach(function (map) { + mline.push(map.number); + }); + } + } else { + mline.push(desc.media); + mline.push('1'); + if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) { + mline.push('RTP/SAVPF'); + } else { + mline.push('RTP/AVPF'); + } + payloads.forEach(function (payload) { + mline.push(payload.id); + }); + } -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ -var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; -}; + sdp.push('m=' + mline.join(' ')); -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; -} + sdp.push('c=IN IP4 0.0.0.0'); + if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) { + sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth); + } + if (desc.descType == 'rtp') { + sdp.push('a=rtcp:1 IN IP4 0.0.0.0'); + } -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} + if (transport) { + if (transport.ufrag) { + sdp.push('a=ice-ufrag:' + transport.ufrag); + } + if (transport.pwd) { + sdp.push('a=ice-pwd:' + transport.pwd); + } -/** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ -function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); -} + var pushedSetup = false; + fingerprints.forEach(function (fingerprint) { + sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value); + if (fingerprint.setup && !pushedSetup) { + sdp.push('a=setup:' + fingerprint.setup); + } + }); -module.exports = isArray; + if (transport.sctp) { + transport.sctp.forEach(function (map) { + sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams); + }); + } + } -},{}],33:[function(require,module,exports){ -/** - * lodash 3.7.2 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ + if (desc.descType == 'rtp') { + sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv')); + } + sdp.push('a=mid:' + content.name); -/** - * The base implementation of `get` without support for string paths - * and default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path of the property to get. - * @param {string} [pathKey] The key representation of path. - * @returns {*} Returns the resolved value. - */ -function baseGet(object, path, pathKey) { - if (object == null) { - return; - } - if (pathKey !== undefined && pathKey in toObject(object)) { - path = [pathKey]; - } - var index = 0, - length = path.length; + if (desc.mux) { + sdp.push('a=rtcp-mux'); + } - while (object != null && index < length) { - object = object[path[index++]]; - } - return (index && index == length) ? object : undefined; -} + var encryption = desc.encryption || []; + encryption.forEach(function (crypto) { + sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : '')); + }); + if (desc.googConferenceFlag) { + sdp.push('a=x-google-flag:conference'); + } -/** - * Converts `value` to an object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Object} Returns the object. - */ -function toObject(value) { - return isObject(value) ? value : Object(value); -} + payloads.forEach(function (payload) { + var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate; + if (payload.channels && payload.channels != '1') { + rtpmap += '/' + payload.channels; + } + sdp.push(rtpmap); -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} + if (payload.parameters && payload.parameters.length) { + var fmtp = ['a=fmtp:' + payload.id]; + var parameters = []; + payload.parameters.forEach(function (param) { + parameters.push((param.key ? param.key + '=' : '') + param.value); + }); + fmtp.push(parameters.join(';')); + sdp.push(fmtp.join(' ')); + } -module.exports = baseGet; + if (payload.feedback) { + payload.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0')); + } else { + sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } + }); -},{}],35:[function(require,module,exports){ -/** - * lodash 3.0.4 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ + if (desc.feedback) { + desc.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0')); + } else { + sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } -/** `Object#toString` result references. */ -var arrayTag = '[object Array]', - funcTag = '[object Function]'; + var hdrExts = desc.headerExtensions || []; + hdrExts.forEach(function (hdr) { + sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri); + }); -/** Used to detect host constructors (Safari > 5). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; + var ssrcGroups = desc.sourceGroups || []; + ssrcGroups.forEach(function (ssrcGroup) { + sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' ')); + }); -/** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} + var ssrcs = desc.sources || []; + ssrcs.forEach(function (ssrc) { + for (var i = 0; i < ssrc.parameters.length; i++) { + var param = ssrc.parameters[i]; + sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : '')); + } + }); -/** Used for native method references. */ -var objectProto = Object.prototype; + var candidates = transport.candidates || []; + candidates.forEach(function (candidate) { + sdp.push(exports.toCandidateSDP(candidate)); + }); -/** Used to resolve the decompiled source of functions. */ -var fnToString = Function.prototype.toString; + return sdp.join('\r\n'); +}; -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; +exports.toCandidateSDP = function (candidate) { + var sdp = []; -/** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ -var objToString = objectProto.toString; + sdp.push(candidate.foundation); + sdp.push(candidate.component); + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.ip); + sdp.push(candidate.port); -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); + var type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type === 'srflx' || type === 'prflx' || type === 'relay') { + if (candidate.relAddr && candidate.relPort) { + sdp.push('raddr'); + sdp.push(candidate.relAddr); + sdp.push('rport'); + sdp.push(candidate.relPort); + } + } + if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } -/* Native method references for those with the same name as other `lodash` methods. */ -var nativeIsArray = getNative(Array, 'isArray'); + sdp.push('generation'); + sdp.push(candidate.generation || '0'); -/** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; + // FIXME: apparently this is wrong per spec + // but then, we need this when actually putting this into + // SDP so it's going to stay. + // decision needs to be revisited when browsers dont + // accept this any longer + return 'a=candidate:' + sdp.join(' '); +}; -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; -} +},{"./senders":35}],26:[function(require,module,exports){ +var SENDERS = require('./senders'); +var parsers = require('./parsers'); +var idCounter = Math.random(); -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ -var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; +exports._setIdCounter = function (counter) { + idCounter = counter; }; -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; -} +exports.toSessionJSON = function (sdp, opts) { + var i; + var creators = opts.creators || []; + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} -/** - * Checks if `value` is a native function. + // Divide the SDP into session and media sections. + var media = sdp.split('\r\nm='); + for (i = 1; i < media.length; i++) { + media[i] = 'm=' + media[i]; + if (i !== media.length - 1) { + media[i] += '\r\n'; + } + } + var session = media.shift() + '\r\n'; + var sessionLines = parsers.lines(session); + var parsed = {}; + + var contents = []; + for (i = 0; i < media.length; i++) { + contents.push(exports.toMediaJSON(media[i], session, { + role: role, + direction: direction, + creator: creators[i] || 'initiator' + })); + } + parsed.contents = contents; + + var groupLines = parsers.findLines('a=group:', sessionLines); + if (groupLines.length) { + parsed.groups = parsers.groups(groupLines); + } + + return parsed; +}; + +exports.toMediaJSON = function (media, session, opts) { + var creator = opts.creator || 'initiator'; + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + + var lines = parsers.lines(media); + var sessionLines = parsers.lines(session); + var mline = parsers.mline(lines[0]); + + var content = { + creator: creator, + name: mline.media, + description: { + descType: 'rtp', + media: mline.media, + payloads: [], + encryption: [], + feedback: [], + headerExtensions: [] + }, + transport: { + transType: 'iceUdp', + candidates: [], + fingerprints: [] + } + }; + if (mline.media == 'application') { + // FIXME: the description is most likely to be independent + // of the SDP and should be processed by other parts of the library + content.description = { + descType: 'datachannel' + }; + content.transport.sctp = []; + } + var desc = content.description; + var trans = content.transport; + + // If we have a mid, use that for the content name instead. + var mid = parsers.findLine('a=mid:', lines); + if (mid) { + content.name = mid.substr(6); + } + + if (parsers.findLine('a=sendrecv', lines, sessionLines)) { + content.senders = 'both'; + } else if (parsers.findLine('a=sendonly', lines, sessionLines)) { + content.senders = SENDERS[role][direction].sendonly; + } else if (parsers.findLine('a=recvonly', lines, sessionLines)) { + content.senders = SENDERS[role][direction].recvonly; + } else if (parsers.findLine('a=inactive', lines, sessionLines)) { + content.senders = 'none'; + } + + if (desc.descType == 'rtp') { + var bandwidth = parsers.findLine('b=', lines); + if (bandwidth) { + desc.bandwidth = parsers.bandwidth(bandwidth); + } + + var ssrc = parsers.findLine('a=ssrc:', lines); + if (ssrc) { + desc.ssrc = ssrc.substr(7).split(' ')[0]; + } + + var rtpmapLines = parsers.findLines('a=rtpmap:', lines); + rtpmapLines.forEach(function (line) { + var payload = parsers.rtpmap(line); + payload.parameters = []; + payload.feedback = []; + + var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines); + // There should only be one fmtp line per payload + fmtpLines.forEach(function (line) { + payload.parameters = parsers.fmtp(line); + }); + + var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines); + fbLines.forEach(function (line) { + payload.feedback.push(parsers.rtcpfb(line)); + }); + + desc.payloads.push(payload); + }); + + var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines); + cryptoLines.forEach(function (line) { + desc.encryption.push(parsers.crypto(line)); + }); + + if (parsers.findLine('a=rtcp-mux', lines)) { + desc.mux = true; + } + + var fbLines = parsers.findLines('a=rtcp-fb:*', lines); + fbLines.forEach(function (line) { + desc.feedback.push(parsers.rtcpfb(line)); + }); + + var extLines = parsers.findLines('a=extmap:', lines); + extLines.forEach(function (line) { + var ext = parsers.extmap(line); + + ext.senders = SENDERS[role][direction][ext.senders]; + + desc.headerExtensions.push(ext); + }); + + var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines); + desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []); + + var ssrcLines = parsers.findLines('a=ssrc:', lines); + desc.sources = parsers.sources(ssrcLines || []); + + if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) { + desc.googConferenceFlag = true; + } + } + + // transport specific attributes + var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines); + var setup = parsers.findLine('a=setup:', lines, sessionLines); + fingerprintLines.forEach(function (line) { + var fp = parsers.fingerprint(line); + if (setup) { + fp.setup = setup.substr(8); + } + trans.fingerprints.push(fp); + }); + + var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines); + var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines); + if (ufragLine && pwdLine) { + trans.ufrag = ufragLine.substr(12); + trans.pwd = pwdLine.substr(10); + trans.candidates = []; + + var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines); + candidateLines.forEach(function (line) { + trans.candidates.push(exports.toCandidateJSON(line)); + }); + } + + if (desc.descType == 'datachannel') { + var sctpmapLines = parsers.findLines('a=sctpmap:', lines); + sctpmapLines.forEach(function (line) { + var sctp = parsers.sctpmap(line); + trans.sctp.push(sctp); + }); + } + + return content; +}; + +exports.toCandidateJSON = function (line) { + var candidate = parsers.candidate(line.split('\r\n')[0]); + candidate.id = (idCounter++).toString(36).substr(0, 12); + return candidate; +}; + +},{"./parsers":36,"./senders":35}],33:[function(require,module,exports){ +/** + * lodash 3.7.2 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * The base implementation of `get` without support for string paths + * and default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path, pathKey) { + if (object == null) { + return; + } + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return (index && index == length) ? object : undefined; +} + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * - * _.isNative(Array.prototype.push); + * _.isObject({}); * // => true * - * _.isNative(_); + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); * // => false */ -function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); -} - -module.exports = isArray; +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +module.exports = baseGet; + +},{}],21:[function(require,module,exports){ +// based on https://github.com/ESTOS/strophe.jingle/ +// adds wildemitter support +var util = require('util'); +var webrtc = require('webrtcsupport'); +var WildEmitter = require('wildemitter'); + +function dumpSDP(description) { + return { + type: description.type, + sdp: description.sdp + }; +} + +function dumpStream(stream) { + var info = { + label: stream.id, + }; + if (stream.getAudioTracks().length) { + info.audio = stream.getAudioTracks().map(function (track) { + return track.id; + }); + } + if (stream.getVideoTracks().length) { + info.video = stream.getVideoTracks().map(function (track) { + return track.id; + }); + } + return info; +} + +function TraceablePeerConnection(config, constraints) { + var self = this; + WildEmitter.call(this); + + this.peerconnection = new webrtc.PeerConnection(config, constraints); + + this.trace = function (what, info) { + self.emit('PeerConnectionTrace', { + time: new Date(), + type: what, + value: info || "" + }); + }; + + this.onicecandidate = null; + this.peerconnection.onicecandidate = function (event) { + self.trace('onicecandidate', event.candidate); + if (self.onicecandidate !== null) { + self.onicecandidate(event); + } + }; + this.onaddstream = null; + this.peerconnection.onaddstream = function (event) { + self.trace('onaddstream', dumpStream(event.stream)); + if (self.onaddstream !== null) { + self.onaddstream(event); + } + }; + this.onremovestream = null; + this.peerconnection.onremovestream = function (event) { + self.trace('onremovestream', dumpStream(event.stream)); + if (self.onremovestream !== null) { + self.onremovestream(event); + } + }; + this.onsignalingstatechange = null; + this.peerconnection.onsignalingstatechange = function (event) { + self.trace('onsignalingstatechange', self.signalingState); + if (self.onsignalingstatechange !== null) { + self.onsignalingstatechange(event); + } + }; + this.oniceconnectionstatechange = null; + this.peerconnection.oniceconnectionstatechange = function (event) { + self.trace('oniceconnectionstatechange', self.iceConnectionState); + if (self.oniceconnectionstatechange !== null) { + self.oniceconnectionstatechange(event); + } + }; + this.onnegotiationneeded = null; + this.peerconnection.onnegotiationneeded = function (event) { + self.trace('onnegotiationneeded'); + if (self.onnegotiationneeded !== null) { + self.onnegotiationneeded(event); + } + }; + self.ondatachannel = null; + this.peerconnection.ondatachannel = function (event) { + self.trace('ondatachannel', event); + if (self.ondatachannel !== null) { + self.ondatachannel(event); + } + }; + this.getLocalStreams = this.peerconnection.getLocalStreams.bind(this.peerconnection); + this.getRemoteStreams = this.peerconnection.getRemoteStreams.bind(this.peerconnection); +} + +util.inherits(TraceablePeerConnection, WildEmitter); + +Object.defineProperty(TraceablePeerConnection.prototype, 'signalingState', { + get: function () { + return this.peerconnection.signalingState; + } +}); + +Object.defineProperty(TraceablePeerConnection.prototype, 'iceConnectionState', { + get: function () { + return this.peerconnection.iceConnectionState; + } +}); + +Object.defineProperty(TraceablePeerConnection.prototype, 'localDescription', { + get: function () { + return this.peerconnection.localDescription; + } +}); + +Object.defineProperty(TraceablePeerConnection.prototype, 'remoteDescription', { + get: function () { + return this.peerconnection.remoteDescription; + } +}); + +TraceablePeerConnection.prototype.addStream = function (stream) { + this.trace('addStream', dumpStream(stream)); + this.peerconnection.addStream(stream); +}; + +TraceablePeerConnection.prototype.removeStream = function (stream) { + this.trace('removeStream', dumpStream(stream)); + this.peerconnection.removeStream(stream); +}; + +TraceablePeerConnection.prototype.createDataChannel = function (label, opts) { + this.trace('createDataChannel', label, opts); + return this.peerconnection.createDataChannel(label, opts); +}; + +TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) { + var self = this; + this.trace('setLocalDescription', dumpSDP(description)); + this.peerconnection.setLocalDescription(description, + function () { + self.trace('setLocalDescriptionOnSuccess'); + successCallback(); + }, + function (err) { + self.trace('setLocalDescriptionOnFailure', err); + failureCallback(err); + } + ); +}; + +TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) { + var self = this; + this.trace('setRemoteDescription', dumpSDP(description)); + this.peerconnection.setRemoteDescription(description, + function () { + self.trace('setRemoteDescriptionOnSuccess'); + successCallback(); + }, + function (err) { + self.trace('setRemoteDescriptionOnFailure', err); + failureCallback(err); + } + ); +}; + +TraceablePeerConnection.prototype.close = function () { + this.trace('stop'); + if (this.statsinterval !== null) { + window.clearInterval(this.statsinterval); + this.statsinterval = null; + } + if (this.peerconnection.signalingState != 'closed') { + this.peerconnection.close(); + } +}; + +TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) { + var self = this; + this.trace('createOffer', constraints); + this.peerconnection.createOffer( + function (offer) { + self.trace('createOfferOnSuccess', dumpSDP(offer)); + successCallback(offer); + }, + function (err) { + self.trace('createOfferOnFailure', err); + failureCallback(err); + }, + constraints + ); +}; + +TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) { + var self = this; + this.trace('createAnswer', constraints); + this.peerconnection.createAnswer( + function (answer) { + self.trace('createAnswerOnSuccess', dumpSDP(answer)); + successCallback(answer); + }, + function (err) { + self.trace('createAnswerOnFailure', err); + failureCallback(err); + }, + constraints + ); +}; + +TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) { + var self = this; + this.trace('addIceCandidate', candidate); + this.peerconnection.addIceCandidate(candidate, + function () { + //self.trace('addIceCandidateOnSuccess'); + if (successCallback) successCallback(); + }, + function (err) { + self.trace('addIceCandidateOnFailure', err); + if (failureCallback) failureCallback(err); + } + ); +}; + +TraceablePeerConnection.prototype.getStats = function (callback, errback) { + if (navigator.mozGetUserMedia) { + this.peerconnection.getStats(null, callback, errback); + } else { + this.peerconnection.getStats(callback); + } +}; + +module.exports = TraceablePeerConnection; + +},{"util":8,"webrtcsupport":5,"wildemitter":4}],35:[function(require,module,exports){ +module.exports = { + initiator: { + incoming: { + initiator: 'recvonly', + responder: 'sendonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'initiator', + sendonly: 'responder', + sendrecv: 'both', + inactive: 'none' + }, + outgoing: { + initiator: 'sendonly', + responder: 'recvonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'responder', + sendonly: 'initiator', + sendrecv: 'both', + inactive: 'none' + } + }, + responder: { + incoming: { + initiator: 'sendonly', + responder: 'recvonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'responder', + sendonly: 'initiator', + sendrecv: 'both', + inactive: 'none' + }, + outgoing: { + initiator: 'recvonly', + responder: 'sendonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'initiator', + sendonly: 'responder', + sendrecv: 'both', + inactive: 'none' + } + } +}; -},{}],38:[function(require,module,exports){ +},{}],36:[function(require,module,exports){ exports.lines = function (sdp) { return sdp.split('\r\n').filter(function (line) { return line.length > 0; @@ -10066,355 +9195,84 @@ exports.candidate = function (line) { } else if (parts[i] === 'rport') { candidate.relPort = parts[i + 1]; } else if (parts[i] === 'generation') { - candidate.generation = parts[i + 1]; - } else if (parts[i] === 'tcptype') { - candidate.tcpType = parts[i + 1]; - } - } - - candidate.network = '1'; - - return candidate; -}; - -exports.sourceGroups = function (lines) { - var parsed = []; - for (var i = 0; i < lines.length; i++) { - var parts = lines[i].substr(13).split(' '); - parsed.push({ - semantics: parts.shift(), - sources: parts - }); - } - return parsed; -}; - -exports.sources = function (lines) { - // http://tools.ietf.org/html/rfc5576 - var parsed = []; - var sources = {}; - for (var i = 0; i < lines.length; i++) { - var parts = lines[i].substr(7).split(' '); - var ssrc = parts.shift(); - - if (!sources[ssrc]) { - var source = { - ssrc: ssrc, - parameters: [] - }; - parsed.push(source); - - // Keep an index - sources[ssrc] = source; - } - - parts = parts.join(' ').split(':'); - var attribute = parts.shift(); - var value = parts.join(':') || null; - - sources[ssrc].parameters.push({ - key: attribute, - value: value - }); - } - - return parsed; -}; - -exports.groups = function (lines) { - // http://tools.ietf.org/html/rfc5888 - var parsed = []; - var parts; - for (var i = 0; i < lines.length; i++) { - parts = lines[i].substr(8).split(' '); - parsed.push({ - semantics: parts.shift(), - contents: parts - }); - } - return parsed; -}; - -exports.bandwidth = function (line) { - var parts = line.substr(2).split(':'); - var parsed = {}; - parsed.type = parts.shift(); - parsed.bandwidth = parts.shift(); - return parsed; -}; - -exports.msid = function (line) { - var data = line.substr(7); - var parts = data.split(' '); - return { - msid: data, - mslabel: parts[0], - label: parts[1] - }; -}; - -},{}],37:[function(require,module,exports){ -module.exports = { - initiator: { - incoming: { - initiator: 'recvonly', - responder: 'sendonly', - both: 'sendrecv', - none: 'inactive', - recvonly: 'initiator', - sendonly: 'responder', - sendrecv: 'both', - inactive: 'none' - }, - outgoing: { - initiator: 'sendonly', - responder: 'recvonly', - both: 'sendrecv', - none: 'inactive', - recvonly: 'responder', - sendonly: 'initiator', - sendrecv: 'both', - inactive: 'none' - } - }, - responder: { - incoming: { - initiator: 'sendonly', - responder: 'recvonly', - both: 'sendrecv', - none: 'inactive', - recvonly: 'responder', - sendonly: 'initiator', - sendrecv: 'both', - inactive: 'none' - }, - outgoing: { - initiator: 'recvonly', - responder: 'sendonly', - both: 'sendrecv', - none: 'inactive', - recvonly: 'initiator', - sendonly: 'responder', - sendrecv: 'both', - inactive: 'none' - } - } -}; - -},{}],22:[function(require,module,exports){ -// based on https://github.com/ESTOS/strophe.jingle/ -// adds wildemitter support -var util = require('util'); -var adapter = require('webrtc-adapter-test'); -var WildEmitter = require('wildemitter'); - -function dumpSDP(description) { - return { - type: description.type, - sdp: description.sdp - }; -} - -function dumpStream(stream) { - var info = { - label: stream.id, - }; - if (stream.getAudioTracks().length) { - info.audio = stream.getAudioTracks().map(function (track) { - return track.id; - }); - } - if (stream.getVideoTracks().length) { - info.video = stream.getVideoTracks().map(function (track) { - return track.id; - }); - } - return info; -} - -function TraceablePeerConnection(config, constraints) { - var self = this; - WildEmitter.call(this); - - this.peerconnection = new window.RTCPeerConnection(config, constraints); - - this.trace = function (what, info) { - self.emit('PeerConnectionTrace', { - time: new Date(), - type: what, - value: info || "" - }); - }; - - this.onicecandidate = null; - this.peerconnection.onicecandidate = function (event) { - self.trace('onicecandidate', event.candidate); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - }; - this.onaddstream = null; - this.peerconnection.onaddstream = function (event) { - self.trace('onaddstream', dumpStream(event.stream)); - if (self.onaddstream !== null) { - self.onaddstream(event); - } - }; - this.onremovestream = null; - this.peerconnection.onremovestream = function (event) { - self.trace('onremovestream', dumpStream(event.stream)); - if (self.onremovestream !== null) { - self.onremovestream(event); - } - }; - this.onsignalingstatechange = null; - this.peerconnection.onsignalingstatechange = function (event) { - self.trace('onsignalingstatechange', self.signalingState); - if (self.onsignalingstatechange !== null) { - self.onsignalingstatechange(event); - } - }; - this.oniceconnectionstatechange = null; - this.peerconnection.oniceconnectionstatechange = function (event) { - self.trace('oniceconnectionstatechange', self.iceConnectionState); - if (self.oniceconnectionstatechange !== null) { - self.oniceconnectionstatechange(event); - } - }; - this.onnegotiationneeded = null; - this.peerconnection.onnegotiationneeded = function (event) { - self.trace('onnegotiationneeded'); - if (self.onnegotiationneeded !== null) { - self.onnegotiationneeded(event); - } - }; - self.ondatachannel = null; - this.peerconnection.ondatachannel = function (event) { - self.trace('ondatachannel', event); - if (self.ondatachannel !== null) { - self.ondatachannel(event); - } - }; - this.getLocalStreams = this.peerconnection.getLocalStreams.bind(this.peerconnection); - this.getRemoteStreams = this.peerconnection.getRemoteStreams.bind(this.peerconnection); -} - -util.inherits(TraceablePeerConnection, WildEmitter); - -['signalingState', 'iceConnectionState', 'localDescription', 'remoteDescription'].forEach(function (prop) { - Object.defineProperty(TraceablePeerConnection.prototype, prop, { - get: function () { - return this.peerconnection[prop]; - } - }); -}); - -TraceablePeerConnection.prototype.addStream = function (stream) { - this.trace('addStream', dumpStream(stream)); - this.peerconnection.addStream(stream); -}; - -TraceablePeerConnection.prototype.removeStream = function (stream) { - this.trace('removeStream', dumpStream(stream)); - this.peerconnection.removeStream(stream); -}; - -TraceablePeerConnection.prototype.createDataChannel = function (label, opts) { - this.trace('createDataChannel', label, opts); - return this.peerconnection.createDataChannel(label, opts); -}; - -TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) { - var self = this; - this.trace('setLocalDescription', dumpSDP(description)); - this.peerconnection.setLocalDescription(description, - function () { - self.trace('setLocalDescriptionOnSuccess'); - if (successCallback) successCallback(); - }, - function (err) { - self.trace('setLocalDescriptionOnFailure', err); - if (failureCallback) failureCallback(err); + candidate.generation = parts[i + 1]; + } else if (parts[i] === 'tcptype') { + candidate.tcpType = parts[i + 1]; } - ); -}; + } -TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) { - var self = this; - this.trace('setRemoteDescription', dumpSDP(description)); - this.peerconnection.setRemoteDescription(description, - function () { - self.trace('setRemoteDescriptionOnSuccess'); - if (successCallback) successCallback(); - }, - function (err) { - self.trace('setRemoteDescriptionOnFailure', err); - if (failureCallback) failureCallback(err); - } - ); + candidate.network = '1'; + + return candidate; }; -TraceablePeerConnection.prototype.close = function () { - this.trace('stop'); - if (this.peerconnection.signalingState != 'closed') { - this.peerconnection.close(); +exports.sourceGroups = function (lines) { + var parsed = []; + for (var i = 0; i < lines.length; i++) { + var parts = lines[i].substr(13).split(' '); + parsed.push({ + semantics: parts.shift(), + sources: parts + }); } + return parsed; }; -TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) { - var self = this; - this.trace('createOffer', constraints); - this.peerconnection.createOffer( - function (offer) { - self.trace('createOfferOnSuccess', dumpSDP(offer)); - if (successCallback) successCallback(offer); - }, - function (err) { - self.trace('createOfferOnFailure', err); - if (failureCallback) failureCallback(err); - }, - constraints - ); -}; +exports.sources = function (lines) { + // http://tools.ietf.org/html/rfc5576 + var parsed = []; + var sources = {}; + for (var i = 0; i < lines.length; i++) { + var parts = lines[i].substr(7).split(' '); + var ssrc = parts.shift(); -TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) { - var self = this; - this.trace('createAnswer', constraints); - this.peerconnection.createAnswer( - function (answer) { - self.trace('createAnswerOnSuccess', dumpSDP(answer)); - if (successCallback) successCallback(answer); - }, - function (err) { - self.trace('createAnswerOnFailure', err); - if (failureCallback) failureCallback(err); - }, - constraints - ); -}; + if (!sources[ssrc]) { + var source = { + ssrc: ssrc, + parameters: [] + }; + parsed.push(source); -TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) { - var self = this; - this.trace('addIceCandidate', candidate); - this.peerconnection.addIceCandidate(candidate, - function () { - //self.trace('addIceCandidateOnSuccess'); - if (successCallback) successCallback(); - }, - function (err) { - self.trace('addIceCandidateOnFailure', err); - if (failureCallback) failureCallback(err); + // Keep an index + sources[ssrc] = source; } - ); + + parts = parts.join(' ').split(':'); + var attribute = parts.shift(); + var value = parts.join(':') || null; + + sources[ssrc].parameters.push({ + key: attribute, + value: value + }); + } + + return parsed; }; -TraceablePeerConnection.prototype.getStats = function () { - this.peerconnection.getStats.apply(this.peerconnection, arguments); +exports.groups = function (lines) { + // http://tools.ietf.org/html/rfc5888 + var parsed = []; + var parts; + for (var i = 0; i < lines.length; i++) { + parts = lines[i].substr(8).split(' '); + parsed.push({ + semantics: parts.shift(), + contents: parts + }); + } + return parsed; }; -module.exports = TraceablePeerConnection; +exports.bandwidth = function (line) { + var parts = line.substr(2).split(':'); + var parsed = {}; + parsed.type = parts.shift(); + parsed.bandwidth = parts.shift(); + return parsed; +}; -},{"util":8,"webrtc-adapter-test":20,"wildemitter":4}],30:[function(require,module,exports){ +},{}],28:[function(require,module,exports){ /** * lodash 3.0.4 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -10597,88 +9455,7 @@ function isObject(value) { module.exports = baseEach; -},{"lodash.keys":39}],40:[function(require,module,exports){ -/** - * lodash 3.0.0 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.7.0 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * A specialized version of `_.map` for arrays without support for callback - * shorthands or `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ -function arrayMap(array, iteratee) { - var index = -1, - length = array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; -} - -module.exports = arrayMap; - -},{}],34:[function(require,module,exports){ -/** - * lodash 3.8.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var isArray = require('lodash.isarray'); - -/** Used to match property names within property paths. */ -var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; - -/** Used to match backslashes in property paths. */ -var reEscapeChar = /\\(\\)?/g; - -/** - * Converts `value` to a string if it's not one. An empty string is returned - * for `null` or `undefined` values. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ -function baseToString(value) { - return value == null ? '' : (value + ''); -} - -/** - * Converts `value` to property path array if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array} Returns the property path array. - */ -function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; -} - -module.exports = toPath; - -},{"lodash.isarray":35}],36:[function(require,module,exports){ +},{"lodash.keys":37}],32:[function(require,module,exports){ /** * lodash 3.1.4 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -10818,21 +9595,105 @@ function isLength(value) { * { 'user': 'fred' } * ]; * - * // using the `_.property` callback shorthand - * _.map(users, 'user'); - * // => ['barney', 'fred'] + * // using the `_.property` callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ +function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = baseCallback(iteratee, thisArg, 3); + return func(collection, iteratee); +} + +module.exports = map; + +},{"lodash._arraymap":39,"lodash._basecallback":38,"lodash._baseeach":40,"lodash.isarray":31}],34:[function(require,module,exports){ +/** + * lodash 3.8.0 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isArray = require('lodash.isarray'); + +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `value` to a string if it is not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} + +/** + * Converts `value` to property path array if it is not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ +function toPath(value) { + if (isArray(value)) { + return value; + } + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +} + +module.exports = toPath; + +},{"lodash.isarray":31}],39:[function(require,module,exports){ +/** + * lodash 3.0.0 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.7.0 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A specialized version of `_.map` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. */ -function map(collection, iteratee, thisArg) { - var func = isArray(collection) ? arrayMap : baseMap; - iteratee = baseCallback(iteratee, thisArg, 3); - return func(collection, iteratee); +function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; } -module.exports = map; +module.exports = arrayMap; -},{"lodash._arraymap":40,"lodash._basecallback":41,"lodash._baseeach":42,"lodash.isarray":35}],43:[function(require,module,exports){ +},{}],41:[function(require,module,exports){ /** - * lodash 3.9.1 (Custom Build) + * lodash 3.9.0 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -10843,10 +9704,33 @@ module.exports = map; /** `Object#toString` result references. */ var funcTag = '[object Function]'; +/** + * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). + * In addition to special characters the forward slash is escaped to allow for + * easier `eval` use and `Function` compilation. + */ +var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + /** Used to detect host constructors (Safari > 5). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} + +/** * Checks if `value` is object-like. * * @private @@ -10867,14 +9751,14 @@ var fnToString = Function.prototype.toString; var hasOwnProperty = objectProto.hasOwnProperty; /** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * of values. */ var objToString = objectProto.toString; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + escapeRegExp(fnToString.call(hasOwnProperty)) .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); @@ -10892,56 +9776,6 @@ function getNative(object, key) { } /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; -} - -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -/** * Checks if `value` is a native function. * * @static @@ -10961,17 +9795,38 @@ function isNative(value) { if (value == null) { return false; } - if (isFunction(value)) { + if (objToString.call(value) == funcTag) { return reIsNative.test(fnToString.call(value)); } return isObjectLike(value) && reIsHostCtor.test(value); } +/** + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' + */ +function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; +} + module.exports = getNative; -},{}],44:[function(require,module,exports){ +},{}],42:[function(require,module,exports){ /** - * lodash 3.0.4 (Custom Build) + * lodash 3.0.3 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -10979,6 +9834,9 @@ module.exports = getNative; * Available under MIT license */ +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; + /** * Checks if `value` is object-like. * @@ -10993,14 +9851,14 @@ function isObjectLike(value) { /** Used for native method references. */ var objectProto = Object.prototype; -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** Native method references. */ -var propertyIsEnumerable = objectProto.propertyIsEnumerable; +/** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * of an array-like value. */ var MAX_SAFE_INTEGER = 9007199254740991; @@ -11044,7 +9902,7 @@ function isArrayLike(value) { /** * Checks if `value` is a valid array-like length. * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). * * @private * @param {*} value The value to check. @@ -11071,80 +9929,12 @@ function isLength(value) { * // => false */ function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); + return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag; } module.exports = isArguments; -},{}],45:[function(require,module,exports){ -/** - * lodash 3.0.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * A specialized version of `baseCallback` which only supports `this` binding - * and specifying the number of arguments to provide to `func`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ -function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: return function(value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function() { - return func.apply(thisArg, arguments); - }; -} - -/** - * This method returns the first argument provided to it. - * - * @static - * @memberOf _ - * @category Utility - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'user': 'fred' }; - * - * _.identity(object) === object; - * // => true - */ -function identity(value) { - return value; -} - -module.exports = bindCallback; - -},{}],42:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ /** * lodash 3.0.4 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -11299,37 +10089,104 @@ function toObject(value) { } /** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +module.exports = baseEach; + +},{"lodash.keys":43}],44:[function(require,module,exports){ +/** + * lodash 3.0.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ +function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (thisArg === undefined) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; +} + +/** + * This method returns the first argument provided to it. * * @static * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @category Utility + * @param {*} value Any value. + * @returns {*} Returns `value`. * @example * - * _.isObject({}); - * // => true + * var object = { 'user': 'fred' }; * - * _.isObject([1, 2, 3]); + * _.identity(object) === object; * // => true - * - * _.isObject(1); - * // => false */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); +function identity(value) { + return value; } -module.exports = baseEach; +module.exports = bindCallback; -},{"lodash.keys":46}],39:[function(require,module,exports){ +},{}],37:[function(require,module,exports){ /** - * lodash 3.1.2 (Custom Build) + * lodash 3.1.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -11353,7 +10210,7 @@ var hasOwnProperty = objectProto.hasOwnProperty; var nativeKeys = getNative(Object, 'keys'); /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * of an array-like value. */ var MAX_SAFE_INTEGER = 9007199254740991; @@ -11411,7 +10268,7 @@ function isIndex(value, length) { /** * Checks if `value` is a valid array-like length. * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). * * @private * @param {*} value The value to check. @@ -11480,7 +10337,7 @@ function isObject(value) { * Creates an array of the own enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) * for more details. * * @static @@ -11504,7 +10361,7 @@ function isObject(value) { * // => ['0', '1'] */ var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; + var Ctor = object == null ? null : object.constructor; if ((typeof Ctor == 'function' && Ctor.prototype === object) || (typeof object != 'function' && isArrayLike(object))) { return shimKeys(object); @@ -11565,9 +10422,9 @@ function keysIn(object) { module.exports = keys; -},{"lodash._getnative":43,"lodash.isarguments":44,"lodash.isarray":32}],41:[function(require,module,exports){ +},{"lodash._getnative":41,"lodash.isarguments":42,"lodash.isarray":27}],38:[function(require,module,exports){ /** - * lodash 3.3.1 (Custom Build) + * lodash 3.3.0 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -11596,6 +10453,9 @@ var reEscapeChar = /\\(\\)?/g; * @returns {string} Returns the string. */ function baseToString(value) { + if (typeof value == 'string') { + return value; + } return value == null ? '' : (value + ''); } @@ -11727,7 +10587,8 @@ function baseMatches(source) { } /** - * The base implementation of `_.matchesProperty` which does not clone `srcValue`. + * The base implementation of `_.matchesProperty` which does not which does + * not clone `value`. * * @private * @param {string} path The path of the property to get. @@ -11962,7 +10823,7 @@ function identity(value) { } /** - * Creates a function that returns the property value at `path` on a + * Creates a function which returns the property value at `path` on a * given object. * * @static @@ -11989,7 +10850,7 @@ function property(path) { module.exports = baseCallback; -},{"lodash._baseisequal":47,"lodash._bindcallback":45,"lodash.isarray":35,"lodash.pairs":48}],49:[function(require,module,exports){ +},{"lodash._baseisequal":45,"lodash._bindcallback":44,"lodash.isarray":31,"lodash.pairs":46}],47:[function(require,module,exports){ /** * lodash 3.0.2 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -12101,9 +10962,9 @@ function isTypedArray(value) { module.exports = isTypedArray; -},{}],50:[function(require,module,exports){ +},{}],48:[function(require,module,exports){ /** - * lodash 3.9.1 (Custom Build) + * lodash 3.0.3 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -12112,10 +10973,7 @@ module.exports = isTypedArray; */ /** `Object#toString` result references. */ -var funcTag = '[object Function]'; - -/** Used to detect host constructors (Safari > 5). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; +var argsTag = '[object Arguments]'; /** * Checks if `value` is object-like. @@ -12131,118 +10989,92 @@ function isObjectLike(value) { /** Used for native method references. */ var objectProto = Object.prototype; -/** Used to resolve the decompiled source of functions. */ -var fnToString = Function.prototype.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - /** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * of values. */ var objToString = objectProto.toString; -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; /** - * Gets the native function at `key` of `object`. + * The base implementation of `_.property` without support for deep paths. * * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. */ -function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; } /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example + * Gets the "length" property value of `object`. * - * _.isFunction(_); - * // => true + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. * - * _.isFunction(/abc/); - * // => false + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; -} +var getLength = baseProperty('length'); /** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * Checks if `value` is array-like. * - * @static - * @memberOf _ - * @category Lang + * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { + return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like length. * - * _.isObject([1, 2, 3]); - * // => true + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). * - * _.isObject(1); - * // => false + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } /** - * Checks if `value` is a native function. + * Checks if `value` is classified as an `arguments` object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * - * _.isNative(Array.prototype.push); + * _.isArguments(function() { return arguments; }()); * // => true * - * _.isNative(_); + * _.isArguments([1, 2, 3]); * // => false */ -function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); +function isArguments(value) { + return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag; } -module.exports = getNative; +module.exports = isArguments; -},{}],51:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ /** - * lodash 3.0.4 (Custom Build) + * lodash 3.9.0 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -12250,6 +11082,35 @@ module.exports = getNative; * Available under MIT license */ +/** `Object#toString` result references. */ +var funcTag = '[object Function]'; + +/** + * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). + * In addition to special characters the forward slash is escaped to allow for + * easier `eval` use and `Function` compilation. + */ +var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} + /** * Checks if `value` is object-like. * @@ -12264,91 +11125,87 @@ function isObjectLike(value) { /** Used for native method references. */ var objectProto = Object.prototype; +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; -/** Native method references. */ -var propertyIsEnumerable = objectProto.propertyIsEnumerable; - /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. */ -var MAX_SAFE_INTEGER = 9007199254740991; +var objToString = objectProto.toString; -/** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ -function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; -} +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + escapeRegExp(fnToString.call(hasOwnProperty)) + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); /** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. + * Gets the native function at `key` of `object`. * * @private * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. */ -var getLength = baseProperty('length'); +function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; +} /** - * Checks if `value` is array-like. + * Checks if `value` is a native function. * - * @private + * @static + * @memberOf _ + * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ -function isArrayLike(value) { - return value != null && isLength(getLength(value)); -} - -/** - * Checks if `value` is a valid array-like length. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * _.isNative(Array.prototype.push); + * // => true * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * _.isNative(_); + * // => false */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); } /** - * Checks if `value` is classified as an `arguments` object. + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. * * @static * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. * @example * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' */ -function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); +function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; } -module.exports = isArguments; +module.exports = getNative; -},{}],48:[function(require,module,exports){ +},{}],46:[function(require,module,exports){ /** * lodash 3.0.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -12428,7 +11285,7 @@ function pairs(object) { module.exports = pairs; -},{"lodash.keys":46}],47:[function(require,module,exports){ +},{"lodash.keys":43}],45:[function(require,module,exports){ /** * lodash 3.0.7 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -12772,9 +11629,9 @@ function isObject(value) { module.exports = baseIsEqual; -},{"lodash.isarray":35,"lodash.istypedarray":49,"lodash.keys":46}],46:[function(require,module,exports){ +},{"lodash.isarray":31,"lodash.istypedarray":47,"lodash.keys":43}],43:[function(require,module,exports){ /** - * lodash 3.1.2 (Custom Build) + * lodash 3.1.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -12798,7 +11655,7 @@ var hasOwnProperty = objectProto.hasOwnProperty; var nativeKeys = getNative(Object, 'keys'); /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * of an array-like value. */ var MAX_SAFE_INTEGER = 9007199254740991; @@ -12856,7 +11713,7 @@ function isIndex(value, length) { /** * Checks if `value` is a valid array-like length. * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). * * @private * @param {*} value The value to check. @@ -12925,7 +11782,7 @@ function isObject(value) { * Creates an array of the own enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) * for more details. * * @static @@ -12949,7 +11806,7 @@ function isObject(value) { * // => ['0', '1'] */ var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; + var Ctor = object == null ? null : object.constructor; if ((typeof Ctor == 'function' && Ctor.prototype === object) || (typeof object != 'function' && isArrayLike(object))) { return shimKeys(object); @@ -13010,6 +11867,6 @@ function keysIn(object) { module.exports = keys; -},{"lodash._getnative":50,"lodash.isarguments":51,"lodash.isarray":35}]},{},[1])(1) +},{"lodash._getnative":49,"lodash.isarguments":48,"lodash.isarray":31}]},{},[1])(1) }); ;