vdo.ninja/results.html

533 lines
16 KiB
HTML

<html>
<head>
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
<link rel="stylesheet" href="./speedtest.css?ver=1" />
<meta charset="utf8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>VDON Speed Test</title>
<style>
.fullscreen {
width:100%;
height: calc(100% - 35px);
position:absolute;
left:0;
display:block;
background-color: #444;
color:white;
margin: auto;
padding-top: 35px;
transition: all ease-in 1s;
animation-name: fadein;
animation-duration: .3s;
}
@keyframes fadein {
0% {opacity: 0.5;}
100% {opacity: 1;}
}
a {
color: white;
}
#controls button {
cursor: pointer;
display: inline;
padding: 20px;
}
.hidden {
display:none!important;
}
body {
text-align: center;
height:unset;
background: #444;
font-family: 'Noto Sans', sans-serif;
color:white;
}
h2 {
width: 760px;
max-width: 90%;
margin: auto;
}
li {
text-align: left;
}
button{
margin: 50px auto;
font-size: 120%;
padding: 20px 30px;
cursor:pointer;
}
</style>
</head>
<body>
<div id="mainapp" >
<h1>
Video and stream quality check results
</h1>
<div id="container">
</div>
<div id="graphs">
<div class="graph">
<h3>Bitrate (kbps)</h3>
<span>0</span>
<canvas id="bitrate-graph"></canvas>
</div>
<div class="graph">
<h3>Buffer delay (ms)</h3>
<span>0</span>
<canvas id="buffer-graph"></canvas>
</div>
<div class="graph">
<h3>Packet Loss (%)</h3>
<span>0</span>
<canvas id="packetloss-graph"></canvas>
</div>
</div>
<div id="details">
</div>
</div>
<script>
function getChromiumVersion() {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
return raw ? parseInt(raw[2], 10) : false;
}
function next1(){
document.getElementById("page1").classList.add("hidden");
document.getElementById("page2").classList.remove("hidden");
}
function next2(){
document.getElementById("page2").classList.add("hidden");
document.getElementById("page3").classList.remove("hidden");
loadIframe();
}
function next3(){
document.getElementById("page3").classList.add("hidden");
document.getElementById("mainapp").classList.remove("hidden");
loadIframe();
}
(function (w) {
w.URLSearchParams =
w.URLSearchParams ||
function (searchString) {
var self = this;
self.searchString = searchString;
self.get = function (name) {
var results = new RegExp("[\?&]" + name + "=([^&#]*)").exec(
self.searchString
);
if (results == null) {
return null;
} else {
return decodeURI(results[1]) || 0;
}
};
};
})(window);
var urlParams = new URLSearchParams(window.location.search);
function copyFunction(copyText) {
alert("Log copied to the clipboard.");
try {
copyText.select();
copyText.setSelectionRange(0, 99999);
document.execCommand("copy");
} catch (e) {
var dummy = document.createElement("input");
document.body.appendChild(dummy);
dummy.value = copyText;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
return false;
}
}
function timeConverter(UNIX_timestamp){
var a = new Date(UNIX_timestamp);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hours = a.getHours();
var minutes = a.getMinutes();
var ampm = hours >= 12 ? 'pm' : 'am';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0'+minutes : minutes;
var strTime = hours + ':' + minutes + ' ' + ampm;
var time = date + ' ' + month + ' ' + year + ' ' + hours + ':' + minutes + ampm;
return time;
}
function printValues(obj) {
var out = "";
for (var key in obj) {
if (typeof obj[key] === "object") {
out += "<br />";
out += printValues(obj[key]);
} else {
if (key.startsWith("_")) {
} else {
out += "<b>" + key + "</b>: " + obj[key] + "<br />";
}
}
}
return out;
}
var streamID = "";
if (urlParams.has("id")) {
streamID = urlParams.get("id");
}
var bitrate = {
element: "bitrate-graph",
data: 0,
max: 6000,
target: 2500,
};
var frames;
var buffer = {
element: "buffer-graph",
data: 0,
max: 200,
target: 100,
};
var packetloss = {
element: "packetloss-graph",
data: 0,
max: 3,
target: 2,
};
// https://record.vdo.workers.dev/?name="+recordResults
var QLR_1 = 0;
var QLR_2 = 0;
var QLR_3 = 0;
var BBB = 0;
var counter = 0;
var BUFF = 0;
var BUFFCCC = 0;
var PAK = 0;
var PAKCCC = 0;
function process(arr) {
var maxResolution = "0 x 0";
console.log(arr);
arr.forEach(data=>{
if ("bitrate" in data){
updateData("bitrate", data.bitrate);
if (data.bitrate!==null){
BBB += data.bitrate;
counter += 1;
}
}
if ("target" in data){
updateData("target", data.target);
}
if ("buffer" in data){
updateData("buffer", data.buffer);
if (data.buffer!==null){
BUFF += data.buffer;
BUFFCCC += 1;
}
}
if ("packetloss" in data){
updateData("packetloss", data.packetloss);
if (data.packetloss!==null){
PAK += parseFloat(data.packetloss) || 0;
PAKCCC += 1;
}
}
if (data.timestart){
document.getElementById("details").innerHTML += "<br /><b>Test start time:</b> "+timeConverter(data.timestart)+"<br />";
}
if ("peakhour" in data){
if (!data.peakhour){
document.getElementById("details").innerHTML += "<small><i>(This test was completed outside of peak streaming hours.</br>Results are normally worse during peak hours.)</i></small><br />";
}
}
if (data.summary){
if (data.summary.download && data.summary.upload){
document.getElementById("details").innerHTML += "<br /><b>Max download bandwidth:</b> "+parseInt(data.summary.download/(1024*1024))+"-mbps<br />";
document.getElementById("details").innerHTML += "<br /><b>Max Upload bandwidth:</b> "+parseInt(data.summary.upload/(1024*1024))+"-mbps<br />";
}
}
if (data.scores && data.scores.gaming && data.scores.gaming.classificationName && data.scores.rtc && data.scores.rtc.classificationName && data.scores.streaming && data.scores.streaming.classificationName){
document.getElementById("details").innerHTML += "<br /><b>Gaming:</b> "+data.scores.gaming.classificationName+", <b>RTC:</b> "+data.scores.rtc.classificationName+", <b>Streaming:</b> "+data.scores.streaming.classificationName+"<br />";
}
if ("resolution" in data){
try {
if (parseInt(data.resolution.split("x ")[1])>parseInt(maxResolution.split("x ")[1])){
maxResolution = data.resolution;
}
} catch(e){}
//updateData("resolution", data.resolution);
}
if ("QLR" in data){
if (data.QLR == "none"){
QLR_1 +=1;
} else if (data.QLR.toLowerCase() == "cpu"){
QLR_2 +=1;
} else if (data.QLR.toLowerCase() == "network"){
QLR_3 +=1;
}
}
if ("info" in data){
if (data.info.Browser){
document.getElementById("details").innerHTML += "<br /><b>Browser used:</b> "+data.info.Browser+"<br />";
if (!data.info.Browser.startsWith("Chromium")){
document.getElementById("details").innerHTML += "<h3>A Chromium-based browser is recommended.</h3>";
}
}
if ("plugged_in" in data.info){
if (!data.info.plugged_in){
document.getElementById("details").innerHTML += "<h3>The user's power is not plugged in</h3>";
}
}
if (data.info.platform){
document.getElementById("details").innerHTML += "<br /><b>Platform (os):</b> "+data.info.platform+"<br />";
if (data.info.platform.toLowerCase() == "macintel"){
document.getElementById("details").innerHTML += "<i>(Intel or Apple Silicon)</i><br />";
}
}
if (data.info.gpGPU){
document.getElementById("details").innerHTML += "<br /><b>GPU:</b> "+data.info.gpGPU+"<br />";
}
if (data.info.CPU){
document.getElementById("details").innerHTML += "<br /><b>CPU:</b> "+data.info.CPU+"<br />";
}
if (data.info.conn_type){
document.getElementById("details").innerHTML += "<br /><b>Connection type:</b> "+data.info.conn_type+"<br />";
if (data.info.conn_type == "wifi"){
document.getElementById("details").innerHTML += "<h3>Avoid using WiFi if at all possible</h3>";
}
}
}
if (data.encoder){
if (data.encoder.toLowerCase() == "libvpx"){
document.getElementById("details").innerHTML += "<br /><b>Default video codec used:</b> VP8<br />";
} else {
document.getElementById("details").innerHTML += "<br /><b>Default video codec used:</b> "+data.encoder.toUpperCase()+"<br />";
}
}
});
// container
if (maxResolution){
document.getElementById("details").innerHTML += "<br /><b>Highest video resolution reached:</b> "+maxResolution+"<br />";
}
var total = QLR_1 + QLR_2 + QLR_3;
if (QLR_2/total>0.5){
document.getElementById("container").innerHTML += "Serious CPU overload issues. Consider reducing the capture resolution.<br />";
} else if (QLR_2/total>0.1){
document.getElementById("container").innerHTML += "Occassional CPU overload issues. Consider reducing the capture resolution.<br />";
}
if (QLR_3/total>0.5){
document.getElementById("container").innerHTML += "The network quality or bandwidth limited the performance.<br />";
} else if (QLR_3/total>0.1){
document.getElementById("container").innerHTML += "The network quality or bandwidth may have limited the performance.<br />";
}
document.getElementById("container").innerHTML += "The average video bitrate was: "+parseInt(BBB/counter)+"-kbps<br />";
if (BBB/counter<500){
document.getElementById("container").innerHTML += "<small><i>Did they select an active camera?</i></small><h3>Bitrate is really bad</h3>";
}
else if (BBB/counter<1000){
document.getElementById("container").innerHTML += "<h3>Bitrate is poor</h3>";
}
else if (BBB/counter<2000){
document.getElementById("container").innerHTML += "<h3>Bitrate a bit low</h3>";
}
else {
document.getElementById("container").innerHTML += "<h3>Bitrate is good</h3>";
}
document.getElementById("container").innerHTML += "<br />The average video buffer length was: "+parseInt(BUFF/BUFFCCC)+"-ms<br />";
if (BUFF/BUFFCCC>500){
document.getElementById("container").innerHTML += "<h3>Video delay is really bad</h3><br />";
}
else if (BUFF/BUFFCCC>200){
document.getElementById("container").innerHTML += "<h3>Video delay is poor</h3><br />";
}
else if (BUFF/BUFFCCC>100){
document.getElementById("container").innerHTML += "<h3>Video delay is sub-optimal</h3><br />";
}
else {
document.getElementById("container").innerHTML += "<h3>Video delay is good</h3><br />";
}
document.getElementById("container").innerHTML += "The average video packet loss was: "+(parseInt(PAK*1000/PAKCCC)/1000.0)+"%<br />";
if (PAK/PAKCCC>3){
document.getElementById("container").innerHTML += "<h3>Packet loss is extremely bad; Must Fix This</h3>";
}
else if (PAK/PAKCCC>0.8){
document.getElementById("container").innerHTML += "<h3>Packet loss is quite bad; expect problems with audio and video</h3>";
}
else if (PAK/PAKCCC>.15){
document.getElementById("container").innerHTML += "<h3>Packet loss is a bit high; might be a testing-server issue though</h3>";
}
else {
document.getElementById("container").innerHTML += "<h3>Packet loss is good</h3>";
}
console.log(QLR_1, QLR_2, QLR_3);
}
var xmlhttp = new XMLHttpRequest();
var url = "https://record.vdo.workers.dev/?name="+streamID;
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
process(myArr);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
function updateData(type, data) {
if (type == "target"){
bitrate.target = data;
}
if (type == "bitrate") {
bitrate.data = data;
plotData("bitrate", bitrate);
plotData("bitrate", bitrate);
plotData("bitrate", bitrate);
}
if (type == "buffer") {
buffer.data = data;
plotData("buffer", buffer);
plotData("buffer", buffer);
plotData("buffer", buffer);
}
if (type == "packetloss") {
packetloss.data = data;
plotData("packetloss", packetloss);
plotData("packetloss", packetloss);
plotData("packetloss", packetloss);
}
}
function plotData(type, stat) {
var canvas;
var context;
var yScale;
canvas = document.getElementById(stat.element);
context = canvas.getContext("2d");
if (isNaN(stat.data)) {
stat.data = 0;
}
var text = (canvas.previousElementSibling.innerHTML = stat.data);
var height = context.canvas.height;
var width = context.canvas.width;
var borderWidth = 5;
var offset = borderWidth * 2;
// Create gradient
var grd = context.createLinearGradient(0, 0, 0, height);
if (type == "bitrate") {
if (stat.target <= 3000){
grd.addColorStop(0, "#33C433");
grd.addColorStop(0.7, "#33C433");
grd.addColorStop(0.8, "#F3F304");
grd.addColorStop(0.92, "#F30404");
} else if (stat.target <= 4000){
grd.addColorStop(0, "#33C433");
grd.addColorStop(0.5, "#33C433");
grd.addColorStop(0.8, "#F3F304");
grd.addColorStop(0.92, "#F30404");
} else {
grd.addColorStop(0, "#33C433");
grd.addColorStop(0.3, "#33C433");
grd.addColorStop(0.8, "#F3F304");
grd.addColorStop(0.92, "#F30404");
}
} else {
// Higher values are red
grd.addColorStop(0, "#F30404");
grd.addColorStop(0.3, "#F3F304");
grd.addColorStop(0.7, "#33C433");
}
context.strokeStyle = "white";
context.fillStyle = grd;
//context.fillStyle = "#009933";
//context.imageSmoothingEnabled = true;
yScale = height / stat.max;
if (stat.data > stat.max) {
stat.data = stat.max;
}
if (type == "packetloss" && stat.data == 0.0) {
stat.data = 0.1;
}
var x = width - 1;
var y = height - stat.data * yScale;
var w = 1;
context.fillStyle = grd;
context.fillRect(x, y, w, height);
// shift everything to the left:
var imageData = context.getImageData(1, 0, width - 1, height);
context.putImageData(imageData, 0, 0);
// now clear the right-most pixels:
context.clearRect(width - 1, 0, 1, height);
}
</script>
</body>
</html>