mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 13:48:38 +00:00
just syncing up a bit of mid-dev code
THIS IS NOT FOR RELEASE YET
This commit is contained in:
parent
f886e485db
commit
791aaf497e
172
chat.html
Normal file
172
chat.html
Normal file
@ -0,0 +1,172 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>OBSN Chat Overlay</title>
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: 'Cousine';
|
||||
src: url('fonts/Cousine-Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
padding:0 10px;
|
||||
height:100%;
|
||||
border: 0;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
position:absolute;
|
||||
bottom:0;
|
||||
overflow:hidden;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin:0;
|
||||
background-color: #0000;
|
||||
color: white;
|
||||
font-family: Cousine, monospace;
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1em;
|
||||
letter-spacing: 0.0em;
|
||||
text-transform: uppercase;
|
||||
padding: 0em;
|
||||
text-shadow: 0.05em 0.05em 0px rgba(0,0,0,1);
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
ul li {
|
||||
background-color: black;
|
||||
padding: 8px 8px 0px 8px;
|
||||
margin:0;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color:white;
|
||||
font-size:1.2em;
|
||||
text-transform: none;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
}
|
||||
</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 iframe = document.createElement("iframe");
|
||||
|
||||
var view= "";
|
||||
if (urlParams.has("view")) {
|
||||
view = "&view="+(urlParams.get("view") || "");
|
||||
}
|
||||
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 = "./?novideo&noaudio&label=chatOverlay&scene"+room+view+password;
|
||||
|
||||
iframe.src = srcString;
|
||||
iframe.style.width="0";
|
||||
iframe.style.height="0";
|
||||
iframe.style.border="0";
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
|
||||
/// If you have a routing system setup, you could have just one global listener for all iframes instead.
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
|
||||
console.log(e);
|
||||
if ("gotChat" in e.data){
|
||||
logData(e.data.gotChat.label,e.data.gotChat.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
var log = document.body.getElementsByTagName("ul")[0];
|
||||
var entry = document.createElement('li');
|
||||
if (type){
|
||||
type = "<i>"+type+"</i>";
|
||||
}
|
||||
entry.innerHTML = type + data;
|
||||
|
||||
//setTimeout(function(entry){ // hide message after 60 seconds
|
||||
// entry.innerHTML="";
|
||||
// entry.remove();
|
||||
// },60000,entry);
|
||||
|
||||
log.appendChild(entry);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadIframe();">
|
||||
<ul></ul>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
178
index.html
178
index.html
@ -162,7 +162,7 @@
|
||||
onclick="submitDebugLog();"
|
||||
style="cursor: pointer; visibility: hidden; display:none;z-index:7;"
|
||||
>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 46px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-bug" aria-hidden="true"></i>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 55px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-bug" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span
|
||||
id="helpbutton"
|
||||
@ -171,10 +171,13 @@
|
||||
style="cursor: pointer; display:none;"
|
||||
alt="How to Use This with OBS"
|
||||
>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 24px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-question-circle" aria-hidden="true"></i>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 33px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-question-circle" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span title="Language Options" onclick="toggle(document.getElementById('languages'));" id="translateButton">
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 2px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-language" aria-hidden="true"></i>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 10px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-language" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span title="Add to Calendar" onclick="toggle(document.getElementById('calendar'));" id="calendarButton">
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 33px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-calendar" aria-hidden="true"></i>
|
||||
</span>
|
||||
<div id="mainmenu" class="row" style="opacity: 0; align: center;">
|
||||
<div id="container-1" title="Add Group Chat to OBS" alt="Add Group Chat to OBS" tabindex="2" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="column columnfade pointer card" style=" overflow-y: auto;">
|
||||
@ -662,8 +665,12 @@
|
||||
<li>
|
||||
Chrome on Android 11 has an issue with the browser freezing at times. To unfreeze it, background the browser and then foreground it again.
|
||||
</li>
|
||||
<li>
|
||||
A list of less common issues can <a href="https://github.com/steveseguin/obsninja/wiki/Known-Issues-(browser-bugs-and-more)">be found here</a>.
|
||||
</li>
|
||||
|
||||
<br />
|
||||
Site Updated: <a href="https://github.com/steveseguin/obsninja/wiki/v16.4-update-notes">March 3rd, 2021</a> (v16.5). The previous version can be found at <a href="https://obs.ninja/v16/">https://obs.ninja/v16/</a> if you are having issues with this minor update.
|
||||
Site Updated: <a href="https://github.com/steveseguin/obsninja/wiki/v16.4-update-notes">March 9th, 2021</a> (v16.5). The previous version can be found at <a href="https://obs.ninja/v16/">https://obs.ninja/v16/</a> if you are having issues with this minor update.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
@ -796,6 +803,12 @@
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show display names
|
||||
<Br />
|
||||
<label class="switch" title="Display Names will be shown in the bottom-left corner of videos">
|
||||
<input type="checkbox" data-param="&activespeaker" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show active speakers
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch" title="Request 1080p60 from the Guest instead of 720p60, if possible">
|
||||
@ -820,9 +833,21 @@
|
||||
<input type="checkbox" data-param="&ns" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide Settings Button
|
||||
Hide settings button
|
||||
<Br />
|
||||
<label class="switch" title="The guest won't have access to changing camera settings or screenshare">
|
||||
<input type="checkbox" data-param="&mini" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Mini self-preview
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch" title="Increase video quality that guests in room see.">
|
||||
<input type="checkbox" data-param="&trb=2000" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<font class="tooltip" style='cursor: help;position:relative;bottom:2px;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort;'>⚠<span class="tooltiptext">Only use with powerful computers and small groups!!</span></font> Guests see HD video
|
||||
<Br />
|
||||
<label class="switch" title="The guest will not see their own self-preview after joining">
|
||||
<input type="checkbox" data-param="&np" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
@ -940,7 +965,7 @@
|
||||
<span data-translate="send-direct-chat"><i class="las la-envelope"></i> Message</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="addToScene" style="grid-column: 1;" data-value="0" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event, 1);">
|
||||
<button data-action-type="addToScene" data-scene="1" style="grid-column: 1;" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event, 1);">
|
||||
<i class="las la-plus-square"></i>
|
||||
<span data-translate="add-to-scene">add to scene</span>
|
||||
</button>
|
||||
@ -949,14 +974,23 @@
|
||||
<span data-translate="mute-scene" >mute in scene</span>
|
||||
</button>
|
||||
|
||||
<button class="" data-action-type="solo-chat" title="Toggle Solo Voice Chat" onclick="session.toggleSoloChat(this.dataset.UUID);">
|
||||
<span data-translate="voice-chat"><i class="las la-microphone"></i> Solo Talk</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="hangup" data-value="0" title="Force the user to Disconnect. They can always reconnect." onclick="directHangup(this, event);">
|
||||
<i class="las la-sign-out-alt"></i>
|
||||
<span data-translate="disconnect-guest" >Hangup</span>
|
||||
</button>
|
||||
|
||||
<span id="sceneGroup1" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-scene-2" title="Add to Scene 2" onclick="directEnable(this, event, 2);">
|
||||
<button style="width: 35.2px" data-scene="2" data-action-type="add-scene-2" title="Add to Scene 2" onclick="directEnable(this, event, 2);">
|
||||
<span >S2</span>
|
||||
</button>
|
||||
<button style="width:35.2px;" data-action-type="add-scene-3" title="Add to Scene 3" onclick="directEnable(this, event, 3);">
|
||||
<button style="width:35.2px;" data-scene="3" data-action-type="add-scene-3" title="Add to Scene 3" onclick="directEnable(this, event, 3);">
|
||||
<span >S3</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-4" title="Add to Scene 4" onclick="directEnable(this, event, 4);">
|
||||
<button style="width: 35.2px" data-scene="4" data-action-type="add-scene-4" title="Add to Scene 4" onclick="directEnable(this, event, 4);">
|
||||
<span >S4</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -966,20 +1000,17 @@
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" onclick="remoteVolume(this);" style="grid-column: 2; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span>
|
||||
</font>
|
||||
<span id="sceneGroup2" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-scene-5" title="Add to Scene 5" onclick="directEnable(this, event, 5);">
|
||||
<button style="width: 35.2px" data-scene="5" data-action-type="add-scene-5" title="Add to Scene 5" onclick="directEnable(this, event, 5);">
|
||||
<span >S5</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-6" title="Add to Scene 6" onclick="directEnable(this, event, 6);">
|
||||
<button style="width: 35.2px" data-scene="6" data-action-type="add-scene-6" title="Add to Scene 6" onclick="directEnable(this, event, 6);">
|
||||
<span >S6</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-7" title="Add to Scene 7" onclick="directEnable(this, event, 7);">
|
||||
<button style="width: 35.2px" data-scene="7" data-action-type="add-scene-7" title="Add to Scene 7" onclick="directEnable(this, event, 7);">
|
||||
<span >S7</span>
|
||||
</button>
|
||||
</span>
|
||||
<button data-action-type="mute-guest" style="grid-column: 2;" title="Mute this guest everywhere" onclick="remoteMute(this, event);">
|
||||
<i class="las la-microphone-slash"></i>
|
||||
<span data-translate="mute-guest" >mute guest</span>
|
||||
</button>
|
||||
|
||||
|
||||
<span>
|
||||
<button style="width: 35.2px" data-action-type="change-quality1" title="Disable Video Preview" onclick="toggleQualityDirector(0, this.dataset.UUID, this);">
|
||||
@ -992,36 +1023,17 @@
|
||||
<span data-translate="change-to-high-quality"> <i class="las la-binoculars"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="mute-guest" style="grid-column: 1;" title="Mute this guest everywhere" onclick="remoteMute(this, event);">
|
||||
<i class="las la-microphone-slash"></i>
|
||||
<span data-translate="mute-guest" >mute guest</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="hide-guest" style="grid-column: 2;" title="Hide this guest everywhere" onclick="remoteMuteVideo(this, event);">
|
||||
<i class="las la-video-slash"></i>
|
||||
<span data-translate="hide-guest" >hide guest</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="hangup" data-value="0" title="Force the user to Disconnect. They can always reconnect." onclick="directHangup(this, event);">
|
||||
<i class="las la-sign-out-alt"></i>
|
||||
<span data-translate="disconnect-guest" >Hangup</span>
|
||||
</button>
|
||||
<button data-action-type="recorder-local" title="Start Recording this remote stream to this local drive. *experimental*'" onclick="recordVideo(this, event)">
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record-local"> Record Local</span>
|
||||
</button>
|
||||
<button data-action-type="recorder-remote" data-value="0" title="The Remote Guest will record their local stream to their local drive. *experimental*" onclick="requestVideoRecord(this)">
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record-remote"> Record Remote</span>
|
||||
</button>
|
||||
|
||||
<button class="" data-action-type="solo-chat" title="Toggle Solo Voice Chat" onclick="session.toggleSoloChat(this.dataset.UUID);">
|
||||
<span data-translate="voice-chat"><i class="las la-microphone"></i> Solo Talk</span>
|
||||
</button>
|
||||
|
||||
<span>
|
||||
<button style="width:34px;" data-action-type="order-down" title="Shift this Video Down in Order" onclick="changeOrder(-1,this.dataset.UUID);">
|
||||
<span data-translate="order-down"><i class="las la-minus"></i></span>
|
||||
</button>
|
||||
<span class="orderspan">
|
||||
<div style="text-align: center;font-size: 150%;" data-action-type="order-value" title="Current Index Order of this Video" >0</div>
|
||||
Mix Order
|
||||
</span>
|
||||
<button style="width:34px;margin-left:0;" data-action-type="order-up" title="Shift this Video Up in Order" onclick="changeOrder(1,this.dataset.UUID);">
|
||||
<span data-translate="order-up"><i class="las la-plus"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span id="channelGroup1" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-channel" class="pressed" title="Set to Default Audio Channel" onclick="changeChannelOffset(this.dataset.UUID, false);">
|
||||
@ -1035,10 +1047,6 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="toggle-remote-speaker" title="Toggle the remote guest's speaker output" onclick="remoteSpeakerMute(this, event);">
|
||||
<i class="las la-volume-off"></i> <span data-translate="toggle-remote-speaker">Deafen Guest</span>
|
||||
</button>
|
||||
|
||||
<span id="channelGroup2" style="display:none" >
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 3" onclick="changeChannelOffset(this.dataset.UUID, 2);">
|
||||
<span >C3</span>
|
||||
@ -1051,6 +1059,12 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<button data-action-type="toggle-remote-speaker" style="grid-column: 1;" title="Toggle the remote guest's speaker output" onclick="remoteSpeakerMute(this, event);">
|
||||
<i class="las la-volume-off"></i> <span data-translate="toggle-remote-speaker">Deafen Guest</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="toggle-remote-display" style="grid-column: 2;" title="Toggle the remote guest's display output" onclick="remoteDisplayMute(this, event);">
|
||||
<i class="las la-eye-slash"></i> <span data-translate="toggle-remote-display">Blind Guest</span>
|
||||
</button>
|
||||
@ -1073,6 +1087,40 @@
|
||||
<span data-translate="force-keyframe">Rainbow Puke</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="solo-video" data-value="0" title="Solo this video everywhere" onclick="requestInfocus(this);">
|
||||
<i class="las la-user"></i>
|
||||
<span data-translate="solo-video">Highlight guest</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="recorder-local" title="Start Recording this remote stream to this local drive. *experimental*'" onclick="recordVideo(this, event)">
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record-local"> Record Local</span>
|
||||
</button>
|
||||
<button data-action-type="recorder-remote" data-value="0" title="The Remote Guest will record their local stream to their local drive. *experimental*" onclick="requestVideoRecord(this)">
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record-remote"> Record Remote</span>
|
||||
</button>
|
||||
|
||||
|
||||
|
||||
<span>
|
||||
<button style="width:34px;" data-action-type="order-down" title="Shift this Video Down in Order" onclick="changeOrder(-1,this.dataset.UUID);">
|
||||
<span data-translate="order-down"><i class="las la-minus"></i></span>
|
||||
</button>
|
||||
<span class="orderspan">
|
||||
<div style="text-align: center;font-size: 150%;" data-action-type="order-value" title="Current Index Order of this Video" >0</div>
|
||||
Mix Order
|
||||
</span>
|
||||
<button style="width:34px;margin-left:0;" data-action-type="order-up" title="Shift this Video Up in Order" onclick="changeOrder(1,this.dataset.UUID);">
|
||||
<span data-translate="order-up"><i class="las la-plus"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="stats-remote" data-value="0" title="Request the statistics of this video in any active scene" onclick="session.sendRequest({'requestStats':'true', }, this.dataset.UUID);">
|
||||
<i class="las la-info-circle"></i>
|
||||
<span data-translate="stats-remote"> Scene Stats</span>
|
||||
</button>
|
||||
|
||||
<button class="" data-action-type="advanced-audio-settings" data-active="false" style="grid-column: 1;" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
|
||||
<span data-translate="advanced-audio-settings"><i class="las la-sliders-h"></i> Audio Settings</span>
|
||||
</button>
|
||||
@ -1223,7 +1271,20 @@
|
||||
<a href="https://github.com/steveseguin/obsninja/tree/master/translations" target="_blank" rel="noopener noreferrer" data-translate='add-more-here'>Add More Here!</a>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="calendar" class="popup-message" style="display: none; right: 0; padding-left:5px; bottom: 25px; position: absolute;">
|
||||
<b data-translate='add-to-calendar'>Add details to your Calendar:</b>
|
||||
<br />
|
||||
<u>
|
||||
<br />
|
||||
<a onclick="addToGoogleCalendar();" style="cursor: pointer;">Add to Google Calendar</a>
|
||||
<br />
|
||||
<a onclick="addToOutlookCalendar();" style="cursor: pointer;">Add to Outlook Calendar</a>
|
||||
<br />
|
||||
<a onclick="addToYahooCalendar();" style="cursor: pointer;">Add to Yahoo Calendar</a>
|
||||
<br />
|
||||
<br />
|
||||
</u>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
if (window.location.hostname.indexOf("www.obs.ninja") == 0) {
|
||||
@ -1231,7 +1292,7 @@
|
||||
}
|
||||
|
||||
var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js.
|
||||
session.version = "16.4";
|
||||
session.version = "17.beta";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Disabling improves compatibility and is helpful for debugging.
|
||||
@ -1243,13 +1304,11 @@
|
||||
// ],
|
||||
// sdpSemantics: 'unified-plan'
|
||||
// };
|
||||
|
||||
// var turn = {};
|
||||
// turn.username = "steve";
|
||||
// turn.credential = "justtesting";
|
||||
// turn.urls = ["turn:turn.obs.ninja:443"]; // US CENTRAL
|
||||
// session.configuration.iceServers.push(turn);
|
||||
|
||||
// turn = {};
|
||||
// turn.username = "steve";
|
||||
// turn.credential = "justtesting";
|
||||
@ -1258,8 +1317,15 @@
|
||||
|
||||
// session.configuration.iceTransportPolicy = "relay"; // uncomment to enable "&privacy" and force the TURN server
|
||||
|
||||
// session.wss = "wss://wss14.obs.ninja:443"; //false; // uses default handshake wss
|
||||
|
||||
///// Different endpoints are available; each isolated from each other.
|
||||
// session.wss = "wss://wss13.obs.ninja:443"; // US-East (Default)
|
||||
// session.wss = "wss://apibackup.obs.ninja:443"; // US-West
|
||||
// session.wss = "wss://jp1wss.obs.ninja:443"; // Japan
|
||||
// session.wss = "wss://au1wss.obs.ninja:443"; // Australia
|
||||
// session.wss = "wss://de1wss.obs.ninja:443"; // Germany
|
||||
// session.wss = "wss://insecure.cam:444"; // China
|
||||
|
||||
|
||||
///// The following lets you set the defaults
|
||||
|
||||
// session.webcamonly // true,false
|
||||
@ -1296,7 +1362,7 @@
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="mixer-js" src="./mixer.js?ver=2"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=174"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=175"></script>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){ // lazy load
|
||||
var script = document.createElement('script');
|
||||
|
||||
12
main.css
12
main.css
@ -1063,7 +1063,7 @@ input[type=range]:focus::-ms-fill-upper {
|
||||
width: 505px;
|
||||
right: -400px;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@ -1315,6 +1315,11 @@ img {
|
||||
position: relative !important;
|
||||
top: 50% !important;
|
||||
}
|
||||
#calendarButton {
|
||||
cursor: pointer;
|
||||
z-index: 6;
|
||||
display:none;
|
||||
}
|
||||
#translateButton {
|
||||
cursor: pointer;
|
||||
z-index: 6;
|
||||
@ -1567,8 +1572,8 @@ video.clean::-webkit-media-controls-timeline-container {
|
||||
display: none;
|
||||
align-text: center;
|
||||
position: absolute;
|
||||
z-index: 10 !important;
|
||||
padding: 3px 0 !important;
|
||||
z-index: 21 !important;
|
||||
padding: 3px !important;
|
||||
min-width: 180px !important;
|
||||
background-color: #fff !important;
|
||||
border: solid 1px #dfdfdf !important;
|
||||
@ -2425,6 +2430,7 @@ input:checked + .slider:before {
|
||||
z-index:2;
|
||||
width:400px;
|
||||
max-width:90%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.alertModalInner {
|
||||
|
||||
506
main.js
506
main.js
@ -137,22 +137,40 @@ function warnUser(message){
|
||||
// Allows for multiple alerts to stack better.
|
||||
// Every modal and backdrop has an increasing z-index
|
||||
// to block the previous modal
|
||||
if (document.getElementById("alertModalBackdrop")){
|
||||
getById("alertModal").innerHTML = ''; // Delete modal
|
||||
getById("alertModal").remove();
|
||||
getById("alertModalBackdrop").innerHTML = ''; // Delete modal
|
||||
getById("alertModalBackdrop").remove();
|
||||
}
|
||||
|
||||
zindex = document.querySelectorAll('.alertModal').length;
|
||||
message = message.replace(/\n/g,"<br />");
|
||||
modalTemplate =
|
||||
`<div class="alertModal" onclick="closeModal(this)" style="z-index:${zindex + 2}">
|
||||
`<div class="alertModal" id="alertModal" style="z-index:${zindex + 2}">
|
||||
<div class="alertModalInner">
|
||||
<span class='alertModalClose'>×</span>
|
||||
<span class='alertModalClose' onclick="closeModal()">×</span>
|
||||
<span class='alertModalMessage'>${message}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alertModalBackdrop" style="z-index:${zindex + 1}"></div>`;
|
||||
<div class="alertModalBackdrop" id="alertModalBackdrop" style="z-index:${zindex + 1}"></div>`;
|
||||
document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
|
||||
|
||||
document.getElementById("alertModalBackdrop").addEventListener("click", closeModal);
|
||||
|
||||
|
||||
getById("alertModal").addEventListener("click", function(e) {
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function closeModal(element){
|
||||
element.nextElementSibling.outerHTML = ''; // Delete backdrop
|
||||
element.outerHTML = ''; // Delete modal
|
||||
function closeModal(){
|
||||
getById("alertModalBackdrop").innerHTML = ''; // Delete modal
|
||||
getById("alertModalBackdrop").remove();
|
||||
getById("alertModal").innerHTML = ''; // Delete modal
|
||||
getById("alertModal").remove();
|
||||
}
|
||||
|
||||
var filename = false;
|
||||
@ -664,6 +682,7 @@ if (urlParams.has('screenshareid') || urlParams.has('ssid')) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
//session.webcamonly = true;
|
||||
getById("shareScreenGear").style.display = "none";
|
||||
@ -934,7 +953,30 @@ if (session.webcamonly == true) {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
getById("main").classList.remove('hidden');
|
||||
if (urlParams.has('css')){
|
||||
var cssURL = urlParams.get('css');
|
||||
cssURL = decodeURI(cssURL);
|
||||
log(cssURL);
|
||||
var cssStylesheet = document.createElement('link');
|
||||
cssStylesheet.rel = 'stylesheet';
|
||||
cssStylesheet.type = 'text/css';
|
||||
cssStylesheet.media = 'screen';
|
||||
cssStylesheet.href = cssURL;
|
||||
document.getElementsByTagName('head')[0].appendChild(cssStylesheet);
|
||||
|
||||
cssStylesheet.onload = function() {
|
||||
getById("main").classList.remove('hidden');
|
||||
log("loaded remote style sheet");
|
||||
}
|
||||
|
||||
cssStylesheet.onerror = function() {
|
||||
getById("main").classList.remove('hidden');
|
||||
errorlog("REMOTE STYLE SHEET HAD ERROR");
|
||||
}
|
||||
|
||||
} else {
|
||||
getById("main").classList.remove('hidden');
|
||||
}
|
||||
|
||||
if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) {
|
||||
session.password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p');
|
||||
@ -1235,6 +1277,10 @@ if (urlParams.has('nopreview') || urlParams.has('np')) {
|
||||
} else if ((urlParams.has('preview')) || (urlParams.has('showpreview'))) {
|
||||
log("preview ON");
|
||||
session.nopreview = false;
|
||||
} else if ((urlParams.has('minipreview')) || (urlParams.has('mini'))) {
|
||||
log("preview ON");
|
||||
session.nopreview = false;
|
||||
session.minipreview = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('obsfix')) {
|
||||
@ -1263,7 +1309,7 @@ if (urlParams.has('controlroombitrate') || urlParams.has('crb')) {
|
||||
|
||||
if (urlParams.has('remote') || urlParams.has('rem')) {
|
||||
log("remote ENABLED");
|
||||
session.remote = urlParams.get('remote') || urlParams.get('rem');
|
||||
session.remote = urlParams.get('remote') || urlParams.get('rem') || "nosecurity";
|
||||
session.remote = session.remote.trim();
|
||||
}
|
||||
|
||||
@ -2113,6 +2159,13 @@ if (urlParams.has('effects') || urlParams.has('effect')) {
|
||||
// green = 4
|
||||
}
|
||||
|
||||
if (urlParams.has('activespeaker') || urlParams.has('speakerview')){
|
||||
session.activeSpeaker = true;
|
||||
setInterval(function(){activeSpeaker(false)},100);
|
||||
} else {
|
||||
setInterval(function(){activeSpeaker(true)},100);
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('style') || urlParams.has('st')) {
|
||||
session.style = urlParams.get('style') || urlParams.get('st') || 1;
|
||||
@ -2148,6 +2201,13 @@ if (urlParams.has('noaudioprocessing') || urlParams.has('noap')) {
|
||||
session.audioMeterGuest = false;
|
||||
}
|
||||
|
||||
if (urlParams.has('tcp')){ // forces the TURN servers to use TCP mode; still need to add &private to force TURN also tho
|
||||
session.forceTcpMode = true;
|
||||
}
|
||||
if (urlParams.has('speedtest')){ // forces essentially UDP mode, unless TCP is specified, and some other stuff
|
||||
session.speedtest = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('turn')) {
|
||||
var turnstring = urlParams.get('turn');
|
||||
if (turnstring == "twilio") {
|
||||
@ -2206,6 +2266,8 @@ if (urlParams.has('turn')) {
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chooseBestTURN(); // obs.ninja turn servers, if needed.
|
||||
}
|
||||
|
||||
|
||||
@ -2221,7 +2283,7 @@ if (urlParams.has('privacy') || urlParams.has('private') || urlParams.has('relay
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
if (urlParams.has('speedtest')){
|
||||
if (session.speedtest){
|
||||
if (session.maxvideobitrate !== false) {
|
||||
if (session.maxvideobitrate > 6000) {
|
||||
session.maxvideobitrate = 6000; // Please feel free to get rid of this if using your own TURN servers...
|
||||
@ -2432,7 +2494,7 @@ if (isIFrame) { // reduce CPU load if not needed.
|
||||
if (stat.kind == "video") {
|
||||
|
||||
if ("qualityLimitationReason" in stat) {
|
||||
session.pcs[UUID].stats.quality_Limitation_Reason = stat.qualityLimitationReason;
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
}
|
||||
if ("framesPerSecond" in stat) {
|
||||
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight + " @ " + stat.framesPerSecond;
|
||||
@ -2478,6 +2540,10 @@ if (isIFrame) { // reduce CPU load if not needed.
|
||||
}, "*");
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if ("getRemoteStats" in e.data) {
|
||||
session.sendRequest({"requestStats":true, "remote":session.remote});
|
||||
}
|
||||
|
||||
if ("getLoudness" in e.data) {
|
||||
log("GOT LOUDNESS REQUEST");
|
||||
@ -2607,13 +2673,13 @@ eventer(messageEvent, function(e) { // this listens for child IFRAMES.
|
||||
|
||||
function requestKeyframeScene(ele) {
|
||||
var UUID = ele.dataset.UUID;
|
||||
if (ele.dataset.active == "true") {
|
||||
if (ele.dataset.value == 1) {
|
||||
} else {
|
||||
ele.dataset.active = "true";
|
||||
ele.dataset.value = 1;
|
||||
ele.classList.add("pressed");
|
||||
session.requestKeyframe(UUID, true);
|
||||
setTimeout(function(el){
|
||||
el.dataset.active = "false";
|
||||
el.dataset.value = 0;
|
||||
el.classList.remove("pressed");
|
||||
}, 1000, ele)
|
||||
}
|
||||
@ -2694,23 +2760,23 @@ function setupCanvas() {
|
||||
if (session.canvas === null) {
|
||||
warnlog("SETUP CANVAS");
|
||||
session.canvas = document.createElement("canvas");
|
||||
session.canvas.width = 1280;
|
||||
session.canvas.height = 720;
|
||||
session.canvas.width = 512;
|
||||
session.canvas.height = 288;
|
||||
session.canvasCtx = session.canvas.getContext('2d');
|
||||
//session.canvasCtx.width=1280;
|
||||
//session.canvasCtx.width=288;
|
||||
//session.canvasCtx.height=720;
|
||||
session.canvasCtx.fillStyle = "blue";
|
||||
session.canvasCtx.fillRect(0, 0, 1280, 720);
|
||||
session.canvasCtx.fillRect(0, 0, 512, 288);
|
||||
session.canvasSource = document.createElement("video");
|
||||
session.canvasSource.width=1280;
|
||||
session.canvasSource.height=720;
|
||||
session.canvasSource.width=512;
|
||||
session.canvasSource.height=288;
|
||||
session.canvasSource.autoplay = true;
|
||||
session.canvasSource.srcObject = new MediaStream();
|
||||
}
|
||||
}
|
||||
|
||||
function applyEffects(track, stream) {
|
||||
|
||||
|
||||
setupCanvas();
|
||||
if (session.effects == 1) {
|
||||
|
||||
@ -2810,10 +2876,11 @@ function applyEffects(track, stream) {
|
||||
session.streamSrc.addTrack(trk);
|
||||
});
|
||||
|
||||
session.videoElement.srcObject = session.streamSrc;
|
||||
|
||||
session.canvasSource.requestVideoFrameCallback(draw2CanvasGreen);
|
||||
session.canvasSource.requestVideoFrameCallback(segmentFilterGreen);
|
||||
|
||||
session.videoElement.srcObject = session.streamSrc;
|
||||
warnlog("APPLY EFFECTS DONE");
|
||||
} else if (session.effects == 6){
|
||||
|
||||
@ -2906,8 +2973,8 @@ async function segmentFilterBlur(now, metadata) { // runs at like 15fps
|
||||
active2=true;
|
||||
try {
|
||||
if (net){
|
||||
session.canvasSource.width = metadata.width;
|
||||
session.canvasSource.height = metadata.height;
|
||||
session.canvasCtx.width = session.canvasSource.srcObject.getSettings().width
|
||||
session.canvasCtx.height = session.canvasSource.srcObject.getSettings().height;
|
||||
mask = await net.segmentPerson(session.canvasSource);
|
||||
}
|
||||
} catch (e){
|
||||
@ -2921,6 +2988,10 @@ function draw2CanvasGreen(now, metadata) { // runs fast; maybe like 30fps
|
||||
active1=true;
|
||||
try {
|
||||
if (mask) {
|
||||
session.canvasCtx.width = session.canvasSource.srcObject.getSettings().width
|
||||
session.canvasCtx.height = session.canvasSource.srcObject.getSettings().height;
|
||||
//session.canvasCtx.width = metadata.width;
|
||||
//session.canvasCtx.height = metadata.height;
|
||||
bodyPix.drawMask(session.canvas, session.canvasSource, mask, 1, 0, false);
|
||||
}
|
||||
} catch (e){
|
||||
@ -2933,8 +3004,8 @@ async function segmentFilterGreen(now, metadata) { // runs at like 15fps
|
||||
if (active2){return;}
|
||||
active2=true;
|
||||
try {
|
||||
session.canvasSource.width = metadata.width;
|
||||
session.canvasSource.height = metadata.height;
|
||||
//session.canvasCtx.width = metadata.width;
|
||||
//session.canvasCtx.height = metadata.height;
|
||||
var segment = await net.segmentPerson(session.canvasSource);
|
||||
mask = bodyPix.toMask(segment, {r: 0, g: 0, b: 0, a: 0}, {r: 0, g: 255, b: 0, a: 255});
|
||||
} catch (e){
|
||||
@ -3349,6 +3420,11 @@ function printValues(obj) { // see: printViewStats
|
||||
value = sanitizeChat((value));
|
||||
}
|
||||
|
||||
// <i class='las la-copy' data-sid='" + streamID + "' onmousedown='copyFunction(this.dataset.sid)' onclick='popupMessage(event);copyFunction(this.dataset.sid)' title='Copy this Stream ID to the clipboard' style='cursor:pointer'></i>
|
||||
if (key == 'useragent') {
|
||||
value = "<span style='cursor: pointer;' onmousedown='copyFunction(this.innerText)' onclick='popupMessage(event);copyFunction(this.innerText);' title='Copy this user-agent to the clipboard' style='cursor:pointer'>"+value+"</span>"
|
||||
}
|
||||
|
||||
if (key == 'Bitrate_in_kbps') {
|
||||
var unit = " kbps";
|
||||
stat = "Bitrate";
|
||||
@ -3547,6 +3623,7 @@ function updateLocalStats(){
|
||||
stats.forEach(stat => {
|
||||
if (stat.type == "outbound-rtp") {
|
||||
if (stat.kind == "video") {
|
||||
|
||||
if ("qualityLimitationReason" in stat) {
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
}
|
||||
@ -3557,7 +3634,7 @@ function updateLocalStats(){
|
||||
session.pcs[UUID].stats.video_encoder = stat.encoderImplementation;
|
||||
}
|
||||
if ("bytesSent" in stat) {
|
||||
if (session.pcs[UUID].stats._bytesSent){
|
||||
if ("_bytesSent" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp){
|
||||
if (stat.timestamp){
|
||||
session.pcs[UUID].stats.video_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp));
|
||||
@ -3565,26 +3642,52 @@ function updateLocalStats(){
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("timestamp" in stat) {
|
||||
session.pcs[UUID].stats._timestamp = stat.timestamp;
|
||||
|
||||
if ("nackCount" in stat) {
|
||||
if ("_nackCount" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp){
|
||||
if (stat.timestamp){
|
||||
session.pcs[UUID].stats.nacks_per_second = parseInt(10000*(stat.nackCount - session.pcs[UUID].stats._nackCount)/(stat.timestamp - session.pcs[UUID].stats._timestamp))/10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("retransmittedBytesSent" in stat) {
|
||||
if ("_retransmittedBytesSent" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp){
|
||||
if (stat.timestamp){
|
||||
session.pcs[UUID].stats.retransmitted_kbps = parseInt(8*(stat.retransmittedBytesSent - session.pcs[UUID].stats._retransmittedBytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("bytesSent" in stat) {
|
||||
session.pcs[UUID].stats._bytesSent = stat.bytesSent;
|
||||
|
||||
}
|
||||
if ("retransmittedBytesSent" in stat) {
|
||||
session.pcs[UUID].stats.retransmitted_bytes_sent = stat.retransmittedBytesSent;
|
||||
|
||||
if ("nackCount" in stat) {
|
||||
session.pcs[UUID].stats._nackCount = stat.nackCount;
|
||||
|
||||
}
|
||||
|
||||
if ("retransmittedBytesSent" in stat) {
|
||||
session.pcs[UUID].stats._retransmittedBytesSent = stat.retransmittedBytesSent;
|
||||
|
||||
}
|
||||
|
||||
if ("timestamp" in stat) {
|
||||
session.pcs[UUID].stats._timestamp = stat.timestamp;
|
||||
}
|
||||
|
||||
if ("pliCount" in stat) {
|
||||
session.pcs[UUID].stats.total_pli_count = stat.pliCount;
|
||||
}
|
||||
if ("keyFramesEncoded" in stat) {
|
||||
session.pcs[UUID].stats.total_key_frames_encoded = stat.keyFramesEncoded;
|
||||
}
|
||||
if ("nackCount" in stat) {
|
||||
session.pcs[UUID].stats.total_nack_ount = stat.nackCount;
|
||||
}
|
||||
|
||||
|
||||
} else if (stat.kind == "audio") {
|
||||
if ("bytesSent" in stat) {
|
||||
@ -4049,7 +4152,7 @@ function hangup() { // TODO: I need to have this be MUTE, toggle, with volume no
|
||||
function hangup2() {
|
||||
session.hangupDirector();
|
||||
getById("miniPerformer").innerHTML = "";
|
||||
getById("press2talk").dataset.enabled = "false";
|
||||
getById("press2talk").dataset.value = 0;
|
||||
getById("screensharebutton").classList.add("advanced");
|
||||
getById("settingsbutton").classList.add("advanced");
|
||||
getById("mutebutton").classList.add("advanced");
|
||||
@ -4215,15 +4318,15 @@ function directHangup(ele, event) { // everyone in the room will hangup this gue
|
||||
|
||||
function directEnable(ele, event, scene=1) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.enable == 1) {
|
||||
ele.dataset.enable = 0;
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "";
|
||||
if (ele.children[1]){
|
||||
ele.children[1].innerHTML = "Add to Scene";
|
||||
getById("container_" + ele.dataset.UUID).style.backgroundColor = null;
|
||||
}
|
||||
} else {
|
||||
ele.dataset.enable = 1;
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "pressed";
|
||||
if (ele.children[1]){
|
||||
ele.children[1].innerHTML = "Remove";
|
||||
@ -4236,7 +4339,7 @@ function directEnable(ele, event, scene=1) { // A directing room only is control
|
||||
//msg.roomid = session.roomid;
|
||||
msg.scene = scene;
|
||||
msg.action = "display";
|
||||
msg.value = ele.dataset.enable;
|
||||
msg.value = ele.dataset.value;
|
||||
msg.target = ele.dataset.UUID;
|
||||
|
||||
//session.anysend(msg);
|
||||
@ -4247,12 +4350,12 @@ function directEnable(ele, event, scene=1) { // A directing room only is control
|
||||
function directMute(ele, event) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("mute");
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.mute == 0) {
|
||||
ele.dataset.mute = 1;
|
||||
if (ele.dataset.value == 0) {
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "Mute in scene";
|
||||
} else {
|
||||
ele.dataset.mute = 0;
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Un-mute";
|
||||
}
|
||||
@ -4262,7 +4365,7 @@ function directMute(ele, event) { // A directing room only is controlled by the
|
||||
//msg.roomid = session.roomid;
|
||||
msg.scene = "1";
|
||||
msg.action = "mute";
|
||||
msg.value = ele.dataset.mute;
|
||||
msg.value = ele.dataset.value;
|
||||
msg.target = ele.dataset.UUID;
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
@ -4270,22 +4373,22 @@ function directMute(ele, event) { // A directing room only is controlled by the
|
||||
function remoteSpeakerMute(ele, event) {
|
||||
log("speaker mute");
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.mute == 1) {
|
||||
ele.dataset.mute = 0;
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "deafen guest";
|
||||
} else {
|
||||
ele.dataset.mute = 1;
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Un-deafen";
|
||||
}
|
||||
}
|
||||
|
||||
var msg = {};
|
||||
if (ele.dataset.mute == 0) {
|
||||
msg.speakerMute = false;
|
||||
if (ele.dataset.value == 0) {
|
||||
msg.speakerMute = ele.dataset.value;
|
||||
} else {
|
||||
msg.speakerMute = true;
|
||||
msg.speakerMute = ele.dataset.value;
|
||||
}
|
||||
msg.UUID = ele.dataset.UUID;
|
||||
session.sendRequest(msg, ele.dataset.UUID);
|
||||
@ -4295,7 +4398,7 @@ function updateRemoteSpeakerMute(UUID) {
|
||||
var ele = document.querySelectorAll('[data-action-type="toggle-remote-speaker"][data--u-u-i-d="' + UUID + '"]');
|
||||
if (ele[0]) {
|
||||
ele[0].classList.add("pressed");
|
||||
ele[0].dataset.mute = 1;
|
||||
ele[0].dataset.value = 1;
|
||||
ele[0].className = "pressed";
|
||||
ele[0].children[1].innerHTML = "Un-deafen";
|
||||
}
|
||||
@ -4305,7 +4408,7 @@ function updateRemoteDisplayMute(UUID) {
|
||||
var ele = document.querySelectorAll('[data-action-type="toggle-remote-display"][data--u-u-i-d="' + UUID + '"]');
|
||||
if (ele[0]) {
|
||||
ele[0].classList.add("pressed");
|
||||
ele[0].dataset.mute = 1;
|
||||
ele[0].dataset.value = 1;
|
||||
ele[0].className = "pressed";
|
||||
ele[0].children[1].innerHTML = "Un-blind";
|
||||
}
|
||||
@ -4314,19 +4417,19 @@ function updateRemoteDisplayMute(UUID) {
|
||||
function remoteDisplayMute(ele, event) {
|
||||
log("display mute");
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.mute == 1) {
|
||||
ele.dataset.mute = 0;
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "blind guest";
|
||||
} else {
|
||||
ele.dataset.mute = 1;
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Un-blind";
|
||||
}
|
||||
}
|
||||
|
||||
var msg = {};
|
||||
if (ele.dataset.mute == 0) {
|
||||
if (ele.dataset.value == 0) {
|
||||
msg.displayMute = false;
|
||||
} else {
|
||||
msg.displayMute = true;
|
||||
@ -4346,12 +4449,12 @@ function remoteLowerhands(UUID) {
|
||||
function remoteMute(ele, event) {
|
||||
log("mute");
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.mute == 1) {
|
||||
ele.dataset.mute = 0;
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "mute guest";
|
||||
} else {
|
||||
ele.dataset.mute = 1;
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Un-mute guest";
|
||||
}
|
||||
@ -4366,7 +4469,7 @@ function remoteMute(ele, event) {
|
||||
}
|
||||
|
||||
var msg = {};
|
||||
if (ele.dataset.mute == 0) {
|
||||
if (ele.dataset.value == 0) {
|
||||
msg.volume = volume;
|
||||
} else {
|
||||
msg.volume = 0;
|
||||
@ -4375,6 +4478,57 @@ function remoteMute(ele, event) {
|
||||
session.sendRequest(msg, ele.dataset.UUID);
|
||||
}
|
||||
|
||||
function remoteMuteVideo(ele, event) {
|
||||
log("video mute");
|
||||
|
||||
if ((event.ctrlKey) || (event.metaKey)) {
|
||||
ele.children[1].innerHTML = "ARMED";
|
||||
ele.style.backgroundColor = "#BF3F3F";
|
||||
Callbacks.push([remoteMuteVideo, ele, false]);
|
||||
log("video queued");
|
||||
return;
|
||||
} else {
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "hide guest";
|
||||
} else {
|
||||
ele.dataset.value = 1;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Unhide guest";
|
||||
}
|
||||
ele.style.backgroundColor = null;
|
||||
}
|
||||
|
||||
var msg = {};
|
||||
if (ele.dataset.value == 0) {
|
||||
msg.directVideoMuted = false;
|
||||
} else {
|
||||
msg.directVideoMuted = true;
|
||||
}
|
||||
|
||||
for (var i in session.pcs){
|
||||
if (i === msg.target){
|
||||
msg.target = true;
|
||||
} else {
|
||||
msg.target = ele.dataset.UUID;
|
||||
}
|
||||
try{
|
||||
session.pcs[i].sendChannel.send(JSON.stringify(msg));
|
||||
} catch(e){}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function updateDirectorVideoMute(UUID) {
|
||||
var ele = document.querySelectorAll('[data-action-type="hide-guest"][data--u-u-i-d="' + UUID + '"]');
|
||||
if (ele[0]) {
|
||||
ele[0].dataset.value = 1;
|
||||
ele[0].className = "pressed";
|
||||
ele[0].children[1].innerHTML = "Unhide guest";
|
||||
}
|
||||
}
|
||||
|
||||
function directVolume(ele) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("volume");
|
||||
var msg = {};
|
||||
@ -5062,39 +5216,59 @@ function audioLimiter(mediaStreamSource, audioContext) {
|
||||
return compressor;
|
||||
}
|
||||
|
||||
function activeSpeaker() {
|
||||
|
||||
function activeSpeaker(border=false) {
|
||||
var lastActiveSpeaker = null;
|
||||
var changed = false;
|
||||
for (var UUID in session.rpcs) {
|
||||
if (session.rpcs[UUID].stats.Audio_Loudness_average) {
|
||||
session.rpcs[UUID].stats.Audio_Loudness_average = parseFloat(session.rpcs[UUID].stats.Audio_Loudness + session.rpcs[UUID].stats.Audio_Loudness_average) / 2;
|
||||
if (session.rpcs[UUID].stats._Audio_Loudness_average) {
|
||||
session.rpcs[UUID].stats._Audio_Loudness_average = parseFloat(session.rpcs[UUID].stats.Audio_Loudness*0.2 + session.rpcs[UUID].stats._Audio_Loudness_average*0.8);
|
||||
} else {
|
||||
session.rpcs[UUID].stats.Audio_Loudness_average = 1;
|
||||
session.rpcs[UUID].stats._Audio_Loudness_average = 1;
|
||||
}
|
||||
log(session.rpcs[UUID].stats.Audio_Loudness_average);
|
||||
|
||||
if (session.rpcs[UUID].stats.Audio_Loudness_average > 10) {
|
||||
if (session.rpcs[UUID].videoElement.style.display != "block") {
|
||||
session.rpcs[UUID].videoElement.style.display = "block";
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (session.rpcs[UUID].videoElement) {
|
||||
if (session.rpcs[UUID].videoElement.style.display != "none") {
|
||||
changed = true;
|
||||
session.rpcs[UUID].videoElement.style.display = "none";
|
||||
//log(session.rpcs[UUID].stats._Audio_Loudness_average);
|
||||
if (session.rpcs[UUID].stats._Audio_Loudness_average > 13) {
|
||||
|
||||
if (border) {
|
||||
if (session.rpcs[UUID].videoElement) {
|
||||
session.rpcs[UUID].videoElement.style.border = "green solid 1px";
|
||||
session.rpcs[UUID].videoElement.style.padding = "0";
|
||||
}
|
||||
} else {
|
||||
session.rpcs[UUID].videoElement.style.display = "none";
|
||||
} else if (!session.rpcs[UUID].activelySpeaking){
|
||||
session.rpcs[UUID].activelySpeaking = true;
|
||||
changed = true;
|
||||
lastActiveSpeaker = UUID;
|
||||
session.rpcs[UUID].stats._Audio_Loudness_average+=2000000;
|
||||
}
|
||||
|
||||
} else if (session.rpcs[UUID].stats._Audio_Loudness_average > 6) {
|
||||
|
||||
} else {
|
||||
if (border){
|
||||
if (session.rpcs[UUID].videoElement) {
|
||||
session.rpcs[UUID].videoElement.style.border = "";
|
||||
session.rpcs[UUID].videoElement.style.padding = "1px";
|
||||
}
|
||||
} else if (session.rpcs[UUID].activelySpeaking) {
|
||||
changed = true;
|
||||
session.rpcs[UUID].activelySpeaking=false;
|
||||
lastActiveSpeaker = UUID;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (changed) {
|
||||
updateMixer();
|
||||
|
||||
var speaker = false;
|
||||
for (var UUID in session.rpcs) {
|
||||
if (session.rpcs[UUID].activelySpeaking){speaker=true;}
|
||||
}
|
||||
|
||||
if (!speaker && lastActiveSpeaker && (session.nopreview || session.minipreview)){
|
||||
session.rpcs[lastActiveSpeaker].activelySpeaking=true;
|
||||
|
||||
} else if (changed) {
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
}
|
||||
}
|
||||
//setInterval(function(){activeSpeaker()},1000);
|
||||
|
||||
|
||||
|
||||
function randomizeArray(unshuffled) {
|
||||
@ -5387,6 +5561,8 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
getById("director_block_3").dataset.raw = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2;
|
||||
getById("director_block_3").href = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2;
|
||||
getById("director_block_3").innerText = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2;
|
||||
|
||||
getById("calendarButton").style.display = "inline-block";
|
||||
|
||||
|
||||
} else {
|
||||
@ -5465,15 +5641,84 @@ function handleRoomSelect(room) {
|
||||
}
|
||||
}
|
||||
|
||||
function getDirectorSettings(scene){
|
||||
var settings = {};
|
||||
var eles = document.querySelectorAll('[data-action-type="solo-video"]');
|
||||
settings.soloVideo = false;
|
||||
for (var i=0;i<eles.length;i++) {
|
||||
if (parseInt(eles[i].dataset.value)==1){
|
||||
warnlog(eles[i]);
|
||||
if (eles[i].dataset.UUID){
|
||||
settings.soloVideo = eles[i].dataset.UUID;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scene){
|
||||
var eles = document.querySelectorAll('[data-action-type="addToScene"]');
|
||||
settings.scene = {};
|
||||
for (var i=0;i<eles.length;i++) {
|
||||
if (parseInt(eles[i].dataset.value)==1){
|
||||
if (parseInt(eles[i].dataset.scene) == scene){
|
||||
if (eles[i].dataset.UUID){
|
||||
|
||||
var msg = {};
|
||||
//msg.request = "sendroom";
|
||||
//msg.roomid = session.roomid;
|
||||
msg.scene = scene;
|
||||
msg.action = "display";
|
||||
msg.value = eles[i].dataset.value;
|
||||
msg.target = eles[i].dataset.UUID;
|
||||
|
||||
settings.scene[eles[i].dataset.UUID]=msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
function requestInfocus(ele) {
|
||||
var UUID = ele.dataset.UUID;
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.classList.remove("pressed");
|
||||
var actionMsg = {};
|
||||
actionMsg.infocus = false;
|
||||
session.sendMessage(actionMsg);
|
||||
|
||||
} else {
|
||||
var actionMsg = {};
|
||||
for (var i in session.pcs){
|
||||
if (i === UUID){
|
||||
actionMsg.infocus = true;
|
||||
} else {
|
||||
actionMsg.infocus = UUID;
|
||||
}
|
||||
try {
|
||||
session.pcs[i].sendChannel.send(JSON.stringify(actionMsg));
|
||||
} catch(e){}
|
||||
}
|
||||
var eles = document.querySelectorAll('[data-action-type="solo-video"]');
|
||||
for (var i=0;i<eles.length;i++) {
|
||||
log(eles);
|
||||
eles[i].classList.remove("pressed");
|
||||
eles[i].dataset.value = 0;
|
||||
}
|
||||
ele.dataset.value = 1;
|
||||
ele.classList.add("pressed");
|
||||
}
|
||||
}
|
||||
|
||||
function requestAudioSettings(ele) {
|
||||
var UUID = ele.dataset.UUID;
|
||||
if (ele.dataset.active == "true") {
|
||||
ele.dataset.active = "false";
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.classList.remove("pressed");
|
||||
getById("advanced_audio_director_" + UUID).innerHTML = "";
|
||||
getById("advanced_audio_director_" + UUID).className = "advanced";
|
||||
} else {
|
||||
ele.dataset.active = "true";
|
||||
ele.dataset.value = 1;
|
||||
ele.classList.add("pressed");
|
||||
getById("advanced_audio_director_" + UUID).innerHTML = "";
|
||||
var actionMsg = {};
|
||||
@ -5484,13 +5729,13 @@ function requestAudioSettings(ele) {
|
||||
|
||||
function requestVideoSettings(ele) {
|
||||
var UUID = ele.dataset.UUID;
|
||||
if (ele.dataset.active == "true") {
|
||||
ele.dataset.active = "false";
|
||||
if (ele.dataset.value == 1) {
|
||||
ele.dataset.value = 0;
|
||||
ele.classList.remove("pressed");
|
||||
getById("advanced_video_director_" + UUID).innerHTML = "";
|
||||
getById("advanced_video_director_" + UUID).className = "advanced";
|
||||
} else {
|
||||
ele.dataset.active = "true";
|
||||
ele.dataset.value = 1;
|
||||
ele.classList.add("pressed");
|
||||
getById("advanced_video_director_" + UUID).innerHTML = "";
|
||||
var actionMsg = {};
|
||||
@ -5579,7 +5824,7 @@ function createDirectorCam(vid, clean) {
|
||||
getById("press2talk").outerHTML = "";
|
||||
|
||||
getById("miniPerformer").appendChild(vid);
|
||||
getById("press2talk").dataset.enabled = "true";
|
||||
getById("press2talk").dataset.value = 1;
|
||||
session.muted = false;
|
||||
toggleMute(true);
|
||||
getById("screensharebutton").classList.remove("advanced");
|
||||
@ -5608,6 +5853,45 @@ function press2talk(clean = false) {
|
||||
|
||||
}
|
||||
|
||||
function addToGoogleCalendar(){
|
||||
var title = "Live Stream";
|
||||
//var dates = "20180512T230000Z/20180513T030000Z";
|
||||
var linkout = getById("director_block_1").innerText;
|
||||
var details = "Join the live stream as a performer at the following link:<br/><br/>===> "+linkout+"<br/><br/>To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest<br/><br/>Do not share the details of this invite with others, unless explicitly told to.";
|
||||
details = details.split(' ').join('+');
|
||||
details = details.split('&').join('%26');
|
||||
var linkToOpen = "https://calendar.google.com/calendar/r/eventedit?text="+title+"&details="+details;
|
||||
//https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
|
||||
|
||||
window.open(linkToOpen);
|
||||
|
||||
}
|
||||
|
||||
function addToOutlookCalendar(){
|
||||
var title = "Live Stream";
|
||||
var linkout = getById("director_block_1").innerText;
|
||||
var details = "Join the live stream as a performer at the following link:<br/><br/>===> "+linkout+"<br/><br/>To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest<br/><br/>Do not share the details of this invite with others, unless explicitly told to.";
|
||||
details = details.split(' ').join('%20');
|
||||
details = details.split('&').join('%26');
|
||||
|
||||
|
||||
var linkToOpen = "https://outlook.live.com/owa/?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&subject="+title+"&body="+details;
|
||||
//https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
|
||||
|
||||
window.open(linkToOpen);
|
||||
}
|
||||
|
||||
function addToYahooCalendar(){
|
||||
var title = "Live Stream";
|
||||
var linkout = getById("director_block_1").innerText;
|
||||
var details = "Join the live stream as a performer at the following link:<br/><br/>===> "+linkout+"<br/><br/>To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest<br/><br/>Do not share the details of this invite with others, unless explicitly told to.";
|
||||
details = details.split(' ').join('%20');
|
||||
details = details.split('&').join('%26');
|
||||
var linkToOpen = "https://calendar.yahoo.com?v60&title="+title+"&desc="+details;
|
||||
//https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
|
||||
|
||||
window.open(linkToOpen);
|
||||
}
|
||||
|
||||
function toggle(ele, tog = false, inline = true) {
|
||||
var x = ele;
|
||||
@ -7880,8 +8164,9 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
}
|
||||
if (eleName == "previewWebcam") {
|
||||
session.videoElement.controls = true;
|
||||
} else {
|
||||
updateConstraintSliders();
|
||||
}
|
||||
updateConstraintSliders();
|
||||
|
||||
dragElement(session.videoElement);
|
||||
}, 1000); // focus
|
||||
@ -9335,7 +9620,7 @@ function listAudioSettings() {
|
||||
input.onchange = function(e) {
|
||||
getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
|
||||
//updateAudioConstraints(e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(track0, e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(e.target.dataset.keyname, e.target.value);
|
||||
};
|
||||
|
||||
|
||||
@ -9390,7 +9675,7 @@ function listAudioSettings() {
|
||||
input.onchange = function(e) {
|
||||
//getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
|
||||
//updateAudioConstraints(e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(track0, e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(e.target.dataset.keyname, e.target.value);
|
||||
log(e.target.dataset.keyname, e.target.value);
|
||||
};
|
||||
getById("popupSelector_constraints_audio").appendChild(div);
|
||||
@ -9425,7 +9710,7 @@ function listAudioSettings() {
|
||||
input.onchange = function(e) {
|
||||
//getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
|
||||
//updateAudioConstraints(e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(track0, e.target.dataset.keyname, e.target.value);
|
||||
applyAudioHack(e.target.dataset.keyname, e.target.value);
|
||||
log(e.target.dataset.keyname, e.target.value);
|
||||
};
|
||||
getById("popupSelector_constraints_audio").appendChild(div);
|
||||
@ -9440,7 +9725,7 @@ function listAudioSettings() {
|
||||
}
|
||||
|
||||
|
||||
function applyAudioHack(track, constraint, value = null) {
|
||||
function applyAudioHack(constraint, value = null) {
|
||||
if (value == parseFloat(value)) {
|
||||
value = parseFloat(value);
|
||||
value = {
|
||||
@ -9452,7 +9737,34 @@ function applyAudioHack(track, constraint, value = null) {
|
||||
value = false;
|
||||
}
|
||||
log(constraint);
|
||||
var new_constraints = Object.assign(track.getSettings(), {
|
||||
////////////////
|
||||
try {
|
||||
var track0 = session.streamSrc.getAudioTracks();
|
||||
if (track0.length) {
|
||||
track0 = track0[0];
|
||||
if (track0.getCapabilities) {
|
||||
session.audioConstraints = track0.getCapabilities();
|
||||
}
|
||||
log(session.audioConstraints);
|
||||
} else {
|
||||
warnlog("session.streamSrc contains no audio tracks");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
warnlog("session.streamSrc contains no audio tracks");
|
||||
errorlog(e);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (track0.getSettings) {
|
||||
session.currentAudioConstraints = track0.getSettings();
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
////////
|
||||
|
||||
var new_constraints = Object.assign(track0.getSettings(), {
|
||||
[constraint]: value
|
||||
}, );
|
||||
new_constraints = {
|
||||
@ -9984,6 +10296,7 @@ function createIframePopup() {
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.overflow = "hidden";
|
||||
iframe.id = "screensharesource";
|
||||
iframe.style.zIndex = "-1";
|
||||
|
||||
|
||||
session.screenShareElement = iframe;
|
||||
@ -10885,7 +11198,7 @@ function sendChatMessage(chatMsg = false) { // filtered + visual
|
||||
|
||||
function toggleQualityDirector(bitrate, UUID, ele = null) { // ele is specific to the button in the director's room
|
||||
var eles = ele.parentNode.childNodes;
|
||||
for (i in eles) {
|
||||
for (var i=0;i<eles.length;i++) {
|
||||
eles[i].className = "";
|
||||
}
|
||||
ele.className = "pressed";
|
||||
@ -12008,7 +12321,7 @@ function fftWaveform( source, UUID, trackid){ // append the delay Node to the t
|
||||
session.rpcs[uuid].canvasCtx.moveTo(0, dataArray[0]*m);
|
||||
for (var i = 1; i < bufferLength; i++){
|
||||
var y = dataArray[i] * m;
|
||||
session.rpcs[uuid].canvasCtx.lineTo(x, y);
|
||||
session.rpcs[uuid].canvasCtx.lineTo(x, y);
|
||||
x += sliceWidth;
|
||||
}
|
||||
session.rpcs[uuid].canvasCtx.lineTo(session.rpcs[uuid].canvas.width, session.rpcs[uuid].canvas.height / 2);
|
||||
@ -12087,7 +12400,6 @@ function audioMeterGuest(mediaStreamSource, UUID, trackid){
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((session.effects==3) || (session.effects==4) || (session.effects==5)){
|
||||
var mask = null;
|
||||
var script = document.createElement('script');
|
||||
|
||||
366
monitor.html
Normal file
366
monitor.html
Normal file
@ -0,0 +1,366 @@
|
||||
<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>
|
||||
@ -116,7 +116,15 @@ canvas {
|
||||
padding: 20px 0px;
|
||||
border: 1px solid #383838;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.graphContainer {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
background: #313131;
|
||||
padding: 20px 0px;
|
||||
border: 1px solid #383838;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.graph {
|
||||
|
||||
@ -59,13 +59,18 @@
|
||||
// this is pretty important if you want to avoid camera permission popup problems. YOu need to load the iFRAME after you load the parent body. A quick solution is like: <body onload=>loadIframe();"> !!!
|
||||
|
||||
var streamID = "";
|
||||
var possible =
|
||||
"ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789";
|
||||
var possible = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789";
|
||||
for (var i = 0; i < 7; i++) {
|
||||
streamID += possible.charAt(
|
||||
Math.floor(Math.random() * possible.length)
|
||||
);
|
||||
}
|
||||
|
||||
if (urlParams.has("sid")) {
|
||||
streamID = urlParams.get("sid");
|
||||
}
|
||||
|
||||
document.getElementById("remote").innerHTML = "<a style='color:#CCC' href='./monitor?sid="+streamID+"'>Remote Monitoring Link</a><br /><br /><br /><br />";
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("span");
|
||||
@ -75,7 +80,7 @@
|
||||
iframe.allowfullscreen ="true";
|
||||
|
||||
//iframe.allow = "autoplay";
|
||||
var srcString = "./?push=" + streamID + "&cleanoutput&privacy&speedtest&webcam&audiodevice=0&fullscreen&transparent";
|
||||
var srcString = "./?push=" + streamID + "&cleanoutput&privacy&speedtest&webcam&audiodevice=0&fullscreen&transparent&remote";
|
||||
|
||||
if (urlParams.has("turn")) {
|
||||
srcString = srcString + "&turn=" + urlParams.get("turn");
|
||||
@ -115,7 +120,7 @@
|
||||
var iframeContainer = document.createElement("span");
|
||||
|
||||
iframe.allow = "autoplay";
|
||||
var srcString = "./?view=" + streamID + "&cleanoutput&privacy&noaudio&scale=0";
|
||||
var srcString = "./?view=" + streamID + "&cleanoutput&privacy&noaudio&speedtest&scale=0";
|
||||
|
||||
if (urlParams.has("turn")) {
|
||||
srcString = srcString + "&turn=" + urlParams.get("turn");
|
||||
@ -187,13 +192,12 @@
|
||||
? "addEventListener"
|
||||
: "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent =
|
||||
eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
var previousResolution;
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if ("action" in e.data) {
|
||||
logData(e.data.action, e.data.value);
|
||||
logData(e.data.action, e.data.value || "");
|
||||
|
||||
if (e.data.action == "new-view-connection") {
|
||||
buttonContainer.querySelectorAll(
|
||||
@ -230,9 +234,9 @@
|
||||
}
|
||||
|
||||
for (var streamID in e.data.stats.outbound_stats) {
|
||||
if (e.data.stats.outbound_stats[streamID].quality_Limitation_Reason){
|
||||
if (quality_reason != e.data.stats.outbound_stats[streamID].quality_Limitation_Reason) {
|
||||
quality_reason = e.data.stats.outbound_stats[streamID].quality_Limitation_Reason;
|
||||
if (e.data.stats.outbound_stats[streamID].quality_limitation_reason){
|
||||
if (quality_reason != e.data.stats.outbound_stats[streamID].quality_limitation_reason) {
|
||||
quality_reason = e.data.stats.outbound_stats[streamID].quality_limitation_reason;
|
||||
logData("Quality Limitation Reason:", quality_reason);
|
||||
}
|
||||
}
|
||||
@ -357,7 +361,9 @@
|
||||
Change the video bitrate by pressing the buttons below the video. It
|
||||
should approach 6000-kbps if the network allows.
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
<div id="remote"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
1
thirdparty/adapter.min.js
vendored
1
thirdparty/adapter.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user