vdo.ninja/monitor.html
Steve Seguin 791aaf497e
just syncing up a bit of mid-dev code
THIS IS NOT FOR RELEASE YET
2021-03-16 08:50:27 -04:00

367 lines
10 KiB
HTML

<html>
<head>
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
<link rel="stylesheet" href="./speedtest.css?ver=2" />
<meta charset="utf8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OBSN Monitoring</title>
<script>
function getChromeVersion() {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
return raw ? parseInt(raw[2], 10) : false;
}
if (!getChromeVersion()){
alert("This speedtest is optimized for Chromium-based browsers; graphs will not work for Firefox or Safari browsers.");
}
(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);
var quality_reason = "";
var video_encoder="";
var resolution="";
function copyFunction(copyText) {
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 loadIframe() {
var iframe = document.createElement("iframe");
if (urlParams.has("remote")) {
var remote = urlParams.get("remote");
} else {
var remote="";
}
if (urlParams.has("sid")) {
var streamID = urlParams.get("sid");
} else if (urlParams.has("view")) {
var streamID = urlParams.get("view");
} else {
return;
}
var room="";
if (urlParams.has("room")) {
room = "&room="+urlParams.get("room");
}
var password="";
if (urlParams.has("password")) {
password = "&password="+urlParams.get("password");
}
iframe.allow = "autoplay";
var srcString = "./?view=" + streamID + room + password + "&vd=0&ad=0&autostart&novideo&noaudio&remote="+remote;
iframe.src = srcString;
iframe.style.width="0";
iframe.style.height="0";
iframe.style.border="0";
document.body.appendChild(iframe);
//var button = document.createElement("button");
//button.innerHTML = "Disconnect";
//button.className = "red";
//button.style.display = "none";
//button.onclick = function () {
// iframe.contentWindow.postMessage({ close: true }, "*");
//};
//buttonContainer.appendChild(button);
//document.getElementById("container").appendChild(buttonContainer);
setInterval(function () {
iframe.contentWindow.postMessage({ getRemoteStats: true }, "*");
}, 3000);
var eventMethod = window.addEventListener
? "addEventListener"
: "attachEvent";
var eventer = window[eventMethod];
var messageEvent =
eventMethod === "attachEvent" ? "onmessage" : "message";
var previousResolution;
eventer(messageEvent, function (e) {
if ("remoteStats" in e.data) {
var out = "";
console.log(e.data);
for (var UUID in e.data.remoteStats) {
if (e.data.remoteStats[UUID].quality_limitation_reason){
if (quality_reason != e.data.remoteStats[UUID].quality_limitation_reason) {
quality_reason = e.data.remoteStats[UUID].quality_limitation_reason;
logData("Quality Limitation Reason:", quality_reason, UUID);
}
}
if (e.data.remoteStats[UUID].video_encoder){
if (video_encoder != e.data.remoteStats[UUID].video_encoder) {
video_encoder = e.data.remoteStats[UUID].video_encoder;
logData("Video encoder used:", video_encoder, UUID);
}
}
if (e.data.remoteStats[UUID].resolution){
if (resolution != e.data.remoteStats[UUID].resolution) {
resolution = e.data.remoteStats[UUID].resolution;
logData("Resolution:", resolution, UUID);
}
}
if (e.data.remoteStats[UUID].video_bitrate_kbps){
var video_bitrate_kbps = e.data.remoteStats[UUID].video_bitrate_kbps;
updateData("bitrate", video_bitrate_kbps, UUID);
} else if (document.getElementById(UUID)){
updateData("bitrate", 0, UUID);
}
if (e.data.remoteStats[UUID].nacks_per_second){
var nacks_per_second = e.data.remoteStats[UUID].nacks_per_second;
updateData("nackrate", nacks_per_second, UUID);
} else if (document.getElementById(UUID)){
updateData("nackrate", 0, UUID);
}
if (e.data.remoteStats[UUID].retransmitted_kbps){
var retransmitted_kbps = e.data.remoteStats[UUID].retransmitted_kbps;
updateData("retransmit", retransmitted_kbps, UUID);
} else if (document.getElementById(UUID)){
updateData("retransmit", 0, UUID);
}
//updateData("buffer", buffer);
//if (packetloss != undefined) {
// packetloss = packetloss.toFixed(2);
// updateData("packetloss", packetloss);
//}
}
}
});
}
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;
}
function logData(type, data, UUID) {
try{
var log = document.getElementById(UUID).querySelectorAll('[data-log]')[0].getElementsByTagName("ul")[0];
var entry = document.createElement('li');
entry.style.color ="white";
entry.textContent = "[" + new Date().toLocaleTimeString() + "] " + type + " : " + data;
log.prepend(entry);
} catch(e){}
}
</script>
</head>
<body onload="loadIframe();">
<div id="container">
<h1>
OBS.Ninja Remote Monitor
</h1>
</div>
<div id="graphs" style="display:none">
<div data-log="true" onclick="copyFunction(this.innerText)" style="max-height:400px;display:inline-block;">
<ul></ul>
</div>
<div class="graph">
<h2>Bitrate (kbps)</h2>
<span>0</span>
<canvas data-bitrate-graph="true"></canvas>
</div>
<div class="graph">
<h2>Nacks (per second)</h2>
<span>0</span>
<canvas data-nackrate-graph="true"></canvas>
</div>
<div class="graph">
<h2>Retransmitted (kbps)</h2>
<span>0</span>
<canvas data-retransmit-graph="true"></canvas>
</div>
</div>
<script>
var bitrate = {
element: "bitrate-graph",
data: 0,
max: 6000,
target: 3000,
};
var frames;
var nackrate = {
element: "nackrate-graph",
data: 0,
max: 15,
target: 15,
};
var retransmit = {
element: "retransmit-graph",
data: 0,
max: 100,
target: 100,
};
function updateData(type, data, UUID) {
if (type == "bitrate") {
bitrate.data = data;
plotData("bitrate", bitrate, UUID);
}
if (type == "nackrate") {
nackrate.data = data;
plotData("nackrate", nackrate, UUID);
}
if (type == "retransmit") {
retransmit.data = data;
plotData("retransmit", retransmit, UUID);
}
}
function plotData(type, stat, UUID) {
var canvas;
var context;
var yScale;
console.log(type);
console.log(stat);
var container = document.getElementById(UUID);
if (container){
canvas = container.querySelectorAll('[data-'+stat.element+']')[0];
} else {
container = document.getElementById("graphs").cloneNode(true);
container.id = UUID;
container.className = "graphContainer";
container.style.display = "block";
document.getElementById("graphs").parentNode.insertBefore(container, document.getElementById("graphs").nextSibling);
canvas = container.querySelectorAll('[data-'+stat.element+']')[0];
}
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") {
// Higher values are green
grd.addColorStop(0, "#33C433");
grd.addColorStop(0.7, "#F3F304");
grd.addColorStop(0.9, "#F30404");
} else {
// Higher values are red
grd.addColorStop(0, "#F30404");
grd.addColorStop(0.85, "#F3F304");
grd.addColorStop(0.95, "#33C433");
}
context.strokeStyle = "white";
context.fillStyle = grd;
//context.fillStyle = "#009933";
//context.imageSmoothingEnabled = true;
yScale = height / stat.target;
if (stat.data > stat.target) {
stat.data = stat.target;
}
if (type == "retransmit" && stat.data == 0.0) {
stat.data = 0.5;
}
if (type == "nackrate" && 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>