push to talk, room fixes, minor tweaks

largely Untested -- not a proper release.
This commit is contained in:
Steve Seguin 2020-09-04 07:33:53 -04:00 committed by GitHub
parent af516397d8
commit fb9bfcc12b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 418 additions and 88 deletions

View File

@ -3,6 +3,8 @@
html {
border:0;
margin:0;
outline:0;
}
video {
@ -28,8 +30,18 @@ body {
flex-flow: column;
border:0;
margin:0;
outline:0;
}
button.glyphicon-button:focus,
button.glyphicon-button:active:focus,
button.glyphicon-button.active:focus,
button.glyphicon-button.focus,
button.glyphicon-button:active.focus,
button.glyphicon-button.active.focus {
outline: none !important;
}
button{
padding:10px;
font-size: 20px;

View File

@ -54,7 +54,7 @@
<script type="text/javascript" crossorigin="anonymous" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="./main.css?ver=10" />
</head>
<body id="main">
<body id="main" >
<span itemprop="image" itemscope itemtype="image/png">
<link itemprop="url" href="./images/obsNinja_logo_full.png" />
</span>
@ -62,10 +62,10 @@
<span itemprop="thumbnail" itemscope itemtype="http://schema.org/ImageObject">
<link itemprop="url" href="./images/obsNinja_logo_full.png" />
</span>
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=17"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=56"></script>
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=18"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=57"></script>
<input id="zoomSlider" type="range" style="display: none;" />
<div id="header">
<div id="header"">
<a id="logoname" href="./" style="text-decoration: none; color: white; margin: 2px;">
<span data-translate="logo-header">
<font id="qos">O</font>BS.Ninja
@ -104,7 +104,7 @@
</div>
</div>
<div id="controlButtons">
<div id="controlButtons" >
<div id="chatbutton" title="Toggle the Chat" onclick="toggleChat()" class="advanced float" style="cursor: pointer;" alt="Toggle the Chat">
<i id="chattoggle" class="toggleSize las la-comment-alt my-float"></i>
<div id="chatNotification"></div>
@ -324,9 +324,12 @@
</select>
</p>
<br />
<span id="headphonesDiv2" style="background-color: #f3f3f3; min-width: 290px; display: none; padding: 5px 10px; border: 1px solid #ccc; vertical-align: middle;">
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination: <button onclick="playtone(true)" style="margin:0;margin-left:15px;" type="button">Test</button></span></span><br />
<select id="outputSourceScreenshare" style="background-color: #FFF; padding:10px 5px; min-width: 288px; display: display:inline-block;vertical-align: middle;" onclick="requestOutputAudioStream();">
<span id="headphonesDiv2" style="background-color: #f3f3f3; min-width: 270px; display: none; padding: 5px 10px; border: 1px solid #ccc; vertical-align: middle;">
<i class="las la-headphones"></i>
<span data-translate="select-output-source"> Audio Output Destination: <button onclick="playtone(true)" style="padding:2px 5px; margin:0;margin-left:15px; position: relative; top: -2px;" type="button">Test</button></span>
<br />
<select id="outputSourceScreenshare" style="background-color: #FFF; padding:10px 5px; min-width: 268px; display:inline-block; vertical-align: middle;" onclick="requestOutputAudioStream();">
<option value="default">
<span data-translate="default">Default Device</span>
</option>
@ -479,7 +482,7 @@
</li>
<br />
Site last updated: <a href="https://www.reddit.com/r/OBSNinja/comments/ib7vhk/version_10_released_text_chat_and_more_added_see/">August 26th, 2020</a>. The previous version can be found at
Site last updated: <a href="https://www.reddit.com/r/OBSNinja/comments/ib7vhk/version_10_released_text_chat_and_more_added_see/">August 30th, 2020</a>. The previous version can be found at
<a href="https://obs.ninja/v9/">https://obs.ninja/v9/</a> if you are having new issues.
@ -512,7 +515,8 @@
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
</div>
</div>
<div id="gridlayout"></div>
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:20%;-webkit-app-region: drag;"></span>
<div id="gridlayout" ></div>
<div id="controls_blank" style="display: none;">
<b>
<button data-value="0" style="padding: 2px 10px 3px 5px;font-weight:display-block;margin: 2px 0 0 5px;" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event);">
@ -638,10 +642,10 @@
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
// session.configuration = {
// iceServers: [
// iceServers: [
// { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"] }, // more than 4 stun+turn servers may cause issues
// ],
// sdpSemantics: 'unified-plan'
// ],
// sdpSemantics: 'unified-plan'
// };
// var turn = {};
@ -658,6 +662,8 @@
// session.configuration.iceTransportPolicy = "relay"; // uncomment to enable "&privacy" and force the TURN server
// session.wss = false;
///// The following lets you set the defaults
// session.webcamonly // true,false
@ -692,7 +698,7 @@
// If you wish to change branding, blank offers a good clean start.
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
-->
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=37"></script>
<script type="text/javascript" crossorigin="anonymous" src="./animations.js?ver=8"></script>
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=39"></script>
<script type="text/javascript" crossorigin="anonymous" src="./animations.js?ver=9"></script>
</body>
</html>

View File

@ -50,12 +50,13 @@ a:active {
input {
border-radius: 4px;
padding:2px;
-webkit-app-region: no-drag;
}
button {
border-radius: 7px;
border: 1px solid #4444;
-webkit-app-region: no-drag;
padding:5px 10px 3px 10px;
margin:10px 0px;
}
@ -192,7 +193,7 @@ hr {
overflow-y: auto !important;
}
.directorsgrid video {
.directorsgrid .vidcon video {
height: 169px;
width: 300px;
padding:10px 10px 0px 10px !important;
@ -229,6 +230,21 @@ hr {
margin: 0;
}
button.glyphicon-button:focus,
button.glyphicon-button:active:focus,
button.glyphicon-button.active:focus,
button.glyphicon-button.focus,
button.glyphicon-button:active.focus,
button.glyphicon-button.active.focus {
outline: none !important;
}
#main{
-webkit-tap-highlight-color: rgba(255, 255, 255, 0) !important;
-webkit-tap-highlight-color: transparent !important;
outline: 0px !important;
}
video::-webkit-media-controls-current-time-display{
display:none;
}
@ -250,7 +266,6 @@ video::-webkit-media-controls-toggle-closed-captions-button{
}
@keyframes pulse {
0% {
transform: scale(0.95);
@ -288,6 +303,7 @@ video::-webkit-media-controls-toggle-closed-captions-button{
html {
border:0;
margin:0;
outline:0;
}
li {
@ -917,7 +933,6 @@ img {
}
video {
background-color: transparent !important;
border:0;
margin:0;

251
main.js
View File

@ -323,6 +323,8 @@ if (urlParams.has('stereo') || urlParams.has('s') || urlParams.has('proaudio')){
session.stereo = 1;
} else if (session.stereo==="3"){
session.stereo = 3;
} else if (session.stereo==="4"){
session.stereo = 4;
} else if (session.stereo==="2"){
session.stereo = 2;
} else {
@ -330,7 +332,7 @@ if (urlParams.has('stereo') || urlParams.has('s') || urlParams.has('proaudio')){
}
}
if ((session.stereo==1) || (session.stereo==3)){
if ((session.stereo==1) || (session.stereo==3) || (session.stereo==4)){
session.echoCancellation = false;
session.autoGainControl = false;
session.noiseSuppression = false;
@ -437,11 +439,6 @@ if (urlParams.has('streamid') || urlParams.has('view') || urlParams.has('v') ||
}
if (urlParams.has('icefilter')){
log("ICE FILTER ENABLED");
session.icefilter = urlParams.get('icefilter');
}
if (urlParams.has('nopreview')){
log("preview OFF");
@ -556,7 +553,6 @@ if (urlParams.has('novideo') || urlParams.has('nv') || urlParams.has('hidevideo'
if (urlParams.has('noaudio') || urlParams.has('na') || urlParams.has('hideaudio')){
session.noaudio = urlParams.get('noaudio') || urlParams.get('na') || urlParams.get('hideaudio');
errorlog(session.noaudio);
if (!(session.noaudio)){
session.noaudio=[];
@ -917,22 +913,60 @@ if ((session.mirrored) && (session.flipped)){
}
if (urlParams.has('icefilter')){
log("ICE FILTER ENABLED");
session.icefilter = urlParams.get('icefilter');
}
if (urlParams.has('twilio')){ // Not for public use.
}
var turn = {};
if (urlParams.has('turn')){
try {
var turnstring = urlParams.get('turn').split(";");
if (turnstring !== "false"){ // false disables the TURN server. Useful for debuggin
turn = {};
turn.username = turnstring[0]; // myusername
turn.credential = turnstring[1]; //mypassword
turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"];
session.configuration.iceServers = [{ urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302" ]}]
session.configuration.iceServers.push(turn);
var turnstring = urlParams.get('turn');
if (turnstring=="twilio"){
try{
var request = new XMLHttpRequest();
request.open('GET', 'https://api.obs.ninja/twilio', false); // `false` makes the request synchronous
request.send(null);
if (request.status === 200) {
log(request.responseText);
var res = JSON.parse(request.responseText);
session.configuration = {
iceServers: [
{ "username": res["1"],
"credential": res["2"],
"url": "turn:global.turn.twilio.com:3478?transport=tcp",
"urls": "turn:global.turn.twilio.com:3478?transport=tcp"
},
{ "username": res["1"],
"credential": res["2"],
"url": "turn:global.turn.twilio.com:443?transport=tcp",
"urls": "turn:global.turn.twilio.com:443?transport=tcp"
}
],
sdpSemantics: 'unified-plan' // future-proofing
};
}
} catch(e){errorlog("Twilio Failed");}
} else {
try {
turnstring = turnstring.split(";");
if (turnstring !== "false"){ // false disables the TURN server. Useful for debuggin
var turn = {};
turn.username = turnstring[0]; // myusername
turn.credential = turnstring[1]; //mypassword
turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"];
session.configuration.iceServers = [{ urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302" ]}]
session.configuration.iceServers.push(turn);
}
} catch (e){
alert("TURN server parameters were wrong.");
errorlog(e);
}
} catch (e){
alert("TURN server parameters were wrong.");
errorlog(e);
}
}
@ -1143,9 +1177,9 @@ if ( (session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (u
}
getById("info").innerHTML = "";
getById("info").style.color="#CCC";
getById("videoname1").value = roomid;
getById("dirroomid").innerHTML = roomid;
getById("roomid").innerHTML = roomid;
getById("videoname1").value = session.roomid;
getById("dirroomid").innerHTML = session.roomid;
getById("roomid").innerHTML = session.roomid;
getById("container-1").className = 'column columnfade advanced';
getById("container-4").className = 'column columnfade advanced';
getById("mainmenu").style.alignSelf= "center";
@ -1188,7 +1222,7 @@ if ( (session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (u
getById("translateButton").style.display = "none";
log("Update Mixer Event on REsize SET");
window.addEventListener("resize", updateMixer);
joinRoom(roomid); // this is a scene, so we want high resolutions
joinRoom(session.roomid); // this is a scene, so we want high resolutions
getById("main").style.overflow = "hidden";
}
} else if (urlParams.has('director')){ // if I do a short form of this, it will cause duplications in the code elsewhere.
@ -1207,6 +1241,11 @@ if (urlParams.has('hidemenu')){ // needs to happen the room and permaid applica
getById("header").style.opacity = 0;
}
if (urlParams.has('hideheader')){ // needs to happen the room and permaid applications
getById("header").style.display="none";
getById("header").style.opacity = 0;
}
function checkConnection(){
if (document.getElementById("qos")){ // true or false; null might cause problems?
if ((session.ws) && (session.ws.readyState === WebSocket.OPEN)) {
@ -1218,6 +1257,70 @@ function checkConnection(){
}
setInterval(function(){checkConnection();},5000);
function printValues(obj) {
var out = "";
for (var key in obj) {
if (typeof obj[key] === "object") {
if (obj[key]!=null){
out += "<br /><u>"+key+"</u><br />"
out += printValues(obj[key]);
}
} else {
if (key.startsWith("_")){
// if it starts with _, we don't want to show it.
} else {
out +="<b>"+key+"</b>: "+obj[key]+"<br />";
}
}
}
return out;
}
function printMyStats(ele){
session.stats.outbound_connections = Object.keys(session.pcs).length;
session.stats.inbound_connections = Object.keys(session.rpcs).length;
ele.innerHTML="Click window to close<br /><br />";
function printValues(obj) {
for (var key in obj) {
if (typeof obj[key] === "object") {
ele.innerHTML +="<br />";
printValues(obj[key]);
} else {
ele.innerHTML +="<b>"+key+"</b>: "+obj[key]+"<br />";
}
}
}
printValues(session.stats);
ele.innerHTML+="<br /><button style='margin:5px;padding:20px;' onclick='session.forcePLI(null,event);'>Send Video Keyframe to Remote Viewers</button>";
for (var uid in session.pcs){
printValues(session.pcs[uid].stats);
}
};
function setupStatsMenu(e){
var menu = document.createElement("div");
menu.style.left= parseInt(Math.random()*20)+100+"px"
menu.style.top= parseInt(Math.random()*20)+100+"px"
menu.style.width="300px";
menu.style.minHeight="200px";
menu.style.backgroundColor="white";
menu.style.position="absolute";
menu.style.zIndex="20";
menu.style.border="1px solid black";
menu.style.padding="2px";
//menu.id = "stats_"+e.currentTarget.dataset.UUID
getById('main').appendChild(menu);
menu.innerHTML = "";
printMyStats(menu);
menu.interval = setInterval(printMyStats,3000, menu);
menu.addEventListener('click', function(e) {
clearInterval(e.currentTarget.interval);
e.currentTarget.parentNode.removeChild(e.currentTarget);
});
}
function updateStats(obsvc=false){
log('resolution found');
@ -1683,42 +1786,42 @@ function volumeAudioProcess( event ) {
this.volume = Math.max(rms, this.volume*this.averaging);
}
function joinRoom(roomname, maxbitrate=false){
function joinRoom(roomname){
roomname = roomname.replace(/[^0-9a-z]/gi, '');
if (roomname.length){
log("Join room",roomname);
log(roomname);
session.joinRoom(roomname, maxbitrate).then(function(response){ // callback from server; we've joined the room
if (roomname.length){
log("Join room");
log(roomname);
session.joinRoom(roomname).then(function(response){ // callback from server; we've joined the room
if (session.director){
var msg = {};
msg.request = "claim";
session.sendMsg(msg);
}
if (session.director){
var msg = {};
msg.request = "claim";
session.sendMsg(msg);
}
log("Members in Room");
log(response);
for (var i in response){
if ("UUID" in response[i]){
if ("streamID" in response[i]){
if (response[i].UUID in session.pcs){
log("RTC already connected"); /// lets just say instead of Stream, we have
} else {
//var title = ""; // TODO: Assign labels
//if ("title" in response[i]){
// title = response[i]["title"];
//}
play(response[i].streamID); // play handles the group room mechanics here
}
log("Members in Room");
log(response);
for (var i in response){
if ("UUID" in response[i]){
if ("streamID" in response[i]){
if (response[i].UUID in session.pcs){
log("RTC already connected"); /// lets just say instead of Stream, we have
} else {
//var title = ""; // TODO: Assign labels
//if ("title" in response[i]){
// title = response[i]["title"];
//}
play(response[i].streamID); // play handles the group room mechanics here
}
}
}
}
},function(error){return {};});
} else {
log("Room name not long enough or contained all bad characaters");
}
},function(error){return {};});
} else {
log("Room name not long enough or contained all bad characaters");
}
}
@ -1775,14 +1878,19 @@ function createRoom(roomname=false){
gridlayout.innerHTML = "<br /><div style='display:inline-block'><font style='font-size:130%;color:white;'></font><input onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#78F; width:400px; font-size:100%; padding:10px; border:2px solid black; margin:5px;' class='task' value='https://"+location.host+location.pathname+"?room="+session.roomid+passAdd+"' /><font style='font-size:110%;color:white;'><i class='las la-video' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - Invites users to join the group and broadcast their feed to it. These users will see every feed in the room.</font></div>";
gridlayout.innerHTML += "<br /><font style='font-size:130%;color:white;'></font><input class='task' onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#F45;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?room="+session.roomid+passAdd+"&view' /><font style='font-size:110%;color:white;'><i class='las la-video' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - Link to Invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.</font><br />";
gridlayout.innerHTML += "<br /><font style='font-size:130%;color:white;'></font><input class='task' onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#F45;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?room="+session.roomid+passAdd+"&view' /><font style='font-size:110%;color:white;'><i class='las la-video' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - Link to invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.</font><br />";
gridlayout.innerHTML += "<font style='font-size:130%;color:white'></font><input class='task' onmousedown='copyFunction(this)' data-drag='1' onclick='popupMessage(event);copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#5F4;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?scene=1&room="+session.roomid+passAdd2+"' /><font style='font-size:110%;color:white'><i class='las la-th-large' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - This is an OBS Browser Source link that contains the group chat in just a single scene. Videos must be manually added to this scene.</font><br />";
gridlayout.innerHTML += "<font style='font-size:130%;color:white'></font><input class='task' onmousedown='copyFunction(this)' data-drag='1' onclick='popupMessage(event);copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#5F4;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?scene=1&room="+session.roomid+passAdd2+"' /><font style='font-size:110%;color:white'><i class='las la-th-large' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - This is an OBS Browser Source link that is empty by default. Videos in the room can be manually added to this scene.</font><br />";
gridlayout.innerHTML += '<button style="margin:10px;" onclick="toggle(getById(\'roomnotes2\'),this);">❔ Click Here for a quick overview and help</button><br />';
gridlayout.innerHTML += "<font style='font-size:130%;color:white'></font><input class='task' onmousedown='copyFunction(this)' data-drag='1' onclick='popupMessage(event);copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#7C7;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?scene=0&room="+session.roomid+passAdd2+"' /><font style='font-size:110%;color:white'><i class='las la-th-large' style='position:relative;top:7px;font-size:2em;' aria-hidden='true'></i> - Also an OBS Browser Source link, all videos in this group chat room will automatically be added into this scene.</font><br />";
gridlayout.innerHTML += "<div id='roomnotes2' style='display:none;padding:0 0 0 10px;' ><br />\
gridlayout.innerHTML += '<button style="margin:10px;" onclick="toggle(getById(\'roomnotes2\'),this);">❔ Click Here for a quick overview and help</button> ';
gridlayout.innerHTML += '<button id="press2talk" style="margin:10px;" onclick="press2talk(this);">🔊 Enable Press to Talk</button>';
gridlayout.innerHTML += "<br /><div id='roomnotes2' style='display:none;padding:0 0 0 10px;' ><br />\
<font style='color:#CCC;'>Welcome. This is the control-room for the group-chat. There are different things you can use this room for:<br /><br />\
<li>You can host a group chat with friends using a room. Share the blue link to invite guests who will join the chat automatically.</li>\
<li>A group room can handle around 4 to 30 guests, depending on numerous factors, including CPU and available bandwidth of all guests in the room.</li>\
@ -1802,10 +1910,35 @@ function createRoom(roomname=false){
<div style='display:inline-block;width:300px;height:350px;border:2px solid white;background-color:#999;margin:40px;'><br /><br />GUEST SLOT #2<br /><br />(A video will appear here when a guest joins)<br /><br /><i class='las la-user ' style='font-size:8em;' aria-hidden='true'></i><br /><br />A Solo Link for OBS will appear here</div>\
<div style='display:inline-block;width:300px;height:350px;border:2px solid white;background-color:#999;margin:40px;'><br /><br />GUEST SLOT #3<br /><br />(A video will appear here when a guest joins)<br /><br /><i class='las la-user ' style='font-size:8em;'aria-hidden='true'></i><br /><br />A Solo Link for OBS will appear here</div>\
<div style='display:inline-block;width:300px;height:350px;border:2px solid white;background-color:#999;margin:40px;'><br /><br />GUEST SLOT #4<br /><br />(A video will appear here when a guest joins)<br /><br /><i class='las la-user ' style='font-size:8em;'aria-hidden='true'></i><br /><br />A Solo Link for OBS will appear here</div></center></div>";
joinRoom(roomname); // setting this to limit bitrate may break things.
joinRoom(roomname);
}
function press2talk(ele){
log(ele);
if (!(document.getElementById("videosource"))){
ele.innerHTML = "🔴 Push to Mute";
session.publishDirector();
return;
}
if (ele.dataset.enabled=="false"){
ele.innerHTML = "🔴 Push to Mute";
ele.dataset.enabled="true";
session.streamSrc.getAudioTracks().forEach((track) => {
track.enabled = true;
});
log("PUSHED TO TALK 1");
} else {
ele.innerHTML = "🔴 Push to Talk ";
ele.dataset.enabled="false";
session.streamSrc.getAudioTracks().forEach((track) => {
track.enabled = false;
});
log("PUSHED TO TALK 2");
}
}
function toggle(ele, tog=false) {
var x = ele;
if (x.style.display === "none") {

172
speedtest.html Normal file
View File

@ -0,0 +1,172 @@
<html>
<head><title>OBSN Speed Test</title>
<style>
body{
padding:0;
margin:0;
}
iframe {
border:0;
margin:0;
padding:0;
display:inline-block;
margin:0;
width:100%;
height:100%;
}
span {
border:0;
margin:0;
padding:0;
display:inline-block;
margin:0;
width:50%;
height:45%;
}
#viewlink {
width:400px;
}
#container {
display:block;
padding:0px;
}
input{
padding:5px;
margin:5px;
}
button{
padding:5px;
margin:5px;
}
</style>
<script>
(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 loadIframe(){
var streamID = "";
var possible = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789";
for (var i = 0; i < 7; i++){
streamID += possible.charAt(Math.floor(Math.random() * possible.length));
}
var iframe = document.createElement("iframe");
var iframeContainer = document.createElement("span");
iframe.allow="autoplay";
var srcString = "./?push="+streamID+"&cleanoutput&privacy&autojoin&videodevice";
if (urlParams.has('turn')){
iframe.src = srcString+"&turn="+urlParams.get("turn");
} else {
iframe.src = srcString;
}
iframeContainer.appendChild(iframe);
document.getElementById("container").appendChild(iframeContainer);
var iframe = document.createElement("iframe");
var iframeContainer = document.createElement("span");
iframe.allow="autoplay";
iframe.src = "./?view="+streamID+"&cleanoutput&privacy&noaudio";
iframeContainer.appendChild(iframe);
document.getElementById("container").appendChild(iframeContainer);
var button = document.createElement("br");
document.getElementById("container").appendChild(button);
var button = document.createElement("button");
button.innerHTML = "Disconnect";
button.onclick = function(){iframe.contentWindow.postMessage({"close":true}, '*');}
document.getElementById("container").appendChild(button);
var button = document.createElement("button");
button.innerHTML = "Low Bitrate";
button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":30}, '*');}
document.getElementById("container").appendChild(button);
var button = document.createElement("button");
button.innerHTML = "High Bitrate";
button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":6000}, '*');}
document.getElementById("container").appendChild(button);
var button = document.createElement("button");
button.innerHTML = "Default Bitrate";
button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":-1}, '*');}
document.getElementById("container").appendChild(button);
setInterval(function(){iframe.contentWindow.postMessage({"getStats":true}, '*');},1000);
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
if ("stats" in e.data){
var out = "";
for (var streamID in e.data.stats.inbound_stats){
out += printValues(e.data.stats.inbound_stats[streamID]);
}
document.getElementById("statsdiv").innerHTML = out;
}
});
}
function printValues( obj) {
var out = "";
for (var key in obj) {
if (typeof obj[key] === "object") {
out +="<br />";
out += printValues(obj[key]);
} else {
out +="<b>"+key+"</b>: "+obj[key]+"<br />";
}
}
return out;
}
</script>
</head>
<body onload="loadIframe();">
<div id="container">
</div>
<div style="width:48%;padding:0;margin:0;border:0;display:inline-block;">
<h3>OBS.Ninja Speed Test - prototype version</h3>
(Tests connection to TURN server and back)<br /><br />
<li>1.Select your camera.</li>
<li>2.Hit start</li>
<li>3.Wait for the video to load side-by-side. *If it does not auto-load within 20s, refresh and try again.*</li>
<li>4.Stats will load on the right-hand side of the page here. (or press CTRL + LeftClick on the new video to open stats that way)</li>
<li>5.Bitrate_in_kbps, Buffer_Delay_in_ms, and packetLoss_percentage are important connection quality metrics</li>
<li>6.Increase the video bitrate by pressing <i>High Bitrate</i>; it should approach 6000-kbps if the network allows.</li>
</div>
<div id="statsdiv" style="width:48%;padding:0;margin:0;border:0;display:inline-block;">
</div>
</body>
</html>

File diff suppressed because one or more lines are too long