mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-14 23:28:30 +00:00
push to talk, room fixes, minor tweaks
largely Untested -- not a proper release.
This commit is contained in:
parent
af516397d8
commit
fb9bfcc12b
@ -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;
|
||||
|
||||
36
index.html
36
index.html
@ -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>
|
||||
|
||||
23
main.css
23
main.css
@ -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
251
main.js
@ -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
172
speedtest.html
Normal 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>
|
||||
Loading…
x
Reference in New Issue
Block a user