From bcb5ebac519836c12d2f29dce60b0ac327af2b95 Mon Sep 17 00:00:00 2001 From: ojack Date: Fri, 3 Apr 2020 12:13:03 +0200 Subject: [PATCH] updated version --- hydra-server/public/bundle.js | 11547 +++++--------------------------- package-lock.json | 793 +-- package.json | 2 +- 3 files changed, 1660 insertions(+), 10682 deletions(-) diff --git a/hydra-server/public/bundle.js b/hydra-server/public/bundle.js index 2ce74bc..102ef3d 100644 --- a/hydra-server/public/bundle.js +++ b/hydra-server/public/bundle.js @@ -73,7 +73,7 @@ function init () { window.onload = init -},{"./keymaps.js":2,"./src/editor.js":5,"./src/gallery.js":7,"./src/log.js":8,"./src/menu.js":9,"./src/p5-wrapper.js":10,"./src/pb-live.js":11,"./src/repl.js":12,"hydra-synth":72,"raf-loop":102}],2:[function(require,module,exports){ +},{"./keymaps.js":2,"./src/editor.js":5,"./src/gallery.js":7,"./src/log.js":8,"./src/menu.js":9,"./src/p5-wrapper.js":10,"./src/pb-live.js":11,"./src/repl.js":12,"hydra-synth":62,"raf-loop":94}],2:[function(require,module,exports){ module.exports = { init : ({ editor, gallery, menu, repl, log}) => { window.onkeydown = (e) => { @@ -822,7 +822,7 @@ class Gallery { module.exports = Gallery -},{"./examples.json":6,"superagent":144}],8:[function(require,module,exports){ +},{"./examples.json":6,"superagent":134}],8:[function(require,module,exports){ var logElement module.exports = { @@ -998,7 +998,7 @@ class P5 extends p5lib{ module.exports = P5 -},{"p5":96,"p5/lib/addons/p5.dom":95}],11:[function(require,module,exports){ +},{"p5":88,"p5/lib/addons/p5.dom":87}],11:[function(require,module,exports){ /* globals sessionStorage */ // Extends rtc-patch-bay to include support for nicknames and persistent session storage @@ -1132,7 +1132,7 @@ PBLive.prototype._processBroadcast = function (data) { // PBExtended.prototype. module.exports = PBLive -},{"./rtc-patch-bay.js":13,"inherits":89}],12:[function(require,module,exports){ +},{"./rtc-patch-bay.js":13,"inherits":81}],12:[function(require,module,exports){ const log = require('./log.js').log module.exports = { @@ -1407,7 +1407,7 @@ PatchBay.prototype._destroy = function () { module.exports = PatchBay -},{"events":26,"inherits":89,"shortid":119,"simple-peer":129,"socket.io-client":133}],14:[function(require,module,exports){ +},{"events":26,"inherits":81,"shortid":109,"simple-peer":119,"socket.io-client":123}],14:[function(require,module,exports){ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : @@ -10839,7 +10839,7 @@ function numberIsNaN (obj) { return obj !== obj // eslint-disable-line no-self-compare } -},{"base64-js":23,"ieee754":87}],28:[function(require,module,exports){ +},{"base64-js":23,"ieee754":79}],28:[function(require,module,exports){ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE @@ -22622,7 +22622,7 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":90}],38:[function(require,module,exports){ +},{"../../is-buffer/index.js":82}],38:[function(require,module,exports){ /** * Helpers. */ @@ -22965,7 +22965,7 @@ function localstorage() { } }).call(this,require('_process')) -},{"./debug":40,"_process":101}],40:[function(require,module,exports){ +},{"./debug":40,"_process":93}],40:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser @@ -23928,7 +23928,7 @@ Socket.prototype.filterUpgrades = function (upgrades) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./transport":43,"./transports/index":44,"component-emitter":35,"debug":50,"engine.io-parser":53,"indexof":88,"parseqs":97,"parseuri":98}],43:[function(require,module,exports){ +},{"./transport":43,"./transports/index":44,"component-emitter":35,"debug":50,"engine.io-parser":53,"indexof":80,"parseqs":89,"parseuri":90}],43:[function(require,module,exports){ /** * Module dependencies. */ @@ -25050,7 +25050,7 @@ Polling.prototype.uri = function () { return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query; }; -},{"../transport":43,"component-inherit":36,"debug":50,"engine.io-parser":53,"parseqs":97,"xmlhttprequest-ssl":49,"yeast":163}],48:[function(require,module,exports){ +},{"../transport":43,"component-inherit":36,"debug":50,"engine.io-parser":53,"parseqs":89,"xmlhttprequest-ssl":49,"yeast":141}],48:[function(require,module,exports){ (function (global){ /** * Module dependencies. @@ -25340,7 +25340,7 @@ WS.prototype.check = function () { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../transport":43,"component-inherit":36,"debug":50,"engine.io-parser":53,"parseqs":97,"ws":25,"yeast":163}],49:[function(require,module,exports){ +},{"../transport":43,"component-inherit":36,"debug":50,"engine.io-parser":53,"parseqs":89,"ws":25,"yeast":141}],49:[function(require,module,exports){ (function (global){ // browser shim for xmlhttprequest module @@ -25381,7 +25381,7 @@ module.exports = function (opts) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"has-cors":71}],50:[function(require,module,exports){ +},{"has-cors":60}],50:[function(require,module,exports){ (function (process){ /** * This is the web browser implementation of `debug()`. @@ -25580,7 +25580,7 @@ function localstorage() { } }).call(this,require('_process')) -},{"./debug":51,"_process":101}],51:[function(require,module,exports){ +},{"./debug":51,"_process":93}],51:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser @@ -26419,7 +26419,7 @@ exports.decodePayloadAsBinary = function (data, binaryType, callback) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./keys":54,"./utf8":55,"after":15,"arraybuffer.slice":16,"base64-arraybuffer":22,"blob":24,"has-binary2":69}],54:[function(require,module,exports){ +},{"./keys":54,"./utf8":55,"after":15,"arraybuffer.slice":16,"base64-arraybuffer":22,"blob":24,"has-binary2":58}],54:[function(require,module,exports){ /** * Gets the keys for an object. @@ -26772,2905 +26772,6 @@ module.exports = function getBrowserRTC () { } },{}],58:[function(require,module,exports){ -// getUserMedia helper by @HenrikJoreteg used for navigator.getUserMedia shim -var adapter = require('webrtc-adapter'); - -module.exports = function (constraints, cb) { - var 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 (typeof navigator === 'undefined' || !navigator.getUserMedia) { - // throw proper error per spec - error = new Error('MediaStreamError'); - error.name = 'NotSupportedError'; - - // keep all callbacks async - return 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 setTimeout(function () { - cb(error); - }, 0); - } - - navigator.mediaDevices.getUserMedia(constraints) - .then(function (stream) { - cb(null, stream); - }).catch(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":60}],59:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parts[1], - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - 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); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr - sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.split(' '); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } - }; - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(5), 10); - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -SDPUtils.writeSessionBoilerplate = function() { - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -// Expose public methods. -module.exports = SDPUtils; - -},{}],60:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ - -'use strict'; - -// Shimming starts here. -(function() { - // Utils. - var logging = require('./utils').log; - var browserDetails = require('./utils').browserDetails; - // Export to the adapter global object visible in the browser. - module.exports.browserDetails = browserDetails; - module.exports.extractVersion = require('./utils').extractVersion; - module.exports.disableLog = require('./utils').disableLog; - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'opera': // fallthrough as it uses chrome shims - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection) { - logging('Chrome shim is not included in this adapter release.'); - return; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - module.exports.browserShim = chromeShim; - - chromeShim.shimGetUserMedia(); - chromeShim.shimMediaStream(); - chromeShim.shimSourceObject(); - chromeShim.shimPeerConnection(); - chromeShim.shimOnTrack(); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection) { - logging('Firefox shim is not included in this adapter release.'); - return; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - module.exports.browserShim = firefoxShim; - - firefoxShim.shimGetUserMedia(); - firefoxShim.shimSourceObject(); - firefoxShim.shimPeerConnection(); - firefoxShim.shimOnTrack(); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection) { - logging('MS edge shim is not included in this adapter release.'); - return; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - module.exports.browserShim = edgeShim; - - edgeShim.shimGetUserMedia(); - edgeShim.shimPeerConnection(); - break; - case 'safari': - if (!safariShim) { - logging('Safari shim is not included in this adapter release.'); - return; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - module.exports.browserShim = safariShim; - - safariShim.shimGetUserMedia(); - break; - default: - logging('Unsupported browser!'); - } -})(); - -},{"./chrome/chrome_shim":61,"./edge/edge_shim":63,"./firefox/firefox_shim":65,"./safari/safari_shim":67,"./utils":68}],61:[function(require,module,exports){ - -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; -var logging = require('../utils.js').log; -var browserDetails = require('../utils.js').browserDetails; - -var chromeShim = { - shimMediaStream: function() { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function() { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - var self = this; - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var event = new Event('track'); - event.track = te.track; - event.receiver = {track: te.track}; - event.streams = [e.stream]; - self.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - }, - - shimSourceObject: function() { - 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() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimPeerConnection: function() { - // The RTCPeerConnection object. - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); - var origGetStats = pc.getStats.bind(pc); - pc.getStats = function(selector, successCallback, errorCallback) { - 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; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats, legacyStats) { - var map = new Map(Object.keys(stats).map(function(key) { - return[key, stats[key]]; - })); - legacyStats = legacyStats || stats; - Object.keys(legacyStats).forEach(function(key) { - map[key] = legacyStats[key]; - }); - return map; - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - if (args.length === 1 && typeof selector === 'object') { - origGetStats.apply(self, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - } else { - // Preserve legacy chrome stats only on legacy access of stats obj - origGetStats.apply(self, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response), - response.result())); - }, reject]); - } - }).then(successCallback, errorCallback); - }; - - return pc; - }; - window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return webkitRTCPeerConnection.generateCertificate; - } - }); - } - - ['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]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - var args = arguments; - var self = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(self, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = webkitRTCPeerConnection.prototype[method]; - webkitRTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - RTCIceCandidate : RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - RTCPeerConnection.prototype.addIceCandidate; - RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - - -// Expose public methods. -module.exports = { - shimMediaStream: chromeShim.shimMediaStream, - shimOnTrack: chromeShim.shimOnTrack, - shimSourceObject: chromeShim.shimSourceObject, - shimPeerConnection: chromeShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; - -},{"../utils.js":68,"./getusermedia":62}],62:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; -var logging = require('../utils.js').log; - -// Expose public methods. -module.exports = function() { - 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; - }; - - var shimConstraints_ = function(constraints, func) { - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && constraints.audio) { - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile, where it defaults to "user". - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode)) { - delete constraints.video.facingMode; - if (face.exact === 'environment' || face.ideal === 'environment') { - // Look for "back" in label, or use last cam (typically back cam). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var back = devices.find(function(d) { - return d.label.toLowerCase().indexOf('back') !== -1; - }) || (devices.length && devices[devices.length - 1]); - if (back) { - constraints.video.deviceId = face.exact ? {exact: back.deviceId} : - {ideal: back.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - ConstraintNotSatisfiedError: 'OverconstrainedError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - onError(shimError_(e)); - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - 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 getUserMediaPromise_(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(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":68}],63:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var browserDetails = require('../utils').browserDetails; - -var edgeShim = { - shimPeerConnection: function() { - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. - var origMSTEnabled = Object.getOwnPropertyDescriptor( - MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - - window.RTCPeerConnection = function(config) { - var self = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - self[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.onicecandidate = null; - this.onaddstream = null; - this.ontrack = null; - this.onremovestream = null; - this.onsignalingstatechange = null; - this.oniceconnectionstatechange = null; - this.onnegotiationneeded = null; - this.ondatachannel = null; - - this.localStreams = []; - this.remoteStreams = []; - this.getLocalStreams = function() { - return self.localStreams; - }; - this.getRemoteStreams = function() { - return self.remoteStreams; - }; - - this.localDescription = new RTCSessionDescription({ - type: '', - sdp: '' - }); - this.remoteDescription = new RTCSessionDescription({ - type: '', - sdp: '' - }); - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - this.iceOptions = { - gatherPolicy: 'all', - iceServers: [] - }; - if (config && config.iceTransportPolicy) { - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - this.iceOptions.gatherPolicy = config.iceTransportPolicy; - break; - case 'none': - // FIXME: remove once implementation and spec have added this. - throw new TypeError('iceTransportPolicy "none" not supported'); - default: - // don't set iceTransportPolicy. - break; - } - } - this.usingBundle = config && config.bundlePolicy === 'max-bundle'; - - if (config && config.iceServers) { - // Edge does not like - // 1) stun: - // 2) turn: that does not have all of turn:host:port?transport=udp - // 3) turn: with ipv6 addresses - var iceServers = JSON.parse(JSON.stringify(config.iceServers)); - this.iceOptions.iceServers = iceServers.filter(function(server) { - if (server && server.urls) { - var urls = server.urls; - if (typeof urls === 'string') { - urls = [urls]; - } - urls = urls.filter(function(url) { - return (url.indexOf('turn:') === 0 && - url.indexOf('transport=udp') !== -1 && - url.indexOf('turn:[') === -1) || - (url.indexOf('stun:') === 0 && - browserDetails.version >= 14393); - })[0]; - return !!urls; - } - return false; - }); - } - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - // since the iceGatherer is currently created in createOffer but we - // must not emit candidates until after setLocalDescription we buffer - // them in this array. - this._localIceCandidatesBuffer = []; - }; - - window.RTCPeerConnection.prototype._emitBufferedCandidates = function() { - var self = this; - var sections = SDPUtils.splitSections(self.localDescription.sdp); - // FIXME: need to apply ice candidates in a way which is async but - // in-order - this._localIceCandidatesBuffer.forEach(function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - if (end) { - for (var j = 1; j < sections.length; j++) { - if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) { - sections[j] += 'a=end-of-candidates\r\n'; - } - } - } else if (event.candidate.candidate.indexOf('typ endOfCandidates') - === -1) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } - self.localDescription.sdp = sections.join(''); - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - if (!event.candidate && self.iceGatheringState !== 'complete') { - var complete = self.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - if (complete) { - self.iceGatheringState = 'complete'; - } - } - }); - this._localIceCandidatesBuffer = []; - }; - - window.RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - window.RTCPeerConnection.prototype.addStream = function(stream) { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - this.localStreams.push(clonedStream); - this._maybeFireNegotiationNeeded(); - }; - - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var idx = this.localStreams.indexOf(stream); - if (idx > -1) { - this.localStreams.splice(idx, 1); - this._maybeFireNegotiationNeeded(); - } - }; - - window.RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - window.RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - // Determines the intersection of local and remote capabilities. - window.RTCPeerConnection.prototype._getCommonCapabilities = - function(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions - .forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; - }; - - // Create ICE gatherer, ICE transport and DTLS transport. - window.RTCPeerConnection.prototype._createIceAndDtlsTransports = - function(mid, sdpMLineIndex) { - var self = this; - var iceGatherer = new RTCIceGatherer(self.iceOptions); - var iceTransport = new RTCIceTransport(iceGatherer); - iceGatherer.onlocalcandidate = function(evt) { - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - var end = !cand || Object.keys(cand).length === 0; - // Edge emits an empty object for RTCIceCandidateComplete‥ - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === undefined) { - iceGatherer.state = 'completed'; - } - - // Emit a candidate with type endOfCandidates to make the samples - // work. Edge requires addIceCandidate with this empty candidate - // to start checking. The real solution is to signal - // end-of-candidates to the other side when getting the null - // candidate but some apps (like the samples) don't do that. - event.candidate.candidate = - 'candidate:1 1 udp 1 0.0.0.0 9 typ endOfCandidates'; - } else { - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = iceTransport.component === 'RTCP' ? 2 : 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(self.localDescription.sdp); - if (event.candidate.candidate.indexOf('typ endOfCandidates') - === -1) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - self.localDescription.sdp = sections.join(''); - - var complete = self.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - // Emit candidate if localDescription is set. - // Also emits null candidate when all gatherers are complete. - switch (self.iceGatheringState) { - case 'new': - self._localIceCandidatesBuffer.push(event); - if (end && complete) { - self._localIceCandidatesBuffer.push( - new Event('icecandidate')); - } - break; - case 'gathering': - self._emitBufferedCandidates(); - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - if (complete) { - self.dispatchEvent(new Event('icecandidate')); - if (self.onicecandidate !== null) { - self.onicecandidate(new Event('icecandidate')); - } - self.iceGatheringState = 'complete'; - } - break; - case 'complete': - // should not happen... currently! - break; - default: // no-op. - break; - } - }; - iceTransport.onicestatechange = function() { - self._updateConnectionState(); - }; - - var dtlsTransport = new RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - self._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - dtlsTransport.state = 'failed'; - self._updateConnectionState(); - }; - - return { - iceGatherer: iceGatherer, - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Start the RTP Sender and Receiver for a transceiver. - window.RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = this._getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - params.encodings = transceiver.recvEncodingParameters; - params.rtcp = { - cname: transceiver.cname - }; - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - window.RTCPeerConnection.prototype.setLocalDescription = - function(description) { - var self = this; - var sections; - var sessionpart; - if (description.type === 'offer') { - // FIXME: What was the purpose of this empty if statement? - // if (!this._pendingOffer) { - // } else { - if (this._pendingOffer) { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - self._pendingOffer[sdpMLineIndex].localCapabilities = caps; - }); - this.transceivers = this._pendingOffer; - delete this._pendingOffer; - } - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(self.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = self.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - var rejected = mediaSection.split('\n', 1)[0] - .split(' ', 2)[1] === '0'; - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - if (isIceLite) { - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === '1'; - }); - // ice-lite only includes host candidates in the SDP so we can - // use setRemoteCandidates (which implies an - // RTCIceCandidateComplete) - if (cands.length) { - iceTransport.setRemoteCandidates(cands); - } - } - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - dtlsTransport.start(remoteDtlsParameters); - } - - // Calculate intersection of capabilities. - var params = self._getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - self._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - // If a success callback was provided, emit ICE candidates after it - // has been executed. Otherwise, emit callback after the Promise is - // resolved. - var hasCallback = arguments.length > 1 && - typeof arguments[1] === 'function'; - if (hasCallback) { - var cb = arguments[1]; - window.setTimeout(function() { - cb(); - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - } - self._emitBufferedCandidates(); - }, 0); - } - var p = Promise.resolve(); - p.then(function() { - if (!hasCallback) { - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - } - // Usually candidates will be emitted earlier. - window.setTimeout(self._emitBufferedCandidates.bind(self), 500); - } - }); - return p; - }; - - window.RTCPeerConnection.prototype.setRemoteDescription = - function(description) { - var self = this; - var stream = new MediaStream(); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - this.usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].substr(2).split(' '); - var kind = mline[0]; - var rejected = mline[1] === '0'; - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:'); - if (mid.length) { - mid = mid[0].substr(6); - } else { - mid = SDPUtils.generateIdentifier(); - } - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && mline[2] === 'DTLS/SCTP') { - self.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpSender; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - cname = remoteSsrc.value; - } - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === '1'; - }); - if (description.type === 'offer' && !rejected) { - var transports = self.usingBundle && sdpMLineIndex > 0 ? { - iceGatherer: self.transceivers[0].iceGatherer, - iceTransport: self.transceivers[0].iceTransport, - dtlsTransport: self.transceivers[0].dtlsTransport - } : self._createIceAndDtlsTransports(mid, sdpMLineIndex); - - if (isComplete) { - transports.iceTransport.setRemoteCandidates(cands); - } - - localCapabilities = RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - - sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind); - - track = rtpReceiver.track; - receiverList.push([track, rtpReceiver]); - // FIXME: not correct when there are multiple streams but that is - // not currently supported in this shim. - stream.addTrack(track); - - // FIXME: look at direction. - if (self.localStreams.length > 0 && - self.localStreams[0].getTracks().length >= sdpMLineIndex) { - var localTrack; - if (kind === 'audio') { - localTrack = self.localStreams[0].getAudioTracks()[0]; - } else if (kind === 'video') { - localTrack = self.localStreams[0].getVideoTracks()[0]; - } - if (localTrack) { - rtpSender = new RTCRtpSender(localTrack, - transports.dtlsTransport); - } - } - - self.transceivers[sdpMLineIndex] = { - iceGatherer: transports.iceGatherer, - iceTransport: transports.iceTransport, - dtlsTransport: transports.dtlsTransport, - localCapabilities: localCapabilities, - remoteCapabilities: remoteCapabilities, - rtpSender: rtpSender, - rtpReceiver: rtpReceiver, - kind: kind, - mid: mid, - cname: cname, - sendEncodingParameters: sendEncodingParameters, - recvEncodingParameters: recvEncodingParameters - }; - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - self._transceive(self.transceivers[sdpMLineIndex], - false, - direction === 'sendrecv' || direction === 'sendonly'); - } else if (description.type === 'answer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpSender = transceiver.rtpSender; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - self.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - self.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - self.transceivers[sdpMLineIndex].cname = cname; - - if ((isIceLite || isComplete) && cands.length) { - iceTransport.setRemoteCandidates(cands); - } - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - dtlsTransport.start(remoteDtlsParameters); - } - - self._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - receiverList.push([track, rtpReceiver]); - stream.addTrack(track); - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - if (stream.getTracks().length) { - self.remoteStreams.push(stream); - window.setTimeout(function() { - var event = new Event('addstream'); - event.stream = stream; - self.dispatchEvent(event); - if (self.onaddstream !== null) { - window.setTimeout(function() { - self.onaddstream(event); - }, 0); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.streams = [stream]; - self.dispatchEvent(event); - if (self.ontrack !== null) { - window.setTimeout(function() { - self.ontrack(trackEvent); - }, 0); - } - }); - }, 0); - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - window.RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - window.RTCPeerConnection.prototype._updateSignalingState = - function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this.dispatchEvent(event); - if (this.onsignalingstatechange !== null) { - this.onsignalingstatechange(event); - } - }; - - // Determine whether to fire the negotiationneeded event. - window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded = - function() { - // Fire away (for now). - var event = new Event('negotiationneeded'); - this.dispatchEvent(event); - if (this.onnegotiationneeded !== null) { - this.onnegotiationneeded(event); - } - }; - - // Update the connection state. - window.RTCPeerConnection.prototype._updateConnectionState = function() { - var self = this; - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== self.iceConnectionState) { - self.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this.dispatchEvent(event); - if (this.oniceconnectionstatechange !== null) { - this.oniceconnectionstatechange(event); - } - } - }; - - window.RTCPeerConnection.prototype.createOffer = function() { - var self = this; - if (this._pendingOffer) { - throw new Error('createOffer called while there is a pending offer.'); - } - var offerOptions; - if (arguments.length === 1 && typeof arguments[0] !== 'function') { - offerOptions = arguments[0]; - } else if (arguments.length === 3) { - offerOptions = arguments[2]; - } - - var tracks = []; - var numAudioTracks = 0; - var numVideoTracks = 0; - // Default to sendrecv. - if (this.localStreams.length) { - numAudioTracks = this.localStreams[0].getAudioTracks().length; - numVideoTracks = this.localStreams[0].getVideoTracks().length; - } - // Determine number of audio and video tracks we need to send/recv. - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - if (offerOptions.offerToReceiveVideo !== undefined) { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - if (this.localStreams.length) { - // Push local streams. - this.localStreams[0].getTracks().forEach(function(track) { - tracks.push({ - kind: track.kind, - track: track, - wantReceive: track.kind === 'audio' ? - numAudioTracks > 0 : numVideoTracks > 0 - }); - if (track.kind === 'audio') { - numAudioTracks--; - } else if (track.kind === 'video') { - numVideoTracks--; - } - }); - } - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - tracks.push({ - kind: 'audio', - wantReceive: true - }); - numAudioTracks--; - } - if (numVideoTracks > 0) { - tracks.push({ - kind: 'video', - wantReceive: true - }); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(); - var transceivers = []; - tracks.forEach(function(mline, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = mline.track; - var kind = mline.kind; - var mid = SDPUtils.generateIdentifier(); - - var transports = self.usingBundle && sdpMLineIndex > 0 ? { - iceGatherer: transceivers[0].iceGatherer, - iceTransport: transceivers[0].iceTransport, - dtlsTransport: transceivers[0].dtlsTransport - } : self._createIceAndDtlsTransports(mid, sdpMLineIndex); - - var localCapabilities = RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - var rtpSender; - var rtpReceiver; - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - rtpSender = new RTCRtpSender(track, transports.dtlsTransport); - } - - if (mline.wantReceive) { - rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind); - } - - transceivers[sdpMLineIndex] = { - iceGatherer: transports.iceGatherer, - iceTransport: transports.iceTransport, - dtlsTransport: transports.dtlsTransport, - localCapabilities: localCapabilities, - remoteCapabilities: null, - rtpSender: rtpSender, - rtpReceiver: rtpReceiver, - kind: kind, - mid: mid, - sendEncodingParameters: sendEncodingParameters, - recvEncodingParameters: null - }; - }); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - tracks.forEach(function(mline, sdpMLineIndex) { - var transceiver = transceivers[sdpMLineIndex]; - sdp += SDPUtils.writeMediaSection(transceiver, - transceiver.localCapabilities, 'offer', self.localStreams[0]); - }); - - this._pendingOffer = transceivers; - var desc = new RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - window.RTCPeerConnection.prototype.createAnswer = function() { - var self = this; - - var sdp = SDPUtils.writeSessionBoilerplate(); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - this.transceivers.forEach(function(transceiver) { - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - // Calculate intersection of capabilities. - var commonCapabilities = self._getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities, - 'answer', self.localStreams[0]); - }); - - var desc = new RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - if (!candidate) { - this.transceivers.forEach(function(transceiver) { - transceiver.iceTransport.addRemoteCandidate({}); - }); - } else { - var mLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - mLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[mLineIndex]; - if (transceiver) { - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return; - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component !== '1') { - return; - } - // A dirty hack to make samples work. - if (cand.type === 'endOfCandidates') { - cand = {}; - } - transceiver.iceTransport.addRemoteCandidate(cand); - - // update the remoteDescription. - var sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim() - : 'a=end-of-candidates') + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - window.RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var cb = arguments.length > 1 && typeof arguments[1] === 'function' && - arguments[1]; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - results.set(id, result[id]); - results[id] = result[id]; - }); - }); - if (cb) { - window.setTimeout(cb, 0, results); - } - resolve(results); - }); - }); - }; - } -}; - -// Expose public methods. -module.exports = { - shimPeerConnection: edgeShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; - -},{"../utils":68,"./getusermedia":64,"sdp":59}],64:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function() { - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],65:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var browserDetails = require('../utils').browserDetails; - -var firefoxShim = { - shimOnTrack: function() { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - }, - - shimSourceObject: function() { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - 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() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function() { - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 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); - }; - window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = mozRTCSessionDescription; - window.RTCIceCandidate = mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - RTCIceCandidate : RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - RTCPeerConnection.prototype.addIceCandidate; - RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - if (browserDetails.version < 48) { - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var nativeGetStats = RTCPeerConnection.prototype.getStats; - RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - return makeMapStats(stats); - }) - .then(onSucc, onErr); - }; - } - } -}; - -// Expose public methods. -module.exports = { - shimOnTrack: firefoxShim.shimOnTrack, - shimSourceObject: firefoxShim.shimSourceObject, - shimPeerConnection: firefoxShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; - -},{"../utils":68,"./getusermedia":66}],66:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var logging = require('../utils').log; -var browserDetails = require('../utils').browserDetails; - -// Expose public methods. -module.exports = function() { - var shimError_ = function(e) { - return { - name: { - SecurityError: 'NotAllowedError', - PermissionDeniedError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var 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; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - 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 (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - console.warn('navigator.getUserMedia has been replaced by ' + - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":68}],67:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ -'use strict'; -var safariShim = { - // TODO: DrAlex, should be here, double check against LayoutTests - // shimOnTrack: function() { }, - - // TODO: once the back-end for the mac port is done, add. - // TODO: check for webkitGTK+ - // shimPeerConnection: function() { }, - - shimGetUserMedia: function() { - navigator.getUserMedia = navigator.webkitGetUserMedia; - } -}; - -// Expose public methods. -module.exports = { - shimGetUserMedia: safariShim.shimGetUserMedia - // TODO - // shimOnTrack: safariShim.shimOnTrack, - // shimPeerConnection: safariShim.shimPeerConnection -}; - -},{}],68:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; - -// Utility methods. -var utils = { - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ - extractVersion: function(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function() { - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - // Firefox. - if (navigator.mozGetUserMedia) { - result.browser = 'firefox'; - result.version = this.extractVersion(navigator.userAgent, - /Firefox\/([0-9]+)\./, 1); - - // all webkit-based browsers - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera, all use the chrome shim for now - if (window.webkitRTCPeerConnection) { - result.browser = 'chrome'; - result.version = this.extractVersion(navigator.userAgent, - /Chrom(e|ium)\/([0-9]+)\./, 2); - - // Safari or unknown webkit-based - // for the time being Safari has support for MediaStreams but not webRTC - } else { - // Safari UA substrings of interest for reference: - // - webkit version: AppleWebKit/602.1.25 (also used in Op,Cr) - // - safari UI version: Version/9.0.3 (unique to Safari) - // - safari UI webkit version: Safari/601.4.4 (also used in Op,Cr) - // - // if the webkit version and safari UI webkit versions are equals, - // ... this is a stable version. - // - // only the internal webkit version is important today to know if - // media streams are supported - // - if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) { - result.browser = 'safari'; - result.version = this.extractVersion(navigator.userAgent, - /AppleWebKit\/([0-9]+)\./, 1); - - // unknown webkit-based browser - } else { - result.browser = 'Unsupported webkit-based browser ' + - 'with GUM support but no WebRTC support.'; - return result; - } - } - - // Edge. - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { - result.browser = 'edge'; - result.version = this.extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - - // Default fallthrough: not supported. - } else { - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -// Export. -module.exports = { - log: utils.log, - disableLog: utils.disableLog, - browserDetails: utils.detectBrowser(), - extractVersion: utils.extractVersion -}; - -},{}],69:[function(require,module,exports){ (function (global){ /* global Blob File */ @@ -29736,14 +26837,14 @@ function hasBinary (obj) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"isarray":70}],70:[function(require,module,exports){ +},{"isarray":59}],59:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],71:[function(require,module,exports){ +},{}],60:[function(require,module,exports){ /** * Module exports. @@ -29762,18 +26863,20 @@ try { module.exports = false; } -},{}],72:[function(require,module,exports){ +},{}],61:[function(require,module,exports){ const Output = require('./src/output.js') const loop = require('raf-loop') const Source = require('./src/hydra-source.js') -const GeneratorFactory = require('./src/GeneratorFactory.js') -const getUserMedia = require('getusermedia') -const mouse = require('mouse-change')() -const Audio = require('./src/audio.js') -const VidRecorder = require('./src/video-recorder.js') +const Mouse = require('mouse-change')() +const Audio = require('./src/lib/audio.js') +const VidRecorder = require('./src/lib/video-recorder.js') +const ArrayUtils = require('./src/lib/array-utils.js') +const Sandbox = require('./src/eval-sandbox.js') + +const Generator = require('./src/generator-factory.js') // to do: add ability to pass in certain uniforms and transforms -class HydraSynth { +class HydraRenderer { constructor ({ pb = null, @@ -29785,50 +26888,75 @@ class HydraSynth { autoLoop = true, detectAudio = true, enableStreamCapture = true, - canvas + canvas, + precision = 'mediump', + extendTransforms = {} // add your own functions on init } = {}) { - this.bpm = 60 this.pb = pb this.width = width this.height = height - this.time = 0 - this.makeGlobal = makeGlobal this.renderAll = false this.detectAudio = detectAudio + // object that contains all properties that will be made available on the global context and during local evaluation + this.synth = { + time: 0, + bpm: 30, + width: this.width, + height: this.height, + fps: null, + mouse: Mouse, + render: this._render.bind(this), + resize: this.resize.bind(this), + update: (dt) => {} // user defined update function + } + + // only allow valid precision options + let precisionOptions = ['lowp','mediump','highp'] + let precisionValid = precisionOptions.includes(precision.toLowerCase()) + + this.precision = precisionValid ? precision.toLowerCase() : 'mediump' + + if(!precisionValid){ + console.warn('[hydra-synth warning]\nConstructor was provided an invalid floating point precision value of "' + precision + '". Using default value of "mediump" instead.') + } + + this.extendTransforms = extendTransforms + // boolean to store when to save screenshot this.saveFrame = false // if stream capture is enabled, this object contains the capture stream this.captureStream = null + this.generator = undefined + this._initCanvas(canvas) this._initRegl() this._initOutputs(numOutputs) this._initSources(numSources) this._generateGlslTransforms() - window.screencap = () => { + this.synth.screencap = () => { this.saveFrame = true } if (enableStreamCapture) { this.captureStream = this.canvas.captureStream(25) - // to do: enable capture stream of specific sources and outputs - window.vidRecorder = new VidRecorder(this.captureStream) + this.synth.vidRecorder = new VidRecorder(this.captureStream) } if(detectAudio) this._initAudio() - //if(makeGlobal) { - window.mouse = mouse - window.time = this.time - window['render'] = this.render.bind(this) - // window.bpm = this.bpm - window.bpm = this._setBpm.bind(this) - // } + if(autoLoop) loop(this.tick.bind(this)).start() + + this.sandbox = new Sandbox(this.synth, makeGlobal) + } + + eval(code) { + this.sandbox.eval(code) } getScreenImage(callback) { @@ -29836,6 +26964,20 @@ class HydraSynth { this.saveFrame = true } + resize(width, height) { + // console.log(width, height) + this.canvas.width = width + this.canvas.height = height + this.width = width + this.height = height + this.o.forEach((output) => { + output.resize(width, height) + }) + this.s.forEach((source) => { + source.resize(width, height) + }) + } + canvasToImage (callback) { const a = document.createElement('a') a.style.display = 'none' @@ -29845,8 +26987,6 @@ class HydraSynth { document.body.appendChild(a) var self = this this.canvas.toBlob( (blob) => { - // var url = window.URL.createObjectURL(blob) - if(self.imageCallback){ self.imageCallback(blob) delete self.imageCallback @@ -29863,11 +27003,24 @@ class HydraSynth { } _initAudio () { - this.audio = new Audio({ - numBins: 4 + const that = this + this.synth.a = new Audio({ + numBins: 4, + // changeListener: ({audio}) => { + // that.a = audio.bins.map((_, index) => + // (scale = 1, offset = 0) => () => (audio.fft[index] * scale + offset) + // ) + // + // if (that.makeGlobal) { + // that.a.forEach((a, index) => { + // const aname = `a${index}` + // window[aname] = a + // }) + // } + // } }) - if(this.makeGlobal) window.a = this.audio } + // create main output canvas and add to screen _initCanvas (canvas) { if (canvas) { @@ -29886,16 +27039,18 @@ class HydraSynth { _initRegl () { this.regl = require('regl')({ + // profile: true, canvas: this.canvas, - pixelRatio: 1, - extensions: [ - 'oes_texture_half_float', - 'oes_texture_half_float_linear' - ], - optionalExtensions: [ - 'oes_texture_float', - 'oes_texture_float_linear' - ]}) + pixelRatio: 1//, + // extensions: [ + // 'oes_texture_half_float', + // 'oes_texture_half_float_linear' + // ], + // optionalExtensions: [ + // 'oes_texture_float', + // 'oes_texture_float_linear' + //] + }) // This clears the color buffer to black and the depth buffer to 1 this.regl.clear({ @@ -29904,7 +27059,7 @@ class HydraSynth { this.renderAll = this.regl({ frag: ` - precision mediump float; + precision ${this.precision} float; varying vec2 uv; uniform sampler2D tex0; uniform sampler2D tex1; @@ -29932,7 +27087,7 @@ class HydraSynth { } `, vert: ` - precision mediump float; + precision ${this.precision} float; attribute vec2 position; varying vec2 uv; @@ -29959,7 +27114,7 @@ class HydraSynth { this.renderFbo = this.regl({ frag: ` - precision mediump float; + precision ${this.precision} float; varying vec2 uv; uniform vec2 resolution; uniform sampler2D tex0; @@ -29969,7 +27124,7 @@ class HydraSynth { } `, vert: ` - precision mediump float; + precision ${this.precision} float; attribute vec2 position; varying vec2 uv; @@ -29996,10 +27151,15 @@ class HydraSynth { _initOutputs (numOutputs) { const self = this this.o = (Array(numOutputs)).fill().map((el, index) => { - var o = new Output({regl: this.regl, width: this.width, height: this.height}) - o.render() + var o = new Output({ + regl: this.regl, + width: this.width, + height: this.height, + precision: this.precision + }) + // o.render() o.id = index - if (self.makeGlobal) window['o' + index] = o + self.synth['o'+index] = o return o }) @@ -30014,32 +27174,34 @@ class HydraSynth { } } - _setBpm(bpm) { - this.bpm = bpm - } - createSource () { let s = new Source({regl: this.regl, pb: this.pb, width: this.width, height: this.height}) - if(this.makeGlobal) { - window['s' + this.s.length] = s - } + this.synth['s' + this.s.length] = s this.s.push(s) return s } _generateGlslTransforms () { - const self = this - const gen = new GeneratorFactory(this.o[0]) - window.generator = gen - Object.keys(gen.functions).forEach((key)=>{ - self[key] = gen.functions[key] - if(self.makeGlobal === true) { - window[key] = gen.functions[key] + var self = this + this.generator = new Generator({ + defaultOutput: this.o[0], + defaultUniforms: this.o[0].uniforms, + extendTransforms: this.extendTransforms, + changeListener: ({type, method, synth}) => { + if (type === 'add') { + self.synth[method] = synth.generators[method] + if(self.sandbox) self.sandbox.add(method) + } else if (type === 'remove') { + // what to do here? dangerously deleting window methods + //delete window[method] + } + // } } }) + this.synth.setFunction = this.generator.setFunction.bind(this.generator) } - render (output) { + _render (output) { if (output) { this.output = output this.isRenderingAll = false @@ -30049,31 +27211,23 @@ class HydraSynth { } tick (dt, uniforms) { - - // if(self.detectAudio === true) self.fft = self.audio.frequencies() - // this.regl.frame(function () { - this.time += dt * 0.001 - // console.log(this.time) - // this.regl.clear({ - // color: [0, 0, 0, 1] - // }) - window.time = this.time - if(this.detectAudio === true) this.audio.tick() + this.synth.time += dt * 0.001 + if(this.synth.update) { + try { this.synth.update(dt) } catch (e) { console.log(error) } + } + if(this.detectAudio === true) this.synth.a.tick() for (let i = 0; i < this.s.length; i++) { - this.s[i].tick(this.time) + this.s[i].tick(this.synth.time) } for (let i = 0; i < this.o.length; i++) { - // console.log('WIDTH', this.canvas.width, this.o[0].getCurrent()) this.o[i].tick({ - time: this.time, - mouse: mouse, - bpm: this.bpm, + time: this.synth.time, + mouse: this.synth.mouse, + bpm: this.synth.bpm, resolution: [this.canvas.width, this.canvas.height] }) } - - // console.log("looping", self.o[0].fbo) if (this.isRenderingAll) { this.renderAll({ tex0: this.o[0].getCurrent(), @@ -30083,7 +27237,7 @@ class HydraSynth { resolution: [this.canvas.width, this.canvas.height] }) } else { - // console.log('out', self.output.id) + this.renderFbo({ tex0: this.output.getCurrent(), resolution: [this.canvas.width, this.canvas.height] @@ -30093,219 +27247,319 @@ class HydraSynth { this.canvasToImage() this.saveFrame = false } + // this.regl.poll() } } -module.exports = HydraSynth +module.exports = HydraRenderer -},{"./src/GeneratorFactory.js":73,"./src/audio.js":74,"./src/hydra-source.js":78,"./src/output.js":81,"./src/video-recorder.js":85,"getusermedia":58,"mouse-change":93,"raf-loop":102,"regl":114}],73:[function(require,module,exports){ -/* globals tex */ -const { seq, sin, ramp, createFades } = require('./timingUtils.js') -const glslTransforms = require('./composable-glsl-functions.js') +},{"./src/eval-sandbox.js":63,"./src/generator-factory.js":64,"./src/hydra-source.js":69,"./src/lib/array-utils.js":70,"./src/lib/audio.js":71,"./src/lib/video-recorder.js":76,"./src/output.js":78,"mouse-change":85,"raf-loop":94,"regl":106}],62:[function(require,module,exports){ +const Synth = require('./hydra-synth.js') +//const ShaderGenerator = require('./shader-generator.js') -// in progress: implementing multiple renderpasses within a single -// function string -const renderPassFunctions = require('./renderpass-functions.js') +module.exports = Synth -const counter = require('./counter.js') -const shaderManager = require('./shaderManager.js') +// console.log('module', module) +// +// console.log('exports', exports) +// +// module.exports = { +// synth : Synth, +// shaderGenerator: ShaderGenerator +// } +// // }else{ +// // var Hydra = { +// // synth: Synth, +// // shaderGenerator: shaderGenerator +// // } +// // } -var Generator = function (param) { - return Object.create(Generator.prototype) -} +},{"./hydra-synth.js":61}],63:[function(require,module,exports){ +// handles code evaluation and attaching relevant objects to global and evaluation contexts -// Functions that return a new transformation function based on the existing function chain as well -// as the new function passed in. -const compositionFunctions = { - coord: existingF => newF => x => existingF(newF(x)), // coord transforms added onto beginning of existing function chain - color: existingF => newF => x => newF(existingF(x)), // color transforms added onto end of existing function chain - combine: existingF1 => existingF2 => newF => x => newF(existingF1(x))(existingF2(x)), // - combineCoord: existingF1 => existingF2 => newF => x => existingF1(newF(x)(existingF2(x))) -} -// gl_FragColor = osc(modulate(osc(rotate(st, 10., 0.), 32., 0.1, 0.), st, 0.5), 199., 0.1, 0.); +const Sandbox = require('./lib/sandbox.js') +const ArrayUtils = require('./lib/array-utils.js') -// hydra code: osc().rotate().color().repeat().out() -// pseudo shader code: gl_FragColor = color(osc(rotate(repeat()))) - -// hydra code: osc().rotate().add(s0).repeat().out() -// gl_FragColor = osc(rotate(repeat())) + tex(repeat()) - -// Parses javascript args to use in glsl -function generateGlsl (inputs) { - var str = '' - inputs.forEach((input) => { - str += ', ' + input.name - }) - return str -} - -// when possible, reformats arguments to be the correct type -// creates unique names for variables requiring a uniform to be passed in (i.e. a texture) -// returns an object that contains the type and value of each argument -// to do: add much more type checking, validation, and transformation to this part -function formatArguments (userArgs, defaultArgs) { - return defaultArgs.map((input, index) => { - var typedArg = {} - - // if there is a user input at a certain index, create a uniform for this variable so that the value is passed in on each render pass - // to do (possibly): check whether this is a function in order to only use uniforms when needed - - counter.increment() - typedArg.name = input.name + counter.get() - typedArg.isUniform = true - - if (userArgs.length > index) { - // console.log("arg", userArgs[index]) - typedArg.value = userArgs[index] - // if argument passed in contains transform property, i.e. is of type generator, do not add uniform - if (userArgs[index].transform) typedArg.isUniform = false - - if (typeof userArgs[index] === 'function') { - typedArg.value = (context, props, batchId) => (userArgs[index](props)) - } else if (userArgs[index].constructor === Array) { - // console.log("is Array") - typedArg.value = (context, props, batchId) => seq(userArgs[index])(props) - } - } else { - // use default value for argument - typedArg.value = input.default - } - // if input is a texture, set unique name for uniform - if (input.type === 'texture') { - // typedArg.tex = typedArg.value - var x = typedArg.value - typedArg.value = () => (x.getTexture()) - } else { - // if passing in a texture reference, when function asks for vec4, convert to vec4 - if (typedArg.value.getTexture && input.type === 'vec4') { - var x1 = typedArg.value - typedArg.value = src(x1) - typedArg.isUniform = false - } - } - typedArg.type = input.type - return typedArg - }) -} - - -var GeneratorFactory = function (defaultOutput) { - - let self = this - self.functions = {} - - // set global utility functions. to do: make global optional - window.sin = sin - window.ramp = ramp - window.frag = shaderManager(defaultOutput) - - createFades(6) - // extend Array prototype - Array.prototype.fast = function(speed) { - // console.log("array fast", speed, this) - this.speed = speed - return this +class EvalSandbox { + constructor(parent, makeGlobal) { + this.makeGlobal = makeGlobal + this.sandbox = Sandbox(parent) + this.parent = parent + var properties = Object.keys(parent) + properties.forEach((property) => this.add(property)) } - Object.keys(glslTransforms).forEach((method) => { - const transform = glslTransforms[method] + add(name) { + if(this.makeGlobal) window[name] = this.parent[name] + this.sandbox.addToContext(name, `parent.${name}`) + } - // if type is a source, create a new global generator function that inherits from Generator object + eval(code) { + this.sandbox.eval(code) + } +} + +module.exports = EvalSandbox + +},{"./lib/array-utils.js":70,"./lib/sandbox.js":74}],64:[function(require,module,exports){ +const glslTransforms = require('./glsl/composable-glsl-functions.js') +const GlslSource = require('./glsl-source.js') + +//const renderpassFunctions = require('./glsl/renderpass-functions.js') + +Array.prototype.fast = function (speed) { + this.speed = speed + return this +} + +class GeneratorFactory { + constructor ({ + defaultUniforms, + defaultOutput, + extendTransforms = (x => x), + changeListener = (() => {}) + } = {} + ) { + this.defaultOutput = defaultOutput + this.defaultUniforms = defaultUniforms + this.changeListener = changeListener + this.extendTransforms = extendTransforms + this.generators = {} + this.init() + } + init () { + this.glslTransforms = {} + this.generators = Object.entries(this.generators).reduce((prev, [method, transform]) => { + this.changeListener({type: 'remove', synth: this, method}) + return prev + }, {}) + + this.sourceClass = (() => { + return class extends GlslSource { + } + })() + + let functions = {} + const addTransforms = (transforms) => + Object.entries(transforms).forEach(([method, transform]) => { + functions[method] = transform + }) + + addTransforms(glslTransforms) + //addTransforms(renderpassFunctions) + + if (typeof this.extendTransforms === 'function') { + functions = this.extendTransforms(functions) + } else if (Array.isArray(this.extendTransforms)) { + addTransforms(this.extendTransforms.reduce((h, transform) => { + h[transform.name] = transform + return h + }, {})) + } else if (typeof this.extendTransforms === 'object') { + addTransforms(this.extendTransforms) + } + + Object.entries(functions).forEach(([method, transform]) => { + if (typeof transform.glsl_return_type === 'undefined' && transform.glsl) { + transform.glsl_return_type = transform.glsl.replace(new RegExp(`^(?:[\\s\\S]*\\W)?(\\S+)\\s+${method}\\s*[(][\\s\\S]*`, 'ugm'), '$1') + } + + functions[method] = this._addMethod(method, transform) + }) + + return functions + } + + _addMethod (method, transform) { + console.log('adding', method, transform) + this.glslTransforms[method] = transform if (transform.type === 'src') { - self.functions[method] = (...args) => { - var obj = Object.create(Generator.prototype) - obj.name = method - const inputs = formatArguments(args, transform.inputs) - obj.transform = (x) => { - var glslString = `${method}(${x}` - glslString += generateGlsl(inputs) - glslString += ')' - return glslString - } - obj.defaultOutput = defaultOutput - obj.uniforms = [] - inputs.forEach((input, index) => { - if (input.isUniform) { - obj.uniforms.push(input) - } - }) - - obj.passes = [] - let pass = { - transform: (x) => { - var glslString = `${method}(${x}` - glslString += generateGlsl(inputs) - glslString += ')' - return glslString - }, - uniforms: [] - } - inputs.forEach((input, index) => { - if (input.isUniform) { - pass.uniforms.push(input) - } - }) - obj.passes.push(pass) - return obj - } - } else { - Generator.prototype[method] = function (...args) { - const inputs = formatArguments(args, transform.inputs) - - if (transform.type === 'combine' || transform.type === 'combineCoord') { - // composition function to be executed when all transforms have been added - // c0 and c1 are two inputs.. (explain more) - var f = (c0) => (c1) => { - var glslString = `${method}(${c0}, ${c1}` - glslString += generateGlsl(inputs.slice(1)) - glslString += ')' - return glslString - } - this.transform = compositionFunctions[glslTransforms[method].type](this.transform)(inputs[0].value.transform)(f) - - this.uniforms = this.uniforms.concat(inputs[0].value.uniforms) - - var pass = this.passes[this.passes.length - 1] - pass.transform = this.transform - pass.uniform + this.uniform - } else { - var f1 = (x) => { - var glslString = `${method}(${x}` - glslString += generateGlsl(inputs) - glslString += ')' - return glslString - } - this.transform = compositionFunctions[glslTransforms[method].type](this.transform)(f1) - this.passes[this.passes.length - 1].transform = this.transform - } - - inputs.forEach((input, index) => { - if (input.isUniform) { - this.uniforms.push(input) - } - }) - this.passes[this.passes.length - 1].uniforms = this.uniforms + const func = (...args) => new this.sourceClass({ + name: method, + transform: transform, + userArgs: args, + defaultOutput: this.defaultOutput, + defaultUniforms: this.defaultUniforms, + synth: this + }) + this.generators[method] = func + this.changeListener({type: 'add', synth: this, method}) + return func + } else { + this.sourceClass.prototype[method] = function (...args) { + this.transforms.push({name: method, transform: transform, userArgs: args}) return this } } - }) + return undefined + } + + setFunction(obj) { + var processedGlsl = processGlsl(obj) + console.log(processedGlsl) + this._addMethod(obj.name, processedGlsl) + } } -// -// iterate through transform types and create a function for each -// -Generator.prototype.compile = function (pass) { -// console.log("compiling", pass) + + +const typeLookup = { + 'src': { + returnType: 'vec4', + args: ['vec2 _st'] + }, + 'coord': { + returnType: 'vec2', + args: ['vec2 _st'] + }, + 'color': { + returnType: 'vec4', + args: ['vec4 _c0'] + }, + 'combine': { + returnType: 'vec4', + args: ['vec4 _c0', 'vec4 _c1'] + }, + 'combineCoords': { + returnType: 'vec2', + args: ['vec2 _st', 'vec4 c0'] + } +} +// expects glsl of format +// { +// name: 'osc', // name that will be used to access function as well as within glsl +// type: 'src', // can be src: vec4(vec2 _st), coord: vec2(vec2 _st), color: vec4(vec4 _c0), combine: vec4(vec4 _c0, vec4 _c1), combineCoord: vec2(vec2 _st, vec4 _c0) +// inputs: [ +// { +// name: 'freq', +// type: 'float', // 'float' //, 'texture', 'vec4' +// default: 0.2 +// }, +// { +// name: 'sync', +// type: 'float', +// default: 0.1 +// }, +// { +// name: 'offset', +// type: 'float', +// default: 0.0 +// } +// ], + // glsl: ` + // vec2 st = _st; + // float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; + // float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; + // float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; + // return vec4(r, g, b, 1.0); + // ` +// } + +// // generates glsl function: +// `vec4 osc(vec2 _st, float freq, float sync, float offset){ +// vec2 st = _st; +// float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; +// float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; +// float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; +// return vec4(r, g, b, 1.0); +// }` + +function processGlsl(obj) { + let t = typeLookup[obj.type] + let baseArgs = t.args.map((arg) => arg).join(", ") + // @todo: make sure this works for all input types, add validation + let customArgs = obj.inputs.map((input) => `${input.type} ${input.name}`).join(', ') + let args = `${baseArgs}${customArgs.length > 0 ? ', '+ customArgs: ''}` + console.log('args are ', args) + if(t) { + let glslFunction = +` + ${t.returnType} ${obj.name}(${args}) { + ${obj.glsl} + } +` + console.log('function', glslFunction) + return Object.assign({}, obj, { glsl: glslFunction}) + } else { + console.error(`type ${obj.type} not recognized`) + } + +} + +module.exports = GeneratorFactory + +},{"./glsl-source.js":65,"./glsl/composable-glsl-functions.js":67}],65:[function(require,module,exports){ +const generateGlsl = require('./glsl-utils.js').generateGlsl +const formatArguments = require('./glsl-utils.js').formatArguments + +const glslTransforms = require('./glsl/composable-glsl-functions.js') +const utilityGlsl = require('./glsl/utility-functions.js') + +var GlslSource = function (obj) { + this.transforms = [] + this.transforms.push(obj) + this.defaultOutput = obj.defaultOutput + this.synth = obj.synth + this.defaultUniforms = obj.defaultUniforms + return this +} + +GlslSource.prototype.addTransform = function (obj) { + this.transforms.push(obj) +} + +GlslSource.prototype.out = function (_output) { + var output = _output || this.defaultOutput + var glsl = this.glsl(output) + this.synth.currentFunctions = [] + // output.renderPasses(glsl) + if(output) output.render(glsl) +} + +GlslSource.prototype.glsl = function () { + //var output = _output || this.defaultOutput + var self = this + // uniforms included in all shaders +// this.defaultUniforms = output.uniforms + var passes = [] + var transforms = [] +// console.log('output', output) + this.transforms.forEach((transform) => { + if(transform.transform.type === 'renderpass'){ + if (transforms.length > 0) passes.push(this.compile(transforms, output)) + transforms = [] + var uniforms = {} + const inputs = formatArguments(transform, -1) + inputs.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) + + passes.push({ + frag: transform.transform.frag, + uniforms: Object.assign({}, self.defaultUniforms, uniforms) + }) + transforms.push({name: 'prev', transform: glslTransforms['prev'], synth: this.synth}) + } else { + transforms.push(transform) + } + }) + + if (transforms.length > 0) passes.push(this.compile(transforms)) + + return passes +} + +GlslSource.prototype.compile = function (transforms) { + + var shaderInfo = generateGlsl(transforms) + var uniforms = {} + shaderInfo.uniforms.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) + var frag = ` precision mediump float; - ${pass.uniforms.map((uniform) => { - let type = '' + ${Object.values(shaderInfo.uniforms).map((uniform) => { + let type = uniform.type switch (uniform.type) { - case 'float': - type = 'float' - break case 'texture': type = 'sampler2D' break @@ -30316,407 +27570,257 @@ Generator.prototype.compile = function (pass) { uniform float time; uniform vec2 resolution; varying vec2 uv; + uniform sampler2D prevBuffer; - ${Object.values(glslTransforms).map((transform) => { + ${Object.values(utilityGlsl).map((transform) => { // console.log(transform.glsl) return ` ${transform.glsl} ` }).join('')} + ${shaderInfo.glslFunctions.map((transform) => { + return ` + ${transform.transform.glsl} + ` + }).join('')} + void main () { vec4 c = vec4(1, 0, 0, 1); - //vec2 st = uv; - vec2 st = gl_FragCoord.xy/resolution; - gl_FragColor = ${pass.transform('st')}; + vec2 st = gl_FragCoord.xy/resolution.xy; + gl_FragColor = ${shaderInfo.fragColor}; } ` - return frag -} -// creates a fragment shader from an object containing uniforms and a snippet of -// fragment shader code -Generator.prototype.compileRenderPass = function (pass) { - var frag = ` - precision mediump float; - ${pass.uniforms.map((uniform) => { - let type = '' - switch (uniform.type) { - case 'float': - type = 'float' - break - case 'texture': - type = 'sampler2D' - break - } - return ` - uniform ${type} ${uniform.name};` - }).join('')} - uniform float time; - uniform vec2 resolution; - uniform sampler2D prevBuffer; - varying vec2 uv; - - ${Object.values(renderPassFunctions).filter(transform => transform.type === 'renderpass_util') - .map((transform) => { - // console.log(transform.glsl) - return ` - ${transform.glsl} - ` - }).join('')} - - ${pass.glsl} - ` - return frag -} - -Generator.prototype.glsl = function (_output) { - var output = _output || this.defaultOutput - - var passes = this.passes.map((pass) => { - var uniforms = {} - pass.uniforms.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) - if(pass.hasOwnProperty('transform')){ - // console.log(" rendering pass", pass) - - return { - frag: this.compile(pass), - uniforms: Object.assign(output.uniforms, uniforms) - } - } else { - // console.log(" not rendering pass", pass) - return { - frag: pass.frag, - uniforms: Object.assign(output.uniforms, uniforms) - } - } - }) - return passes -} - - - -Generator.prototype.out = function (_output) { -// console.log('UNIFORMS', this.uniforms, output) - var output = _output || this.defaultOutput - - output.renderPasses(this.glsl(output)) + return { + frag: frag, + uniforms: Object.assign({}, this.defaultUniforms, uniforms) + } } -module.exports = GeneratorFactory +module.exports = GlslSource -},{"./composable-glsl-functions.js":75,"./counter.js":76,"./renderpass-functions.js":82,"./shaderManager.js":83,"./timingUtils.js":84}],74:[function(require,module,exports){ -const Meyda = require('meyda') -const getUserMedia = require('getusermedia') +},{"./glsl-utils.js":66,"./glsl/composable-glsl-functions.js":67,"./glsl/utility-functions.js":68}],66:[function(require,module,exports){ +// converts a tree of javascript functions to a shader -class Audio { - constructor ({ - numBins = 4, - cutoff = 2, - smooth = 0.4, - max = 15, - scale = 10, - isDrawing = false - }) { - this.vol = 0 - this.scale = scale - this.max = max - this.cutoff = cutoff - this.smooth = smooth - this.setBins(numBins) +// Add extra functionality to Array.prototype for generating sequences in time +const arrayUtils = require('./lib/array-utils.js') - // beat detection from: https://github.com/therewasaguy/p5-music-viz/blob/gh-pages/demos/01d_beat_detect_amplitude/sketch.js - this.beat = { - holdFrames: 20, - threshold: 40, - _cutoff: 0, // adaptive based on sound state - decay: 0.98, - _framesSinceBeat: 0 // keeps track of frames - } - - this.onBeat = () => { - console.log("beat") - } - - this.canvas = document.createElement('canvas') - this.canvas.width = 100 - this.canvas.height = 80 - this.canvas.style.width = "100px" - this.canvas.style.height = "80px" - this.canvas.style.position = 'absolute' - this.canvas.style.right = '0px' - this.canvas.style.bottom = '0px' - document.body.appendChild(this.canvas) - - this.isDrawing = isDrawing - this.ctx = this.canvas.getContext('2d') - this.ctx.fillStyle="#DFFFFF" - this.ctx.strokeStyle="#0ff" - this.ctx.lineWidth=0.5 - - getUserMedia( - {video: false, audio: true}, - (err, stream) => { - if(err) { - console.log('ERROR', err) - } else { - console.log('got mic stream', stream) - this.stream = stream - this.context = new AudioContext() - // this.context = new AudioContext() - let audio_stream = this.context.createMediaStreamSource(stream) - - console.log(this.context) - this.meyda = Meyda.createMeydaAnalyzer({ - audioContext: this.context, - source: audio_stream, - featureExtractors: [ - 'loudness', - // 'perceptualSpread', - // 'perceptualSharpness', - // 'spectralCentroid' - ] - }) - } - }) - } - - detectBeat (level) { - //console.log(level, this.beat._cutoff) - if (level > this.beat._cutoff && level > this.beat.threshold) { - this.onBeat() - this.beat._cutoff = level *1.2 - this.beat._framesSinceBeat = 0 - } else { - if (this.beat._framesSinceBeat <= this.beat.holdFrames){ - this.beat._framesSinceBeat ++; - } else { - this.beat._cutoff *= this.beat.decay - this.beat._cutoff = Math.max( this.beat._cutoff, this.beat.threshold); - } - } - } - - tick() { - if(this.meyda){ - var features = this.meyda.get() - if(features && features !== null){ - this.vol = features.loudness.total - this.detectBeat(this.vol) - // reduce loudness array to number of bins - const reducer = (accumulator, currentValue) => accumulator + currentValue; - let spacing = Math.floor(features.loudness.specific.length/this.bins.length) - this.prevBins = this.bins.slice(0) - this.bins = this.bins.map((bin, index) => { - return features.loudness.specific.slice(index * spacing, (index + 1)*spacing).reduce(reducer) - }).map((bin, index) => { - // map to specified range - - // return (bin * (1.0 - this.smooth) + this.prevBins[index] * this.smooth) - return (bin * (1.0 - this.settings[index].smooth) + this.prevBins[index] * this.settings[index].smooth) - }) - // var y = this.canvas.height - scale*this.settings[index].cutoff - // this.ctx.beginPath() - // this.ctx.moveTo(index*spacing, y) - // this.ctx.lineTo((index+1)*spacing, y) - // this.ctx.stroke() - // - // var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) - this.fft = this.bins.map((bin, index) => ( - // Math.max(0, (bin - this.cutoff) / (this.max - this.cutoff)) - Math.max(0, (bin - this.settings[index].cutoff)/this.settings[index].scale) - )) - if(this.isDrawing) this.draw() - } - } - } - - setCutoff (cutoff) { - this.cutoff = cutoff - this.settings = this.settings.map((el) => { - el.cutoff = cutoff - return el - }) - } - - setSmooth (smooth) { - this.smooth = smooth - this.settings = this.settings.map((el) => { - el.smooth = smooth - return el - }) - } - - setBins (numBins) { - this.bins = Array(numBins).fill(0) - this.prevBins = Array(numBins).fill(0) - this.fft = Array(numBins).fill(0) - this.settings = Array(numBins).fill(0).map(() => ({ - cutoff: this.cutoff, - scale: this.scale, - smooth: this.smooth - })) - // to do: what to do in non-global mode? - this.bins.forEach((bin, index) => { - window['a' + index] = (scale = 1, offset = 0) => () => (a.fft[index] * scale + offset) - }) - console.log(this.settings) - } - - setScale(scale){ - this.scale = scale - this.settings = this.settings.map((el) => { - el.scale = scale - return el - }) - } - - setMax(max) { - this.max = max - console.log('set max is deprecated') - } - hide() { - this.isDrawing = false - this.canvas.style.display = 'none' - } - - show() { - this.isDrawing = true - this.canvas.style.display = 'block' - - } - - draw () { - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) - var spacing = this.canvas.width / this.bins.length - var scale = this.canvas.height / (this.max * 2) - // console.log(this.bins) - this.bins.forEach((bin, index) => { - - var height = bin * scale - - this.ctx.fillRect(index * spacing, this.canvas.height - height, spacing, height) - - // console.log(this.settings[index]) - var y = this.canvas.height - scale*this.settings[index].cutoff - this.ctx.beginPath() - this.ctx.moveTo(index*spacing, y) - this.ctx.lineTo((index+1)*spacing, y) - this.ctx.stroke() - - var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) - this.ctx.beginPath() - this.ctx.moveTo(index*spacing, yMax) - this.ctx.lineTo((index+1)*spacing, yMax) - this.ctx.stroke() - }) - - - /*var y = this.canvas.height - scale*this.cutoff - this.ctx.beginPath() - this.ctx.moveTo(0, y) - this.ctx.lineTo(this.canvas.width, y) - this.ctx.stroke() - - var yMax = this.canvas.height - scale*this.max - this.ctx.beginPath() - this.ctx.moveTo(0, yMax) - this.ctx.lineTo(this.canvas.width, yMax) - this.ctx.stroke()*/ +// [WIP] how to treat different dimensions (?) +const DEFAULT_CONVERSIONS = { + float: { + 'vec4': {name: 'sum', args: [[1, 1, 1, 1]]}, + 'vec2': {name: 'sum', args: [[1, 1]]} } } -module.exports = Audio - -},{"getusermedia":58,"meyda":92}],75:[function(require,module,exports){ -// to add: ripple: https://www.shadertoy.com/view/4djGzz -// mask -// convolution -// basic sdf shapes -// repeat -// iq color palletes - module.exports = { + generateGlsl: function (transforms) { + var shaderParams = { + uniforms: [], // list of uniforms used in shader + glslFunctions: [], // list of functions used in shader + fragColor: '' + } - _noise: { - type: 'util', - glsl: ` - // Simplex 3D Noise - // by Ian McEwan, Ashima Arts - vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} -vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} - -float _noise(vec3 v){ - const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - -// First corner - vec3 i = floor(v + dot(v, C.yyy) ); - vec3 x0 = v - i + dot(i, C.xxx) ; - -// Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min( g.xyz, l.zxy ); - vec3 i2 = max( g.xyz, l.zxy ); - - // x0 = x0 - 0. + 0.0 * C - vec3 x1 = x0 - i1 + 1.0 * C.xxx; - vec3 x2 = x0 - i2 + 2.0 * C.xxx; - vec3 x3 = x0 - 1. + 3.0 * C.xxx; - -// Permutations - i = mod(i, 289.0 ); - vec4 p = permute( permute( permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) - + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); - -// Gradients -// ( N*N points uniformly over a square, mapped onto an octahedron.) - float n_ = 1.0/7.0; // N=7 - vec3 ns = n_ * D.wyz - D.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) - - vec4 x = x_ *ns.x + ns.yyyy; - vec4 y = y_ *ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4( x.xy, y.xy ); - vec4 b1 = vec4( x.zw, y.zw ); - - vec4 s0 = floor(b0)*2.0 + 1.0; - vec4 s1 = floor(b1)*2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; - vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; - - vec3 p0 = vec3(a0.xy,h.x); - vec3 p1 = vec3(a0.zw,h.y); - vec3 p2 = vec3(a1.xy,h.z); - vec3 p3 = vec3(a1.zw,h.w); - -//Normalise gradients - vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - -// Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); - m = m * m; - return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), - dot(p2,x2), dot(p3,x3) ) ); -} - ` + var gen = generateGlsl(transforms, shaderParams)('st') + shaderParams.fragColor = gen + return shaderParams }, + formatArguments: formatArguments +} +// recursive function for generating shader string from object containing functions and user arguments. Order of functions in string depends on type of function +// to do: improve variable names +function generateGlsl (transforms, shaderParams) { + + // transform function that outputs a shader string corresponding to gl_FragColor + var fragColor = () => '' + // var uniforms = [] + // var glslFunctions = [] + transforms.forEach((transform) => { + var inputs = formatArguments(transform, shaderParams.uniforms.length) + inputs.forEach((input) => { + if(input.isUniform) shaderParams.uniforms.push(input) + }) + + // add new glsl function to running list of functions + if(!contains(transform, shaderParams.glslFunctions)) shaderParams.glslFunctions.push(transform) + + // current function for generating frag color shader code + var f0 = fragColor + if (transform.transform.type === 'src') { + fragColor = (uv) => `${shaderString(uv, transform.name, inputs, shaderParams)}` + } else if (transform.transform.type === 'coord') { + fragColor = (uv) => `${f0(`${shaderString(uv, transform.name, inputs, shaderParams)}`)}` + } else if (transform.transform.type === 'color') { + fragColor = (uv) => `${shaderString(`${f0(uv)}`, transform.name, inputs, shaderParams)}` + } else if (transform.transform.type === 'combine') { + // combining two generated shader strings (i.e. for blend, mult, add funtions) + var f1 = inputs[0].value && inputs[0].value.transforms ? + (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : + (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) + fragColor = (uv) => `${shaderString(`${f0(uv)}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}` + } else if (transform.transform.type === 'combineCoord') { + // combining two generated shader strings (i.e. for modulate functions) + var f1 = inputs[0].value && inputs[0].value.transforms ? + (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : + (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) + fragColor = (uv) => `${f0(`${shaderString(`${uv}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}`)}` + } + }) + + return fragColor +} + +// assembles a shader string containing the arguments and the function name, i.e. 'osc(uv, frequency)' +function shaderString (uv, method, inputs, shaderParams) { + const str = inputs.map((input) => { + if (input.isUniform) { + return input.name + } else if (input.value && input.value.transforms) { + // this by definition needs to be a generator, hence we start with 'st' as the initial value for generating the glsl fragment + return `${generateGlsl(input.value.transforms, shaderParams)('st')}` + } + return input.value + }).reduce((p, c) => `${p}, ${c}`, '') + + return `${method}(${uv}${str})` +} + +// merge two arrays and remove duplicates +function mergeArrays (a, b) { + return a.concat(b.filter(function (item) { + return a.indexOf(item) < 0; + })) +} + +// check whether array +function contains(object, arr) { + for(var i = 0; i < arr.length; i++){ + if(object.name == arr[i].name) return true + } + return false +} + +function fillArrayWithDefaults (arr, len) { + // fill the array with default values if it's too short + while (arr.length < len) { + if (arr.length === 3) { // push a 1 as the default for .a in vec4 + arr.push(1.0) + } else { + arr.push(0.0) + } + } + return arr.slice(0, len) +} + +const ensure_decimal_dot = (val) => { + val = val.toString() + if (val.indexOf('.') < 0) { + val += '.' + } + return val +} + +function formatArguments (transform, startIndex) { +// console.log('processing args', transform, startIndex) + const defaultArgs = transform.transform.inputs + const userArgs = transform.userArgs + return defaultArgs.map( (input, index) => { + const typedArg = { + value: input.default, + type: input.type, // + isUniform: false, + name: input.name, + vecLen: 0 + // generateGlsl: null // function for creating glsl + } + + if (input.type.startsWith('vec')) { + try { + typedArg.vecLen = Number.parseInt(input.type.substr(3)) + } catch (e) { + console.log(`Error determining length of vector input type ${input.type} (${input.name})`) + } + } + + // if user has input something for this argument + if(userArgs.length > index) { + typedArg.value = userArgs[index] + // do something if a composite or transform + + if (typeof userArgs[index] === 'function') { + if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar + typedArg.value = (context, props, batchId) => (fillArrayWithDefaults(userArgs[index](props), typedArg.vecLen)) + } else { + typedArg.value = (context, props, batchId) => (userArgs[index](props)) + } + + typedArg.isUniform = true + } else if (userArgs[index].constructor === Array) { + if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar + typedArg.isUniform = true + typedArg.value = fillArrayWithDefaults(typedArg.value, typedArg.vecLen) + } else { + // console.log("is Array") + typedArg.value = (context, props, batchId) => arrayUtils.getValue(userArgs[index])(props) + typedArg.isUniform = true + } + } + } + + if(startIndex< 0){ + } else { + if (typedArg.value && typedArg.value.transforms) { + const final_transform = typedArg.value.transforms[typedArg.value.transforms.length - 1] + + + + if (final_transform.transform.glsl_return_type !== input.type) { + const defaults = DEFAULT_CONVERSIONS[input.type] + if (typeof defaults !== 'undefined') { + const default_def = defaults[final_transform.transform.glsl_return_type] + if (typeof default_def !== 'undefined') { + const {name, args} = default_def + typedArg.value = typedArg.value[name](...args) + } + } + } + + typedArg.isUniform = false + } else if (typedArg.type === 'float' && typeof typedArg.value === 'number') { + typedArg.value = ensure_decimal_dot(typedArg.value) + } else if (typedArg.type.startsWith('vec') && typeof typedArg.value === 'object' && Array.isArray(typedArg.value)) { + typedArg.isUniform = false + typedArg.value = `${typedArg.type}(${typedArg.value.map(ensure_decimal_dot).join(', ')})` + } else if (input.type === 'texture') { + // typedArg.tex = typedArg.value + var x = typedArg.value + typedArg.value = () => (x.getTexture()) + typedArg.isUniform = true + } else { + // if passing in a texture reference, when function asks for vec4, convert to vec4 + if (typedArg.value.getTexture && input.type === 'vec4') { + var x1 = typedArg.value + typedArg.value = src(x1) + typedArg.isUniform = false + } + } + + // add tp uniform array if is a function that will pass in a different value on each render frame, + // or a texture/ external source + + if(typedArg.isUniform) { + typedArg.name += startIndex + // shaderParams.uniforms.push(typedArg) + } +} + return typedArg + }) +} + +},{"./lib/array-utils.js":70}],67:[function(require,module,exports){ +module.exports = { noise: { type: 'src', inputs: [ @@ -30757,17 +27861,13 @@ float _noise(vec3 v){ notes: 'from https://thebookofshaders.com/edit.php#12/vorono-01.frag, https://www.shadertoy.com/view/ldB3zc', glsl: `vec4 voronoi(vec2 st, float scale, float speed, float blending) { vec3 color = vec3(.0); - // Scale st *= scale; - // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); - float m_dist = 10.; // minimun distance vec2 m_point; // minimum point - for (int j=-1; j<=1; j++ ) { for (int i=-1; i<=1; i++ ) { vec2 neighbor = vec2(float(i),float(j)); @@ -30776,14 +27876,12 @@ float _noise(vec3 v){ point = 0.5 + 0.5*sin(time*speed + 6.2831*point); vec2 diff = neighbor + point - f_st; float dist = length(diff); - if( dist < m_dist ) { m_dist = dist; m_point = point; } } } - // Assign a color using the closest point position color += dot(m_point,vec2(.3,.6)); color *= 1.0 - blending*m_dist; @@ -31116,7 +28214,6 @@ float _noise(vec3 v){ glsl: `vec2 repeatX(vec2 _st, float reps, float offset){ vec2 st = _st * vec2(reps, 1.0); // float f = mod(_st.y,2.0); - st.y += step(1., mod(st.x,2.0))* offset; return fract(st); }` @@ -31143,7 +28240,6 @@ float _noise(vec3 v){ vec2 st = _st * vec2(reps, 1.0); // float f = mod(_st.y,2.0); st.y += step(1., mod(st.x,2.0)) + c1.r * offset; - return fract(st); }` }, @@ -31234,6 +28330,36 @@ float _noise(vec3 v){ return (c1.r+r)*vec2(cos(a), sin(a)); }` }, + scroll: { + type: 'coord', + inputs: [ + { + name: 'scrollX', + type: 'float', + default: 0.5 + }, + { + name: 'scrollY', + type: 'float', + default: 0.5 + }, + { + name: 'speedX', + type: 'float', + default: 0.0 + }, + { + name: 'speedY', + type: 'float', + default: 0.0 + } + ], + glsl: `vec2 scroll(vec2 st, float scrollX, float scrollY, float speedX, float speedY){ + st.x += scrollX + time*speedX; + st.y += scrollY + time*speedY; + return st; + }` + }, scrollX: { type: 'coord', inputs: [ @@ -31250,7 +28376,7 @@ float _noise(vec3 v){ ], glsl: `vec2 scrollX(vec2 st, float amount, float speed){ st.x += amount + time*speed; - return fract(st); + return st; }` }, modulateScrollX: { @@ -31273,7 +28399,7 @@ float _noise(vec3 v){ ], glsl: `vec2 modulateScrollX(vec2 st, vec4 c1, float amount, float speed){ st.x += c1.r*amount + time*speed; - return fract(st); + return st; }` }, scrollY: { @@ -31292,7 +28418,7 @@ float _noise(vec3 v){ ], glsl: `vec2 scrollY(vec2 st, float amount, float speed){ st.y += amount + time*speed; - return fract(st); + return st; }` }, modulateScrollY: { @@ -31315,7 +28441,7 @@ float _noise(vec3 v){ ], glsl: `vec2 modulateScrollY(vec2 st, vec4 c1, float amount, float speed){ st.y += c1.r*amount + time*speed; - return fract(st); + return st; }` }, add: { @@ -31328,13 +28454,30 @@ float _noise(vec3 v){ { name: 'amount', type: 'float', - default: 0.5 + default: 1.0 } ], glsl: `vec4 add(vec4 c0, vec4 c1, float amount){ return (c0+c1)*amount + c0*(1.0-amount); }` }, + sub: { + type: 'combine', + inputs: [ + { + name: 'color', + type: 'vec4' + }, + { + name: 'amount', + type: 'float', + default: 1.0 + } + ], + glsl: `vec4 add(vec4 c0, vec4 c1, float amount){ + return (c0-c1)*amount + c0*(1.0-amount); + }` + }, layer: { type: 'combine', inputs: [ @@ -31504,7 +28647,6 @@ float _noise(vec3 v){ } ], glsl: `vec2 modulateHue(vec2 st, vec4 c1, float amount){ - return st + (vec2(c1.g - c1.r, c1.b - c1.g) * amount * 1.0/resolution); }` }, @@ -31550,13 +28692,6 @@ float _noise(vec3 v){ } ` }, - luminance: { - type: 'util', - glsl: `float luminance(vec3 rgb){ - const vec3 W = vec3(0.2125, 0.7154, 0.0721); - return dot(rgb, W); - }` - }, mask: { type: 'combine', inputs: [ @@ -31566,7 +28701,7 @@ float _noise(vec3 v){ } ], glsl: `vec4 mask(vec4 c0, vec4 c1){ - float a = luminance(c1.rgb); + float a = _luminance(c1.rgb); return vec4(c0.rgb*a, a); }` }, @@ -31585,7 +28720,7 @@ float _noise(vec3 v){ } ], glsl: `vec4 luma(vec4 c0, float threshold, float tolerance){ - float a = smoothstep(threshold-tolerance, threshold+tolerance, luminance(c0.rgb)); + float a = smoothstep(threshold-tolerance, threshold+tolerance, _luminance(c0.rgb)); return vec4(c0.rgb*a, a); }` }, @@ -31603,7 +28738,7 @@ float _noise(vec3 v){ } ], glsl: `vec4 thresh(vec4 c0, float threshold, float tolerance){ - return vec4(vec3(smoothstep(threshold-tolerance, threshold+tolerance, luminance(c0.rgb))), c0.a); + return vec4(vec3(smoothstep(threshold-tolerance, threshold+tolerance, _luminance(c0.rgb))), c0.a); }` }, color: { @@ -31634,32 +28769,11 @@ float _noise(vec3 v){ glsl: `vec4 color(vec4 c0, float _r, float _g, float _b, float _a){ vec4 c = vec4(_r, _g, _b, _a); vec4 pos = step(0.0, c); // detect whether negative - // if > 0, return r * c0 // if < 0 return (1.0-r) * c0 return vec4(mix((1.0-c0)*abs(c), c*c0, pos)); }` }, - _rgbToHsv: { - type: 'util', - glsl: `vec3 _rgbToHsv(vec3 c){ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); - }` - }, - _hsvToRgb: { - type: 'util', - glsl: `vec3 _hsvToRgb(vec3 c){ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); - }` - }, saturate: { type: 'color', inputs: [ @@ -31707,379 +28821,191 @@ float _noise(vec3 v){ c = fract(c); return vec4(c, c0.a); }` + }, + prev: { + type: 'src', + notes: 'renders previous buffer', + inputs: [], + glsl: `vec4 prev(vec2 _st) { + return texture2D(prevBuffer, fract(_st)); + } + ` + }, + sum: { + type: 'color', + inputs: [ + { + name: 'scale', + type: 'vec4', + default: [1, 1, 1, 1] + } + ], + glsl: `float sum(vec4 c0, vec4 s) { + vec4 v = c0 * s; + return v.r + v.g + v.b + v.a; + } +float sum(vec2 _st, vec4 s) { // vec4 is not a typo, because argument type is not overloaded + vec2 v = _st.xy * s.xy; + return v.x + v.y; +}` + }, + r: { + type: 'color', + inputs: [ + {name: 'scale', type: 'float', default: 1}, + {name: 'offset', type: 'float', default: 0} + ], + glsl: `vec4 r(vec4 c0, float scale, float offset) { + return vec4(c0.r * scale + offset); + }` + }, + g: { + type: 'color', + inputs: [ + {name: 'scale', type: 'float', default: 1}, + {name: 'offset', type: 'float', default: 0} + ], + glsl: `vec4 g(vec4 c0, float scale, float offset) { + return vec4(c0.g * scale + offset); + }` + }, + b: { + type: 'color', + inputs: [ + {name: 'scale', type: 'float', default: 1}, + {name: 'offset', type: 'float', default: 0} + ], + glsl: `vec4 b(vec4 c0, float scale, float offset) { + return vec4(c0.b * scale + offset); + }` + }, + a: { + type: 'color', + inputs: [ + {name: 'scale', type: 'float', default: 1}, + {name: 'offset', type: 'float', default: 0} + ], + glsl: `vec4 a(vec4 c0, float scale, float offset) { + return vec4(c0.a * scale + offset); + }` } } -},{}],76:[function(require,module,exports){ -// singleton class that generates ids to use has unique variable names for variables -// counter.js - -let value = 0 +},{}],68:[function(require,module,exports){ +// functions that are only used within other functions module.exports = { - increment: () => value++, - get: () => value -} + _luminance: { + type: 'util', + glsl: `float _luminance(vec3 rgb){ + const vec3 W = vec3(0.2125, 0.7154, 0.0721); + return dot(rgb, W); + }` + }, + _noise: { + type: 'util', + glsl: ` + // Simplex 3D Noise + // by Ian McEwan, Ashima Arts + vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} + vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} -},{}],77:[function(require,module,exports){ -module.exports = { - src: { - transformType: 'color', - isSource: true, - inputs: [{ - name: 'src', - type: 'image' - }], - fragBody: ` - c = texture2D(<0>, st); - ` - }, - invert: { - transformType: 'color', - fragBody: ` - c = 1.0-c; - c = vec4(c.xyz, 1.0); - ` - }, - osc: { - transformType: 'color', - isSource: true, - inputs: [ - { - name: 'frequency', - type: 'float', - default: 60 - }, - { - name: 'sync', - type: 'float', - default: 0.1 - }, - { - name: 'offset', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - float r<0> = sin((st.x-<2>/100.+time*<1>)*<0>)*0.5 + 0.5; - float g<0> = sin((st.x+time*<1>)*<0>)*0.5 + 0.5; - float b<0> = sin((st.x+<2>/100.+time*<1>)*<0>)*0.5 + 0.5; - c = vec4(r<0>, g<0>, b<0>, 1.0); - ` - }, - blend: { - transformType: 'color', - inputs: [ - { - name: 'src', - type: 'image' - }, - { - name: 'blendAmount', - type: 'float', - default: 0.4 - } - ], - fragBody: ` - c*=(1.0-<1>); - c+= texture2D(<0>, uv)*<1>; - ` - }, - mult: { - transformType: 'color', - inputs: [ - { - name: 'src', - type: 'image' - }, - { - name: 'amount', - type: 'float', - default: 1.0 - } - ], - fragBody: ` - vec4 c<1> = c*(texture2D(<0>, uv)); - c*=(1.0-<1>); - c+= c<1>*<1>; - ` - }, - add: { - transformType: 'color', - inputs: [ - { - name: 'src', - type: 'image' - } - ], - fragBody: ` - c += texture2D(<0>, uv); - ` - }, - diff: { - transformType: 'color', - inputs: [ - { - name: 'src', - type: 'image' - } - ], - fragBody: ` - c -= texture2D(<0>, uv); - c = vec4(abs(c).xyz, 1.0); - ` - }, - scale: { - transformType: 'coord', - inputs: [ - { - name: 'scaleAmount', - type: 'float', - default: 1.5 - } - ], - fragBody: ` - st = vec2(1.0/<0>)*st; - ` - }, - pixelate: { - transformType: 'coord', - inputs: [ - { - name: 'pixelX', - type: 'float', - default: 20 - }, { - name: 'pixelY', - type: 'float', - default: 20 - } - ], - fragBody: ` - st *= vec2(<0>, <1>); - st = floor(st) + 0.5; - st /= vec2(<0>, <1>); - ` - }, - contrast: { - transformType: 'color', - inputs: [ - { - name: 'contrast', - type: 'float', - default: 1.6 - } - ], - fragBody: ` - c = (c-vec4(0.5))*<0> + vec4(0.5); - c = vec4(c.xyz, 1.0); - ` - }, - kaleid: { - transformType: 'coord', - inputs: [ - { - name: 'nSides', - type: 'float', - default: 4.0 - } - ], - fragBody: ` - st -= 0.5; - float r<0> = length(st); - float a<0> = atan(st.y, st.x); - float pi<0> = 2.*3.1416; - a<0> = mod(a<0>, pi<0>/<0>); - a<0> = abs(a<0>-pi<0>/<0>/2.); - st = r<0>*vec2(cos(a<0>), sin(a<0>)); - ` - }, - brightness: { - transformType: 'color', - inputs: [ - { - name: 'brightness', - type: 'float', - default: 0.4 - } - ], - fragBody: ` - c = vec4(c.xyz + vec3(<0>), 1.0); - ` - }, - posterize: { - transformType: 'color', - inputs: [ - { - name: 'bins', - type: 'float', - default: 3.0 - }, - { - name: 'gamma', - type: 'float', - default: 0.6 - } - ], - fragBody: ` - c = pow(c, vec4(<1>)); - c*=vec4(<0>); - c = floor(c); - c/=vec4(<0>); - c = pow(c, vec4(1.0/<1>)); - c = vec4(c.xyz, 1.0); - ` - }, - modulate: { - transformType: 'coord', - inputs: [ - { - name: 'src', - type: 'image' - }, - { - name: 'amount', - type: 'float', - default: 0.1 - } - ], - fragBody: ` - st += texture2D(<0>, uv).xy*<1>; + float _noise(vec3 v){ + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0. + 0.0 * C + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; + + // Permutations + i = mod(i, 289.0 ); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + + // Gradients + // ( N*N points uniformly over a square, mapped onto an octahedron.) + float n_ = 1.0/7.0; // N=7 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); + } ` }, - color: { - transformType: 'color', - inputs: [{ - name: 'color', - type: 'color', - default: [1.0, 0.5, 0.0] - }], - fragBody: ` - c.rgb = c.rgb*<0>; - c = vec4(c.rgb, 1.0); - ` + + _rgbToHsv: { + type: 'util', + glsl: `vec3 _rgbToHsv(vec3 c){ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + }` }, - gradient: { - transformType: 'color', - isSource: true, - fragBody: ` - c = vec4(st, sin(time), 1.0); - ` - }, - scrollX: { - transformType: 'coord', - inputs: [ - { - name: 'scrollX', - type: 'float', - default: 0.5 - }, - { - name: 'speed', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - st.x += <0> + time*<1>; - st = fract(st); - ` - }, - repeatX: { - transformType: 'coord', - inputs: [ - { - name: 'repeatX', - type: 'float', - default: 3.0 - }, { - name: 'offsetX', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - st*= vec2(<0>, 1.0); - st.x += step(1., mod(st.y,2.0)) * <1>; - st = fract(st); - ` - }, - repeatY: { - transformType: 'coord', - inputs: [ - { - name: 'repeatY', - type: 'float', - default: 3.0 - }, { - name: 'offsetY', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - st*= vec2(1.0, <0>); - st.y += step(1., mod(st.x,2.0)) * <1>; - st = fract(st); - ` - }, - repeat: { - transformType: 'coord', - inputs: [ - { - name: 'repeatX', - type: 'float', - default: 3.0 - }, - { - name: 'repeatY', - type: 'float', - default: 3.0 - }, - { - name: 'offsetX', - type: 'float', - default: 0.0 - }, - { - name: 'offsetY', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - st*= vec2(<0>, <1>); - st.x += step(1., mod(st.y,2.0)) * <2>; - st.y += step(1., mod(st.x,2.0)) * <3>; - st = fract(st); - ` - }, - rotate: { - transformType: 'coord', - inputs: [ - { - name: 'angle', - type: 'float', - default: 10.0 - }, { - name: 'speed', - type: 'float', - default: 0.0 - } - ], - fragBody: ` - st -= vec2(0.5); - float angle<0> = <0> + <1>*time; - st = mat2(cos(angle<0>),-sin(angle<0>), sin(angle<0>),cos(angle<0>))*st; - st += vec2(0.5); - ` + _hsvToRgb: { + type: 'util', + glsl: `vec3 _hsvToRgb(vec3 c){ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + }` } } -},{}],78:[function(require,module,exports){ -const Webcam = require('./webcam.js') +},{}],69:[function(require,module,exports){ +const Webcam = require('./lib/webcam.js') const Screen = require('./lib/screenmedia.js') class HydraSource { @@ -32137,6 +29063,11 @@ class HydraSource { }) } + resize (width, height) { + this.width = width + this.height = height + } + clear () { this.src = null this.tex = this.regl.texture({ @@ -32147,9 +29078,11 @@ class HydraSource { tick (time) { if (this.src !== null && this.dynamic === true) { + if(this.src.videoWidth && this.src.videoWidth !== this.tex.width) { this.tex.resize(this.src.videoWidth, this.src.videoHeight) } + this.tex.subimage(this.src) //this.tex = this.regl.texture(this.src) } @@ -32162,8 +29095,323 @@ class HydraSource { module.exports = HydraSource -},{"./lib/screenmedia.js":80,"./webcam.js":86}],79:[function(require,module,exports){ -var adapter = require('webrtc-adapter'); +},{"./lib/screenmedia.js":75,"./lib/webcam.js":77}],70:[function(require,module,exports){ +// WIP utils for working with arrays +// Possibly should be integrated with lfo extension, etc. +// to do: transform time rather than array values, similar to working with coordinates in hydra + +var easing = require('./easing-functions.js') + +var map = (num, in_min, in_max, out_min, out_max) => { + return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +module.exports = { + init: () => { + + + Array.prototype.fast = function(speed = 1) { + this._speed = speed + return this + } + + Array.prototype.smooth = function(smooth = 1) { + this._smooth = smooth + return this + } + + Array.prototype.ease = function(ease) { + if(ease && easing[ease]) { + this._smooth = 1 + this._ease = easing[ease] + } + return this + } + + + // Array.prototype.bounce = function() { + // this.modifiers.bounce = true + // return this + // } + + Array.prototype.fit = function(low = 0, high =1) { + let lowest = Math.min(...this) + let highest = Math.max(...this) + var newArr = this.map((num) => map(num, lowest, highest, low, high)) + newArr._speed = this._speed + newArr._smooth = this._smooth + newArr._ease = this._ease + return newArr + } + }, + getValue: (arr = []) => ({time, bpm}) =>{ + let speed = arr._speed ? arr._speed : 1 + let smooth = arr._smooth ? arr._smooth : 0 + let ease = arr._ease ? arr._ease : easing['linear'] + // console.log(smooth) + let index = time * speed * (bpm / 60) + + let currValue = arr[Math.floor(index % (arr.length))] + let nextValue = arr[Math.floor((index + 1) % (arr.length))] + + let _t = (index%1)*smooth + let t = ease(_t) + // console.log(arr, Math.floor(index/newArr.length), index/newArr.length) + return nextValue*t + currValue*(1-t) + } +} + +},{"./easing-functions.js":72}],71:[function(require,module,exports){ +const Meyda = require('meyda') + +class Audio { + constructor ({ + numBins = 4, + cutoff = 2, + smooth = 0.4, + max = 15, + scale = 10, + isDrawing = false + }) { + this.vol = 0 + this.scale = scale + this.max = max + this.cutoff = cutoff + this.smooth = smooth + this.setBins(numBins) + + // beat detection from: https://github.com/therewasaguy/p5-music-viz/blob/gh-pages/demos/01d_beat_detect_amplitude/sketch.js + this.beat = { + holdFrames: 20, + threshold: 40, + _cutoff: 0, // adaptive based on sound state + decay: 0.98, + _framesSinceBeat: 0 // keeps track of frames + } + + this.onBeat = () => { + // console.log("beat") + } + + this.canvas = document.createElement('canvas') + this.canvas.width = 100 + this.canvas.height = 80 + this.canvas.style.width = "100px" + this.canvas.style.height = "80px" + this.canvas.style.position = 'absolute' + this.canvas.style.right = '0px' + this.canvas.style.bottom = '0px' + document.body.appendChild(this.canvas) + + this.isDrawing = isDrawing + this.ctx = this.canvas.getContext('2d') + this.ctx.fillStyle="#DFFFFF" + this.ctx.strokeStyle="#0ff" + this.ctx.lineWidth=0.5 + + window.navigator.mediaDevices.getUserMedia({video: false, audio: true}) + .then((stream) => { + // console.log('got mic stream', stream) + this.stream = stream + this.context = new AudioContext() + // this.context = new AudioContext() + let audio_stream = this.context.createMediaStreamSource(stream) + + // console.log(this.context) + this.meyda = Meyda.createMeydaAnalyzer({ + audioContext: this.context, + source: audio_stream, + featureExtractors: [ + 'loudness', + // 'perceptualSpread', + // 'perceptualSharpness', + // 'spectralCentroid' + ] + }) + }) + .catch((err) => console.log('ERROR', err)) + } + + detectBeat (level) { + //console.log(level, this.beat._cutoff) + if (level > this.beat._cutoff && level > this.beat.threshold) { + this.onBeat() + this.beat._cutoff = level *1.2 + this.beat._framesSinceBeat = 0 + } else { + if (this.beat._framesSinceBeat <= this.beat.holdFrames){ + this.beat._framesSinceBeat ++; + } else { + this.beat._cutoff *= this.beat.decay + this.beat._cutoff = Math.max( this.beat._cutoff, this.beat.threshold); + } + } + } + + tick() { + if(this.meyda){ + var features = this.meyda.get() + if(features && features !== null){ + this.vol = features.loudness.total + this.detectBeat(this.vol) + // reduce loudness array to number of bins + const reducer = (accumulator, currentValue) => accumulator + currentValue; + let spacing = Math.floor(features.loudness.specific.length/this.bins.length) + this.prevBins = this.bins.slice(0) + this.bins = this.bins.map((bin, index) => { + return features.loudness.specific.slice(index * spacing, (index + 1)*spacing).reduce(reducer) + }).map((bin, index) => { + // map to specified range + + // return (bin * (1.0 - this.smooth) + this.prevBins[index] * this.smooth) + return (bin * (1.0 - this.settings[index].smooth) + this.prevBins[index] * this.settings[index].smooth) + }) + // var y = this.canvas.height - scale*this.settings[index].cutoff + // this.ctx.beginPath() + // this.ctx.moveTo(index*spacing, y) + // this.ctx.lineTo((index+1)*spacing, y) + // this.ctx.stroke() + // + // var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) + this.fft = this.bins.map((bin, index) => ( + // Math.max(0, (bin - this.cutoff) / (this.max - this.cutoff)) + Math.max(0, (bin - this.settings[index].cutoff)/this.settings[index].scale) + )) + if(this.isDrawing) this.draw() + } + } + } + + setCutoff (cutoff) { + this.cutoff = cutoff + this.settings = this.settings.map((el) => { + el.cutoff = cutoff + return el + }) + } + + setSmooth (smooth) { + this.smooth = smooth + this.settings = this.settings.map((el) => { + el.smooth = smooth + return el + }) + } + + setBins (numBins) { + this.bins = Array(numBins).fill(0) + this.prevBins = Array(numBins).fill(0) + this.fft = Array(numBins).fill(0) + this.settings = Array(numBins).fill(0).map(() => ({ + cutoff: this.cutoff, + scale: this.scale, + smooth: this.smooth + })) + // to do: what to do in non-global mode? + this.bins.forEach((bin, index) => { + window['a' + index] = (scale = 1, offset = 0) => () => (a.fft[index] * scale + offset) + }) + // console.log(this.settings) + } + + setScale(scale){ + this.scale = scale + this.settings = this.settings.map((el) => { + el.scale = scale + return el + }) + } + + setMax(max) { + this.max = max + console.log('set max is deprecated') + } + hide() { + this.isDrawing = false + this.canvas.style.display = 'none' + } + + show() { + this.isDrawing = true + this.canvas.style.display = 'block' + + } + + draw () { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + var spacing = this.canvas.width / this.bins.length + var scale = this.canvas.height / (this.max * 2) + // console.log(this.bins) + this.bins.forEach((bin, index) => { + + var height = bin * scale + + this.ctx.fillRect(index * spacing, this.canvas.height - height, spacing, height) + + // console.log(this.settings[index]) + var y = this.canvas.height - scale*this.settings[index].cutoff + this.ctx.beginPath() + this.ctx.moveTo(index*spacing, y) + this.ctx.lineTo((index+1)*spacing, y) + this.ctx.stroke() + + var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) + this.ctx.beginPath() + this.ctx.moveTo(index*spacing, yMax) + this.ctx.lineTo((index+1)*spacing, yMax) + this.ctx.stroke() + }) + + + /*var y = this.canvas.height - scale*this.cutoff + this.ctx.beginPath() + this.ctx.moveTo(0, y) + this.ctx.lineTo(this.canvas.width, y) + this.ctx.stroke() + var yMax = this.canvas.height - scale*this.max + this.ctx.beginPath() + this.ctx.moveTo(0, yMax) + this.ctx.lineTo(this.canvas.width, yMax) + this.ctx.stroke()*/ + } +} + +module.exports = Audio + +},{"meyda":84}],72:[function(require,module,exports){ +// from https://gist.github.com/gre/1650294 + +module.exports = { + // no easing, no acceleration + linear: function (t) { return t }, + // accelerating from zero velocity + easeInQuad: function (t) { return t*t }, + // decelerating to zero velocity + easeOutQuad: function (t) { return t*(2-t) }, + // acceleration until halfway, then deceleration + easeInOutQuad: function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t }, + // accelerating from zero velocity + easeInCubic: function (t) { return t*t*t }, + // decelerating to zero velocity + easeOutCubic: function (t) { return (--t)*t*t+1 }, + // acceleration until halfway, then deceleration + easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }, + // accelerating from zero velocity + easeInQuart: function (t) { return t*t*t*t }, + // decelerating to zero velocity + easeOutQuart: function (t) { return 1-(--t)*t*t*t }, + // acceleration until halfway, then deceleration + easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t }, + // accelerating from zero velocity + easeInQuint: function (t) { return t*t*t*t*t }, + // decelerating to zero velocity + easeOutQuint: function (t) { return 1+(--t)*t*t*t*t }, + // acceleration until halfway, then deceleration + easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t } +} + +},{}],73:[function(require,module,exports){ +//var adapter = require('webrtc-adapter'); // to do: clean up this code // cache for constraints and callback var cache = {}; @@ -32180,7 +29428,7 @@ module.exports = function (constraints, cb) { } if (window.navigator.userAgent.match('Chrome')) { - + var chromever = parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10); var maxver = 33; @@ -32372,7 +29620,44 @@ typeof window !== 'undefined' && window.addEventListener('message', function (ev } }); -},{"webrtc-adapter":151}],80:[function(require,module,exports){ +},{}],74:[function(require,module,exports){ +// attempt custom evaluation sandbox for hydra functions +// for now, just avoids polluting the global namespace +// should probably be replaced with an abstract syntax tree + +module.exports = (parent) => { + var initialCode = `` + + var sandbox = createSandbox(initialCode) + + var addToContext = (name, object) => { + initialCode += ` + var ${name} = ${object} + ` + sandbox = createSandbox(initialCode) + } + + + return { + addToContext: addToContext, + eval: (code) => sandbox.eval(code) + } + + function createSandbox (initial) { + eval(initial) + // optional params + var localEval = function (code) { + eval(code) + } + + // API/data for end-user + return { + eval: localEval + } + } +} + +},{}],75:[function(require,module,exports){ const getScreenMedia = require('./getscreenmedia.js') module.exports = function (options) { @@ -32411,362 +29696,7 @@ module.exports = function (options) { } -},{"./getscreenmedia.js":79}],81:[function(require,module,exports){ -const transforms = require('./glsl-transforms.js') - -var Output = function (opts) { - this.regl = opts.regl - this.positionBuffer = this.regl.buffer([ - [-2, 0], - [0, -2], - [2, 2] - ]) - - this.clear() - this.pingPongIndex = 0 - - // for each output, create two fbos to use for ping ponging - this.fbos = (Array(2)).fill().map(() => this.regl.framebuffer({ - color: this.regl.texture({ - width: opts.width, - height: opts.height, - format: 'rgba' - }), - depthStencil: false - })) - - // array containing render passes - this.passes = [] - // console.log("position", this.positionBuffer) -} - -// Object.keys(transforms).forEach((method) => { -// Output.prototype[method] = function (...args) { -// // console.log("applying", method, transforms[method]) -// this.applyTransform(transforms[method], args) -// -// return this -// } -// }) - -Output.prototype.getCurrent = function () { - // console.log("get current",this.pingPongIndex ) - return this.fbos[this.pingPongIndex] -} - -Output.prototype.getTexture = function () { -// return this.fbos[!this.pingPongIndex] - var index = this.pingPongIndex ? 0 : 1 - // console.log("get texture",index) - return this.fbos[index] -} - -Output.prototype.clear = function () { - this.transformIndex = 0 - this.fragHeader = ` - precision mediump float; - - uniform float time; - varying vec2 uv; - ` - this.fragBody = `` - // - // uniform vec4 color; - // void main () { - // gl_FragColor = color; - // }` - this.vert = ` - precision mediump float; - attribute vec2 position; - varying vec2 uv; - - void main () { - uv = position; - gl_Position = vec4(2.0 * position - 1.0, 0, 1); - }` - this.attributes = { - position: this.positionBuffer - } - this.uniforms = { - time: this.regl.prop('time'), - resolution: this.regl.prop('resolution') - } -// this.compileFragShader() - - this.frag = ` - ${this.fragHeader} - - void main () { - vec4 c = vec4(0, 0, 0, 0); - vec2 st = uv; - ${this.fragBody} - gl_FragColor = c; - } - ` - return this -} - - -// Output.prototype.compileFragShader = function () { -// var frag = ` -// ${this.fragHeader} -// -// void main () { -// vec4 c = vec4(0, 0, 0, 0); -// vec2 st = uv; -// ${this.fragBody} -// gl_FragColor = c; -// } -// ` -// // console.log("FRAG", frag) -// this.frag = frag -// } - -Output.prototype.render = function () { - this.draw = this.regl({ - frag: this.frag, - vert: this.vert, - attributes: this.attributes, - uniforms: this.uniforms, - count: 3, - framebuffer: () => { - this.pingPongIndex = this.pingPongIndex ? 0 : 1 - return this.fbos[this.pingPongIndex] - } - }) -} - -Output.prototype.renderPasses = function(passes) { - var self = this -// console.log("passes", passes) - this.passes = passes.map( (pass, passIndex) => { - - // console.log("get texture",index) - var uniforms = Object.assign(pass.uniforms, { prevBuffer: () => { - var index = this.pingPongIndex ? 0 : 1 - // console.log('pass index', passIndex, 'fbo index', index) - return this.fbos[this.pingPongIndex ? 0 : 1] - } - }) - - return { - draw: self.regl({ - frag: pass.frag, - vert: self.vert, - attributes: self.attributes, - uniforms: uniforms, - count: 3, - framebuffer: () => { - - self.pingPongIndex = self.pingPongIndex ? 0 : 1 - // console.log('pass index', passIndex, 'render index', self.pingPongIndex) - return self.fbos[self.pingPongIndex] - } - }) - } - }) -} - -Output.prototype.tick = function (props) { -// this.draw(props) - this.passes.forEach((pass) => pass.draw(props)) -} - -module.exports = Output - -},{"./glsl-transforms.js":77}],82:[function(require,module,exports){ -// to add: ripple: https://www.shadertoy.com/view/4djGzz -// mask -// convolution -// basic sdf shapes -// repeat -// iq color palletes - -module.exports = { - _convolution: { - type: 'renderpass_util', - glsl: ` - float kernel [9]; - - vec4 _convolution (vec2 uv, float[9] _kernel, float kernelWeight) { - vec2 st = uv/resolution; - vec2 onePixel = vec2(4.0, 4.0) / resolution; - // vec2 onePixel = vec2(1.0, 1.0); - vec4 colorSum = - texture2D(prevBuffer, st + onePixel * vec2(-1, -1)) * _kernel[0] + - texture2D(prevBuffer, st + onePixel * vec2( 0, -1)) * _kernel[1] + - texture2D(prevBuffer, st + onePixel * vec2( 1, -1)) * _kernel[2] + - texture2D(prevBuffer, st + onePixel * vec2(-1, 0)) * _kernel[3] + - texture2D(prevBuffer, st + onePixel * vec2( 0, 0)) * _kernel[4] + - texture2D(prevBuffer, st + onePixel * vec2( 1, 0)) * _kernel[5] + - texture2D(prevBuffer, st + onePixel * vec2(-1, 1)) * _kernel[6] + - texture2D(prevBuffer, st + onePixel * vec2( 0, 1)) * _kernel[7] + - texture2D(prevBuffer, st + onePixel * vec2( 1, 1)) * _kernel[8] ; - colorSum /= kernelWeight; - return colorSum; - } - ` - }, - rgbShift: { - type: 'renderpass', - glsl: ` - - void main() { - vec2 p = st; - vec4 shift = vec4(-0.01, 0.02, 0.03, -0.04); - vec2 rs = vec2(shift.x,-shift.y); - vec2 gs = vec2(shift.y,-shift.z); - vec2 bs = vec2(shift.z,-shift.x); - - float r = texture2D(prevBuffer, p+rs, 0.0).x; - float g = texture2D(prevBuffer, p+gs, 0.0).y; - float b = texture2D(prevBuffer, p+bs, 0.0).z; - } - ` - }, - edges: { - type: 'renderpass', - glsl: ` - void main () { - // kernel[0] = -0.125; kernel[1] = -0.125; kernel[2] = -0.125; - // kernel[3] = -0.125; kernel[4] = 1.0; kernel[5] = -0.125; - // kernel[6] = -0.125; kernel[7] = -0.125; kernel[8] = -0.125; - -// blur - kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0; - kernel[3] = 1.0; kernel[4] = 1.0; kernel[5] = 1.0; - kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0; - - kernel[0] = 5.0; kernel[1] = -0.0; kernel[2] = -0.0; - kernel[3] = 0.0; kernel[4] = 0.0; kernel[5] = 0.0; - kernel[6] = -0.0; kernel[7] = -0.0; kernel[8] = -5.0; - - vec4 sum = _convolution( gl_FragCoord.xy, kernel, 10.0); - gl_FragColor = clamp(sum , vec4(0.0), vec4(1.0)); - // vec2 st = gl_FragCoord.xy/resolution; - // vec4 col = texture2D(prevBuffer, fract(st)); - // gl_FragColor = vec4(st, 1.0, 1.0); - } - ` - } -} - -},{}],83:[function(require,module,exports){ -// to do: -// 1. how to handle multi-pass renders -// 2. how to handle vertex shaders - -module.exports = function (defaultOutput) { - - var Frag = function (shaderString) { - var obj = Object.create(Frag.prototype) - obj.shaderString = ` - void main () { - vec2 st = gl_FragCoord.xy/resolution; - gl_FragColor = vec4(st, 1.0, 1.0); - } - ` - if(shaderString) obj.shaderString = shaderString - return obj - } - - Frag.prototype.compile = function () { - var frag = ` - precision mediump float; - uniform float time; - uniform vec2 resolution; - varying vec2 uv; - - ${this.shaderString} - ` - return frag - } - - Frag.prototype.out = function (_output) { - var output = _output || defaultOutput - var frag = this.compile() - output.frag = frag - var pass = { - frag: frag, - uniforms: output.uniforms - } - console.log('rendering', pass) - var passes = [] - passes.push(pass) - output.renderPasses([pass]) - // var uniformObj = {} - // this.uniforms.forEach((uniform) => { uniformObj[uniform.name] = uniform.value }) - // output.uniforms = Object.assign(output.uniforms, uniformObj) - output.render() - } - - return Frag -} - -},{}],84:[function(require,module,exports){ -// some utility functions for managing time within hydra -// to do: add easing functions: https://github.com/bameyrick/js-easing-functions - -// accepts a sequence of values as an array -const seq = (arr = []) => ({time, bpm}) => -{ - let speed = arr.speed ? arr.speed : 1 - return arr[Math.floor(time * speed * (bpm / 60) % (arr.length))] -} - -// base sin oscillation -const sin = (amplitude = 1, period = 0.1, offset = 0, offsetTime = 0) => ({time, bpm}) => { - return amplitude * Math.sin((time + offsetTime) * period * (bpm / 60)) + offset -} - -// continuously increasing -const ramp = (scale = 1, offset = 0) => ({time, bpm}) => (time * scale + offset) - -// Utility functions and variables for managing fade in and outs: -// creates a set of variables to store state. -// usage: osc(f0(10, 100)).out() , where there variables are: minimum, maximum, and multiple in time -// call fadeIn(0) to fade in all instances of f0, and fadeOut(0) to fadeOut -function createFades (numFades) { - // variables containing current state of fade - const gain = Array(numFades).fill().map(() => ({ progress: 0, dir: 1, mult: 1})) - - // fade function to use as parameter - const fade = (i) => (min = 0, max = 10, mult = 1) => () => { - // console.log("gain", gain) - gain[i].progress++ - if(gain[i].dir > 0) { - return Math.min(max, min + gain[i].progress * mult * gain[i].mult) - } else { - return Math.max(min, max - gain[i].progress * mult * gain[i].mult) - } - } - - // to do: put this code somewhere else - gain.forEach((gain, index) => { - window['f'+index] = fade(index) - }) - - window.fadeIn = (index, _mult) => { - gain[index] = { - progress: 0, dir: 1, mult: _mult ? _mult : 1 - } - } - // - window.fadeOut = (index, _mult) => { - gain[index] = { - progress: 0, dir: -1, mult: _mult ? _mult : 1 - } - } -} - -module.exports = { - seq: seq, - sin: sin, - ramp: ramp, - createFades: createFades -} - -},{}],85:[function(require,module,exports){ +},{"./getscreenmedia.js":73}],76:[function(require,module,exports){ class VideoRecorder { constructor(stream) { this.mediaSource = new MediaSource() @@ -32854,43 +29784,156 @@ class VideoRecorder { module.exports = VideoRecorder -},{}],86:[function(require,module,exports){ -const getUserMedia = require('getusermedia') +},{}],77:[function(require,module,exports){ const enumerateDevices = require('enumerate-devices') module.exports = function (deviceId) { - return new Promise(function (resolve, reject) { - enumerateDevices() + return enumerateDevices() .then(devices => devices.filter(devices => devices.kind === 'videoinput')) - .then(cameras => - { - let constraints = { audio: false, video: true} - if(cameras[deviceId]) { - constraints['video'] = { - deviceId: { exact: cameras[deviceId].deviceId } - } + .then(cameras => { + let constraints = { audio: false, video: true} + if (cameras[deviceId]) { + constraints['video'] = { + deviceId: { exact: cameras[deviceId].deviceId } } - getUserMedia(constraints, function (err, stream) { - if(err) { - reject(err) - } else { - const video = document.createElement('video') - // video.src = window.URL.createObjectURL(stream) - video.srcObject = stream - video.addEventListener('loadedmetadata', () => { - video.play().then(() => resolve({video: video})) - }) - } - }) - - console.log(cameras) } - ).catch(console.log.bind(console)) + console.log(cameras) + return window.navigator.mediaDevices.getUserMedia(constraints) + }) + .then(stream => { + const video = document.createElement('video') + // video.src = window.URL.createObjectURL(stream) + video.srcObject = stream + return new Promise((resolve, reject) => { + video.addEventListener('loadedmetadata', () => { + video.play().then(() => resolve({video: video})) + }) + }) + }) + .catch(console.log.bind(console)) +} +},{"enumerate-devices":56}],78:[function(require,module,exports){ +//const transforms = require('./glsl-transforms.js') + +var Output = function (opts) { + this.regl = opts.regl + this.precision = opts.precision + this.positionBuffer = this.regl.buffer([ + [-2, 0], + [0, -2], + [2, 2] + ]) + + this.draw = () => {} + this.clear() + this.pingPongIndex = 0 + + // for each output, create two fbos for pingponging + this.fbos = (Array(2)).fill().map(() => this.regl.framebuffer({ + color: this.regl.texture({ + width: opts.width, + height: opts.height, + format: 'rgba' + }), + depthStencil: false + })) + + // array containing render passes +// this.passes = [] +} + +Output.prototype.resize = function(width, height) { + this.fbos.forEach((fbo) => { + fbo.resize(width, height) }) } -},{"enumerate-devices":56,"getusermedia":58}],87:[function(require,module,exports){ + +Output.prototype.getCurrent = function () { + return this.fbos[this.pingPongIndex] +} + +Output.prototype.getTexture = function () { + var index = this.pingPongIndex ? 0 : 1 + return this.fbos[index] +} + +Output.prototype.clear = function () { + this.transformIndex = 0 + this.fragHeader = ` + precision ${this.precision} float; + + uniform float time; + varying vec2 uv; + ` + this.fragBody = `` + + this.vert = ` + precision ${this.precision} float; + attribute vec2 position; + varying vec2 uv; + + void main () { + uv = position; + gl_Position = vec4(2.0 * position - 1.0, 0, 1); + }` + + this.attributes = { + position: this.positionBuffer + } + this.uniforms = { + time: this.regl.prop('time'), + resolution: this.regl.prop('resolution') + } + + this.frag = ` + ${this.fragHeader} + + void main () { + vec4 c = vec4(0, 0, 0, 0); + vec2 st = uv; + ${this.fragBody} + gl_FragColor = c; + } + ` + return this +} + + +Output.prototype.render = function (passes) { + let pass = passes[0] + //console.log('pass', pass, this.pingPongIndex) + var self = this + var uniforms = Object.assign(pass.uniforms, { prevBuffer: () => { + //var index = this.pingPongIndex ? 0 : 1 + // var index = self.pingPong[(passIndex+1)%2] + // console.log('ping pong', self.pingPongIndex) + return self.fbos[self.pingPongIndex] + } + }) + + self.draw = self.regl({ + frag: pass.frag, + vert: self.vert, + attributes: self.attributes, + uniforms: uniforms, + count: 3, + framebuffer: () => { + self.pingPongIndex = self.pingPongIndex ? 0 : 1 + return self.fbos[self.pingPongIndex] + } + }) +} + + +Output.prototype.tick = function (props) { + this.draw(props) +} + +module.exports = Output + +},{}],79:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = nBytes * 8 - mLen - 1 @@ -32976,7 +30019,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],88:[function(require,module,exports){ +},{}],80:[function(require,module,exports){ var indexOf = [].indexOf; @@ -32987,7 +30030,7 @@ module.exports = function(arr, obj){ } return -1; }; -},{}],89:[function(require,module,exports){ +},{}],81:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -33012,7 +30055,7 @@ if (typeof Object.create === 'function') { } } -},{}],90:[function(require,module,exports){ +},{}],82:[function(require,module,exports){ /*! * Determine if an object is a Buffer * @@ -33035,9 +30078,9 @@ function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -},{}],91:[function(require,module,exports){ -arguments[4][70][0].apply(exports,arguments) -},{"dup":70}],92:[function(require,module,exports){ +},{}],83:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"dup":59}],84:[function(require,module,exports){ !function(t,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports.Meyda=r():t.Meyda=r()}(this,function(){return function(t){function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var e={};return r.m=t,r.c=e,r.i=function(t){return t},r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},r.p="",r(r.s=23)}([function(t,r,e){"use strict";function n(t){if(Array.isArray(t)){for(var r=0,e=Array(t.length);r1;)t/=2;return 1===t}function i(t,r){for(var e=[],n=0;n3&&void 0!==arguments[3]?arguments[3]:5,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:2,a=!(arguments.length>5&&void 0!==arguments[5])||arguments[5],u=arguments.length>6&&void 0!==arguments[6]?arguments[6]:440,c=Math.floor(e/2)+1,f=new Array(e).fill(0).map(function(n,o){return t*p(r*o/e,u)});f[0]=f[1]-1.5*t;var l=f.slice(1).map(function(t,r){return Math.max(t-f[r])},1).concat([1]),s=Math.round(t/2),y=new Array(t).fill(0).map(function(r,e){return f.map(function(r){return(10*t+s+r-e)%t-s})}),h=y.map(function(t,r){return t.map(function(t,e){return Math.exp(-.5*Math.pow(2*y[r][e]/l[e],2))})});if(h=m(h),i){var b=f.map(function(r){return Math.exp(-.5*Math.pow((r/t-o)/i,2))});h=h.map(function(t){return t.map(function(t,r){return t*b[r]})})}return a&&(h=[].concat(n(h.slice(3)),n(h.slice(0,3)))),h.map(function(t){return t.slice(0,c)})}function h(t,r,e){if(t.lengtha;)i[u++]=c,a=u*t.barkScale[o.length-1]/24;i[24]=o.length-1;for(var f=0;f<24;f++){for(var l=0,s=i[f];s=0;u--)if(c[u]!==f[u])return!1;for(u=c.length-1;u>=0;u--)if(a=c[u],!m(t[a],r[a],e,n))return!1;return!0}function b(t,r,e){m(t,r,!0)&&s(t,r,e,"notDeepStrictEqual",b)}function g(t,r){if(!t||!r)return!1;if("[object RegExp]"==Object.prototype.toString.call(r))return r.test(t);try{if(t instanceof r)return!0}catch(t){}return!Error.isPrototypeOf(r)&&!0===r.call({},t)}function S(t){var r;try{t()}catch(t){r=t}return r}function d(t,r,e,n){var o;if("function"!=typeof r)throw new TypeError('"block" argument must be a function');"string"==typeof e&&(n=e,e=null),o=S(r),n=(e&&e.name?" ("+e.name+").":".")+(n?" "+n:"."),t&&!o&&s(o,e,"Missing expected exception"+n);var i="string"==typeof n,a=!t&&v.isError(o),u=!t&&o&&!e;if((a&&i&&g(o,e)||u)&&s(o,e,"Got unwanted exception"+n),t&&o&&e&&!g(o,e)||!t&&o)throw o}var v=e(33),w=Object.prototype.hasOwnProperty,x=Array.prototype.slice,E=function(){return"foo"===function(){}.name}(),_=t.exports=p,M=/\s*function\s+([^\(\s]*)\s*/;_.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=l(this),this.generatedMessage=!0);var r=t.stackStartFunction||s;if(Error.captureStackTrace)Error.captureStackTrace(this,r);else{var e=new Error;if(e.stack){var n=e.stack,o=u(r),i=n.indexOf("\n"+o);if(i>=0){var a=n.indexOf("\n",i+1);n=n.substring(a+1)}this.stack=n}}},v.inherits(_.AssertionError,Error),_.fail=s,_.ok=p,_.equal=function(t,r,e){t!=r&&s(t,r,e,"==",_.equal)},_.notEqual=function(t,r,e){t==r&&s(t,r,e,"!=",_.notEqual)},_.deepEqual=function(t,r,e){m(t,r,!1)||s(t,r,e,"deepEqual",_.deepEqual)},_.deepStrictEqual=function(t,r,e){m(t,r,!0)||s(t,r,e,"deepStrictEqual",_.deepStrictEqual)},_.notDeepEqual=function(t,r,e){m(t,r,!1)&&s(t,r,e,"notDeepEqual",_.notDeepEqual)},_.notDeepStrictEqual=b,_.strictEqual=function(t,r,e){t!==r&&s(t,r,e,"===",_.strictEqual)},_.notStrictEqual=function(t,r,e){t===r&&s(t,r,e,"!==",_.notStrictEqual)},_.throws=function(t,r,e){d(!0,t,r,e)},_.doesNotThrow=function(t,r,e){d(!1,t,r,e)},_.ifError=function(t){if(t)throw t};var A=Object.keys||function(t){var r=[];for(var e in t)w.call(t,e)&&r.push(e);return r}}).call(r,e(5))},function(t,r,e){"use strict";function n(t){if(Array.isArray(t)){for(var r=0,e=Array(t.length);rr&&(r=t.specific[i]);return Math.pow((t.total-r)/t.total,2)}},function(t,r,e){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};r.a=function(t){if("object"!==n(t.signal))throw new TypeError;for(var r=0,e=0;ei&&a>=0;)e-=t[a],--a;return(a+1)*r}},function(t,r,e){"use strict";var n=e(1),o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};r.a=function(t){if("object"!==o(t.ampSpectrum))throw new TypeError;var r=e.i(n.a)(1,t.ampSpectrum),i=e.i(n.a)(2,t.ampSpectrum),a=e.i(n.a)(3,t.ampSpectrum);return(2*Math.pow(r,3)-3*r*i+a)/Math.pow(Math.sqrt(i-Math.pow(r,2)),3)}},function(t,r,e){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};r.a=function(t){if("object"!==n(t.ampSpectrum))throw new TypeError;for(var r=0,e=0,o=new Float32Array(t.ampSpectrum.length),i=0,a=0,u=0;u=0&&arguments[0].signal[r+1]<0||arguments[0].signal[r]<0&&arguments[0].signal[r+1]>=0)&&t++;return t}},function(t,r,e){t.exports=e(6).default},function(t,r,e){"use strict";function n(t,r){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}e.d(r,"a",function(){return u});var o=e(0),i=e(4),a=function(){function t(t,r){for(var e=0;e0;i--)r[t-i]=r[i-1];return r}function o(t){for(var r=Math.PI/(t-1),e=new Float32Array(t),n=0;n1)for(var e=1;e=3&&(n.depth=arguments[2]),arguments.length>=4&&(n.colors=arguments[3]),h(e)?n.showHidden=e:e&&r._extend(n,e),w(n.showHidden)&&(n.showHidden=!1),w(n.depth)&&(n.depth=2),w(n.colors)&&(n.colors=!1),w(n.customInspect)&&(n.customInspect=!0),n.colors&&(n.stylize=i),c(n,t,n.depth)}function i(t,r){var e=o.styles[r];return e?"["+o.colors[e][0]+"m"+t+"["+o.colors[e][1]+"m":t}function a(t,r){return t}function u(t){var r={};return t.forEach(function(t,e){r[t]=!0}),r}function c(t,e,n){if(t.customInspect&&e&&A(e.inspect)&&e.inspect!==r.inspect&&(!e.constructor||e.constructor.prototype!==e)){var o=e.inspect(n,t);return d(o)||(o=c(t,o,n)),o}var i=f(t,e);if(i)return i;var a=Object.keys(e),h=u(a);if(t.showHidden&&(a=Object.getOwnPropertyNames(e)),M(e)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return l(e);if(0===a.length){if(A(e)){var b=e.name?": "+e.name:"";return t.stylize("[Function"+b+"]","special")}if(x(e))return t.stylize(RegExp.prototype.toString.call(e),"regexp");if(_(e))return t.stylize(Date.prototype.toString.call(e),"date");if(M(e))return l(e)}var g="",S=!1,v=["{","}"];if(y(e)&&(S=!0,v=["[","]"]),A(e)){g=" [Function"+(e.name?": "+e.name:"")+"]"}if(x(e)&&(g=" "+RegExp.prototype.toString.call(e)),_(e)&&(g=" "+Date.prototype.toUTCString.call(e)),M(e)&&(g=" "+l(e)),0===a.length&&(!S||0==e.length))return v[0]+g+v[1];if(n<0)return x(e)?t.stylize(RegExp.prototype.toString.call(e),"regexp"):t.stylize("[Object]","special");t.seen.push(e);var w;return w=S?s(t,e,n,h,a):a.map(function(r){return p(t,e,n,h,r,S)}),t.seen.pop(),m(w,g,v)}function f(t,r){if(w(r))return t.stylize("undefined","undefined");if(d(r)){var e="'"+JSON.stringify(r).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(e,"string")}return S(r)?t.stylize(""+r,"number"):h(r)?t.stylize(""+r,"boolean"):b(r)?t.stylize("null","null"):void 0}function l(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,r,e,n,o){for(var i=[],a=0,u=r.length;a-1&&(u=i?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),w(a)){if(i&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function m(t,r,e){var n=0;return t.reduce(function(t,r){return n++,r.indexOf("\n")>=0&&n++,t+r.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60?e[0]+(""===r?"":r+"\n ")+" "+t.join(",\n ")+" "+e[1]:e[0]+r+" "+t.join(", ")+" "+e[1]}function y(t){return Array.isArray(t)}function h(t){return"boolean"==typeof t}function b(t){return null===t}function g(t){return null==t}function S(t){return"number"==typeof t}function d(t){return"string"==typeof t}function v(t){return"symbol"==typeof t}function w(t){return void 0===t}function x(t){return E(t)&&"[object RegExp]"===T(t)}function E(t){return"object"==typeof t&&null!==t}function _(t){return E(t)&&"[object Date]"===T(t)}function M(t){return E(t)&&("[object Error]"===T(t)||t instanceof Error)}function A(t){return"function"==typeof t}function j(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||void 0===t}function T(t){return Object.prototype.toString.call(t)}function F(t){return t<10?"0"+t.toString(10):t.toString(10)}function k(){var t=new Date,r=[F(t.getHours()),F(t.getMinutes()),F(t.getSeconds())].join(":");return[t.getDate(),R[t.getMonth()],r].join(" ")}function z(t,r){return Object.prototype.hasOwnProperty.call(t,r)}var O=/%[sdj%]/g;r.format=function(t){if(!d(t)){for(var r=[],e=0;e=i)return t;switch(t){case"%s":return String(n[e++]);case"%d":return Number(n[e++]);case"%j":try{return JSON.stringify(n[e++])}catch(t){return"[Circular]"}default:return t}}),u=n[e];eThe web is much more than just canvas and p5.dom makes it easy to interact @@ -36255,7 +33298,7 @@ exports.y = mouseRelativeY }; }); -},{"../p5":96}],96:[function(require,module,exports){ +},{"../p5":88}],88:[function(require,module,exports){ (function (global){ /*! p5.js v0.6.1 April 27, 2018 */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.p5 = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o*/ @@ -115408,10 +112451,10 @@ module.exports = { destroy: destroy, undestroy: undestroy }; -},{"process-nextick-args":100}],112:[function(require,module,exports){ +},{"process-nextick-args":92}],104:[function(require,module,exports){ module.exports = require('events').EventEmitter; -},{"events":26}],113:[function(require,module,exports){ +},{"events":26}],105:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); exports.Stream = exports; exports.Readable = exports; @@ -115420,159 +112463,169 @@ exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -},{"./lib/_stream_duplex.js":105,"./lib/_stream_passthrough.js":106,"./lib/_stream_readable.js":107,"./lib/_stream_transform.js":108,"./lib/_stream_writable.js":109}],114:[function(require,module,exports){ -(function(aa,ia){"object"===typeof exports&&"undefined"!==typeof module?module.exports=ia():"function"===typeof define&&define.amd?define(ia):aa.createREGL=ia()})(this,function(){function aa(a,b){this.id=Ab++;this.type=a;this.data=b}function ia(a){if(0===a.length)return[];var b=a.charAt(0),c=a.charAt(a.length-1);if(1>>=b;c=(255>>=c;b|=c;c=(15>>=c;b|=c;c=(3>>c>>1}function cb(){function a(a){a:{for(var b=16;268435456>=b;b*=16)if(a<=b){a=b;break a}a=0}b=c[bb(a)>>2];return 0>2].push(a)}var c=J(8,function(){return[]});return{alloc:a,free:b,allocType:function(b,c){var d=null;switch(b){case 5120:d=new Int8Array(a(c),0,c);break;case 5121:d=new Uint8Array(a(c),0,c);break;case 5122:d=new Int16Array(a(2*c),0,c);break;case 5123:d=new Uint16Array(a(2*c),0,c);break;case 5124:d=new Int32Array(a(4*c),0,c);break;case 5125:d=new Uint32Array(a(4*c),0,c);break;case 5126:d=new Float32Array(a(4*c),0,c);break;default:return null}return d.length!== -c?d.subarray(0,c):d},freeType:function(a){b(a.buffer)}}}function ma(a){return!!a&&"object"===typeof a&&Array.isArray(a.shape)&&Array.isArray(a.stride)&&"number"===typeof a.offset&&a.shape.length===a.stride.length&&(Array.isArray(a.data)||M(a.data))}function db(a,b,c,e,g,d){for(var n=0;nd&&(d=e.buffer.byteLength,5123===f?d>>=1:5125===f&&(d>>=2));e.vertCount=d;d=h;0>h&&(d=4,h=e.buffer.dimension,1===h&&(d=0),2===h&&(d=1),3===h&&(d=4));e.primType=d}function n(a){e.elementsCount--;delete f[a.id];a.buffer.destroy();a.buffer=null}var f={},r=0,q={uint8:5121,uint16:5123};b.oes_element_index_uint&&(q.uint32=5125);g.prototype.bind=function(){this.buffer.bind()};var t=[];return{create:function(a,b){function k(a){if(a)if("number"===typeof a)h(a),l.primType=4,l.vertCount=a|0, -l.type=5121;else{var b=null,c=35044,e=-1,g=-1,f=0,m=0;if(Array.isArray(a)||M(a)||ma(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(c=jb[a.usage]),"primitive"in a&&(e=Sa[a.primitive]),"count"in a&&(g=a.count|0),"type"in a&&(m=q[a.type]),"length"in a)f=a.length|0;else if(f=g,5123===m||5122===m)f*=2;else if(5125===m||5124===m)f*=4;d(l,b,c,e,g,f,m)}else h(),l.primType=4,l.vertCount=0,l.type=5121;return k}var h=c.create(null,34963,!0),l=new g(h._buffer);e.elementsCount++;k(a);k._reglType="elements"; -k._elements=l;k.subdata=function(a,b){h.subdata(a,b);return k};k.destroy=function(){n(l)};return k},createStream:function(a){var b=t.pop();b||(b=new g(c.create(null,34963,!0,!1)._buffer));d(b,a,35040,-1,-1,0,0);return b},destroyStream:function(a){t.push(a)},getElements:function(a){return"function"===typeof a&&a._elements instanceof g?a._elements:null},clear:function(){S(f).forEach(n)}}}function kb(a){for(var b=x.allocType(5123,a.length),c=0;c>>31<<15,d=(e<<1>>>24)-127,e=e>>13&1023;b[c]=-24>d?g:-14>d?g+(e+1024>>-14-d):15>=e,c.height>>=e,C(c,d[e]),a.mipmask|=1<b;++b)a.images[b]=null;return a}function ib(a){for(var b=a.images,c=0;cb){for(var c=0;c=--this.refCount&&A(this)}});n.profile&&(d.getTotalTextureSize=function(){var a=0;Object.keys(X).forEach(function(b){a+=X[b].stats.size});return a});return{create2D:function(b,c){function e(a,b){var c=f.texInfo;y.call(c);var d=D();"number"===typeof a?"number"===typeof b?v(d,a|0,b|0):v(d,a|0,a|0):a?(O(c,a),N(d,a)):v(d,1,1);c.genMipmaps&&(d.mipmask=(d.width<<1)-1);f.mipmask=d.mipmask;r(f,d);f.internalformat=d.internalformat; -e.width=d.width;e.height=d.height;T(f);B(d,3553);R(c,3553);Aa();ib(d);n.profile&&(f.stats.size=Ja(f.internalformat,f.type,d.width,d.height,c.genMipmaps,!1));e.format=J[f.internalformat];e.type=da[f.type];e.mag=oa[c.magFilter];e.min=za[c.minFilter];e.wrapS=ka[c.wrapS];e.wrapT=ka[c.wrapT];return e}var f=new F(3553);X[f.id]=f;d.textureCount++;e(b,c);e.subimage=function(a,b,c,d){b|=0;c|=0;d|=0;var p=h();r(p,f);p.width=0;p.height=0;C(p,a);p.width=p.width||(f.width>>d)-b;p.height=p.height||(f.height>>d)- -c;T(f);k(p,3553,b,c,d);Aa();l(p);return e};e.resize=function(b,c){var d=b|0,h=c|0||d;if(d===f.width&&h===f.height)return e;e.width=f.width=d;e.height=f.height=h;T(f);for(var p,w=f.channels,z=f.type,I=0;f.mipmask>>I;++I){var fa=d>>I,ga=h>>I;if(!fa||!ga)break;p=x.zero.allocType(z,fa*ga*w);a.texImage2D(3553,I,f.format,fa,ga,0,f.format,f.type,p);p&&x.zero.freeType(p)}Aa();n.profile&&(f.stats.size=Ja(f.internalformat,f.type,d,h,!1,!1));return e};e._reglType="texture2d";e._texture=f;n.profile&&(e.stats= -f.stats);e.destroy=function(){f.decRef()};return e},createCube:function(b,c,e,f,g,ua){function A(a,b,c,d,e,f){var H,Y=m.texInfo;y.call(Y);for(H=0;6>H;++H)p[H]=D();if("number"===typeof a||!a)for(a=a|0||1,H=0;6>H;++H)v(p[H],a,a);else if("object"===typeof a)if(b)N(p[0],a),N(p[1],b),N(p[2],c),N(p[3],d),N(p[4],e),N(p[5],f);else if(O(Y,a),q(m,a),"faces"in a)for(a=a.faces,H=0;6>H;++H)r(p[H],m),N(p[H],a[H]);else for(H=0;6>H;++H)N(p[H],a);r(m,p[0]);m.mipmask=Y.genMipmaps?(p[0].width<<1)-1:p[0].mipmask;m.internalformat= -p[0].internalformat;A.width=p[0].width;A.height=p[0].height;T(m);for(H=0;6>H;++H)B(p[H],34069+H);R(Y,34067);Aa();n.profile&&(m.stats.size=Ja(m.internalformat,m.type,A.width,A.height,Y.genMipmaps,!0));A.format=J[m.internalformat];A.type=da[m.type];A.mag=oa[Y.magFilter];A.min=za[Y.minFilter];A.wrapS=ka[Y.wrapS];A.wrapT=ka[Y.wrapT];for(H=0;6>H;++H)ib(p[H]);return A}var m=new F(34067);X[m.id]=m;d.cubeCount++;var p=Array(6);A(b,c,e,f,g,ua);A.subimage=function(a,b,c,p,d){c|=0;p|=0;d|=0;var e=h();r(e,m); -e.width=0;e.height=0;C(e,b);e.width=e.width||(m.width>>d)-c;e.height=e.height||(m.height>>d)-p;T(m);k(e,34069+a,c,p,d);Aa();l(e);return A};A.resize=function(b){b|=0;if(b!==m.width){A.width=m.width=b;A.height=m.height=b;T(m);for(var c=0;6>c;++c)for(var p=0;m.mipmask>>p;++p)a.texImage2D(34069+c,p,m.format,b>>p,b>>p,0,m.format,m.type,null);Aa();n.profile&&(m.stats.size=Ja(m.internalformat,m.type,A.width,A.height,!1,!0));return A}};A._reglType="textureCube";A._texture=m;n.profile&&(A.stats=m.stats);A.destroy= -function(){m.decRef()};return A},clear:function(){for(var b=0;bc;++c)if(0!==(b.mipmask&1<> -c,b.height>>c,0,b.internalformat,b.type,null);else for(var d=0;6>d;++d)a.texImage2D(34069+d,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);R(b.texInfo,b.target)})}}}function Ob(a,b,c,e,g,d){function n(a,b,c){this.target=a;this.texture=b;this.renderbuffer=c;var d=a=0;b?(a=b.width,d=b.height):c&&(a=c.width,d=c.height);this.width=a;this.height=d}function f(a){a&&(a.texture&&a.texture._texture.decRef(),a.renderbuffer&&a.renderbuffer._renderbuffer.decRef())}function r(a,b,c){a&& -(a.texture?a.texture._texture.refCount+=1:a.renderbuffer._renderbuffer.refCount+=1)}function q(b,c){c&&(c.texture?a.framebufferTexture2D(36160,b,c.target,c.texture._texture.texture,0):a.framebufferRenderbuffer(36160,b,36161,c.renderbuffer._renderbuffer.renderbuffer))}function t(a){var b=3553,c=null,d=null,e=a;"object"===typeof a&&(e=a.data,"target"in a&&(b=a.target|0));a=e._reglType;"texture2d"===a?c=e:"textureCube"===a?c=e:"renderbuffer"===a&&(d=e,b=36161);return new n(b,c,d)}function m(a,b,c,d, -f){if(c)return a=e.create2D({width:a,height:b,format:d,type:f}),a._texture.refCount=0,new n(3553,a,null);a=g.create({width:a,height:b,format:d});a._renderbuffer.refCount=0;return new n(36161,null,a)}function C(a){return a&&(a.texture||a.renderbuffer)}function k(a,b,c){a&&(a.texture?a.texture.resize(b,c):a.renderbuffer&&a.renderbuffer.resize(b,c),a.width=b,a.height=c)}function h(){this.id=O++;R[this.id]=this;this.framebuffer=a.createFramebuffer();this.height=this.width=0;this.colorAttachments=[];this.depthStencilAttachment= -this.stencilAttachment=this.depthAttachment=null}function l(a){a.colorAttachments.forEach(f);f(a.depthAttachment);f(a.stencilAttachment);f(a.depthStencilAttachment)}function u(b){a.deleteFramebuffer(b.framebuffer);b.framebuffer=null;d.framebufferCount--;delete R[b.id]}function v(b){var d;a.bindFramebuffer(36160,b.framebuffer);var e=b.colorAttachments;for(d=0;dd;++d){for(m=0;ma;++a)c[a].resize(d);b.width=b.height=d;return b},_reglType:"framebufferCube",destroy:function(){c.forEach(function(a){a.destroy()})}})},clear:function(){S(R).forEach(u)},restore:function(){B.cur=null;B.next=null;B.dirty=!0;S(R).forEach(function(b){b.framebuffer=a.createFramebuffer();v(b)})}})}function ub(){this.w=this.z=this.y= -this.x=this.state=0;this.buffer=null;this.size=0;this.normalized=!1;this.type=5126;this.divisor=this.stride=this.offset=0}function Pb(a,b,c,e){a=c.maxAttributes;b=Array(a);for(c=0;c -a&&(a=b.stats.uniformsCount)});return a},c.getMaxAttributesCount=function(){var a=0;C.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var b=a.deleteShader.bind(a);S(q).forEach(b);q={};S(t).forEach(b);t={};C.forEach(function(b){a.deleteProgram(b.program)});C.length=0;m={};c.shaderCount=0},program:function(a,b,d){var e=m[b];e||(e=m[b]={});var g=e[a];g||(g=new f(b,a),c.shaderCount++,r(g,d),e[a]=g,C.push(g));return g},restore:function(){q= -{};t={};for(var a=0;a"+b+"?"+e+".constant["+b+"]:0;"}).join(""),"}}else{", -"if(",f,"(",e,".buffer)){",z,"=",g,".createStream(",34962,",",e,".buffer);","}else{",z,"=",g,".getBuffer(",e,".buffer);","}",k,'="type" in ',e,"?",p.glTypes,"[",e,".type]:",z,".dtype;",w.normalized,"=!!",e,".normalized;");d("size");d("offset");d("stride");d("divisor");c("}}");c.exit("if(",w.isStream,"){",g,".destroyStream(",z,");","}");return w})});return f}function M(a){var b=a["static"],c=a.dynamic,d={};Object.keys(b).forEach(function(a){var c=b[a];d[a]=D(function(a,b){return"number"===typeof c|| -"boolean"===typeof c?""+c:a.link(c)})});Object.keys(c).forEach(function(a){var b=c[a];d[a]=P(b,function(a,c){return a.invoke(c,b)})});return d}function A(a,b,c,d,e){var f=y(a,e),g=x(a,f,e),h=O(a,e),k=R(a,e),m=E(a,e),ba=g.viewport;ba&&(k.viewport=ba);ba=l("scissor.box");(g=g[ba])&&(k[ba]=g);g=0>1)",v],");")}function b(){c(u,".drawArraysInstancedANGLE(",[q,r,t,v],");")}n?da?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}function g(){function a(){c(k+".drawElements("+[q,t,C,r+"<<(("+C+"-5121)>>1)"]+");")}function b(){c(k+".drawArrays("+[q,r,t]+");")}n?da?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")): -b()}var h=a.shared,k=h.gl,m=h.draw,l=d.draw,n=function(){var e=l.elements,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(m,".","elements");e&&f("if("+e+")"+k+".bindBuffer(34963,"+e+".buffer.buffer);");return e}(),q=e("primitive"),r=e("offset"),t=function(){var e=l.count,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(m,".","count");return e}();if("number"===typeof t){if(0===t)return}else c("if(",t,"){"),c.exit("}");var v, -u;ea&&(v=e("instances"),u=a.instancing);var C=n+".type",da=l.elements&&va(l.elements);ea&&("number"!==typeof v||0<=v)?"string"===typeof v?(c("if(",v,">0){"),f(),c("}else if(",v,"<0){"),g(),c("}")):f():g()}function ca(a,b,c,d,e){b=N();e=b.proc("body",e);ea&&(b.instancing=e.def(b.shared.extensions,".angle_instanced_arrays"));a(b,e,c,d);return b.compile().body}function L(a,b,c,d){wa(a,b);U(a,b,c,d.attributes,function(){return!0});W(a,b,c,d.uniforms,function(){return!0});S(a,b,b,c)}function da(a,b){var c= -a.proc("draw",1);wa(a,c);ua(a,c,b.context);K(a,c,b.framebuffer);V(a,c,b);Q(a,c,b.state);G(a,c,b,!1,!0);var d=b.shader.progVar.append(a,c);c(a.shared.gl,".useProgram(",d,".program);");if(b.shader.program)L(a,c,b,b.shader.program);else{var e=a.global.def("{}"),f=c.def(d,".id"),g=c.def(e,"[",f,"]");c(a.cond(g).then(g,".call(this,a0);")["else"](g,"=",e,"[",f,"]=",a.link(function(c){return ca(L,a,b,c,1)}),"(",d,");",g,".call(this,a0);"))}0=--this.refCount&&n(this)};g.profile&&(e.getTotalRenderbufferSize=function(){var a=0;Object.keys(t).forEach(function(b){a+=t[b].stats.size});return a});return{create:function(b,c){function k(b,c){var d=0,e=0,m=32854; -"object"===typeof b&&b?("shape"in b?(e=b.shape,d=e[0]|0,e=e[1]|0):("radius"in b&&(d=e=b.radius|0),"width"in b&&(d=b.width|0),"height"in b&&(e=b.height|0)),"format"in b&&(m=f[b.format])):"number"===typeof b?(d=b|0,e="number"===typeof c?c|0:d):b||(d=e=1);if(d!==h.width||e!==h.height||m!==h.format)return k.width=h.width=d,k.height=h.height=e,h.format=m,a.bindRenderbuffer(36161,h.renderbuffer),a.renderbufferStorage(36161,m,d,e),g.profile&&(h.stats.size=Q[h.format]*h.width*h.height),k.format=r[h.format], -k}var h=new d(a.createRenderbuffer());t[h.id]=h;e.renderbufferCount++;k(b,c);k.resize=function(b,c){var d=b|0,e=c|0||d;if(d===h.width&&e===h.height)return k;k.width=h.width=d;k.height=h.height=e;a.bindRenderbuffer(36161,h.renderbuffer);a.renderbufferStorage(36161,h.format,d,e);g.profile&&(h.stats.size=Q[h.format]*h.width*h.height);return k};k._reglType="renderbuffer";k._renderbuffer=h;g.profile&&(k.stats=h.stats);k.destroy=function(){h.decRef()};return k},clear:function(){S(t).forEach(n)},restore:function(){S(t).forEach(function(b){b.renderbuffer= -a.createRenderbuffer();a.bindRenderbuffer(36161,b.renderbuffer);a.renderbufferStorage(36161,b.format,b.width,b.height)});a.bindRenderbuffer(36161,null)}}},Wa=[];Wa[6408]=4;Wa[6407]=3;var Na=[];Na[5121]=1;Na[5126]=4;Na[36193]=2;var Da=["x","y","z","w"],Ub="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Ga={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771, -"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},Xa={never:512,less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Pa={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056, -invert:5386},wb={cw:2304,ccw:2305},xb=new Z(!1,!1,!1,function(){}),Xb=function(a,b){function c(){this.endQueryIndex=this.startQueryIndex=-1;this.sum=0;this.stats=null}function e(a,b,d){var e=n.pop()||new c;e.startQueryIndex=a;e.endQueryIndex=b;e.sum=0;e.stats=d;f.push(e)}if(!b.ext_disjoint_timer_query)return null;var g=[],d=[],n=[],f=[],r=[],q=[];return{beginQuery:function(a){var c=g.pop()||b.ext_disjoint_timer_query.createQueryEXT();b.ext_disjoint_timer_query.beginQueryEXT(35007,c);d.push(c);e(d.length- -1,d.length,a)},endQuery:function(){b.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:e,update:function(){var a,c;a=d.length;if(0!==a){q.length=Math.max(q.length,a+1);r.length=Math.max(r.length,a+1);r[0]=0;var e=q[0]=0;for(c=a=0;c=G.length&&e()}var c=yb(G,a);G[c]=b}}}function q(){var a=S.viewport,b=S.scissor_box;a[0]=a[1]=b[0]=b[1]=0;O.viewportWidth= -O.framebufferWidth=O.drawingBufferWidth=a[2]=b[2]=k.drawingBufferWidth;O.viewportHeight=O.framebufferHeight=O.drawingBufferHeight=a[3]=b[3]=k.drawingBufferHeight}function t(){O.tick+=1;O.time=y();q();V.procs.poll()}function m(){q();V.procs.refresh();B&&B.update()}function y(){return(zb()-D)/1E3}a=Eb(a);if(!a)return null;var k=a.gl,h=k.getContextAttributes();k.isContextLost();var l=Fb(k,a);if(!l)return null;var u=Bb(),v={bufferCount:0,elementsCount:0,framebufferCount:0,shaderCount:0,textureCount:0, -cubeCount:0,renderbufferCount:0,maxTextureUnits:0},x=l.extensions,B=Xb(k,x),D=zb(),J=k.drawingBufferWidth,P=k.drawingBufferHeight,O={tick:0,time:0,viewportWidth:J,viewportHeight:P,framebufferWidth:J,framebufferHeight:P,drawingBufferWidth:J,drawingBufferHeight:P,pixelRatio:a.pixelRatio},R=Vb(k,x),J=Pb(k,x,R,u),F=Gb(k,v,a,J),T=Hb(k,x,F,v),Q=Qb(k,u,v,a),A=Kb(k,x,R,function(){V.procs.poll()},O,v,a),M=Wb(k,x,R,v,a),K=Ob(k,x,R,A,M,v),V=Tb(k,u,x,R,F,T,A,K,{},J,Q,{elements:null,primitive:4,count:-1,offset:0, -instances:-1},O,B,a),u=Rb(k,K,V.procs.poll,O,h,x,R),S=V.next,L=k.canvas,G=[],U=[],W=[],Z=[a.onDestroy],ca=null;L&&(L.addEventListener("webglcontextlost",g,!1),L.addEventListener("webglcontextrestored",d,!1));var aa=K.setFBO=n({framebuffer:la.define.call(null,1,"framebuffer")});m();h=E(n,{clear:function(a){if("framebuffer"in a)if(a.framebuffer&&"framebufferCube"===a.framebuffer_reglType)for(var b=0;6>b;++b)aa(E({framebuffer:a.framebuffer.faces[b]},a),f);else aa(a,f);else f(null,a)},prop:la.define.bind(null, -1),context:la.define.bind(null,2),"this":la.define.bind(null,3),draw:n({}),buffer:function(a){return F.create(a,34962,!1,!1)},elements:function(a){return T.create(a,!1)},texture:A.create2D,cube:A.createCube,renderbuffer:M.create,framebuffer:K.create,framebufferCube:K.createCube,attributes:h,frame:r,on:function(a,b){var c;switch(a){case "frame":return r(b);case "lost":c=U;break;case "restore":c=W;break;case "destroy":c=Z}c.push(b);return{cancel:function(){for(var a=0;a>>=b;c=(255>>=c;b|=c;c=(15>>=c;b|=c;c=(3>>c>>1}function fb(){function a(a){a:{for(var b= +16;268435456>=b;b*=16)if(a<=b){a=b;break a}a=0}b=c[eb(a)>>2];return 0>2].push(a)}var c=A(8,function(){return[]});return{alloc:a,free:b,allocType:function(b,c){var g=null;switch(b){case 5120:g=new Int8Array(a(c),0,c);break;case 5121:g=new Uint8Array(a(c),0,c);break;case 5122:g=new Int16Array(a(2*c),0,c);break;case 5123:g=new Uint16Array(a(2*c),0,c);break;case 5124:g=new Int32Array(a(4*c),0,c);break;case 5125:g=new Uint32Array(a(4* +c),0,c);break;case 5126:g=new Float32Array(a(4*c),0,c);break;default:return null}return g.length!==c?g.subarray(0,c):g},freeType:function(a){b(a.buffer)}}}function X(a){return!!a&&"object"===typeof a&&Array.isArray(a.shape)&&Array.isArray(a.stride)&&"number"===typeof a.offset&&a.shape.length===a.stride.length&&(Array.isArray(a.data)||G(a.data))}function gb(a,b,c,e,d,g){for(var r=0;rd&&(d=e.buffer.byteLength,5123===v?d>>=1:5125===v&&(d>>=2));e.vertCount=d;d=h;0>h&&(d=4,h=e.buffer.dimension,1===h&&(d=0),2===h&&(d=1),3===h&&(d=4));e.primType=d}function r(a){e.elementsCount--;delete n[a.id];a.buffer.destroy();a.buffer=null}var n={},u=0,q={uint8:5121,uint16:5123};b.oes_element_index_uint&&(q.uint32=5125);d.prototype.bind= +function(){this.buffer.bind()};var t=[];return{create:function(a,b){function k(a){if(a)if("number"===typeof a)h(a),f.primType=4,f.vertCount=a|0,f.type=5121;else{var b=null,c=35044,e=-1,d=-1,l=0,n=0;if(Array.isArray(a)||G(a)||X(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(c=lb[a.usage]),"primitive"in a&&(e=Ta[a.primitive]),"count"in a&&(d=a.count|0),"type"in a&&(n=q[a.type]),"length"in a)l=a.length|0;else if(l=d,5123===n||5122===n)l*=2;else if(5125===n||5124===n)l*=4;g(f,b,c,e,d,l,n)}else h(), +f.primType=4,f.vertCount=0,f.type=5121;return k}var h=c.create(null,34963,!0),f=new d(h._buffer);e.elementsCount++;k(a);k._reglType="elements";k._elements=f;k.subdata=function(a,b){h.subdata(a,b);return k};k.destroy=function(){r(f)};return k},createStream:function(a){var b=t.pop();b||(b=new d(c.create(null,34963,!0,!1)._buffer));g(b,a,35040,-1,-1,0,0);return b},destroyStream:function(a){t.push(a)},getElements:function(a){return"function"===typeof a&&a._elements instanceof d?a._elements:null},clear:function(){J(n).forEach(r)}}} +function nb(a){for(var b=z.allocType(5123,a.length),c=0;c>>31<<15,g=(e<<1>>>24)-127,e=e>>13&1023;b[c]=-24>g?d:-14>g?d+(e+1024>>-14-g):15>=e,c.height>>=e,F(c,f[e]),a.mipmask|=1<b;++b)a.images[b]=null;return a}function wa(a){for(var b=a.images,c=0;cb){for(var c=0;c=--this.refCount&&D(this)}});r.profile&&(g.getTotalTextureSize=function(){var a=0;Object.keys(E).forEach(function(b){a+=E[b].stats.size});return a});return{create2D:function(b,c){function e(a,b){var c=d.texInfo;fa.call(c);var f=C();"number"===typeof a?"number"===typeof b?m(f,a|0,b|0):m(f,a|0,a|0):a?(mb(c,a),v(f,a)):m(f,1,1);c.genMipmaps&&(f.mipmask=(f.width<< +1)-1);d.mipmask=f.mipmask;u(d,f);d.internalformat=f.internalformat;e.width=f.width;e.height=f.height;ta(d);Q(f,3553);Sa(c,3553);Aa();wa(f);r.profile&&(d.stats.size=Ja(d.internalformat,d.type,f.width,f.height,c.genMipmaps,!1));e.format=ba[d.internalformat];e.type=ya[d.type];e.mag=ca[c.magFilter];e.min=Ea[c.minFilter];e.wrapS=ga[c.wrapS];e.wrapT=ga[c.wrapT];return e}var d=new R(3553);E[d.id]=d;g.textureCount++;e(b,c);e.subimage=function(a,b,c,g){b|=0;c|=0;g|=0;var m=h();u(m,d);m.width=0;m.height=0; +F(m,a);m.width=m.width||(d.width>>g)-b;m.height=m.height||(d.height>>g)-c;ta(d);k(m,3553,b,c,g);Aa();f(m);return e};e.resize=function(b,c){var f=b|0,h=c|0||f;if(f===d.width&&h===d.height)return e;e.width=d.width=f;e.height=d.height=h;ta(d);for(var m=0;d.mipmask>>m;++m){var g=f>>m,y=h>>m;if(!g||!y)break;a.texImage2D(3553,m,d.format,g,y,0,d.format,d.type,null)}Aa();r.profile&&(d.stats.size=Ja(d.internalformat,d.type,f,h,!1,!1));return e};e._reglType="texture2d";e._texture=d;r.profile&&(e.stats=d.stats); +e.destroy=function(){d.decRef()};return e},createCube:function(b,c,e,d,p,n){function l(a,b,c,f,e,d){var h,na=x.texInfo;fa.call(na);for(h=0;6>h;++h)D[h]=C();if("number"===typeof a||!a)for(a=a|0||1,h=0;6>h;++h)m(D[h],a,a);else if("object"===typeof a)if(b)v(D[0],a),v(D[1],b),v(D[2],c),v(D[3],f),v(D[4],e),v(D[5],d);else if(mb(na,a),q(x,a),"faces"in a)for(a=a.faces,h=0;6>h;++h)u(D[h],x),v(D[h],a[h]);else for(h=0;6>h;++h)v(D[h],a);u(x,D[0]);x.mipmask=na.genMipmaps?(D[0].width<<1)-1:D[0].mipmask;x.internalformat= +D[0].internalformat;l.width=D[0].width;l.height=D[0].height;ta(x);for(h=0;6>h;++h)Q(D[h],34069+h);Sa(na,34067);Aa();r.profile&&(x.stats.size=Ja(x.internalformat,x.type,l.width,l.height,na.genMipmaps,!0));l.format=ba[x.internalformat];l.type=ya[x.type];l.mag=ca[na.magFilter];l.min=Ea[na.minFilter];l.wrapS=ga[na.wrapS];l.wrapT=ga[na.wrapT];for(h=0;6>h;++h)wa(D[h]);return l}var x=new R(34067);E[x.id]=x;g.cubeCount++;var D=Array(6);l(b,c,e,d,p,n);l.subimage=function(a,b,c,e,d){c|=0;e|=0;d|=0;var aa=h(); +u(aa,x);aa.width=0;aa.height=0;F(aa,b);aa.width=aa.width||(x.width>>d)-c;aa.height=aa.height||(x.height>>d)-e;ta(x);k(aa,34069+a,c,e,d);Aa();f(aa);return l};l.resize=function(b){b|=0;if(b!==x.width){l.width=x.width=b;l.height=x.height=b;ta(x);for(var c=0;6>c;++c)for(var f=0;x.mipmask>>f;++f)a.texImage2D(34069+c,f,x.format,b>>f,b>>f,0,x.format,x.type,null);Aa();r.profile&&(x.stats.size=Ja(x.internalformat,x.type,l.width,l.height,!1,!0));return l}};l._reglType="textureCube";l._texture=x;r.profile&& +(l.stats=x.stats);l.destroy=function(){x.decRef()};return l},clear:function(){for(var b=0;bc;++c)if(0!==(b.mipmask&1<>c,b.height>>c,0,b.internalformat,b.type,null);else for(var f=0;6>f;++f)a.texImage2D(34069+f,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);Sa(b.texInfo,b.target)})}}}function Ob(a,b,c,e,d,g){function r(a,b,c){this.target=a;this.texture=b;this.renderbuffer=c;var f=a=0;b?(a=b.width,f=b.height):c&&(a=c.width,f=c.height);this.width=a;this.height=f}function n(a){a&&(a.texture&&a.texture._texture.decRef(),a.renderbuffer&&a.renderbuffer._renderbuffer.decRef())} +function u(a,b,c){a&&(a.texture?a.texture._texture.refCount+=1:a.renderbuffer._renderbuffer.refCount+=1)}function q(b,c){c&&(c.texture?a.framebufferTexture2D(36160,b,c.target,c.texture._texture.texture,0):a.framebufferRenderbuffer(36160,b,36161,c.renderbuffer._renderbuffer.renderbuffer))}function t(a){var b=3553,c=null,f=null,e=a;"object"===typeof a&&(e=a.data,"target"in a&&(b=a.target|0));a=e._reglType;"texture2d"===a?c=e:"textureCube"===a?c=e:"renderbuffer"===a&&(f=e,b=36161);return new r(b,c,f)} +function l(a,b,c,f,h){if(c)return a=e.create2D({width:a,height:b,format:f,type:h}),a._texture.refCount=0,new r(3553,a,null);a=d.create({width:a,height:b,format:f});a._renderbuffer.refCount=0;return new r(36161,null,a)}function F(a){return a&&(a.texture||a.renderbuffer)}function k(a,b,c){a&&(a.texture?a.texture.resize(b,c):a.renderbuffer&&a.renderbuffer.resize(b,c),a.width=b,a.height=c)}function h(){this.id=z++;w[this.id]=this;this.framebuffer=a.createFramebuffer();this.height=this.width=0;this.colorAttachments= +[];this.depthStencilAttachment=this.stencilAttachment=this.depthAttachment=null}function f(a){a.colorAttachments.forEach(n);n(a.depthAttachment);n(a.stencilAttachment);n(a.depthStencilAttachment)}function p(b){a.deleteFramebuffer(b.framebuffer);b.framebuffer=null;g.framebufferCount--;delete w[b.id]}function m(b){var f;a.bindFramebuffer(36160,b.framebuffer);var e=b.colorAttachments;for(f=0;ff;++f){for(k=0;ka;++a)c[a].resize(f);b.width=b.height=f;return b},_reglType:"framebufferCube",destroy:function(){c.forEach(function(a){a.destroy()})}})},clear:function(){J(w).forEach(p)},restore:function(){Q.cur=null;Q.next=null;Q.dirty=!0;J(w).forEach(function(b){b.framebuffer= +a.createFramebuffer();m(b)})}})}function Ya(){this.w=this.z=this.y=this.x=this.state=0;this.buffer=null;this.size=0;this.normalized=!1;this.type=5126;this.divisor=this.stride=this.offset=0}function Pb(a,b,c,e,d){function g(a){if(a!==h.currentVAO){var c=b.oes_vertex_array_object;a?c.bindVertexArrayOES(a.vao):c.bindVertexArrayOES(null);h.currentVAO=a}}function r(c){if(c!==h.currentVAO){if(c)c.bindAttrs();else for(var d=b.angle_instanced_arrays,e=0;ea&&(a=b.stats.uniformsCount)});return a},c.getMaxAttributesCount=function(){var a=0;F.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var b=a.deleteShader.bind(a);J(q).forEach(b);q={};J(t).forEach(b);t={};F.forEach(function(b){a.deleteProgram(b.program)});F.length=0;l={};c.shaderCount=0},program:function(a,b,e,d){var g=l[b];g||(g=l[b]={});var k=g[a];if(k&&!d)return k;b=new n(b, +a);c.shaderCount++;u(b,e,d);k||(g[a]=b);F.push(b);return b},restore:function(){q={};t={};for(var a=0;a"+b+"?"+e+".constant["+b+"]:0;"}).join(""),"}}else{", +"if(",h,"(",e,".buffer)){",k,"=",f,".createStream(",34962,",",e,".buffer);","}else{",k,"=",f,".getBuffer(",e,".buffer);","}",U,'="type" in ',e,"?",g.glTypes,"[",e,".type]:",k,".dtype;",y.normalized,"=!!",e,".normalized;");d("size");d("offset");d("stride");d("divisor");c("}}");c.exit("if(",y.isStream,"){",f,".destroyStream(",k,");","}");return y})});return g}function D(a,b){var c=a["static"],d=a.dynamic;if("vao"in c){var e=c.vao;null!==e&&null===q.getVAO(e)&&(e=q.createVAO(e));return C(function(a){return a.link(q.getVAO(e))})}if("vao"in +d){var f=d.vao;return L(f,function(a,b){var c=a.invoke(b,f);return b.def(a.shared.vao+".getVAO("+c+")")})}return null}function x(a){var b=a["static"],c=a.dynamic,d={};Object.keys(b).forEach(function(a){var c=b[a];d[a]=C(function(a,b){return"number"===typeof c||"boolean"===typeof c?""+c:a.link(c)})});Object.keys(c).forEach(function(a){var b=c[a];d[a]=L(b,function(a,c){return a.invoke(c,b)})});return d}function ma(a,b,d,e,g){function h(a){var b=n[a];b&&(Za[a]=b)}var k=H(a,b),l=z(a,g),n=w(a,l,g),m=G(a, +g),Za=R(a,g),p=E(a,g,k);h("viewport");h(f("scissor.box"));var r=0>1)",t],");")}function b(){c(v,".drawArraysInstancedANGLE(",[p,q,r,t],");")}n?ca?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}function g(){function a(){c(k+".drawElements("+[p,r,u,q+"<<(("+u+"-5121)>>1)"]+");")} +function b(){c(k+".drawArrays("+[p,q,r]+");")}n?ca?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}var h=a.shared,k=h.gl,l=h.draw,m=d.draw,n=function(){var e=m.elements,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l,".","elements");e&&f("if("+e+")"+k+".bindBuffer(34963,"+e+".buffer.buffer);");return e}(),p=e("primitive"),q=e("offset"),r=function(){var e=m.count,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l, +".","count");return e}();if("number"===typeof r){if(0===r)return}else c("if(",r,"){"),c.exit("}");var t,v;pa&&(t=e("instances"),v=a.instancing);var u=n+".type",ca=m.elements&&va(m.elements);pa&&("number"!==typeof t||0<=t)?"string"===typeof t?(c("if(",t,">0){"),f(),c("}else if(",t,"<0){"),g(),c("}")):f():g()}function ya(a,b,c,d,e){b=v();e=b.proc("body",e);pa&&(b.instancing=e.def(b.shared.extensions,".angle_instanced_arrays"));a(b,e,c,d);return b.compile().body}function ca(a,b,c,d){B(a,b);c.useVAO? +c.drawVAO?b(a.shared.vao,".setVAO(",c.drawVAO.append(a,b),");"):b(a.shared.vao,".setVAO(",a.shared.vao,".targetVAO);"):(b(a.shared.vao,".setVAO(null);"),N(a,b,c,d.attributes,function(){return!0}));xa(a,b,c,d.uniforms,function(){return!0});ba(a,b,b,c)}function Ea(a,b){var c=a.proc("draw",1);B(a,c);T(a,c,b.context);O(a,c,b.framebuffer);S(a,c,b);K(a,c,b.state);V(a,c,b,!1,!0);var d=b.shader.progVar.append(a,c);c(a.shared.gl,".useProgram(",d,".program);");if(b.shader.program)ca(a,c,b,b.shader.program); +else{c(a.shared.vao,".setVAO(null);");var e=a.global.def("{}"),f=c.def(d,".id"),g=c.def(e,"[",f,"]");c(a.cond(g).then(g,".call(this,a0);")["else"](g,"=",e,"[",f,"]=",a.link(function(c){return ya(ca,a,b,c,1)}),"(",d,");",g,".call(this,a0);"))}0= +--this.refCount&&r(this)};d.profile&&(e.getTotalRenderbufferSize=function(){var a=0;Object.keys(t).forEach(function(b){a+=t[b].stats.size});return a});return{create:function(b,c){function k(b,c){var e=0,g=0,l=32854;"object"===typeof b&&b?("shape"in b?(g=b.shape,e=g[0]|0,g=g[1]|0):("radius"in b&&(e=g=b.radius|0),"width"in b&&(e=b.width|0),"height"in b&&(g=b.height|0)),"format"in b&&(l=n[b.format])):"number"===typeof b?(e=b|0,g="number"===typeof c?c|0:e):b||(e=g=1);if(e!==h.width||g!==h.height||l!== +h.format)return k.width=h.width=e,k.height=h.height=g,h.format=l,a.bindRenderbuffer(36161,h.renderbuffer),a.renderbufferStorage(36161,l,e,g),d.profile&&(h.stats.size=E[h.format]*h.width*h.height),k.format=u[h.format],k}var h=new g(a.createRenderbuffer());t[h.id]=h;e.renderbufferCount++;k(b,c);k.resize=function(b,c){var e=b|0,g=c|0||e;if(e===h.width&&g===h.height)return k;k.width=h.width=e;k.height=h.height=g;a.bindRenderbuffer(36161,h.renderbuffer);a.renderbufferStorage(36161,h.format,e,g);d.profile&& +(h.stats.size=E[h.format]*h.width*h.height);return k};k._reglType="renderbuffer";k._renderbuffer=h;d.profile&&(k.stats=h.stats);k.destroy=function(){h.decRef()};return k},clear:function(){J(t).forEach(r)},restore:function(){J(t).forEach(function(b){b.renderbuffer=a.createRenderbuffer();a.bindRenderbuffer(36161,b.renderbuffer);a.renderbufferStorage(36161,b.format,b.width,b.height)});a.bindRenderbuffer(36161,null)}}},Xa=[];Xa[6408]=4;Xa[6407]=3;var Oa=[];Oa[5121]=1;Oa[5126]=4;Oa[36193]=2;var Ca=["x", +"y","z","w"],Ub="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Fa={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771,"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},$a={never:512, +less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Qa={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056,invert:5386},xb={cw:2304,ccw:2305},yb=new P(!1,!1,!1,function(){}),Xb=function(a,b){function c(){this.endQueryIndex=this.startQueryIndex=-1;this.sum=0;this.stats=null}function e(a,b,d){var e=r.pop()||new c;e.startQueryIndex=a;e.endQueryIndex= +b;e.sum=0;e.stats=d;n.push(e)}if(!b.ext_disjoint_timer_query)return null;var d=[],g=[],r=[],n=[],u=[],q=[];return{beginQuery:function(a){var c=d.pop()||b.ext_disjoint_timer_query.createQueryEXT();b.ext_disjoint_timer_query.beginQueryEXT(35007,c);g.push(c);e(g.length-1,g.length,a)},endQuery:function(){b.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:e,update:function(){var a,c;a=g.length;if(0!==a){q.length=Math.max(q.length,a+1);u.length=Math.max(u.length,a+1);u[0]=0;var e=q[0]=0;for(c= +a=0;c=B.length&&e()}var c=zb(B,a);B[c]=b}}}function q(){var a=S.viewport,b=S.scissor_box;a[0]=a[1]=b[0]=b[1]=0;A.viewportWidth=A.framebufferWidth=A.drawingBufferWidth=a[2]=b[2]=k.drawingBufferWidth;A.viewportHeight=A.framebufferHeight=A.drawingBufferHeight=a[3]=b[3]=k.drawingBufferHeight}function t(){A.tick+=1;A.time=z();q(); +O.procs.poll()}function l(){q();O.procs.refresh();w&&w.update()}function z(){return(Ab()-C)/1E3}a=Fb(a);if(!a)return null;var k=a.gl,h=k.getContextAttributes();k.isContextLost();var f=Gb(k,a);if(!f)return null;var p=Cb(),m={vaoCount:0,bufferCount:0,elementsCount:0,framebufferCount:0,shaderCount:0,textureCount:0,cubeCount:0,renderbufferCount:0,maxTextureUnits:0},v=f.extensions,w=Xb(k,v),C=Ab(),E=k.drawingBufferWidth,L=k.drawingBufferHeight,A={tick:0,time:0,viewportWidth:E,viewportHeight:L,framebufferWidth:E, +framebufferHeight:L,drawingBufferWidth:E,drawingBufferHeight:L,pixelRatio:a.pixelRatio},G=Vb(k,v),R=Hb(k,m,a,function(a){return J.destroyBuffer(a)}),J=Pb(k,v,G,m,R),P=Ib(k,v,R,m),D=Qb(k,p,m,a),x=Lb(k,v,G,function(){O.procs.poll()},A,m,a),N=Wb(k,v,G,m,a),T=Ob(k,v,G,x,N,m),O=Tb(k,p,v,G,R,P,x,T,{},J,D,{elements:null,primitive:4,count:-1,offset:0,instances:-1},A,w,a),p=Rb(k,T,O.procs.poll,A,h,v,G),S=O.next,K=k.canvas,B=[],V=[],X=[],Y=[a.onDestroy],ba=null;K&&(K.addEventListener("webglcontextlost",d,!1), +K.addEventListener("webglcontextrestored",g,!1));var Z=T.setFBO=r({framebuffer:ha.define.call(null,1,"framebuffer")});l();h=H(r,{clear:function(a){if("framebuffer"in a)if(a.framebuffer&&"framebufferCube"===a.framebuffer_reglType)for(var b=0;6>b;++b)Z(H({framebuffer:a.framebuffer.faces[b]},a),n);else Z(a,n);else n(null,a)},prop:ha.define.bind(null,1),context:ha.define.bind(null,2),"this":ha.define.bind(null,3),draw:r({}),buffer:function(a){return R.create(a,34962,!1,!1)},elements:function(a){return P.create(a, +!1)},texture:x.create2D,cube:x.createCube,renderbuffer:N.create,framebuffer:T.create,framebufferCube:T.createCube,vao:J.createVAO,attributes:h,frame:u,on:function(a,b){var c;switch(a){case "frame":return u(b);case "lost":c=V;break;case "restore":c=X;break;case "destroy":c=Y}c.push(b);return{cancel:function(){for(var a=0;a= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -function maybeAddCandidate(iceTransport, candidate) { - // Edge's internal representation adds some fields therefore - // not all fieldѕ are taken into account. - var alreadyAdded = iceTransport.getRemoteCandidates() - .find(function(remoteCandidate) { - return candidate.foundation === remoteCandidate.foundation && - candidate.ip === remoteCandidate.ip && - candidate.port === remoteCandidate.port && - candidate.priority === remoteCandidate.priority && - candidate.protocol === remoteCandidate.protocol && - candidate.type === remoteCandidate.type; - }); - if (!alreadyAdded) { - iceTransport.addRemoteCandidate(candidate); - } - return !alreadyAdded; -} - - -function makeError(name, description) { - var e = new Error(description); - e.name = name; - // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names - e.code = { - NotSupportedError: 9, - InvalidStateError: 11, - InvalidAccessError: 15, - TypeError: undefined, - OperationError: undefined - }[name]; - return e; -} - -module.exports = function(window, edgeVersion) { - // https://w3c.github.io/mediacapture-main/#mediastream - // Helper function to add the track to the stream and - // dispatch the event ourselves. - function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', - {track: track})); - } - - function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', - {track: track})); - } - - function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); - } - - var RTCPeerConnection = function(config) { - var pc = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - pc[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.canTrickleIceCandidates = null; - - this.needNegotiation = false; - - this.localStreams = []; - this.remoteStreams = []; - - this._localDescription = null; - this._remoteDescription = null; - - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.connectionState = 'new'; - this.iceGatheringState = 'new'; - - config = JSON.parse(JSON.stringify(config || {})); - - this.usingBundle = config.bundlePolicy === 'max-bundle'; - if (config.rtcpMuxPolicy === 'negotiate') { - throw(makeError('NotSupportedError', - 'rtcpMuxPolicy \'negotiate\' is not supported')); - } else if (!config.rtcpMuxPolicy) { - config.rtcpMuxPolicy = 'require'; - } - - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - break; - default: - config.iceTransportPolicy = 'all'; - break; - } - - switch (config.bundlePolicy) { - case 'balanced': - case 'max-compat': - case 'max-bundle': - break; - default: - config.bundlePolicy = 'balanced'; - break; - } - - config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); - - this._iceGatherers = []; - if (config.iceCandidatePoolSize) { - for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers.push(new window.RTCIceGatherer({ - iceServers: config.iceServers, - gatherPolicy: config.iceTransportPolicy - })); - } - } else { - config.iceCandidatePoolSize = 0; - } - - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - this._sdpSessionVersion = 0; - - this._dtlsRole = undefined; // role for a=setup to use in answers. - - this._isClosed = false; - }; - - Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', { - configurable: true, - get: function() { - return this._localDescription; - } - }); - Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', { - configurable: true, - get: function() { - return this._remoteDescription; - } - }); - - // set up event handlers on prototype - RTCPeerConnection.prototype.onicecandidate = null; - RTCPeerConnection.prototype.onaddstream = null; - RTCPeerConnection.prototype.ontrack = null; - RTCPeerConnection.prototype.onremovestream = null; - RTCPeerConnection.prototype.onsignalingstatechange = null; - RTCPeerConnection.prototype.oniceconnectionstatechange = null; - RTCPeerConnection.prototype.onconnectionstatechange = null; - RTCPeerConnection.prototype.onicegatheringstatechange = null; - RTCPeerConnection.prototype.onnegotiationneeded = null; - RTCPeerConnection.prototype.ondatachannel = null; - - RTCPeerConnection.prototype._dispatchEvent = function(name, event) { - if (this._isClosed) { - return; - } - this.dispatchEvent(event); - if (typeof this['on' + name] === 'function') { - this['on' + name](event); - } - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this._dispatchEvent('icegatheringstatechange', event); - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - RTCPeerConnection.prototype.getLocalStreams = function() { - return this.localStreams; - }; - - RTCPeerConnection.prototype.getRemoteStreams = function() { - return this.remoteStreams; - }; - - // internal helper to create a transceiver object. - // (which is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - associatedRemoteMediaStreams: [], - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - if (!doNotAdd) { - this.transceivers.push(transceiver); - } - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (this._isClosed) { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - - var alreadyExists = this.transceivers.find(function(s) { - return s.track === track; - }); - - if (alreadyExists) { - throw makeError('InvalidAccessError', 'Track already exists.'); - } - - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - this._maybeFireNegotiationNeeded(); - - if (this.localStreams.indexOf(stream) === -1) { - this.localStreams.push(stream); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - if (edgeVersion >= 15025) { - stream.getTracks().forEach(function(track) { - pc.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - pc.addTrack(track, clonedStream); - }); - } - }; - - RTCPeerConnection.prototype.removeTrack = function(sender) { - if (this._isClosed) { - throw makeError('InvalidStateError', - 'Attempted to call removeTrack on a closed peerconnection.'); - } - - if (!(sender instanceof window.RTCRtpSender)) { - throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.'); - } - - var transceiver = this.transceivers.find(function(t) { - return t.rtpSender === sender; - }); - - if (!transceiver) { - throw makeError('InvalidAccessError', - 'Sender was not created by this connection.'); - } - var stream = transceiver.stream; - - transceiver.rtpSender.stop(); - transceiver.rtpSender = null; - transceiver.track = null; - transceiver.stream = null; - - // remove the stream from the set of local streams - var localStreams = this.transceivers.map(function(t) { - return t.stream; - }); - if (localStreams.indexOf(stream) === -1 && - this.localStreams.indexOf(stream) > -1) { - this.localStreams.splice(this.localStreams.indexOf(stream), 1); - } - - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - stream.getTracks().forEach(function(track) { - var sender = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (sender) { - pc.removeTrack(sender); - } - }); - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - - RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, - usingBundle) { - var pc = this; - if (usingBundle && sdpMLineIndex > 0) { - return this.transceivers[0].iceGatherer; - } else if (this._iceGatherers.length) { - return this._iceGatherers.shift(); - } - var iceGatherer = new window.RTCIceGatherer({ - iceServers: this._config.iceServers, - gatherPolicy: this._config.iceTransportPolicy - }); - Object.defineProperty(iceGatherer, 'state', - {value: 'new', writable: true} - ); - - this.transceivers[sdpMLineIndex].bufferedCandidateEvents = []; - this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) { - pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event); - } - }; - iceGatherer.addEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - return iceGatherer; - }; - - // start gathering from an RTCIceGatherer. - RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { - var pc = this; - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer.onlocalcandidate) { - return; - } - var bufferedCandidateEvents = - this.transceivers[sdpMLineIndex].bufferedCandidateEvents; - this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null; - iceGatherer.removeEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - iceGatherer.onlocalcandidate = function(evt) { - if (pc.usingBundle && sdpMLineIndex > 0) { - // if we know that we use bundle we can drop candidates with - // ѕdpMLineIndex > 0. If we don't do this then our state gets - // confused since we dispose the extra ice gatherer. - return; - } - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - // Edge emits an empty object for RTCIceCandidateComplete‥ - var end = !cand || Object.keys(cand).length === 0; - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { - iceGatherer.state = 'completed'; - } - } else { - if (iceGatherer.state === 'new') { - iceGatherer.state = 'gathering'; - } - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - // also the usernameFragment. TODO: update SDP to take both variants. - cand.ufrag = iceGatherer.getLocalParameters().usernameFragment; - - var serializedCandidate = SDPUtils.writeCandidate(cand); - event.candidate = Object.assign(event.candidate, - SDPUtils.parseCandidate(serializedCandidate)); - - event.candidate.candidate = serializedCandidate; - event.candidate.toJSON = function() { - return { - candidate: event.candidate.candidate, - sdpMid: event.candidate.sdpMid, - sdpMLineIndex: event.candidate.sdpMLineIndex, - usernameFragment: event.candidate.usernameFragment - }; - }; - } - - // update local description. - var sections = SDPUtils.getMediaSections(pc._localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex] += - 'a=end-of-candidates\r\n'; - } - pc._localDescription.sdp = - SDPUtils.getDescription(pc._localDescription.sdp) + - sections.join(''); - var complete = pc.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - if (pc.iceGatheringState !== 'gathering') { - pc.iceGatheringState = 'gathering'; - pc._emitGatheringStateChange(); - } - - // Emit candidate. Also emit null candidate when all gatherers are - // complete. - if (!end) { - pc._dispatchEvent('icecandidate', event); - } - if (complete) { - pc._dispatchEvent('icecandidate', new Event('icecandidate')); - pc.iceGatheringState = 'complete'; - pc._emitGatheringStateChange(); - } - }; - - // emit already gathered candidates. - window.setTimeout(function() { - bufferedCandidateEvents.forEach(function(e) { - iceGatherer.onlocalcandidate(e); - }); - }, 0); - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var pc = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - pc._updateIceConnectionState(); - pc._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - pc._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - pc._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - if (transceiver.recvEncodingParameters.length) { - params.encodings = transceiver.recvEncodingParameters; - } else { - params.encodings = [{}]; - } - params.rtcp = { - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.rtcpParameters.cname) { - params.rtcp.cname = transceiver.rtcpParameters.cname; - } - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var pc = this; - - // Note: pranswer is not supported. - if (['offer', 'answer'].indexOf(description.type) === -1) { - return Promise.reject(makeError('TypeError', - 'Unsupported type "' + description.type + '"')); - } - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, pc.signalingState) || pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set local ' + description.type + - ' in state ' + pc.signalingState)); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - pc.transceivers[sdpMLineIndex].localCapabilities = caps; - }); - - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - pc._gather(transceiver.mid, sdpMLineIndex); - }); - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc._remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = pc.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - - if (!rejected && !transceiver.rejected) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!pc.usingBundle || sdpMLineIndex === 0) { - pc._gather(transceiver.mid, sdpMLineIndex); - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - pc._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - pc._localDescription = { - type: description.type, - sdp: description.sdp - }; - if (description.type === 'offer') { - pc._updateSignalingState('have-local-offer'); - } else { - pc._updateSignalingState('stable'); - } - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var pc = this; - - // Note: pranswer is not supported. - if (['offer', 'answer'].indexOf(description.type) === -1) { - return Promise.reject(makeError('TypeError', - 'Unsupported type "' + description.type + '"')); - } - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, pc.signalingState) || pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set remote ' + description.type + - ' in state ' + pc.signalingState)); - } - - var streams = {}; - pc.remoteStreams.forEach(function(stream) { - streams[stream.id] = stream; - }); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - pc.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - pc.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' || - protocol === 'UDP/DTLS/SCTP'))) { - // TODO: this is dangerous in the case where a non-rejected m-line - // becomes rejected. - pc.transceivers[sdpMLineIndex] = { - mid: mid, - kind: kind, - protocol: protocol, - rejected: true - }; - return; - } - - if (!rejected && pc.transceivers[sdpMLineIndex] && - pc.transceivers[sdpMLineIndex].rejected) { - // recycle a rejected transceiver. - pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true); - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - pc.transceivers[sdpMLineIndex]) { - pc._disposeIceAndDtlsTransports(sdpMLineIndex); - pc.transceivers[sdpMLineIndex].iceGatherer = - pc.transceivers[0].iceGatherer; - pc.transceivers[sdpMLineIndex].iceTransport = - pc.transceivers[0].iceTransport; - pc.transceivers[sdpMLineIndex].dtlsTransport = - pc.transceivers[0].dtlsTransport; - if (pc.transceivers[sdpMLineIndex].rtpSender) { - pc.transceivers[sdpMLineIndex].rtpSender.setTransport( - pc.transceivers[0].dtlsTransport); - } - if (pc.transceivers[sdpMLineIndex].rtpReceiver) { - pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - pc.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex] || - pc._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - usingBundle); - } - - if (cands.length && transceiver.iceTransport.state === 'new') { - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - var isNewTrack = false; - if (direction === 'sendrecv' || direction === 'sendonly') { - isNewTrack = !transceiver.rtpReceiver; - rtpReceiver = transceiver.rtpReceiver || - new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); - - if (isNewTrack) { - var stream; - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid && remoteMsid.stream === '-') { - // no-op. a stream id of '-' means: no associated stream. - } else if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - stream = streams[remoteMsid.stream]; - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - stream = streams.default; - } - if (stream) { - addTrackToStreamAndFireEvent(track, stream); - transceiver.associatedRemoteMediaStreams.push(stream); - } - receiverList.push([track, rtpReceiver, stream]); - } - } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { - transceiver.associatedRemoteMediaStreams.forEach(function(s) { - var nativeTrack = s.getTracks().find(function(t) { - return t.id === transceiver.rtpReceiver.track.id; - }); - if (nativeTrack) { - removeTrackFromStreamAndFireEvent(nativeTrack, s); - } - }); - transceiver.associatedRemoteMediaStreams = []; - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - pc._transceive(pc.transceivers[sdpMLineIndex], - false, - isNewTrack); - } else if (description.type === 'answer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - pc.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - pc.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (cands.length && iceTransport.state === 'new') { - if ((isIceLite || isComplete) && - (!usingBundle || sdpMLineIndex === 0)) { - iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - if (!usingBundle || sdpMLineIndex === 0) { - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - pc._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams.default); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - if (pc._dtlsRole === undefined) { - pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; - } - - pc._remoteDescription = { - type: description.type, - sdp: description.sdp - }; - if (description.type === 'offer') { - pc._updateSignalingState('have-remote-offer'); - } else { - pc._updateSignalingState('stable'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - if (pc.remoteStreams.indexOf(stream) === -1) { - pc.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - window.setTimeout(function() { - pc._dispatchEvent('addstream', event); - }); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - fireAddTrack(pc, track, receiver, [stream]); - }); - } - }); - receiverList.forEach(function(item) { - if (item[2]) { - return; - } - fireAddTrack(pc, item[0], item[1], []); - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(pc && pc.transceivers)) { - return; - } - pc.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._isClosed = true; - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this._dispatchEvent('signalingstatechange', event); - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var pc = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (pc.needNegotiation) { - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); - } - }, 0); - }; - - // Update the ice connection state. - RTCPeerConnection.prototype._updateIceConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - }); - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.checking > 0) { - newState = 'checking'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0) { - newState = 'connected'; - } else if (states.completed > 0) { - newState = 'completed'; - } - - if (newState !== this.iceConnectionState) { - this.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this._dispatchEvent('iceconnectionstatechange', event); - } - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0) { - newState = 'connected'; - } - - if (newState !== this.connectionState) { - this.connectionState = newState; - var event = new Event('connectionstatechange'); - this._dispatchEvent('connectionstatechange', event); - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var pc = this; - - if (pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createOffer after close')); - } - - var numAudioTracks = pc.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = pc.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - var offerOptions = arguments[0]; - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - pc.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - pc._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - pc._createTransceiver('video'); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, - pc._sdpSessionVersion++); - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = transceiver.mid || SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - pc.usingBundle); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - - // for subsequent offers, we might have to re-use the payload - // type of the last offer. - if (transceiver.remoteCapabilities && - transceiver.remoteCapabilities.codecs) { - transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) { - if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && - codec.clockRate === remoteCodec.clockRate) { - codec.preferredPayloadType = remoteCodec.payloadType; - } - }); - } - }); - localCapabilities.headerExtensions.forEach(function(hdrExt) { - var remoteExtensions = transceiver.remoteCapabilities && - transceiver.remoteCapabilities.headerExtensions || []; - remoteExtensions.forEach(function(rHdrExt) { - if (hdrExt.uri === rHdrExt.uri) { - hdrExt.id = rHdrExt.id; - } - }); - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video' && - !sendEncodingParameters[0].rtx) { - sendEncodingParameters[0].rtx = { - ssrc: sendEncodingParameters[0].ssrc + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, kind); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (pc._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += writeMediaSection(transceiver, transceiver.localCapabilities, - 'offer', transceiver.stream, pc._dtlsRole); - sdp += 'a=rtcp-rsize\r\n'; - - if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && - (sdpMLineIndex === 0 || !pc.usingBundle)) { - transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { - cand.component = 1; - sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; - }); - - if (transceiver.iceGatherer.state === 'completed') { - sdp += 'a=end-of-candidates\r\n'; - } - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var pc = this; - - if (pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer after close')); - } - - if (!(pc.signalingState === 'have-remote-offer' || - pc.signalingState === 'have-local-pranswer')) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer in signalingState ' + pc.signalingState)); - } - - var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, - pc._sdpSessionVersion++); - if (pc.usingBundle) { - sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - var mediaSectionsInOffer = SDPUtils.getMediaSections( - pc._remoteDescription.sdp).length; - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (sdpMLineIndex + 1 > mediaSectionsInOffer) { - return; - } - if (transceiver.rejected) { - if (transceiver.kind === 'application') { - if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt - sdp += 'm=application 0 DTLS/SCTP 5000\r\n'; - } else { - sdp += 'm=application 0 ' + transceiver.protocol + - ' webrtc-datachannel\r\n'; - } - } else if (transceiver.kind === 'audio') { - sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + - 'a=rtpmap:0 PCMU/8000\r\n'; - } else if (transceiver.kind === 'video') { - sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + - 'a=rtpmap:120 VP8/90000\r\n'; - } - sdp += 'c=IN IP4 0.0.0.0\r\n' + - 'a=inactive\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video' && - !transceiver.sendEncodingParameters[0].rtx) { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream, pc._dtlsRole); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - var pc = this; - var sections; - if (candidate && !(candidate.sdpMLineIndex !== undefined || - candidate.sdpMid)) { - return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required')); - } - - // TODO: needs to go into ops queue. - return new Promise(function(resolve, reject) { - if (!pc._remoteDescription) { - return reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else if (!candidate || candidate.candidate === '') { - for (var j = 0; j < pc.transceivers.length; j++) { - if (pc.transceivers[j].rejected) { - continue; - } - pc.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); - sections[j] += 'a=end-of-candidates\r\n'; - pc._remoteDescription.sdp = - SDPUtils.getDescription(pc._remoteDescription.sdp) + - sections.join(''); - if (pc.usingBundle) { - break; - } - } - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < pc.transceivers.length; i++) { - if (pc.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; - break; - } - } - } - var transceiver = pc.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.rejected) { - return resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== pc.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); - } - sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); - sections[sdpMLineIndex] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - pc._remoteDescription.sdp = - SDPUtils.getDescription(pc._remoteDescription.sdp) + - sections.join(''); - } else { - return reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - resolve(); - }); - }; - - RTCPeerConnection.prototype.getStats = function(selector) { - if (selector && selector instanceof window.MediaStreamTrack) { - var senderOrReceiver = null; - this.transceivers.forEach(function(transceiver) { - if (transceiver.rtpSender && - transceiver.rtpSender.track === selector) { - senderOrReceiver = transceiver.rtpSender; - } else if (transceiver.rtpReceiver && - transceiver.rtpReceiver.track === selector) { - senderOrReceiver = transceiver.rtpReceiver; - } - }); - if (!senderOrReceiver) { - throw makeError('InvalidAccessError', 'Invalid selector.'); - } - return senderOrReceiver.getStats(); - } - - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - return Promise.all(promises).then(function(allStats) { - var results = new Map(); - allStats.forEach(function(stats) { - stats.forEach(function(stat) { - results.set(stat.id, stat); - }); - }); - return results; - }); - }; - - // fix low-level stat names and return Map instead of object. - var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', - 'RTCIceTransport', 'RTCDtlsTransport']; - ortcObjects.forEach(function(ortcObjectName) { - var obj = window[ortcObjectName]; - if (obj && obj.prototype && obj.prototype.getStats) { - var nativeGetstats = obj.prototype.getStats; - obj.prototype.getStats = function() { - return nativeGetstats.apply(this) - .then(function(nativeStats) { - var mapStats = new Map(); - Object.keys(nativeStats).forEach(function(id) { - nativeStats[id].type = fixStatsType(nativeStats[id]); - mapStats.set(id, nativeStats[id]); - }); - return mapStats; - }); - }; - } - }); - - // legacy callback shims. Should be moved to adapter.js some days. - var methods = ['createOffer', 'createAnswer']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[0] === 'function' || - typeof args[1] === 'function') { // legacy - return nativeMethod.apply(this, [arguments[2]]) - .then(function(description) { - if (typeof args[0] === 'function') { - args[0].apply(null, [description]); - } - }, function(error) { - if (typeof args[1] === 'function') { - args[1].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function' || - typeof args[2] === 'function') { // legacy - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }, function(error) { - if (typeof args[2] === 'function') { - args[2].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // getStats is special. It doesn't have a spec legacy method yet we support - // getStats(something, cb) without error callbacks. - ['getStats'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function') { - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - return RTCPeerConnection; -}; - -},{"sdp":118}],117:[function(require,module,exports){ +},{}],108:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -117486,696 +112700,11 @@ SafeBuffer.allocUnsafeSlow = function (size) { return buffer.SlowBuffer(size) } -},{"buffer":27}],118:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// returns the session description. -SDPUtils.getDescription = function(blob) { - var sections = SDPUtils.splitSections(blob); - return sections && sections[0]; -}; - -// returns the individual media sections. -SDPUtils.getMediaSections = function(blob) { - var sections = SDPUtils.splitSections(blob); - sections.shift(); - return sections; -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - case 'ufrag': - candidate.ufrag = parts[i + 1]; // for backward compability. - candidate.usernameFragment = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - 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); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); - sdp.push('rport'); - sdp.push(candidate.relatedPort); - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.usernameFragment || candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.usernameFragment || candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - // legacy alias, got renamed back to channels in ORTC. - parsed.numChannels = parsed.channels; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - var channels = codec.channels || codec.numChannels || 1; - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (channels !== 1 ? '/' + channels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - if (codec.parameters[param]) { - params.push(param + '=' + codec.parameters[param]); - } else { - params.push(param); - } - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - if (caps.headerExtensions) { - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - } - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.substr(17).split(' '); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - }; - if (primarySsrc && secondarySsrc) { - encParam.rtx = {ssrc: secondarySsrc}; - } - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -SDPUtils.parseMLine = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var parts = lines[0].substr(2).split(' '); - return { - kind: parts[0], - port: parseInt(parts[1], 10), - protocol: parts[2], - fmt: parts.slice(3).join(' ') - }; -}; - -SDPUtils.parseOLine = function(mediaSection) { - var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; - var parts = line.substr(2).split(' '); - return { - username: parts[0], - sessionId: parts[1], - sessionVersion: parseInt(parts[2], 10), - netType: parts[3], - addressType: parts[4], - address: parts[5], - }; -} - -// Expose public methods. -if (typeof module === 'object') { - module.exports = SDPUtils; -} - -},{}],119:[function(require,module,exports){ +},{"buffer":27}],109:[function(require,module,exports){ 'use strict'; module.exports = require('./lib/index'); -},{"./lib/index":124}],120:[function(require,module,exports){ +},{"./lib/index":114}],110:[function(require,module,exports){ 'use strict'; var randomFromSeed = require('./random/random-from-seed'); @@ -118275,7 +112804,7 @@ module.exports = { shuffled: getShuffled }; -},{"./random/random-from-seed":127}],121:[function(require,module,exports){ +},{"./random/random-from-seed":117}],111:[function(require,module,exports){ 'use strict'; var encode = require('./encode'); @@ -118325,7 +112854,7 @@ function build(clusterWorkerId) { module.exports = build; -},{"./alphabet":120,"./encode":123}],122:[function(require,module,exports){ +},{"./alphabet":110,"./encode":113}],112:[function(require,module,exports){ 'use strict'; var alphabet = require('./alphabet'); @@ -118344,7 +112873,7 @@ function decode(id) { module.exports = decode; -},{"./alphabet":120}],123:[function(require,module,exports){ +},{"./alphabet":110}],113:[function(require,module,exports){ 'use strict'; var randomByte = require('./random/random-byte'); @@ -118365,7 +112894,7 @@ function encode(lookup, number) { module.exports = encode; -},{"./random/random-byte":126}],124:[function(require,module,exports){ +},{"./random/random-byte":116}],114:[function(require,module,exports){ 'use strict'; var alphabet = require('./alphabet'); @@ -118432,7 +112961,7 @@ module.exports.characters = characters; module.exports.decode = decode; module.exports.isValid = isValid; -},{"./alphabet":120,"./build":121,"./decode":122,"./encode":123,"./is-valid":125,"./util/cluster-worker-id":128}],125:[function(require,module,exports){ +},{"./alphabet":110,"./build":111,"./decode":112,"./encode":113,"./is-valid":115,"./util/cluster-worker-id":118}],115:[function(require,module,exports){ 'use strict'; var alphabet = require('./alphabet'); @@ -118453,7 +112982,7 @@ function isShortId(id) { module.exports = isShortId; -},{"./alphabet":120}],126:[function(require,module,exports){ +},{"./alphabet":110}],116:[function(require,module,exports){ 'use strict'; var crypto = typeof window === 'object' && (window.crypto || window.msCrypto); // IE 11 uses window.msCrypto @@ -118469,7 +112998,7 @@ function randomByte() { module.exports = randomByte; -},{}],127:[function(require,module,exports){ +},{}],117:[function(require,module,exports){ 'use strict'; // Found this seed-based random generator somewhere @@ -118496,12 +113025,12 @@ module.exports = { seed: setSeed }; -},{}],128:[function(require,module,exports){ +},{}],118:[function(require,module,exports){ 'use strict'; module.exports = 0; -},{}],129:[function(require,module,exports){ +},{}],119:[function(require,module,exports){ (function (Buffer){ module.exports = Peer @@ -119433,13 +113962,13 @@ function makeError (message, code) { function noop () {} }).call(this,require("buffer").Buffer) -},{"buffer":27,"debug":130,"get-browser-rtc":57,"inherits":89,"randombytes":104,"readable-stream":113}],130:[function(require,module,exports){ +},{"buffer":27,"debug":120,"get-browser-rtc":57,"inherits":81,"randombytes":96,"readable-stream":105}],120:[function(require,module,exports){ arguments[4][50][0].apply(exports,arguments) -},{"./debug":131,"_process":101,"dup":50}],131:[function(require,module,exports){ +},{"./debug":121,"_process":93,"dup":50}],121:[function(require,module,exports){ arguments[4][51][0].apply(exports,arguments) -},{"dup":51,"ms":132}],132:[function(require,module,exports){ +},{"dup":51,"ms":122}],122:[function(require,module,exports){ arguments[4][38][0].apply(exports,arguments) -},{"dup":38}],133:[function(require,module,exports){ +},{"dup":38}],123:[function(require,module,exports){ /** * Module dependencies. @@ -119535,7 +114064,7 @@ exports.connect = lookup; exports.Manager = require('./manager'); exports.Socket = require('./socket'); -},{"./manager":134,"./socket":136,"./url":137,"debug":39,"socket.io-parser":139}],134:[function(require,module,exports){ +},{"./manager":124,"./socket":126,"./url":127,"debug":39,"socket.io-parser":129}],124:[function(require,module,exports){ /** * Module dependencies. @@ -120110,7 +114639,7 @@ Manager.prototype.onreconnect = function () { this.emitAll('reconnect', attempt); }; -},{"./on":135,"./socket":136,"backo2":21,"component-bind":34,"component-emitter":35,"debug":39,"engine.io-client":41,"indexof":88,"socket.io-parser":139}],135:[function(require,module,exports){ +},{"./on":125,"./socket":126,"backo2":21,"component-bind":34,"component-emitter":35,"debug":39,"engine.io-client":41,"indexof":80,"socket.io-parser":129}],125:[function(require,module,exports){ /** * Module exports. @@ -120136,7 +114665,7 @@ function on (obj, ev, fn) { }; } -},{}],136:[function(require,module,exports){ +},{}],126:[function(require,module,exports){ /** * Module dependencies. @@ -120556,7 +115085,7 @@ Socket.prototype.compress = function (compress) { return this; }; -},{"./on":135,"component-bind":34,"component-emitter":35,"debug":39,"parseqs":97,"socket.io-parser":139,"to-array":149}],137:[function(require,module,exports){ +},{"./on":125,"component-bind":34,"component-emitter":35,"debug":39,"parseqs":89,"socket.io-parser":129,"to-array":139}],127:[function(require,module,exports){ (function (global){ /** @@ -120635,7 +115164,7 @@ function url (uri, loc) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"debug":39,"parseuri":98}],138:[function(require,module,exports){ +},{"debug":39,"parseuri":90}],128:[function(require,module,exports){ (function (global){ /*global Blob,File*/ @@ -120780,7 +115309,7 @@ exports.removeBlobs = function(data, callback) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./is-buffer":140,"isarray":141}],139:[function(require,module,exports){ +},{"./is-buffer":130,"isarray":131}],129:[function(require,module,exports){ /** * Module dependencies. @@ -121182,7 +115711,7 @@ function error() { }; } -},{"./binary":138,"./is-buffer":140,"component-emitter":35,"debug":39,"has-binary2":69}],140:[function(require,module,exports){ +},{"./binary":128,"./is-buffer":130,"component-emitter":35,"debug":39,"has-binary2":58}],130:[function(require,module,exports){ (function (global){ module.exports = isBuf; @@ -121199,9 +115728,9 @@ function isBuf(obj) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],141:[function(require,module,exports){ -arguments[4][70][0].apply(exports,arguments) -},{"dup":70}],142:[function(require,module,exports){ +},{}],131:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"dup":59}],132:[function(require,module,exports){ 'use strict'; var Buffer = require('safe-buffer').Buffer; @@ -121474,7 +116003,7 @@ function simpleWrite(buf) { function simpleEnd(buf) { return buf && buf.length ? this.write(buf) : ''; } -},{"safe-buffer":117}],143:[function(require,module,exports){ +},{"safe-buffer":108}],133:[function(require,module,exports){ function Agent() { this._defaults = []; } @@ -121496,7 +116025,7 @@ Agent.prototype._setDefaults = function(req) { module.exports = Agent; -},{}],144:[function(require,module,exports){ +},{}],134:[function(require,module,exports){ /** * Root reference for iframes. */ @@ -122418,7 +116947,7 @@ request.put = function(url, data, fn) { return req; }; -},{"./agent-base":143,"./is-object":145,"./request-base":146,"./response-base":147,"component-emitter":35}],145:[function(require,module,exports){ +},{"./agent-base":133,"./is-object":135,"./request-base":136,"./response-base":137,"component-emitter":35}],135:[function(require,module,exports){ 'use strict'; /** @@ -122435,7 +116964,7 @@ function isObject(obj) { module.exports = isObject; -},{}],146:[function(require,module,exports){ +},{}],136:[function(require,module,exports){ 'use strict'; /** @@ -123131,7 +117660,7 @@ RequestBase.prototype._setTimeouts = function() { } }; -},{"./is-object":145}],147:[function(require,module,exports){ +},{"./is-object":135}],137:[function(require,module,exports){ 'use strict'; /** @@ -123269,7 +117798,7 @@ ResponseBase.prototype._setStatusProperties = function(status){ this.unprocessableEntity = 422 == status; }; -},{"./utils":148}],148:[function(require,module,exports){ +},{"./utils":138}],138:[function(require,module,exports){ 'use strict'; /** @@ -123342,7 +117871,7 @@ exports.cleanHeader = function(header, changesOrigin){ return header; }; -},{}],149:[function(require,module,exports){ +},{}],139:[function(require,module,exports){ module.exports = toArray function toArray(list, index) { @@ -123357,7 +117886,7 @@ function toArray(list, index) { return array } -},{}],150:[function(require,module,exports){ +},{}],140:[function(require,module,exports){ (function (global){ /** @@ -123428,2851 +117957,7 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],151:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":152}],152:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ - -'use strict'; - -var utils = require('./utils'); -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - var commonShim = require('./common_shim') || null; - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - commonShim.shimCreateObjectURL(window); - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - chromeShim.shimSenderReceiverGetStats(window); - chromeShim.fixNegotiationNeeded(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - commonShim.shimCreateObjectURL(window); - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - firefoxShim.shimSenderGetStats(window); - firefoxShim.shimReceiverGetStats(window); - firefoxShim.shimRTCDataChannel(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - commonShim.shimCreateObjectURL(window); - - edgeShim.shimGetUserMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - commonShim.shimCreateObjectURL(window); - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimCreateOfferLegacy(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":153,"./common_shim":155,"./edge/edge_shim":156,"./firefox/firefox_shim":159,"./safari/safari_shim":161,"./utils":162}],153:[function(require,module,exports){ - -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -/* iterates the stats graph recursively. */ -function walkStats(stats, base, resultSet) { - if (!base || resultSet.has(base.id)) { - return; - } - resultSet.set(base.id, base); - Object.keys(base).forEach(function(name) { - if (name.endsWith('Id')) { - walkStats(stats, stats.get(base[name]), resultSet); - } else if (name.endsWith('Ids')) { - base[name].forEach(function(id) { - walkStats(stats, stats.get(id), resultSet); - }); - } - }); -} - -/* filter getStats for a sender/receiver track. */ -function filterStats(result, track, outbound) { - var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; - var filteredResult = new Map(); - if (track === null) { - return filteredResult; - } - var trackStats = []; - result.forEach(function(value) { - if (value.type === 'track' && - value.trackIdentifier === track.id) { - trackStats.push(value); - } - }); - trackStats.forEach(function(trackStat) { - result.forEach(function(stats) { - if (stats.type === streamStatsType && stats.trackId === trackStat.id) { - walkStats(result, stats, filteredResult); - } - }); - }); - return filteredResult; -} - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - }, - enumerable: true, - configurable: true - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } else if (!('RTCRtpTransceiver' in window)) { - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - if (!e.transceiver) { - e.transceiver = {receiver: e.receiver}; - } - return e; - }); - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSenderReceiverGetStats: function(window) { - if (!(typeof window === 'object' && window.RTCPeerConnection && - window.RTCRtpSender && window.RTCRtpReceiver)) { - return; - } - - // shim sender stats. - if (!('getStats' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - if (origGetSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - } - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - if (origAddTrack) { - window.RTCPeerConnection.prototype.addTrack = function() { - var sender = origAddTrack.apply(this, arguments); - sender._pc = this; - return sender; - }; - } - window.RTCRtpSender.prototype.getStats = function() { - var sender = this; - return this._pc.getStats().then(function(result) { - /* Note: this will include stats of all senders that - * send a track with the same id as sender.track as - * it is not possible to identify the RTCRtpSender. - */ - return filterStats(result, sender.track, true); - }); - }; - } - - // shim receiver stats. - if (!('getStats' in window.RTCRtpReceiver.prototype)) { - var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; - if (origGetReceivers) { - window.RTCPeerConnection.prototype.getReceivers = function() { - var pc = this; - var receivers = origGetReceivers.apply(pc, []); - receivers.forEach(function(receiver) { - receiver._pc = pc; - }); - return receivers; - }; - } - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - e.receiver._pc = e.srcElement; - return e; - }); - window.RTCRtpReceiver.prototype.getStats = function() { - var receiver = this; - return this._pc.getStats().then(function(result) { - return filterStats(result, receiver.track, false); - }); - }; - } - - if (!('getStats' in window.RTCRtpSender.prototype && - 'getStats' in window.RTCRtpReceiver.prototype)) { - return; - } - - // shim RTCPeerConnection.getStats(track). - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function() { - var pc = this; - if (arguments.length > 0 && - arguments[0] instanceof window.MediaStreamTrack) { - var track = arguments[0]; - var sender; - var receiver; - var err; - pc.getSenders().forEach(function(s) { - if (s.track === track) { - if (sender) { - err = true; - } else { - sender = s; - } - } - }); - pc.getReceivers().forEach(function(r) { - if (r.track === track) { - if (receiver) { - err = true; - } else { - receiver = r; - } - } - return r.track === track; - }); - if (err || (sender && receiver)) { - return Promise.reject(new DOMException( - 'There are more than one sender or receiver for the track.', - 'InvalidAccessError')); - } else if (sender) { - return sender.getStats(); - } else if (receiver) { - return receiver.getStats(); - } - return Promise.reject(new DOMException( - 'There is no sender or receiver for the track.', - 'InvalidAccessError')); - } - return origGetStats.apply(pc, arguments); - }; - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - 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() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrackWithNative: function(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function(streamId) { - return pc._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - var existingSenders = pc.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = pc.getSenders().filter(function(newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function(streamId) { - var idx = pc._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - pc._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (pc._shimmedLocalStreams[streamId].length === 1) { - delete pc._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; - }, - - shimAddTrackRemoveTrack: function(window) { - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && - browserDetails.version >= 65) { - return this.shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - var nativeStreams = origGetLocalStreams.apply(this); - pc._reverseStreams = pc._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return pc._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function() { - pc.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), - externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), - internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - var args = arguments; - var isLegacyCall = arguments.length && - typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(pc, [ - function(description) { - var desc = replaceInternalStreamId(pc, description); - args[0].apply(null, [desc]); - }, - function(err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2] - ]); - } - return nativeMethod.apply(pc, arguments) - .then(function(description) { - return replaceInternalStreamId(pc, description); - }); - }; - }); - - var origSetLocalDescription = - window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function() { - var pc = this; - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(pc, arguments); - } - arguments[0] = replaceExternalStreamId(pc, arguments[0]); - return origSetLocalDescription.apply(pc, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor( - window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, - 'localDescription', { - get: function() { - var pc = this; - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(pc, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(pc._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var pc = 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.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(pc, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var pc = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = 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(pc, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - }, - - fixNegotiationNeeded: function(window) { - utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function(e) { - var pc = e.target; - if (pc.signalingState !== 'stable') { - return; - } - return e; - }); - }, - - shimGetDisplayMedia: function(window, getSourceId) { - if ('getDisplayMedia' in window.navigator) { - return; - } - // getSourceId is a function that returns a promise resolving with - // the sourceId of the screen/window/tab to be shared. - if (typeof getSourceId !== 'function') { - console.error('shimGetDisplayMedia: getSourceId argument is not ' + - 'a function'); - return; - } - navigator.getDisplayMedia = function(constraints) { - return getSourceId(constraints) - .then(function(sourceId) { - constraints.video = { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sourceId, - maxFrameRate: constraints.video.frameRate || 3 - } - }; - return navigator.mediaDevices.getUserMedia(constraints); - }); - }; - } -}; - -},{"../utils.js":162,"./getusermedia":154}],154:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - 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; - }; - - var shimConstraints_ = function(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - PermissionDismissedError: 'NotAllowedError', - InvalidStateError: 'NotAllowedError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotAllowedError', - MediaDeviceKillSwitchOn: 'NotAllowedError', - TabCaptureError: 'AbortError', - ScreenCaptureError: 'AbortError', - DeviceCaptureError: 'AbortError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraint || e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // 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 getUserMediaPromise_(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(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":162}],155:[function(require,module,exports){ -/* - * Copyright (c) 2017 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. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var utils = require('./utils'); - -module.exports = { - shimRTCIceCandidate: function(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (!window.RTCIceCandidate || (window.RTCIceCandidate && 'foundation' in - window.RTCIceCandidate.prototype)) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function(args) { - // Remove the a= which shouldn't be part of the candidate string. - if (typeof args === 'object' && args.candidate && - args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - if (args.candidate && args.candidate.length) { - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = SDPUtils.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, - parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment, - }; - }; - return augmentedCandidate; - } - return new NativeRTCIceCandidate(args); - }; - window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype && - URL.createObjectURL && URL.revokeObjectURL)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - }, - - shimMaxMessageSize: function(window) { - if (window.RTCSctpTransport || !window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function(description) { - var sections = SDPUtils.splitSections(description.sdp); - sections.shift(); - return sections.some(function(mediaSection) { - var mLine = SDPUtils.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' - && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else if (browserDetails.version < 60) { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = - browserDetails.version === 57 ? 65535 : 65536; - } else { - // FF >= 60 supports sending ~2 GiB - canSendMaxMessageSize = 2147483637; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' - && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && - remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - pc._sctp = null; - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function() { - return maxMessageSize; - } - }); - pc._sctp = sctp; - } - - return origSetRemoteDescription.apply(pc, arguments); - }; - }, - - shimSendThrowTypeError: function(window) { - if (!(window.RTCPeerConnection && - 'createDataChannel' in window.RTCPeerConnection.prototype)) { - return; - } - - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - function wrapDcSend(dc, pc) { - var origDataChannelSend = dc.send; - dc.send = function() { - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (dc.readyState === 'open' && - pc.sctp && length > pc.sctp.maxMessageSize) { - throw new TypeError('Message too large (can send a maximum of ' + - pc.sctp.maxMessageSize + ' bytes)'); - } - return origDataChannelSend.apply(dc, arguments); - }; - } - var origCreateDataChannel = - window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function() { - var pc = this; - var dataChannel = origCreateDataChannel.apply(pc, arguments); - wrapDcSend(dataChannel, pc); - return dataChannel; - }; - utils.wrapPeerConnectionEvent(window, 'datachannel', function(e) { - wrapDcSend(e.channel, e.target); - return e; - }); - } -}; - -},{"./utils":162,"sdp":118}],156:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var filterIceServers = require('./filtericeservers'); -var shimRTCPeerConnection = require('rtcpeerconnection-shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - // Edge currently only implements the RTCDtmfSender, not the - // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2* - if (window.RTCDtmfSender && !window.RTCDTMFSender) { - window.RTCDTMFSender = window.RTCDtmfSender; - } - - var RTCPeerConnectionShim = shimRTCPeerConnection(window, - browserDetails.version); - window.RTCPeerConnection = function(config) { - if (config && config.iceServers) { - config.iceServers = filterIceServers(config.iceServers); - } - return new RTCPeerConnectionShim(config); - }; - window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype; - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":162,"./filtericeservers":157,"./getusermedia":158,"rtcpeerconnection-shim":116}],157:[function(require,module,exports){ -/* - * Copyright (c) 2018 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. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -// Edge does not like -// 1) stun: filtered after 14393 unless ?transport=udp is present -// 2) turn: that does not have all of turn:host:port?transport=udp -// 3) turn: with ipv6 addresses -// 4) turn: occurring muliple times -module.exports = function(iceServers, edgeVersion) { - var hasTurn = false; - iceServers = JSON.parse(JSON.stringify(iceServers)); - return iceServers.filter(function(server) { - if (server && (server.urls || server.url)) { - var urls = server.urls || server.url; - if (server.url && !server.urls) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - } - var isString = typeof urls === 'string'; - if (isString) { - urls = [urls]; - } - urls = urls.filter(function(url) { - var validTurn = url.indexOf('turn:') === 0 && - url.indexOf('transport=udp') !== -1 && - url.indexOf('turn:[') === -1 && - !hasTurn; - - if (validTurn) { - hasTurn = true; - return true; - } - return url.indexOf('stun:') === 0 && edgeVersion >= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -}; - -},{"../utils":162}],158:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],159:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.transceiver = {receiver: event.receiver}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - if (typeof window === 'object' && window.RTCTrackEvent && - ('receiver' in window.RTCTrackEvent.prototype) && - !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - 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() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 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 window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - }, - - shimSenderGetStats: function(window) { - if (!(typeof window === 'object' && window.RTCPeerConnection && - window.RTCRtpSender)) { - return; - } - if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { - return; - } - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - if (origGetSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - } - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - if (origAddTrack) { - window.RTCPeerConnection.prototype.addTrack = function() { - var sender = origAddTrack.apply(this, arguments); - sender._pc = this; - return sender; - }; - } - window.RTCRtpSender.prototype.getStats = function() { - return this.track ? this._pc.getStats(this.track) : - Promise.resolve(new Map()); - }; - }, - - shimReceiverGetStats: function(window) { - if (!(typeof window === 'object' && window.RTCPeerConnection && - window.RTCRtpSender)) { - return; - } - if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { - return; - } - var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; - if (origGetReceivers) { - window.RTCPeerConnection.prototype.getReceivers = function() { - var pc = this; - var receivers = origGetReceivers.apply(pc, []); - receivers.forEach(function(receiver) { - receiver._pc = pc; - }); - return receivers; - }; - } - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - e.receiver._pc = e.srcElement; - return e; - }); - window.RTCRtpReceiver.prototype.getStats = function() { - return this._pc.getStats(this.track); - }; - }, - - shimRemoveStream: function(window) { - if (!window.RTCPeerConnection || - 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function(sender) { - if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - }, - - shimRTCDataChannel: function(window) { - // rename DataChannel to RTCDataChannel (native fix in FF60): - // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 - if (window.DataChannel && !window.RTCDataChannel) { - window.RTCDataChannel = window.DataChannel; - } - }, - - shimGetDisplayMedia: function(window, preferredMediaSource) { - if ('getDisplayMedia' in window.navigator) { - return; - } - navigator.getDisplayMedia = function(constraints) { - if (!(constraints && constraints.video)) { - var err = new DOMException('getDisplayMedia without video ' + - 'constraints is undefined'); - err.name = 'NotFoundError'; - // from https://heycam.github.io/webidl/#idl-DOMException-error-names - err.code = 8; - return Promise.reject(err); - } - if (constraints.video === true) { - constraints.video = {mediaSource: preferredMediaSource}; - } else { - constraints.video.mediaSource = preferredMediaSource; - } - return navigator.mediaDevices.getUserMedia(constraints); - }; - } -}; - -},{"../utils":162,"./getusermedia":160}],160:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var 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; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - 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 (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":162}],161:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ -'use strict'; -var utils = require('../utils'); - -module.exports = { - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var pc = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(pc, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - return _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var pc = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - var pc = this; - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - e.streams.forEach(function(stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in window.RTCPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - }, - shimTrackEventTransceiver: function(window) { - // Add event.transceiver member over deprecated event.receiver - if (typeof window === 'object' && window.RTCPeerConnection && - ('receiver' in window.RTCTrackEvent.prototype) && - // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is - // defined for some reason even when window.RTCTransceiver is not. - !window.RTCTransceiver) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimCreateOfferLegacy: function(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { - var pc = this; - if (offerOptions) { - if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { - // support bit values - offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; - } - var audioTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && - !audioTransceiver) { - pc.addTransceiver('audio'); - } - - - if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { - // support bit values - offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; - } - var videoTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - videoTransceiver.setDirection('sendonly'); - } else if (videoTransceiver.direction === 'recvonly') { - videoTransceiver.setDirection('inactive'); - } - } else if (offerOptions.offerToReceiveVideo === true && - !videoTransceiver) { - pc.addTransceiver('video'); - } - } - return origCreateOffer.apply(pc, arguments); - }; - } -}; - -},{"../utils":162}],162:[function(require,module,exports){ -/* - * Copyright (c) 2016 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. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object (or false to prevent -// the event). -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function(e) { - var modifiedEvent = wrapper(e); - if (modifiedEvent) { - cb(modifiedEvent); - } - }; - this._eventMap = this._eventMap || {}; - this._eventMap[cb] = wrappedCallback; - return nativeAddEventListener.apply(this, [nativeEventName, - wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap - || !this._eventMap[cb]) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[cb]; - delete this._eventMap[cb]; - return nativeRemoveEventListener.apply(this, [nativeEventName, - unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function() { - return this['_on' + eventNameToWrap]; - }, - set: function(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, - this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, - this['_on' + eventNameToWrap] = cb); - } - }, - enumerable: true, - configurable: true - }); -} - -// Utility methods. -module.exports = { - extractVersion: extractVersion, - wrapPeerConnectionEvent: wrapPeerConnectionEvent, - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - if (navigator.mozGetUserMedia) { // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (window.RTCPeerConnection && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -},{}],163:[function(require,module,exports){ +},{}],141:[function(require,module,exports){ 'use strict'; var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('') diff --git a/package-lock.json b/package-lock.json index 572e9f6..786a035 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,7 +91,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { "version": "2.2.1", @@ -372,11 +373,6 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -432,11 +428,6 @@ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -749,16 +740,6 @@ "type-is": "~1.6.15" } }, - "bole": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bole/-/bole-2.0.0.tgz", - "integrity": "sha1-2KocaQRnv7T+Ebh0rLLoOH44JhU=", - "requires": { - "core-util-is": ">=1.0.1 <1.1.0-0", - "individual": ">=3.0.0 <3.1.0-0", - "json-stringify-safe": ">=5.0.0 <5.1.0-0" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -768,33 +749,6 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -991,67 +945,6 @@ "pako": "~1.0.5" } }, - "budo": { - "version": "11.6.2", - "resolved": "https://registry.npmjs.org/budo/-/budo-11.6.2.tgz", - "integrity": "sha512-y6rcQHf//rqY1hsVJOUXGCHD0IZyVbbzAR1Cs1CYwI/akS7A8VMDhUNU9eXdQF2kM92ogPXEDsHo5ESdv5ZwPA==", - "requires": { - "bole": "^2.0.0", - "browserify": "^16.2.3", - "chokidar": "^2.0.4", - "connect-pushstate": "^1.1.0", - "escape-html": "^1.0.3", - "events": "^1.0.2", - "garnish": "^5.0.0", - "get-ports": "^1.0.2", - "inject-lr-script": "^2.1.0", - "internal-ip": "^3.0.1", - "micromatch": "^3.1.10", - "on-finished": "^2.3.0", - "on-headers": "^1.0.1", - "once": "^1.3.2", - "opn": "^3.0.2", - "path-is-absolute": "^1.0.1", - "pem": "^1.13.2", - "reload-css": "^1.0.0", - "resolve": "^1.1.6", - "serve-static": "^1.10.0", - "simple-html-index": "^1.4.0", - "stacked": "^1.1.1", - "stdout-stream": "^1.4.0", - "strip-ansi": "^3.0.0", - "subarg": "^1.0.0", - "term-color": "^1.0.1", - "url-trim": "^1.0.0", - "watchify-middleware": "^1.8.2", - "ws": "^1.1.1", - "xtend": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" - }, - "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", - "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" - } - } - } - }, "buffer": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", @@ -1220,11 +1113,6 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, "chokidar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", @@ -2185,11 +2073,6 @@ } } }, - "connect-pushstate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/connect-pushstate/-/connect-pushstate-1.1.0.tgz", - "integrity": "sha1-vKsiQnHEOWBKD7D2FMCl9WPojiQ=" - }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -2311,11 +2194,6 @@ } } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -2352,11 +2230,6 @@ "resolved": "https://registry.npmjs.org/dct/-/dct-0.0.3.tgz", "integrity": "sha1-GTkKg0OIodOhNz+e3+UGIgdISdM=" }, - "debounce": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", - "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2389,15 +2262,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "default-gateway": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", - "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", - "requires": { - "execa": "^0.10.0", - "ip-regex": "^2.1.0" - } - }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -2780,11 +2644,6 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" }, - "es6-promisify": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.0.1.tgz", - "integrity": "sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw==" - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2793,7 +2652,8 @@ "escape-string-regexp": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=" + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true }, "eslint": { "version": "4.18.2", @@ -3060,66 +2920,6 @@ "safe-buffer": "^5.1.1" } }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "express": { "version": "4.16.2", "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", @@ -3192,70 +2992,6 @@ "tmp": "^0.0.33" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, "extract-zip": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", @@ -3359,27 +3095,6 @@ "object-assign": "^4.0.1" } }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "finalhandler": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", @@ -3471,23 +3186,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "from2-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/from2-string/-/from2-string-1.1.0.tgz", - "integrity": "sha1-GCgrJ9CKJnyzAwzSuLSw8hKvdSo=", - "requires": { - "from2": "^2.0.3" - } - }, "fs-extra": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", @@ -3514,92 +3212,17 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "garnish": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/garnish/-/garnish-5.2.0.tgz", - "integrity": "sha1-vtQ2WTguSxmOM8eTiXvnxwHmVXc=", - "requires": { - "chalk": "^0.5.1", - "minimist": "^1.1.0", - "pad-left": "^2.0.0", - "pad-right": "^0.2.2", - "prettier-bytes": "^1.0.3", - "pretty-ms": "^2.1.0", - "right-now": "^1.0.0", - "split2": "^0.2.1", - "stdout-stream": "^1.4.0", - "url-trim": "^1.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" - }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" - }, - "chalk": { - "version": "0.5.1", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", - "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" - } - }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", - "requires": { - "ansi-regex": "^0.2.0" - } - }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "requires": { - "ansi-regex": "^0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" - } - } - }, "get-browser-rtc": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz", "integrity": "sha1-u81AyEUaftTvXDc7gWmkCd0dEdk=" }, - "get-ports": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-ports/-/get-ports-1.0.3.tgz", - "integrity": "sha1-9AvVgKyn7A77e5bL/L6wPviUteg=", - "requires": { - "map-limit": "0.0.1" - } - }, "get-stdin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", "dev": true }, - "get-stream": { - "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -3902,18 +3525,41 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "hydra-synth": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/hydra-synth/-/hydra-synth-1.0.21.tgz", - "integrity": "sha512-D8hb5llFfFxKP8fzn6uEZRgEs+jcT1nYYucJM6zUhuMwLjE/2w+TfvNjzWn7KNSK9TMGKoxnR0IfOZGz3F/l8g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hydra-synth/-/hydra-synth-1.1.3.tgz", + "integrity": "sha512-LkSz8O6b3lR6hJWytuFEqmQjXvvKT3BldqCvgQGVxl33PcZkFzuZ1A2AV47ZrjzasPJp57J4sXfjLNt2dL6dPg==", "requires": { - "budo": "^11.3.2", "enumerate-devices": "^1.1.1", - "getusermedia": "^2.0.1", "meyda": "^4.1.3", "mouse-change": "^1.4.0", "raf-loop": "^1.1.3", "regl": "^1.3.9", - "web-audio-analyser": "^2.0.1" + "web-audio-analyser": "^2.0.1", + "webrtc-adapter": "^6.4.0" + }, + "dependencies": { + "rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "requires": { + "sdp": "^2.6.0" + } + }, + "sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==" + }, + "webrtc-adapter": { + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-6.4.8.tgz", + "integrity": "sha512-YM8yl545c/JhYcjGHgaCoA7jRK/KZuMwEDFeP2AcP0Auv5awEd+gZE0hXy9z7Ed3p9HvAXp8jdbe+4ESb1zxAw==", + "requires": { + "rtcpeerconnection-shim": "^1.2.14", + "sdp": "^2.9.0" + } + } } }, "iconv-lite": { @@ -3948,11 +3594,6 @@ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, - "individual": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz", - "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3967,14 +3608,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "inject-lr-script": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/inject-lr-script/-/inject-lr-script-2.1.0.tgz", - "integrity": "sha1-5htehMEYczkGy+oB7D10Zpijn2U=", - "requires": { - "resp-modifier": "^6.0.0" - } - }, "inline-source-map": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", @@ -4033,20 +3666,6 @@ } } }, - "internal-ip": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", - "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", - "requires": { - "default-gateway": "^2.6.0", - "ipaddr.js": "^1.5.2" - } - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, "ipaddr.js": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", @@ -4130,28 +3749,12 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - } - }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -4243,11 +3846,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, "isomorphic-fetch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", @@ -4561,24 +4159,6 @@ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, - "map-limit": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz", - "integrity": "sha1-63lhAxwPDo0AG/LVb6toXViCLzg=", - "requires": { - "once": "~1.3.0" - }, - "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "requires": { - "wrappy": "1" - } - } - } - }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -4587,16 +4167,6 @@ "object-visit": "^1.0.0" } }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, "md5.js": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", @@ -4644,33 +4214,6 @@ "wav": "^1.0.0" } }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -4936,11 +4479,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -4976,19 +4514,6 @@ "remove-trailing-separator": "^1.0.1" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -5068,11 +4593,6 @@ "ee-first": "1.1.1" } }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5090,14 +4610,6 @@ "mimic-fn": "^1.0.0" } }, - "opn": { - "version": "3.0.3", - "resolved": "http://registry.npmjs.org/opn/-/opn-3.0.3.tgz", - "integrity": "sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=", - "requires": { - "object-assign": "^4.0.1" - } - }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -5120,11 +4632,6 @@ } } }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" - }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", @@ -5133,7 +4640,8 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "outpipe": { "version": "1.1.1", @@ -5143,11 +4651,6 @@ "shell-quote": "^1.4.2" } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", @@ -5185,22 +4688,6 @@ "resolved": "https://registry.npmjs.org/package/-/package-1.0.1.tgz", "integrity": "sha1-0lofmeJQbcsn1nBLg9yooxLk7cw=" }, - "pad-left": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", - "integrity": "sha1-FuajstRKjhOMsIOMx8tAOk/J6ZQ=", - "requires": { - "repeat-string": "^1.5.4" - } - }, - "pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", - "requires": { - "repeat-string": "^1.5.2" - } - }, "pako": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", @@ -5235,11 +4722,6 @@ "error-ex": "^1.2.0" } }, - "parse-ms": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", - "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=" - }, "parseqs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", @@ -5296,11 +4778,6 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, "path-parse": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", @@ -5337,27 +4814,6 @@ "sha.js": "^2.4.8" } }, - "pem": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/pem/-/pem-1.14.2.tgz", - "integrity": "sha512-TOnPtq3ZFnCniOZ+rka4pk8UIze9xG1qI+wNE7EmkiR/cg+53uVvk5QbkWZ7M6RsuOxzz62FW1hlAobJr/lTOA==", - "requires": { - "es6-promisify": "^6.0.0", - "md5": "^2.2.1", - "os-tmpdir": "^1.0.1", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -5479,11 +4935,6 @@ "find-up": "^1.0.0" } }, - "plur": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", - "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=" - }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -5531,21 +4982,6 @@ } } }, - "prettier-bytes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prettier-bytes/-/prettier-bytes-1.0.4.tgz", - "integrity": "sha1-mUsCqkb2mcULYle1+qp/4lV+YtY=" - }, - "pretty-ms": { - "version": "2.1.0", - "resolved": "http://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", - "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", - "requires": { - "is-finite": "^1.0.1", - "parse-ms": "^1.0.0", - "plur": "^1.0.0" - } - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -5628,15 +5064,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -5763,17 +5190,9 @@ } }, "regl": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/regl/-/regl-1.3.11.tgz", - "integrity": "sha512-tmt6CRhRqbcsYDWNwv+iG7GGOXdgoOBC7lKzoPMgnzpt3WKBQ3c8i7AxgbvTRZzty29hrW92fAJeZkPFQehfWA==" - }, - "reload-css": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/reload-css/-/reload-css-1.0.2.tgz", - "integrity": "sha1-avsRFi4jFP7M2tbcX96CH9cxgzE=", - "requires": { - "query-string": "^4.2.3" - } + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regl/-/regl-1.4.2.tgz", + "integrity": "sha512-wc/kE6kGmGfQk3G9f1Pai4TZ0K1pWxkD1Jeaj6CxJwEiB1jwHgEpqD84G2t7F0DmNXfQh7IUnoG1opxoONJ7Xg==" }, "remove-trailing-separator": { "version": "1.1.0", @@ -5873,15 +5292,6 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, - "resp-modifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", - "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", - "requires": { - "debug": "^2.2.0", - "minimatch": "^3.0.2" - } - }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -6131,6 +5541,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -6138,7 +5549,8 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true }, "shell-quote": { "version": "1.6.1", @@ -6159,15 +5571,8 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "simple-html-index": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/simple-html-index/-/simple-html-index-1.5.0.tgz", - "integrity": "sha1-LJPurrrAAdihNfwAIr1K3o9YmW8=", - "requires": { - "from2-string": "^1.1.0" - } + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true }, "simple-peer": { "version": "9.1.2", @@ -6419,46 +5824,6 @@ "extend-shallow": "^3.0.0" } }, - "split2": { - "version": "0.2.1", - "resolved": "http://registry.npmjs.org/split2/-/split2-0.2.1.tgz", - "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=", - "requires": { - "through2": "~0.6.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "through2": { - "version": "0.6.5", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6481,11 +5846,6 @@ "tweetnacl": "~0.14.0" } }, - "stacked": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stacked/-/stacked-1.1.1.tgz", - "integrity": "sha1-LH+jjMfjejQRp3zY55LeRI+faXU=" - }, "standard": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/standard/-/standard-11.0.1.tgz", @@ -6539,14 +5899,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" }, - "stdout-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", - "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", - "requires": { - "readable-stream": "^2.0.1" - } - }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", @@ -6604,11 +5956,6 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -6650,11 +5997,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -6761,27 +6103,6 @@ "package": ">= 1.0.0 < 1.2.0" } }, - "term-color": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/term-color/-/term-color-1.0.1.tgz", - "integrity": "sha1-OOGSVTpHPjXkFgT/UZmEa/gRejo=", - "requires": { - "ansi-styles": "2.0.1", - "supports-color": "1.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.0.1.tgz", - "integrity": "sha1-sDP1f5Pi0oreuLwRE4+hPaD9IKM=" - }, - "supports-color": { - "version": "1.3.1", - "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", - "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=" - } - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7095,11 +6416,6 @@ } } }, - "url-trim": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-trim/-/url-trim-1.0.0.tgz", - "integrity": "sha1-QAV+LxZLiOXaynJp2kfm0d2Detw=" - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -7190,29 +6506,6 @@ "xtend": "^4.0.0" } }, - "watchify-middleware": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/watchify-middleware/-/watchify-middleware-1.8.2.tgz", - "integrity": "sha512-A+x5K0mHVEK2WSLOEbazcXDFnSlralMZzk364Ea39F4xFl2jGl4VQLLN5HwrnRzpF5/Ggf1Q2he0HpJtflUiHg==", - "requires": { - "concat-stream": "^1.5.0", - "debounce": "^1.0.0", - "events": "^1.0.2", - "object-assign": "^4.0.1", - "strip-ansi": "^3.0.0", - "watchify": "^3.11.1" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "wav": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.1.tgz", diff --git a/package.json b/package.json index 470babb..5fcc074 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "enumerate-devices": "^1.1.1", "express": "^4.15.2", "getusermedia": "^2.0.1", - "hydra-synth": "^1.0.21", + "hydra-synth": "^1.1.3", "inherits": "^2.0.3", "meyda": "^4.1.3", "multer": "^1.4.1",