New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

webrtc-troubleshoot

Package Overview
Dependencies
Maintainers
1
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

webrtc-troubleshoot - npm Package Compare versions

Comparing version 0.0.3 to 0.1.0

.editorconfig

12

package.json
{
"name": "webrtc-troubleshoot",
"version": "0.0.3",
"version": "0.1.0",
"description": "A way to add webrtc troubleshooting to your app",
"directories": {
"test": "tests"
},
"main": "index.js",
"scripts": {
"build": "browserify -t [ babelify --presets [ es2015 ] ] --s WebRTCTroubleshooter src/index.js -o dist/webrtc-troubleshooter.bundle.js"
"build": "browserify -t [ babelify --presets [ es2015 ] ] --s WebRTCTroubleshooter src/index.js -o dist/webrtc-troubleshooter.bundle.js",
"test": "node_modules/.bin/semistandard src/utils/**/*.js test-page/**/*.js"
},

@@ -17,7 +15,5 @@ "repository": "https://github.com/adflynn/webrtc-troubleshooter",

"devDependencies": {
"attachmediastream": "https://github.com/otalk/attachMediaStream",
"babel-cli": "^6.7.7",
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.2.0",
"babel-preset-es2015": "^6.6.0",
"lodash": "^4.6.1",
"localmedia": "https://github.com/xdumaine/localmedia.git",

@@ -24,0 +20,0 @@ "rtcpeerconnection": "https://github.com/otalk/RTCPeerConnection.git"

@@ -8,12 +8,13 @@ # webrtc-troubleshooter

TODO:
* [ ] create non-ember based webrtc tester
* [ ] create dummy page for testing
* [x] create non-ember based webrtc tester
* [x] create dummy page for testing
* [ ] publish as bower package
# Installation
# Develop
* `git clone` this repository
* `npm install`
* `bower install`
* Serve with your favorite [stupid server](https://www.npmjs.com/package/stupid-server)
* `npm test`

@@ -24,2 +25,2 @@

test-page/index.html
for console output of 6 tests to ensure webrtc is properly functioning
for console output of 6 tests to ensure webrtc is properly functioning

@@ -1,19 +0,12 @@

import { TestSuite } from './utils/TestSuite';
import {
AudioTest,
VideoTest,
ConnectivityTest,
AdvancedCameraTest,
ThroughputTest,
VideoBandwidthTest
} from './utils/tests/defaultTests';
import TestSuite from './utils/TestSuite';
import { AudioTest, VideoTest, ConnectivityTest, AdvancedCameraTest, ThroughputTest, VideoBandwidthTest } from './defaultTests';
export default {
TestSuite,
AudioTest,
VideoTest,
ConnectivityTest,
AdvancedCameraTest,
ThroughputTest,
VideoBandwidthTest
TestSuite,
AudioTest,
VideoTest,
ConnectivityTest,
AdvancedCameraTest,
ThroughputTest,
VideoBandwidthTest
};

@@ -1,3 +0,2 @@

/* global _ */
class TestSuite {
export default class TestSuite {
constructor (options) {

@@ -15,26 +14,31 @@ options = options || {};

runNextTest (done) {
start () {
return new Promise((resolve, reject) => {
return this.runNextTest().then(resolve, reject);
});
}
runNextTest () {
this.running = true;
var test = this.queue.shift();
const test = this.queue.shift();
if (!test) {
this.running = false;
this.allTestsComplete = true;
return done();
return Promise.resolve();
}
this.activeTest = test;
this.logger.log('webrtc-troubleshooter: Starting ' + test.name);
// TODO: There is some repeating functionality here that could be extracted.
test.start().then(() => {
test.callback(null);
this.logger.log('Starting ' + test.name);
const next = () => {
test.running = false;
test.destroy();
this.runNextTest(done);
}).catch((err) => {
test.callback(err, test.log);
test.running = false;
test.destroy();
this.runNextTest(done);
return this.runNextTest();
};
return test.start().then(() => {
return next();
}, (err) => {
this.logger.error('Test failure', err, test);
return next();
});

@@ -48,23 +52,1 @@ }

}
class Test {
constructor (options, callback) {
this.options = options || {};
this.callback = callback || _.noop;
this.logger = this.options.logger || console;
}
start () {
this.timeout = window.setTimeout(() => {
if (this.reject) {
this.reject('timeout');
}
}, 30000);
}
destroy () {
window.clearTimeout(this.timeout);
}
}
export { TestSuite, Test };

@@ -1,4 +0,3 @@

// adapted from https://github.com/webrtc/testrtc
class VideoFrameChecker {
import Ssim from './Ssim.js';
export default class VideoFrameChecker {
constructor (videoElement) {

@@ -11,51 +10,51 @@ this.frameStats = {

this.running_ = true;
this.running = true;
this.nonBlackPixelLumaThreshold = 20;
this.previousFrame_ = [];
this.previousFrame = [];
this.identicalFrameSsimThreshold = 0.985;
this.frameComparator = new Ssim();
this.canvas_ = document.createElement('canvas');
this.videoElement_ = videoElement;
this.listener_ = this.checkVideoFrame_.bind(this);
this.videoElement_.addEventListener('play', this.listener_, false);
this.canvas = document.createElement('canvas');
this.videoElement = videoElement;
this.listener = this.checkVideoFrame.bind(this);
this.videoElement.addEventListener('play', this.listener, false);
}
stop () {
this.videoElement_.removeEventListener('play', this.listener_);
this.running_ = false;
this.videoElement.removeEventListener('play', this.listener);
this.running = false;
}
getCurrentImageData_ () {
this.canvas_.width = this.videoElement_.width;
this.canvas_.height = this.videoElement_.height;
getCurrentImageData () {
this.canvas.width = this.videoElement.width;
this.canvas.height = this.videoElement.height;
var context = this.canvas_.getContext('2d');
context.drawImage(this.videoElement_, 0, 0, this.canvas_.width,
this.canvas_.height);
return context.getImageData(0, 0, this.canvas_.width, this.canvas_.height);
var context = this.canvas.getContext('2d');
context.drawImage(this.videoElement, 0, 0, this.canvas.width,
this.canvas.height);
return context.getImageData(0, 0, this.canvas.width, this.canvas.height);
}
checkVideoFrame_ () {
if (!this.running_) {
checkVideoFrame () {
if (!this.running) {
return;
}
if (this.videoElement_.ended) {
if (this.videoElement.ended) {
return;
}
var imageData = this.getCurrentImageData_();
var imageData = this.getCurrentImageData();
if (this.isBlackFrame_(imageData.data, imageData.data.length)) {
if (this.isBlackFrame(imageData.data, imageData.data.length)) {
this.frameStats.numBlackFrames++;
}
if (this.frameComparator.calculate(this.previousFrame_, imageData.data) >
if (this.frameComparator.calculate(this.previousFrame, imageData.data) >
this.identicalFrameSsimThreshold) {
this.frameStats.numFrozenFrames++;
}
this.previousFrame_ = imageData.data;
this.previousFrame = imageData.data;
this.frameStats.numFrames++;
setTimeout(this.checkVideoFrame_.bind(this), 20);
setTimeout(this.checkVideoFrame.bind(this), 20);
}
isBlackFrame_ (data, length) {
isBlackFrame (data, length) {
// TODO: Use a statistical, histogram-based detection.

@@ -75,136 +74,1 @@ var thresh = this.nonBlackPixelLumaThreshold;

}
VideoFrameChecker.prototype = {
stop: function () {
this.videoElement_.removeEventListener('play', this.listener_);
this.running_ = false;
},
getCurrentImageData_: function () {
this.canvas_.width = this.videoElement_.width;
this.canvas_.height = this.videoElement_.height;
var context = this.canvas_.getContext('2d');
context.drawImage(this.videoElement_, 0, 0, this.canvas_.width,
this.canvas_.height);
return context.getImageData(0, 0, this.canvas_.width, this.canvas_.height);
},
checkVideoFrame_: function () {
if (!this.running_) {
return;
}
if (this.videoElement_.ended) {
return;
}
var imageData = this.getCurrentImageData_();
if (this.isBlackFrame_(imageData.data, imageData.data.length)) {
this.frameStats.numBlackFrames++;
}
if (this.frameComparator.calculate(this.previousFrame_, imageData.data) >
this.identicalFrameSsimThreshold) {
this.frameStats.numFrozenFrames++;
}
this.previousFrame_ = imageData.data;
this.frameStats.numFrames++;
setTimeout(this.checkVideoFrame_.bind(this), 20);
},
isBlackFrame_: function (data, length) {
// TODO: Use a statistical, histogram-based detection.
var thresh = this.nonBlackPixelLumaThreshold;
var accuLuma = 0;
for (var i = 4; i < length; i += 4) {
// Use Luma as in Rec. 709: Y′709 = 0.21R + 0.72G + 0.07B
accuLuma += 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];
// Early termination if the average Luma so far is bright enough.
if (accuLuma > (thresh * i / 4)) {
return false;
}
}
return true;
}
};
/* This is an implementation of the algorithm for calculating the Structural
* SIMilarity (SSIM) index between two images. Please refer to the article [1],
* the website [2] and/or the Wikipedia article [3]. This code takes the value
* of the constants C1 and C2 from the Matlab implementation in [4].
*
* [1] Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image quality
* assessment: From error measurement to structural similarity",
* IEEE Transactions on Image Processing, vol. 13, no. 1, Jan. 2004.
* [2] http://www.cns.nyu.edu/~lcv/ssim/
* [3] http://en.wikipedia.org/wiki/Structural_similarity
* [4] http://www.cns.nyu.edu/~lcv/ssim/ssim_index.m
*/
class Ssim {
// Implementation of Eq.2, a simple average of a vector and Eq.4., except the
// square root. The latter is actually an unbiased estimate of the variance,
// not the exact variance.
statistics (a) {
var accu = 0;
var i;
for (i = 0; i < a.length; ++i) {
accu += a[i];
}
var meanA = accu / (a.length - 1);
var diff = 0;
for (i = 1; i < a.length; ++i) {
diff = a[i - 1] - meanA;
accu += a[i] + (diff * diff);
}
return {mean: meanA, variance: accu / a.length};
}
// Implementation of Eq.11., cov(Y, Z) = E((Y - uY), (Z - uZ)).
covariance (a, b, meanA, meanB) {
var accu = 0;
for (var i = 0; i < a.length; i += 1) {
accu += (a[i] - meanA) * (b[i] - meanB);
}
return accu / a.length;
}
calculate (x, y) {
if (x.length !== y.length) {
return 0;
}
// Values of the constants come from the Matlab code referred before.
var K1 = 0.01;
var K2 = 0.03;
var L = 255;
var C1 = (K1 * L) * (K1 * L);
var C2 = (K2 * L) * (K2 * L);
var C3 = C2 / 2;
var statsX = this.statistics(x);
var muX = statsX.mean;
var sigmaX2 = statsX.variance;
var sigmaX = Math.sqrt(sigmaX2);
var statsY = this.statistics(y);
var muY = statsY.mean;
var sigmaY2 = statsY.variance;
var sigmaY = Math.sqrt(sigmaY2);
var sigmaXy = this.covariance(x, y, muX, muY);
// Implementation of Eq.6.
var luminance = (2 * muX * muY + C1) /
((muX * muX) + (muY * muY) + C1);
// Implementation of Eq.10.
var structure = (sigmaXy + C3) / (sigmaX * sigmaY + C3);
// Implementation of Eq.9.
var contrast = (2 * sigmaX * sigmaY + C2) / (sigmaX2 + sigmaY2 + C2);
// Implementation of Eq.12.
return luminance * contrast * structure;
}
}
export default VideoFrameChecker;

@@ -9,10 +9,10 @@ /* global RTCPeerConnection, mozRTCPeerConnection */

this.pc1.addEventListener('icecandidate', this.onIceCandidate_.bind(this, this.pc2));
this.pc2.addEventListener('icecandidate', this.onIceCandidate_.bind(this, this.pc1));
this.pc1.addEventListener('icecandidate', this.onIceCandidate.bind(this, this.pc2));
this.pc2.addEventListener('icecandidate', this.onIceCandidate.bind(this, this.pc1));
this.iceCandidateFilter_ = WebrtcCall.noFilter;
this.iceCandidateFilter = WebrtcCall.noFilter;
}
establishConnection () {
this.pc1.createOffer(this.gotOffer_.bind(this), console.error.bind(console));
return this.pc1.createOffer().then(this.gotOffer.bind(this), console.error.bind(console));
}

@@ -27,52 +27,54 @@

// of gathered stats.
gatherStats (peerConnection, statsCb, interval) {
const stats = [];
const statsCollectTime = [];
getStats_();
gatherStats (peerConnection, interval) {
let stats = [];
let statsCollectTime = [];
function getStats_ () {
if (peerConnection.signalingState === 'closed') {
statsCb(stats, statsCollectTime);
return;
}
// Work around for webrtc/testrtc#74
if (typeof mozRTCPeerConnection !== 'undefined' && peerConnection instanceof mozRTCPeerConnection) {
setTimeout(getStats_, interval);
} else {
setTimeout(peerConnection.getStats.bind(peerConnection, gotStats_), interval);
}
}
return new Promise((resolve, reject) => {
const getStats = () => {
if (peerConnection.signalingState === 'closed') {
return resolve({stats, statsCollectTime});
}
// Work around for webrtc/testrtc#74
if (typeof mozRTCPeerConnection !== 'undefined' && peerConnection instanceof mozRTCPeerConnection) {
setTimeout(getStats, interval);
} else {
setTimeout(peerConnection.getStats.bind(peerConnection, gotStats), interval);
}
};
function gotStats_ (response) {
for (let index in response.result()) {
stats.push(response.result()[index]);
statsCollectTime.push(Date.now());
}
getStats_();
}
const gotStats = (response) => {
const now = Date.now();
const results = response.result();
stats = results;
statsCollectTime = results.map(() => now);
getStats();
};
getStats();
});
}
gotOffer_ (offer) {
if (this.constrainOfferToRemoveVideoFec_) {
offer.sdp = offer.sdp.replace(/(m=video 1 [^\r]+)(116 117)(\r\n)/g, '$1\r\n');
offer.sdp = offer.sdp.replace(/a=rtpmap:116 red\/90000\r\n/g, '');
offer.sdp = offer.sdp.replace(/a=rtpmap:117 ulpfec\/90000\r\n/g, '');
}
gotOffer (offer) {
// if (this.constrainOfferToRemoveVideoFec) {
// offer.sdp = offer.sdp.replace(/(m=video 1 [^\r]+)(116 117)(\r\n)/g, '$1\r\n');
// offer.sdp = offer.sdp.replace(/a=rtpmap:116 red\/90000\r\n/g, '');
// offer.sdp = offer.sdp.replace(/a=rtpmap:117 ulpfec\/90000\r\n/g, '');
// }
this.pc1.setLocalDescription(offer);
this.pc2.setRemoteDescription(offer);
this.pc2.createAnswer(this.gotAnswer_.bind(this), console.error.bind(console));
return this.pc2.createAnswer().then(this.gotAnswer.bind(this), console.error.bind(console));
}
gotAnswer_ (answer) {
if (this.constrainVideoBitrateKbps_) {
answer.sdp = answer.sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + this.constrainVideoBitrateKbps_ + '\r\n');
gotAnswer (answer) {
if (this.constrainVideoBitrateKbps) {
answer.sdp = answer.sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + this.constrainVideoBitrateKbps + '\r\n');
}
this.pc2.setLocalDescription(answer);
this.pc1.setRemoteDescription(answer);
return this.pc1.setRemoteDescription(answer);
}
onIceCandidate_ (otherPeer, event) {
onIceCandidate (otherPeer, event) {
if (event.candidate) {
var parsed = this.parseCandidate(event.candidate.candidate);
if (this.iceCandidateFilter_(parsed)) {
if (this.iceCandidateFilter(parsed)) {
otherPeer.addIceCandidate(event.candidate);

@@ -95,3 +97,3 @@ }

setIceCandidateFilter (filter) {
this.iceCandidateFilter_ = filter;
this.iceCandidateFilter = filter;
}

@@ -101,3 +103,3 @@

disableVideoFec () {
this.constrainOfferToRemoveVideoFec_ = true;
this.constrainOfferToRemoveVideoFec = true;
}

@@ -107,3 +109,3 @@

constrainVideoBitrate (maxVideoBitrateKbps) {
this.constrainVideoBitrateKbps_ = maxVideoBitrateKbps;
this.constrainVideoBitrateKbps = maxVideoBitrateKbps;
}

@@ -120,2 +122,2 @@

export default WebrtcCall;
export default WebrtcCall;
/* global WebRTCTroubleshooter */
var video = true;
var audio = true;
let video = true;
let audio = true;
var iceServers = [];
var testSuite = new WebRTCTroubleshooter.TestSuite();
let iceServers = [];
const webRTCTroubleshooter = WebRTCTroubleshooter.default;
const testSuite = new webRTCTroubleshooter.TestSuite();
document.getElementById('run-button').onclick = function startTroubleshooter () {
if (!navigator.mediaDevices) {
video = false;
audio = false;
}
const iceServersEntry = document.getElementById('ice-servers');
const runButton = document.getElementById('run-button');
var servers = document.getElementById('ice-servers').value;
if (servers) {
iceServers = JSON.parse(servers);
}
var iceConfig = {
iceServers: iceServers,
iceTransports: 'relay'
};
var mediaOptions = mediaOptions || { audio: true, video: true };
runButton.onclick = function startTroubleshooter () {
if (!navigator.mediaDevices) {
video = false;
audio = false;
}
if (audio) {
var audioTest = new WebRTCTroubleshooter.AudioTest(mediaOptions);
const servers = iceServersEntry.value;
if (servers) {
iceServers = JSON.parse(servers);
window.localStorage.setItem('iceServers', servers);
}
const iceConfig = {
iceServers: iceServers,
iceTransports: 'relay'
};
const mediaOptions = { audio: true, video: true };
testSuite.addTest(audioTest);
}
if (audio) {
const audioTest = new webRTCTroubleshooter.AudioTest(mediaOptions);
if (video) {
var videoTest = new WebRTCTroubleshooter.VideoTest(mediaOptions);
var advancedCameraTest = new WebRTCTroubleshooter.AdvancedCameraTest(mediaOptions);
var bandwidthTest = new WebRTCTroubleshooter.VideoBandwidthTest({ iceConfig: iceConfig, mediaOptions: mediaOptions});
testSuite.addTest(audioTest);
}
testSuite.addTest(videoTest);
testSuite.addTest(advancedCameraTest);
testSuite.addTest(bandwidthTest);
}
if (video) {
const videoTest = new webRTCTroubleshooter.VideoTest(mediaOptions);
const advancedCameraTest = new webRTCTroubleshooter.AdvancedCameraTest(mediaOptions);
const bandwidthTest = new webRTCTroubleshooter.VideoBandwidthTest({ iceConfig: iceConfig, mediaOptions: mediaOptions });
if (window.RTCPeerConnection) {
var connectivityTest = new WebRTCTroubleshooter.ConnectivityTest(iceConfig);
var throughputTest = new WebRTCTroubleshooter.ThroughputTest(iceConfig);
testSuite.addTest(videoTest);
testSuite.addTest(advancedCameraTest);
testSuite.addTest(bandwidthTest);
}
testSuite.addTest(connectivityTest);
testSuite.addTest(throughputTest);
}
if (window.RTCPeerConnection) {
const connectivityTest = new webRTCTroubleshooter.ConnectivityTest(iceConfig);
const throughputTest = new webRTCTroubleshooter.ThroughputTest(iceConfig);
testSuite.runNextTest(function() {
console.log('Finished the tests');
});
testSuite.addTest(connectivityTest);
testSuite.addTest(throughputTest);
}
testSuite.start().then(function () {
console.log('Finished the tests');
});
};
function willDestroyElement () {
try {
if (testSuite && testSuite.running) {
testSuite.stopAllTests();
}
} catch (e) { /* don't care - just want to destroy */ }
const savedIceServers = window.localStorage.getItem('iceServers');
if (iceServers) {
iceServersEntry.value = savedIceServers;
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc