webrtc-adapter
Advanced tools
Comparing version 1.1.0 to 1.2.2
@@ -57,5 +57,67 @@ 'use strict'; | ||
'./src/js/edge/edge_sdp.js' | ||
] | ||
} | ||
}, | ||
// The following entries duplicate the entries above but use babelify | ||
// to create versions safe for old browsers. | ||
adapterGlobalObjectES5: { | ||
src: ['./src/js/adapter_core.js'], | ||
dest: './out/adapter_es5.js', | ||
options: { | ||
browserifyOptions: { | ||
// Exposes shim methods in a global object to the browser. | ||
// The tests require this. | ||
// TODO: Replace adapter with <%= pkg.name %>' which uses the name | ||
// from package.json once we have a better NPM name. | ||
standalone: 'adapter', | ||
transform: 'babelify' | ||
} | ||
} | ||
}, | ||
// Use this if you do not want adapter to expose anything to the global | ||
// scope. | ||
adapterAndNoGlobalObjectES5: { | ||
src: ['./src/js/adapter_core.js'], | ||
dest: './out/adapter_no_global_es5.js', | ||
options: { | ||
browserifyOptions: { | ||
transform: 'babelify' | ||
} | ||
} | ||
}, | ||
// Use this if you do not want MS edge shim to be included. | ||
adapterNoEdgeES5: { | ||
src: ['./src/js/adapter_core.js'], | ||
dest: './out/adapter_no_edge_es5.js', | ||
options: { | ||
// These files will be skipped. | ||
ignore: [ | ||
'./src/js/edge/edge_shim.js', | ||
'./src/js/edge/edge_sdp.js' | ||
], | ||
browserifyOptions: { | ||
// Exposes the shim in a global object to the browser. | ||
// The tests require this. | ||
// TODO: Replace adapter with <%= pkg.name %>' which uses the name | ||
// from package.json once we have a better NPM name. | ||
standalone: 'adapter', | ||
transform: 'babelify' | ||
} | ||
} | ||
}, | ||
// Use this if you do not want MS edge shim to be included and do not | ||
// want adapter to expose anything to the global scope. | ||
adapterNoEdgeAndNoGlobalObjectES5: { | ||
src: ['./src/js/adapter_core.js'], | ||
dest: './out/adapter_no_edge_no_global_es5.js', | ||
options: { | ||
ignore: [ | ||
'./src/js/edge/edge_shim.js', | ||
'./src/js/edge/edge_sdp.js' | ||
], | ||
browserifyOptions: { | ||
transform: 'babelify' | ||
} | ||
} | ||
} | ||
}, | ||
@@ -62,0 +124,0 @@ githooks: { |
@@ -50,2 +50,3 @@ (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<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
chromeShim.shimGetUserMedia(); | ||
chromeShim.shimMediaStream(); | ||
chromeShim.shimSourceObject(); | ||
@@ -78,2 +79,3 @@ chromeShim.shimPeerConnection(); | ||
edgeShim.shimGetUserMedia(); | ||
edgeShim.shimPeerConnection(); | ||
@@ -98,2 +100,3 @@ break; | ||
},{"./chrome/chrome_shim":3,"./edge/edge_shim":1,"./firefox/firefox_shim":5,"./safari/safari_shim":7,"./utils":8}],3:[function(require,module,exports){ | ||
/* | ||
@@ -112,2 +115,6 @@ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | ||
var chromeShim = { | ||
shimMediaStream: function() { | ||
window.MediaStream = window.MediaStream || window.webkitMediaStream; | ||
}, | ||
shimOnTrack: function() { | ||
@@ -232,5 +239,17 @@ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in | ||
// 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](fixChromeStats_(response)); | ||
args[1](makeMapStats(fixChromeStats_(response))); | ||
}; | ||
@@ -245,10 +264,15 @@ | ||
if (args.length === 1 && typeof selector === 'object') { | ||
origGetStats.apply(self, | ||
[function(response) { | ||
resolve.apply(null, [fixChromeStats_(response)]); | ||
}, reject]); | ||
origGetStats.apply(self, [ | ||
function(response) { | ||
resolve(makeMapStats(fixChromeStats_(response))); | ||
}, reject]); | ||
} else { | ||
origGetStats.apply(self, [resolve, reject]); | ||
// 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); | ||
}; | ||
@@ -269,18 +293,44 @@ | ||
// add promise support | ||
['createOffer', 'createAnswer'].forEach(function(method) { | ||
var nativeMethod = webkitRTCPeerConnection.prototype[method]; | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var self = this; | ||
if (arguments.length < 1 || (arguments.length === 1 && | ||
typeof(arguments[0]) === 'object')) { | ||
var opts = arguments.length === 1 ? arguments[0] : undefined; | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [resolve, reject, opts]); | ||
// add promise support -- natively available in Chrome 51 | ||
if (browserDetails.version < 51) { | ||
['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); | ||
}; | ||
}); | ||
['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]); | ||
} | ||
}); | ||
}; | ||
}); | ||
} | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
}); | ||
} | ||
// shim implicit creation of RTCSessionDescription/RTCIceCandidate | ||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] | ||
@@ -290,22 +340,5 @@ .forEach(function(method) { | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var args = arguments; | ||
var self = this; | ||
args[0] = new ((method === 'addIceCandidate')? | ||
RTCIceCandidate : RTCSessionDescription)(args[0]); | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [args[0], | ||
function() { | ||
resolve(); | ||
if (args.length >= 2) { | ||
args[1].apply(null, []); | ||
} | ||
}, | ||
function(err) { | ||
reject(err); | ||
if (args.length >= 3) { | ||
args[2].apply(null, [err]); | ||
} | ||
}] | ||
); | ||
}); | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
@@ -340,2 +373,3 @@ }); | ||
module.exports = { | ||
shimMediaStream: chromeShim.shimMediaStream, | ||
shimOnTrack: chromeShim.shimOnTrack, | ||
@@ -414,13 +448,65 @@ shimSourceObject: chromeShim.shimSourceObject, | ||
var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
var shimConstraints_ = function(constraints, func) { | ||
constraints = JSON.parse(JSON.stringify(constraints)); | ||
if (constraints.audio) { | ||
if (constraints && constraints.audio) { | ||
constraints.audio = constraintsToChrome_(constraints.audio); | ||
} | ||
if (constraints.video) { | ||
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 navigator.webkitGetUserMedia(constraints, onSuccess, onError); | ||
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_; | ||
@@ -466,11 +552,9 @@ | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = function(c) { | ||
if (c) { | ||
logging('spec: ' + JSON.stringify(c)); // whitespace for alignment | ||
c.audio = constraintsToChrome_(c.audio); | ||
c.video = constraintsToChrome_(c.video); | ||
logging('chrome: ' + JSON.stringify(c)); | ||
} | ||
return origGetUserMedia(c); | ||
}.bind(this); | ||
navigator.mediaDevices.getUserMedia = function(cs) { | ||
return shimConstraints_(cs, function(c) { | ||
return origGetUserMedia(c).catch(function(e) { | ||
return Promise.reject(shimError_(e)); | ||
}); | ||
}); | ||
}; | ||
} | ||
@@ -553,2 +637,6 @@ | ||
shimPeerConnection: function() { | ||
if (typeof window !== 'object' || !(window.RTCPeerConnection || | ||
window.mozRTCPeerConnection)) { | ||
return; // probably media.peerconnection.enabled=false in about:config | ||
} | ||
// The RTCPeerConnection object. | ||
@@ -604,3 +692,3 @@ if (!window.RTCPeerConnection) { | ||
RTCPeerConnection.prototype[method] = function() { | ||
arguments[0] = new ((method === 'addIceCandidate')? | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
@@ -610,2 +698,21 @@ return nativeMethod.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 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); | ||
}; | ||
}, | ||
@@ -754,2 +861,18 @@ | ||
module.exports = function() { | ||
var shimError_ = e => ({ | ||
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. | ||
@@ -811,3 +934,4 @@ var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
} | ||
return navigator.mozGetUserMedia(constraints, onSuccess, onError); | ||
return navigator.mozGetUserMedia(constraints, onSuccess, | ||
e => onError(shimError_(e))); | ||
}; | ||
@@ -855,2 +979,8 @@ | ||
} | ||
if (browserDetails.version < 49) { | ||
var origGetUserMedia = navigator.mediaDevices.getUserMedia. | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = c => | ||
origGetUserMedia(c).catch(e => Promise.reject(shimError_(e))); | ||
} | ||
}; | ||
@@ -857,0 +987,0 @@ |
@@ -50,2 +50,3 @@ (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.adapter = 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<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
chromeShim.shimGetUserMedia(); | ||
chromeShim.shimMediaStream(); | ||
chromeShim.shimSourceObject(); | ||
@@ -78,2 +79,3 @@ chromeShim.shimPeerConnection(); | ||
edgeShim.shimGetUserMedia(); | ||
edgeShim.shimPeerConnection(); | ||
@@ -98,2 +100,3 @@ break; | ||
},{"./chrome/chrome_shim":3,"./edge/edge_shim":1,"./firefox/firefox_shim":5,"./safari/safari_shim":7,"./utils":8}],3:[function(require,module,exports){ | ||
/* | ||
@@ -112,2 +115,6 @@ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | ||
var chromeShim = { | ||
shimMediaStream: function() { | ||
window.MediaStream = window.MediaStream || window.webkitMediaStream; | ||
}, | ||
shimOnTrack: function() { | ||
@@ -232,5 +239,17 @@ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in | ||
// 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](fixChromeStats_(response)); | ||
args[1](makeMapStats(fixChromeStats_(response))); | ||
}; | ||
@@ -245,10 +264,15 @@ | ||
if (args.length === 1 && typeof selector === 'object') { | ||
origGetStats.apply(self, | ||
[function(response) { | ||
resolve.apply(null, [fixChromeStats_(response)]); | ||
}, reject]); | ||
origGetStats.apply(self, [ | ||
function(response) { | ||
resolve(makeMapStats(fixChromeStats_(response))); | ||
}, reject]); | ||
} else { | ||
origGetStats.apply(self, [resolve, reject]); | ||
// 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); | ||
}; | ||
@@ -269,18 +293,44 @@ | ||
// add promise support | ||
['createOffer', 'createAnswer'].forEach(function(method) { | ||
var nativeMethod = webkitRTCPeerConnection.prototype[method]; | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var self = this; | ||
if (arguments.length < 1 || (arguments.length === 1 && | ||
typeof(arguments[0]) === 'object')) { | ||
var opts = arguments.length === 1 ? arguments[0] : undefined; | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [resolve, reject, opts]); | ||
// add promise support -- natively available in Chrome 51 | ||
if (browserDetails.version < 51) { | ||
['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); | ||
}; | ||
}); | ||
['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]); | ||
} | ||
}); | ||
}; | ||
}); | ||
} | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
}); | ||
} | ||
// shim implicit creation of RTCSessionDescription/RTCIceCandidate | ||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] | ||
@@ -290,22 +340,5 @@ .forEach(function(method) { | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var args = arguments; | ||
var self = this; | ||
args[0] = new ((method === 'addIceCandidate')? | ||
RTCIceCandidate : RTCSessionDescription)(args[0]); | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [args[0], | ||
function() { | ||
resolve(); | ||
if (args.length >= 2) { | ||
args[1].apply(null, []); | ||
} | ||
}, | ||
function(err) { | ||
reject(err); | ||
if (args.length >= 3) { | ||
args[2].apply(null, [err]); | ||
} | ||
}] | ||
); | ||
}); | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
@@ -340,2 +373,3 @@ }); | ||
module.exports = { | ||
shimMediaStream: chromeShim.shimMediaStream, | ||
shimOnTrack: chromeShim.shimOnTrack, | ||
@@ -414,13 +448,65 @@ shimSourceObject: chromeShim.shimSourceObject, | ||
var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
var shimConstraints_ = function(constraints, func) { | ||
constraints = JSON.parse(JSON.stringify(constraints)); | ||
if (constraints.audio) { | ||
if (constraints && constraints.audio) { | ||
constraints.audio = constraintsToChrome_(constraints.audio); | ||
} | ||
if (constraints.video) { | ||
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 navigator.webkitGetUserMedia(constraints, onSuccess, onError); | ||
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_; | ||
@@ -466,11 +552,9 @@ | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = function(c) { | ||
if (c) { | ||
logging('spec: ' + JSON.stringify(c)); // whitespace for alignment | ||
c.audio = constraintsToChrome_(c.audio); | ||
c.video = constraintsToChrome_(c.video); | ||
logging('chrome: ' + JSON.stringify(c)); | ||
} | ||
return origGetUserMedia(c); | ||
}.bind(this); | ||
navigator.mediaDevices.getUserMedia = function(cs) { | ||
return shimConstraints_(cs, function(c) { | ||
return origGetUserMedia(c).catch(function(e) { | ||
return Promise.reject(shimError_(e)); | ||
}); | ||
}); | ||
}; | ||
} | ||
@@ -553,2 +637,6 @@ | ||
shimPeerConnection: function() { | ||
if (typeof window !== 'object' || !(window.RTCPeerConnection || | ||
window.mozRTCPeerConnection)) { | ||
return; // probably media.peerconnection.enabled=false in about:config | ||
} | ||
// The RTCPeerConnection object. | ||
@@ -604,3 +692,3 @@ if (!window.RTCPeerConnection) { | ||
RTCPeerConnection.prototype[method] = function() { | ||
arguments[0] = new ((method === 'addIceCandidate')? | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
@@ -610,2 +698,21 @@ return nativeMethod.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 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); | ||
}; | ||
}, | ||
@@ -754,2 +861,18 @@ | ||
module.exports = function() { | ||
var shimError_ = e => ({ | ||
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. | ||
@@ -811,3 +934,4 @@ var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
} | ||
return navigator.mozGetUserMedia(constraints, onSuccess, onError); | ||
return navigator.mozGetUserMedia(constraints, onSuccess, | ||
e => onError(shimError_(e))); | ||
}; | ||
@@ -855,2 +979,8 @@ | ||
} | ||
if (browserDetails.version < 49) { | ||
var origGetUserMedia = navigator.mediaDevices.getUserMedia. | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = c => | ||
origGetUserMedia(c).catch(e => Promise.reject(shimError_(e))); | ||
} | ||
}; | ||
@@ -857,0 +987,0 @@ |
{ | ||
"name": "webrtc-adapter", | ||
"version": "1.1.0", | ||
"version": "1.2.2", | ||
"description": "A shim to insulate apps from WebRTC spec changes and browser prefix differences", | ||
@@ -11,2 +11,7 @@ "license": "BSD-3-Clause", | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015" | ||
] | ||
}, | ||
"authors": [ | ||
@@ -22,5 +27,11 @@ "The WebRTC project authors (https://www.webrtc.org/)" | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"sdp": "^1.0.0" | ||
}, | ||
"devDependencies": { | ||
"babel-preset-es2015": "^6.6.0", | ||
"babelify": "^7.3.0", | ||
"chromedriver": "^2.16.0", | ||
"eslint-config-webrtc": "^1.0.0", | ||
"faucet": "0.0.1", | ||
"grunt": "^0.4.5", | ||
@@ -33,5 +44,4 @@ "grunt-browserify": "^4.0.1", | ||
"tape": "^4.0.0", | ||
"travis-multirunner": "^3.0.0", | ||
"faucet": "0.0.1" | ||
"travis-multirunner": "^3.0.1" | ||
} | ||
} |
@@ -47,2 +47,3 @@ /* | ||
chromeShim.shimGetUserMedia(); | ||
chromeShim.shimMediaStream(); | ||
chromeShim.shimSourceObject(); | ||
@@ -75,2 +76,3 @@ chromeShim.shimPeerConnection(); | ||
edgeShim.shimGetUserMedia(); | ||
edgeShim.shimPeerConnection(); | ||
@@ -77,0 +79,0 @@ break; |
@@ -0,1 +1,2 @@ | ||
/* | ||
@@ -14,2 +15,6 @@ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | ||
var chromeShim = { | ||
shimMediaStream: function() { | ||
window.MediaStream = window.MediaStream || window.webkitMediaStream; | ||
}, | ||
shimOnTrack: function() { | ||
@@ -134,5 +139,17 @@ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in | ||
// 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](fixChromeStats_(response)); | ||
args[1](makeMapStats(fixChromeStats_(response))); | ||
}; | ||
@@ -147,10 +164,15 @@ | ||
if (args.length === 1 && typeof selector === 'object') { | ||
origGetStats.apply(self, | ||
[function(response) { | ||
resolve.apply(null, [fixChromeStats_(response)]); | ||
}, reject]); | ||
origGetStats.apply(self, [ | ||
function(response) { | ||
resolve(makeMapStats(fixChromeStats_(response))); | ||
}, reject]); | ||
} else { | ||
origGetStats.apply(self, [resolve, reject]); | ||
// 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); | ||
}; | ||
@@ -171,18 +193,44 @@ | ||
// add promise support | ||
['createOffer', 'createAnswer'].forEach(function(method) { | ||
var nativeMethod = webkitRTCPeerConnection.prototype[method]; | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var self = this; | ||
if (arguments.length < 1 || (arguments.length === 1 && | ||
typeof(arguments[0]) === 'object')) { | ||
var opts = arguments.length === 1 ? arguments[0] : undefined; | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [resolve, reject, opts]); | ||
// add promise support -- natively available in Chrome 51 | ||
if (browserDetails.version < 51) { | ||
['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); | ||
}; | ||
}); | ||
['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]); | ||
} | ||
}); | ||
}; | ||
}); | ||
} | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
}); | ||
} | ||
// shim implicit creation of RTCSessionDescription/RTCIceCandidate | ||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] | ||
@@ -192,22 +240,5 @@ .forEach(function(method) { | ||
webkitRTCPeerConnection.prototype[method] = function() { | ||
var args = arguments; | ||
var self = this; | ||
args[0] = new ((method === 'addIceCandidate')? | ||
RTCIceCandidate : RTCSessionDescription)(args[0]); | ||
return new Promise(function(resolve, reject) { | ||
nativeMethod.apply(self, [args[0], | ||
function() { | ||
resolve(); | ||
if (args.length >= 2) { | ||
args[1].apply(null, []); | ||
} | ||
}, | ||
function(err) { | ||
reject(err); | ||
if (args.length >= 3) { | ||
args[2].apply(null, [err]); | ||
} | ||
}] | ||
); | ||
}); | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
return nativeMethod.apply(this, arguments); | ||
}; | ||
@@ -242,2 +273,3 @@ }); | ||
module.exports = { | ||
shimMediaStream: chromeShim.shimMediaStream, | ||
shimOnTrack: chromeShim.shimOnTrack, | ||
@@ -244,0 +276,0 @@ shimSourceObject: chromeShim.shimSourceObject, |
@@ -65,13 +65,65 @@ /* | ||
var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
var shimConstraints_ = function(constraints, func) { | ||
constraints = JSON.parse(JSON.stringify(constraints)); | ||
if (constraints.audio) { | ||
if (constraints && constraints.audio) { | ||
constraints.audio = constraintsToChrome_(constraints.audio); | ||
} | ||
if (constraints.video) { | ||
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 navigator.webkitGetUserMedia(constraints, onSuccess, onError); | ||
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_; | ||
@@ -117,11 +169,9 @@ | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = function(c) { | ||
if (c) { | ||
logging('spec: ' + JSON.stringify(c)); // whitespace for alignment | ||
c.audio = constraintsToChrome_(c.audio); | ||
c.video = constraintsToChrome_(c.video); | ||
logging('chrome: ' + JSON.stringify(c)); | ||
} | ||
return origGetUserMedia(c); | ||
}.bind(this); | ||
navigator.mediaDevices.getUserMedia = function(cs) { | ||
return shimConstraints_(cs, function(c) { | ||
return origGetUserMedia(c).catch(function(e) { | ||
return Promise.reject(shimError_(e)); | ||
}); | ||
}); | ||
}; | ||
} | ||
@@ -128,0 +178,0 @@ |
@@ -11,3 +11,3 @@ /* | ||
var SDPUtils = require('./edge_sdp'); | ||
var SDPUtils = require('sdp'); | ||
var logging = require('../utils').log; | ||
@@ -169,2 +169,20 @@ | ||
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. | ||
@@ -351,2 +369,4 @@ window.RTCPeerConnection.prototype._getCommonCapabilities = | ||
sessionpart = sections.shift(); | ||
var isIceLite = SDPUtils.matchPrefix(sessionpart, | ||
'a=ice-lite').length > 0; | ||
sections.forEach(function(mediaSection, sdpMLineIndex) { | ||
@@ -365,7 +385,23 @@ var transceiver = self.transceivers[sdpMLineIndex]; | ||
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) | ||
iceTransport.setRemoteCandidates(cands); | ||
} | ||
iceTransport.start(iceGatherer, remoteIceParameters, | ||
'controlled'); | ||
isIceLite ? 'controlling' : 'controlled'); | ||
var remoteDtlsParameters = SDPUtils.getDtlsParameters( | ||
mediaSection, sessionpart); | ||
if (isIceLite) { | ||
remoteDtlsParameters.role = 'server'; | ||
} | ||
dtlsTransport.start(remoteDtlsParameters); | ||
@@ -437,2 +473,4 @@ | ||
var sessionpart = sections.shift(); | ||
var isIceLite = SDPUtils.matchPrefix(sessionpart, | ||
'a=ice-lite').length > 0; | ||
sections.forEach(function(mediaSection, sdpMLineIndex) { | ||
@@ -465,2 +503,3 @@ var lines = SDPUtils.splitLines(mediaSection); | ||
sessionpart); | ||
remoteDtlsParameters.role = 'client'; | ||
} | ||
@@ -565,3 +604,3 @@ recvEncodingParameters = | ||
if (isComplete) { | ||
if (isIceLite || isComplete) { | ||
iceTransport.setRemoteCandidates(cands); | ||
@@ -928,6 +967,8 @@ } | ||
return new Promise(function(resolve) { | ||
var results = {}; | ||
// 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]; | ||
@@ -960,4 +1001,5 @@ }); | ||
shimPeerConnection: edgeShim.shimPeerConnection, | ||
shimGetUserMedia: require('./getusermedia'), | ||
attachMediaStream: edgeShim.attachMediaStream, | ||
reattachMediaStream: edgeShim.reattachMediaStream | ||
}; |
@@ -61,2 +61,6 @@ /* | ||
shimPeerConnection: function() { | ||
if (typeof window !== 'object' || !(window.RTCPeerConnection || | ||
window.mozRTCPeerConnection)) { | ||
return; // probably media.peerconnection.enabled=false in about:config | ||
} | ||
// The RTCPeerConnection object. | ||
@@ -112,3 +116,3 @@ if (!window.RTCPeerConnection) { | ||
RTCPeerConnection.prototype[method] = function() { | ||
arguments[0] = new ((method === 'addIceCandidate')? | ||
arguments[0] = new ((method === 'addIceCandidate') ? | ||
RTCIceCandidate : RTCSessionDescription)(arguments[0]); | ||
@@ -118,2 +122,21 @@ return nativeMethod.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 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); | ||
}; | ||
}, | ||
@@ -120,0 +143,0 @@ |
@@ -16,2 +16,18 @@ /* | ||
module.exports = function() { | ||
var shimError_ = e => ({ | ||
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. | ||
@@ -73,3 +89,4 @@ var getUserMedia_ = function(constraints, onSuccess, onError) { | ||
} | ||
return navigator.mozGetUserMedia(constraints, onSuccess, onError); | ||
return navigator.mozGetUserMedia(constraints, onSuccess, | ||
e => onError(shimError_(e))); | ||
}; | ||
@@ -117,2 +134,8 @@ | ||
} | ||
if (browserDetails.version < 49) { | ||
var origGetUserMedia = navigator.mediaDevices.getUserMedia. | ||
bind(navigator.mediaDevices); | ||
navigator.mediaDevices.getUserMedia = c => | ||
origGetUserMedia(c).catch(e => Promise.reject(shimError_(e))); | ||
} | ||
}; |
@@ -25,3 +25,4 @@ /* | ||
// install browsers via travis-multirunner (on Linux). | ||
if (os.platform() === 'linux') { | ||
if (os.platform() === 'linux' && | ||
process.env.BROWSER !== 'MicrosoftEdge') { | ||
try { | ||
@@ -54,5 +55,2 @@ fs.accessSync(browserbin, fs.X_OK); | ||
// Edge SDP tests. Run in node. | ||
require('./sdp'); | ||
// This is run as a test so it is executed after all tests | ||
@@ -67,3 +65,10 @@ // have completed. | ||
}); | ||
}) | ||
.catch(function(err) { | ||
// Edge doesn't like close->quit | ||
console.log(err.name); | ||
if (process.env.BROWSER === 'MicrosoftEdge') { | ||
t.end(); | ||
} | ||
}); | ||
}); |
@@ -15,2 +15,3 @@ /* | ||
var firefox = require('selenium-webdriver/firefox'); | ||
var edge = require('selenium-webdriver/edge'); | ||
var fs = require('fs'); | ||
@@ -86,2 +87,4 @@ var os = require('os'); | ||
var edgeOptions = new edge.Options(); | ||
sharedDriver = new webdriver.Builder() | ||
@@ -91,7 +94,18 @@ .forBrowser(process.env.BROWSER) | ||
.setChromeOptions(chromeOptions) | ||
.build(); | ||
.setEdgeOptions(edgeOptions); | ||
if (process.env.BROWSER === 'MicrosoftEdge') { | ||
if (process.env.SELENIUM_SERVER) { | ||
sharedDriver.usingServer(process.env.SELENIUM_SERVER); | ||
} else if (os.platform() !== 'win32') { | ||
throw new Error('MicrosoftEdge is only supported on Windows or via ' + | ||
'a selenium server'); | ||
} | ||
} | ||
sharedDriver = sharedDriver.build(); | ||
// Set global executeAsyncScript() timeout (default is 0) to allow async | ||
// callbacks to be caught in tests. | ||
sharedDriver.manage().timeouts().setScriptTimeout(5000); | ||
sharedDriver.manage().timeouts().setScriptTimeout(10 * 1000); | ||
@@ -101,6 +115,16 @@ return sharedDriver; | ||
// loads the dummy page that includes adapter.js. | ||
// In Microsoft Edge (via selenium) this directly injects adapter.js. | ||
function loadTestPage(driver) { | ||
if (process.env.BROWSER === 'MicrosoftEdge') { | ||
return driver.get('about:blank').then(function() { | ||
return driver.executeScript(fs.readFileSync('out/adapter.js').toString()); | ||
}); | ||
} | ||
return driver.get('file://' + process.cwd() + '/test/testpage.html'); | ||
} | ||
// A helper function to query stats from a PeerConnection. | ||
function getStats(driver, peerConnection) { | ||
// Execute getStats on peerconnection named `peerConnection`. | ||
driver.manage().timeouts().setScriptTimeout(1000); | ||
return driver.executeAsyncScript( | ||
@@ -115,3 +139,4 @@ 'var callback = arguments[arguments.length - 1];' + | ||
buildDriver: buildDriver, | ||
loadTestPage: loadTestPage, | ||
getStats: getStats | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
717463
36
18292
1
13
76
+ Addedsdp@^1.0.0
+ Addedsdp@1.5.4(transitive)