mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 13:48:38 +00:00
recent updates; comms app,etc
This commit is contained in:
parent
fbbc6c6c31
commit
25015a33a3
2140
comms.html
Normal file
2140
comms.html
Normal file
File diff suppressed because one or more lines are too long
319
examples/muteguestiframe.html
Normal file
319
examples/muteguestiframe.html
Normal file
@ -0,0 +1,319 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>IFRAME Example</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
background-color: #0000;
|
||||
}
|
||||
iframe {
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
display:block;
|
||||
width:100%;
|
||||
height:90%
|
||||
}
|
||||
#viewlink {
|
||||
width:400px;
|
||||
}
|
||||
#container {
|
||||
display:block;
|
||||
padding:0px;
|
||||
padding:0px;
|
||||
}
|
||||
input{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
button{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
function loadIframe(){
|
||||
|
||||
document.getElementById("container").innerHTML = "";
|
||||
|
||||
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";
|
||||
|
||||
iframe.src = "../?dir=teststeve123&password=1234";
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container").appendChild(iframeContainer);
|
||||
|
||||
var listOfStreamIDs = [
|
||||
"1234_pov"
|
||||
];
|
||||
|
||||
|
||||
for (var i=0;i<listOfStreamIDs.length;i++){
|
||||
|
||||
var button = document.createElement("a");
|
||||
button.innerHTML = "Invite "+listOfStreamIDs[i];
|
||||
button.target = "_blank";
|
||||
button.href = "../?room=teststeve123&password=1234&broadcast&transparent&autostart&nmb&nvb&gain=0&webcam&l=stevetest&push="+listOfStreamIDs[i];
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
|
||||
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "speaker true "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "speaker",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "speaker false "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "speaker",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "display true "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "display",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "display false "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "display",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "MUTE true "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "mic",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "UN-MUTE "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "mic",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "addScene 1 toggle "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "addScene",
|
||||
value: 1,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Scene 1 toggle "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "addScene",
|
||||
value: "toggle",
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "add Scene 1"+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "addScene",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "remove Scene 1"+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "addScene",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
///////////////////
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "MUTE SCENE "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "muteScene",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "un-mute Scene "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "muteScene",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
///////////////////
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "soloChat "+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "soloChat",
|
||||
value: true,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "soloChat off"+listOfStreamIDs[i];
|
||||
button.dataset.sid = listOfStreamIDs[i];
|
||||
button.onclick = function(){
|
||||
iframe.contentWindow.postMessage({
|
||||
action: "soloChat",
|
||||
value: false,
|
||||
target: this.dataset.sid
|
||||
}, '*');
|
||||
|
||||
}; // target can be a stream ID or * for all.
|
||||
iframeContainer.appendChild(button);
|
||||
}
|
||||
|
||||
//////////// 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
|
||||
if (typeof e.data !== "object"){return;}
|
||||
|
||||
if ("action" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = "event: "+e.data.action+"<br />";
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
}
|
||||
|
||||
|
||||
if ("streamIDs" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = "streamID list:<br />";
|
||||
for (var key in e.data.streamIDs) {
|
||||
outputWindow.innerHTML += "streamID: " + key + ", label:"+e.data.streamIDs[key] + "\n";
|
||||
}
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="container">
|
||||
|
||||
<button onclick="loadIframe();">Go to Directors Room</button>
|
||||
<br />
|
||||
The password for guests is 1234<br />
|
||||
<br />
|
||||
<br />
|
||||
Custom guest invites and toggles for add/removing from scene=1 are on the bottom.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
110
index.html
110
index.html
@ -57,8 +57,8 @@
|
||||
<meta property="twitter:image" content="./media/vdoNinja_logo_full.png" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="stylesheet" href="./main.css?ver=215" />
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.min.js"></script>
|
||||
<link rel="stylesheet" href="./main.css?ver=221" />
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.js"></script>
|
||||
<style id="lightbox-animations" type="text/css"></style>
|
||||
<!-- <link rel="manifest" href="manifest.json" /> -->
|
||||
<!-- ios support
|
||||
@ -81,8 +81,9 @@
|
||||
<span itemprop="thumbnail" itemscope itemtype="http://schema.org/ImageObject">
|
||||
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=37"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=521"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=39"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=529"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:2%;-webkit-app-region: drag;min-height:20px;"></span>
|
||||
<div id="header">
|
||||
@ -133,81 +134,81 @@
|
||||
<div id="obsState" class="hidden" >ACTIVE</div>
|
||||
<div id="subControlButtons">
|
||||
|
||||
<div id="blindAllGuests" title="Blind all guests in room (toggle)" alt="Blind all guests in room (toggle)" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="blindAllGuests(this, event)" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<div id="blindAllGuests" title="Blind all guests in room (toggle)" alt="Blind all guests in room (toggle)" aria-label="Blind all guests in room" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="blindAllGuests(this, event)" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<i class="toggleSize las la-eye my-float"></i>
|
||||
</div>
|
||||
|
||||
<div id="queuebutton" title="Load the next guest in queue" alt="Load the next guest in queue" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="nextQueue()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<div id="queuebutton" title="Load the next guest in queue" alt="Load the next guest in queue" aria-label="Load next guest in queue" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="nextQueue()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<i id="queuetoggle" class="toggleSize las la-stream my-float"></i>
|
||||
<div id="queueNotification"></div>
|
||||
</div>
|
||||
|
||||
<div id="sharefilebutton" title="Transfer any file to the group" alt="Transfer any file to the group" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="toggleFileshare()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float" style="cursor: pointer;" >
|
||||
<div id="sharefilebutton" title="Transfer any file to the group" alt="Transfer any file to the group" aria-label="Select file to transfer" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="toggleFileshare()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float" style="cursor: pointer;" >
|
||||
<i id="filesharetoggle" class="toggleSize las la-file-upload my-float"></i>
|
||||
<div id="transferNotification"></div>
|
||||
</div>
|
||||
|
||||
<div id="chatbutton" title="Toggle the Chat" alt="Toggle the Chat" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="toggleChat()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<div id="chatbutton" title="Toggle the Chat" alt="Toggle the Chat" aria-label="Text chat" onmousedown="event.preventDefault(); event.stopPropagation();" onclick="toggleChat()" tabindex="16" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<i id="chattoggle" class="toggleSize las la-comment-alt my-float"></i>
|
||||
<div id="chatNotification"></div>
|
||||
</div>
|
||||
<div id="mutespeakerbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Mute the Speaker" onclick="toggleSpeakerMute()" tabindex="17" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" alt="Toggle the speaker output.">
|
||||
<div id="mutespeakerbutton" onmousedown="event.preventDefault(); event.stopPropagation();" alt="Toggle the speaker output." aria-label="Mute Speaker output" title="Mute the Speaker" onclick="toggleSpeakerMute()" tabindex="17" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" >
|
||||
<i id="mutespeakertoggle" class="toggleSize las la-volume-up my-float" style="position: relative; top: 0.5px;"></i>
|
||||
</div>
|
||||
<div id="mutebutton" onmousedown="toggleMute(false, event);event.preventDefault(); event.stopPropagation();" title="Mute the Mic" ontouchstart="toggleMute(false, event);event.preventDefault(); event.stopPropagation();" tabindex="18" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;" alt="Toggle the mic">
|
||||
<div id="mutebutton" onmousedown="toggleMute(false, event);event.preventDefault(); event.stopPropagation();" alt="Mute the Mic" aria-label="Mute Microphone" title="Mute the Mic" ontouchstart="toggleMute(false, event);event.preventDefault(); event.stopPropagation();" tabindex="18" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;">
|
||||
<i id="mutetoggle" class="toggleSize las la-microphone my-float" style="position: relative; top: 0.5px;"></i>
|
||||
</div>
|
||||
<div id="mutevideobutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Disable the Camera" alt="Disable the Camera" onclick="toggleVideoMute()" tabindex="19" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;">
|
||||
<div id="mutevideobutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Disable the Camera" alt="Disable the Camera" aria-label="Mute Camera" onclick="toggleVideoMute()" tabindex="19" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="hidden float" style="cursor: pointer;">
|
||||
<i id="mutevideotoggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-video my-float"></i>
|
||||
</div>
|
||||
<div id="screensharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a Screen with others" alt="Share a Screen with others" onclick="screenshareTypeDecider(1)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<div id="screensharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a Screen with others" alt="Share a Screen with others" aria-label="Share a screen" onclick="screenshareTypeDecider(1)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<i id="screensharetoggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-desktop my-float"></i>
|
||||
</div>
|
||||
<div id="screenshare2button" onmousedown="event.preventDefault(); event.stopPropagation();" title="Add a Screen Share" alt="Add a Screen Share" onclick="screenshareTypeDecider(2)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<div id="screenshare2button" onmousedown="event.preventDefault(); event.stopPropagation();" title="Add a Screen Share" alt="Add a Screen Share" aria-label="Share a screen" onclick="screenshareTypeDecider(2)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<i id="screenshare2toggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-tv my-float"></i>
|
||||
</div>
|
||||
<div id="screenshare3button" onmousedown="event.preventDefault(); event.stopPropagation();" title="Create a Third Stream" alt="Create a Third Stream" onclick="screenshareTypeDecider(3)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<div id="screenshare3button" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a Screen with others" alt="Add a Screen Share" aria-label="Share a screen" onclick="screenshareTypeDecider(3)" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden task" data-menu="context-menu-screen-share" style="cursor: pointer;">
|
||||
<i id="screenshare3toggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-tv my-float"></i>
|
||||
</div>
|
||||
<div id="websitesharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a website with your guests (IFRAME)" alt="Share a website with your guests (IFRAME)" onclick="shareWebsite(false, event)" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden" style="cursor: pointer;">
|
||||
<div id="websitesharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a website with your guests (IFRAME)" aria-label="Share a website" alt="Share a website with your guests (IFRAME)" onclick="shareWebsite(false, event)" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float hidden" style="cursor: pointer;">
|
||||
<i id="websitesharetoggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-window-maximize my-float"></i>
|
||||
</div>
|
||||
<div id="websitesharebutton2" onmousedown="event.preventDefault(); event.stopPropagation();" title="Hold CTRL (or CMD) and click to spotlight this video" alt="Share a website as an embedded iFRAME" onclick="shareWebsite(false, event)" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float2 orange shake hidden" style="cursor: pointer;max-width: 200px;margin: auto;padding: 0 10px;">
|
||||
<div id="websitesharebutton2" onmousedown="event.preventDefault(); event.stopPropagation();" title="Hold CTRL (or CMD) and click to spotlight this video" alt="Share a website as an embedded iFRAME" aria-label="Share a website" onclick="shareWebsite(false, event)" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float2 orange shake hidden" style="cursor: pointer;max-width: 200px;margin: auto;padding: 0 10px;">
|
||||
<i onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las my-float la-window-close" style="display: inline-block;"></i>
|
||||
<div style="display: inline-block;width: 85px;line-height: 1; font-size: 0.9em;">
|
||||
Stop Sharing Website
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flipcamerabutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Cycle the Cameras" onclick="cycleCameras()" class="hidden float" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Cycle the Cameras">
|
||||
<div id="flipcamerabutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Cycle the Cameras" onclick="cycleCameras()" class="hidden float" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" aria-label="Cycle Cameras" alt="Cycle the Cameras">
|
||||
<i id="settingstoggle" class="toggleSize las la-sync-alt my-float"></i>
|
||||
</div>
|
||||
|
||||
<div id="obscontrolbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="OBS Remote Controller; start/stop and change scenes." onclick="toggleOBSControls();" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Toggle the Remote OBS Controls Menu">
|
||||
<div id="obscontrolbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="OBS Remote Controller; start/stop and change scenes." onclick="toggleOBSControls();" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" aria-label="Remote OBS control menu" alt="Toggle the Remote OBS Controls Menu">
|
||||
<i id="obscontroltoggle" class="toggleSize las la-gamepad my-float"></i>
|
||||
</div>
|
||||
|
||||
<div id="roomsettingsbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Room Settings" onclick="toggleRoomSettings();" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Toggle the Room Settings Menu">
|
||||
<div id="roomsettingsbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Room Settings" onclick="toggleRoomSettings();" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Toggle the Room Settings Menu" aria-label="Room settings menu">
|
||||
<i id="roomsettingstoggle" class="toggleSize las la-users-cog my-float"></i>
|
||||
</div>
|
||||
|
||||
<div id="settingsbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Your audio and video Settings" onclick="toggleSettings()" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Toggle Settings Menu">
|
||||
<div id="settingsbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Your audio and video Settings" onclick="toggleSettings()" class="hidden float" tabindex="22" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Toggle Settings Menu" aria-label="Settings menu">
|
||||
<i id="settingstoggle" class="toggleSize las la-cog my-float"></i>
|
||||
</div>
|
||||
|
||||
<div id="hangupbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Hangup the Call" alt="Hangup the Call" onclick="hangup()" class="hidden float" tabindex="23" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" >
|
||||
<div id="hangupbutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Hangup the Call" aria-label="Hang up" alt="Hangup the Call" onclick="hangup()" class="hidden float" tabindex="23" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" >
|
||||
<i class="toggleSize my-float las la-phone rotate225" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div id="raisehandbutton" onmousedown="event.preventDefault(); event.stopPropagation();" data-raised="0" title="Alert the host you want to speak" alt="Alert the host you want to speak" tabindex="24" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" onclick="raisehand()" class="hidden float" style="cursor: pointer;">
|
||||
<div id="raisehandbutton" onmousedown="event.preventDefault(); event.stopPropagation();" data-raised="0" title="Alert the host you want to speak" aria-label="Raise hand" alt="Alert the host you want to speak" tabindex="24" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" onclick="raisehand()" class="hidden float" style="cursor: pointer;">
|
||||
<i class="toggleSize my-float las la-hand-paper" style="position: relative; right: 1px;" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div id="recordLocalbutton" onmousedown="event.preventDefault(); event.stopPropagation();" data-state="0" title="Record your stream to disk" alt="Record your stream to disk" tabindex="25" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" onclick="recordLocalVideoToggle();" class="hidden float" style="cursor: pointer;">
|
||||
<div id="recordLocalbutton" onmousedown="event.preventDefault(); event.stopPropagation();" data-state="0" title="Record your stream to disk" aria-label="Record your stream to disk" alt="Record your stream to disk" tabindex="25" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" onclick="recordLocalVideoToggle();" class="hidden float" style="cursor: pointer;">
|
||||
<i class="toggleSize my-float las la-dot-circle" style="position: relative;" aria-hidden="true"></i>
|
||||
</div>
|
||||
<span id="miniPerformer" style="pointer-events: auto;" class="hidden"></span>
|
||||
<span id="rooms" class="hidden" style="padding-top:3px;padding-left:6px;pointer-events: auto;color:#fff;"></span>
|
||||
<span id="groups" class="hidden" style="padding-top:3px;padding-left:6px;pointer-events: auto;color:#fff;text-align: center;"></span>
|
||||
<div id="hangupbutton2" onmousedown="event.preventDefault(); event.stopPropagation();" title="Cancel the Director's Video/Audio" onclick="hangup2()" class="hidden float" tabindex="26" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" alt="Disconnect Direcotor's cam">
|
||||
<div id="hangupbutton2" onmousedown="event.preventDefault(); event.stopPropagation();" title="Cancel the Director's Video/Audio" onclick="hangup2()" class="hidden float" tabindex="26" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" style="cursor: pointer;" aria-label="stop publishing audio and video" alt="Disconnect Direcotor's cam">
|
||||
<i class="toggleSize my-float las la-phone rotate225" aria-hidden="true"></i>
|
||||
</div>
|
||||
</div>
|
||||
@ -229,7 +230,7 @@
|
||||
>
|
||||
<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">
|
||||
<span title="Language Options" onclick="toggle(document.getElementById('languages'));" aria-label="language options" aria-pressed="false" id="translateButton">
|
||||
<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">
|
||||
@ -373,7 +374,7 @@
|
||||
<span data-translate="ask-for-permissions">Allow Access to Camera/Microphone</span>
|
||||
</button>
|
||||
<span style="display:block;">
|
||||
<button onclick="publishWebcam(this)" title="start streaming" tabindex="15" id="gowebcam" class="gowebcam" alt="Start Streaming" disabled data-audioready="false" data-ready="false" >
|
||||
<button onclick="publishWebcam(this)" title="start streaming" aria-label="Start streaming" aria-pressed="false" tabindex="15" id="gowebcam" class="gowebcam" alt="Start Streaming" disabled data-audioready="false" data-ready="false" >
|
||||
<span data-translate="waiting-for-camera">Waiting for Camera to Load</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -390,7 +391,7 @@
|
||||
<span id="videoMenu" class="videoMenu">
|
||||
<span style="padding-right:2px;display:inline-block;position:relative;top:1px;"><i class="las la-video"></i><span data-translate="video-source"> Video Source </span></span>
|
||||
<span style="display:inline-block;padding-top: 5px;">
|
||||
<select id="videoSourceSelect" ></select>
|
||||
<select id="videoSourceSelect" alt="Video source list"></select>
|
||||
<span id="gear_webcam" onclick="toggle(document.getElementById('videoSettings'));">
|
||||
<i class="las la-cog" style="font-size: 140%; vertical-align: middle;" aria-hidden="true"></i>
|
||||
</span>
|
||||
@ -404,17 +405,17 @@
|
||||
<center>
|
||||
<span id="videoSettings" style="display: none;">
|
||||
<form id="webcamquality">
|
||||
<input type="radio" id="fullhd" name="resolution" value="0" />
|
||||
<input type="radio" id="fullhd" alt="1080p60 video capture" name="resolution" value="0" />
|
||||
<label for="fullhd">
|
||||
<span data-translate="max-resolution">Max Resolution</span>
|
||||
</label> |
|
||||
|
||||
<input type="radio" checked id="halfhd" name="resolution" value="1" />
|
||||
<input type="radio" checked id="halfhd" alt="720p60 video capture" name="resolution" value="1" />
|
||||
<label for="halfhd">
|
||||
<span data-translate="balanced">Balanced</span>
|
||||
</label> |
|
||||
|
||||
<input type="radio" id="nothd" name="resolution" value="2" />
|
||||
<input type="radio" id="nothd" name="resolution" alt="360p30 video capture" value="2" />
|
||||
<label for="nothd">
|
||||
<span data-translate="smooth-cool">Smooth and Cool</span>
|
||||
</label>
|
||||
@ -424,7 +425,7 @@
|
||||
</center>
|
||||
<div id="audioMenu" class="form-group multiselect" alt="tip: Hold CTRL (command) to select Multiple" title="tip: Hold CTRL (command) to select Multiple">
|
||||
<span class='gear_microphone hidden'>
|
||||
<input type="checkbox" id='micStereoMonoInput' onchange="toggleMonoStereoMic(this);">Mono
|
||||
<input type="checkbox" id='micStereoMonoInput' alt="Mono microphone audio" onchange="toggleMonoStereoMic(this);">Mono
|
||||
</span>
|
||||
<a id="multiselect-trigger" class="form-control multiselect-trigger" >
|
||||
<div class="audioTitle">
|
||||
@ -451,7 +452,7 @@
|
||||
<div class="audioTitle2">
|
||||
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination
|
||||
</span><button onclick="playtone()" class="white" style="margin:0 0 0 15px;padding: 2px 10px 0px 10px;" type="button">Test</button></div>
|
||||
<select id="outputSource" ></select>
|
||||
<select id="outputSource" alt="Audio output device" ></select>
|
||||
<div id="headphoneTip1" class="cameraTip hidden">
|
||||
<i class="las la-info-circle"></i>
|
||||
<p><span id="headphoneTipContext1"></span></p>
|
||||
@ -479,7 +480,7 @@
|
||||
<div style="text-align: left;display: inline-block;">
|
||||
<i class="las la-robot"></i><span data-translate="select-digital-effect"> Digital Video Effects </span>
|
||||
</div>
|
||||
<select id="effectSelector" onchange="effectsDynamicallyUpdate(event, this);">
|
||||
<select id="effectSelector" alt="Digital video effect options" onchange="effectsDynamicallyUpdate(event, this);">
|
||||
<option value="0" data-translate="no-effects-applied">No effects applied</option>
|
||||
<option value="3" data-translate="blurred-background">Blurred background</option>
|
||||
<option value="4" data-translate="digital-greenscreen">Digital greenscreen</option>
|
||||
@ -716,7 +717,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>See the
|
||||
<div class="invite_setting_group_links">See the
|
||||
<a style="text-decoration: none; color: blue;" target="_blank" href="https://docs.vdo.ninja/advanced-settings">documentation</a> for a list of all options and details.<br /><br />
|
||||
Try out the advanced <a style="text-decoration: none; color: blue;" target="_blank" href="https://invite.vdo.ninja/">invite generator</a> here as well.
|
||||
</div>
|
||||
@ -805,7 +806,17 @@
|
||||
</div>
|
||||
|
||||
<div id="container-8" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = './mixer.html';">
|
||||
<h2><span data-translate="try-the-mixer-out">Try out the Mixer</span></h2>
|
||||
<h2><span data-translate="try-the-mixer-out">Create layouts with Mixer</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-blender"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-14" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://versus.cam';">
|
||||
<h2><span data-translate="try-out-versus-cam">Manage streams with Versus</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-blender"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-15" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = './comms.html';">
|
||||
<h2><span data-translate="voice-comms-app">Production voice comms</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-blender"></i>
|
||||
</div>
|
||||
|
||||
@ -873,7 +884,7 @@
|
||||
<font style="color:#daad09;">Welcome to VDO Ninja! We've rebranded! Nothing else is changing and we're staying 100% free.</font>
|
||||
</h4>
|
||||
<br />
|
||||
Site updated August 2022. <a target="_blank" href="https://docs.vdo.ninja/releases/v21">v21 release notes</a>. If having new issues, the previous version <a href="https://vdo.ninja/v20/">is here</a>, and the <a href="https://vdo.ninja/beta/">upcoming next version is here</a>. Development <a target="_blank" href='https://updates.vdo.ninja/'>updates are here.</a>
|
||||
Site updated October 2022. <a target="_blank" href="https://docs.vdo.ninja/releases/v21">v21 release notes</a>. If having new issues, the previous version <a href="https://vdo.ninja/v20/">is here</a>, and the <a href="https://vdo.ninja/beta/">upcoming next version is here</a>. Development <a target="_blank" href='https://updates.vdo.ninja/'>updates are here.</a>
|
||||
<br />
|
||||
<br />
|
||||
<h3>
|
||||
@ -1950,7 +1961,7 @@
|
||||
<div id="chatModule" style="display:none;text-align:right">
|
||||
<a target="popup" id="popOutChat" style="cursor:pointer;text-align:right;color:#B3C7F9;" onclick="createPopoutChat();"><i class="las la-external-link-alt"></i></a>
|
||||
<div id="chatBody">
|
||||
<div class="inMessage" id="welcomeMsg" data-translate='welcome-to-obs-ninja-chat'>
|
||||
<div class="inMessage" id="welcomeMsg" data-translate='welcome-to-vdo-ninja-chat'>
|
||||
Welcome to VDO.Ninja! You can send text messages directly to connected peers from here.
|
||||
</div>
|
||||
</div>
|
||||
@ -1971,6 +1982,22 @@
|
||||
<input id="highlightDirector" style="width: 15px; height: 15px; margin:10px;" name="highlightDirector" data-action-type="solo-video" type="checkbox" onchange="requestInfocus(this);" />
|
||||
<label for="highlightDirector" data-translate="highlight-director-only-video-guests-will-see">Highlight Director (only video guests will see)</label>
|
||||
</span>
|
||||
|
||||
<span style="margin: 20px 0 0 0;display:block" id='globalTimerDirectorSpan'>
|
||||
<button data-action-type="create-timer-global" title="Set a countdown timer that this guest sees. CTRL (cmd) + click to pause." onclick="directTimer(this, event);">
|
||||
<i class="las la-clock"></i>
|
||||
<span data-translate="create-global-timer">Create Global Count-down Timer</span>
|
||||
</button>
|
||||
<button data-action-type="create-timer-up-global" title="Set a count-up timer that this guest sees. CTRL (cmd) + click to pause." onclick="directTimer(this, event);">
|
||||
<i class="las la-clock"></i>
|
||||
<span data-translate="create-global-up-timer">Create Global Count-up Timer</span>
|
||||
</button>
|
||||
<button data-action-type="create-clock-global" title="Set a count-up timer that this guest sees. CTRL (cmd) + click to pause." onclick="directTimer(this, event);">
|
||||
<i class="las la-clock"></i>
|
||||
<span data-translate="create-clock-timer">Toggle Room Clock</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span style="margin: 5px 0 0 0;display:block" id='enableCodirector' title="Allow for remote co-directors">
|
||||
<span id="coDirectorEnableSpan">
|
||||
<input id="coDirectorEnable" style="width: 15px; height: 15px; margin:10px;" name="coDirectorEnable" data-action-type="codirector" type="checkbox" onchange="toggleCoDirector(this);" />
|
||||
@ -2076,7 +2103,7 @@
|
||||
|
||||
<div id="connectUsers">
|
||||
<div style="margin-bottom:5px"><u ><span data-translate="invisible-guests">Not Visible</span></u>
|
||||
<span title="Hide this window" style="cursor:pointer;font-size:1.2em; float: right;" onclick="session.showList=false;getById('connectUsers').style.display = 'none';"><i class="las la-times"></i></span></div>
|
||||
<span title="Hide this window" id='hideusers' style="cursor:pointer;font-size:1.2em; float: right;" onclick="session.showList=false;getById('connectUsers').style.display = 'none';"><i class="las la-times"></i></span></div>
|
||||
<span style="height:5px;display:block;"></span>
|
||||
<div id="userList">
|
||||
</div>
|
||||
@ -2194,7 +2221,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 = "22.4";
|
||||
session.version = "22.5";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Change this password if self-deploying for added security/privacy
|
||||
@ -2265,12 +2292,11 @@
|
||||
// session.darkmode = false; // enable or disable the dark style theme as the default
|
||||
// session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds)
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=488"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=511"></script>
|
||||
<!--
|
||||
// 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=445"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=461"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
470
lib.js
470
lib.js
@ -146,12 +146,25 @@ if (typeof session === 'undefined') { // make sure to init the WebRTC if not exi
|
||||
var urlEdited = window.location.search.replace(/\?\?/g, "?");
|
||||
urlEdited = urlEdited.replace(/\?/g, "&");
|
||||
urlEdited = urlEdited.replace(/\&/, "?");
|
||||
var urlParams = new URLSearchParams(urlEdited);
|
||||
|
||||
if (urlEdited !== window.location.search){
|
||||
if (urlParams.has("invite") || urlParams.has("i") || urlParams.has("code")){
|
||||
session.decodeInvite(urlParams.get("invite") || urlParams.get("i") || urlParams.get("code"));
|
||||
}
|
||||
|
||||
if (session.decrypted){
|
||||
session.decrypted = session.decrypted + urlEdited.replace("?","&");
|
||||
session.decrypted = session.decrypted.replace(/\?/g, "&");
|
||||
session.decrypted = session.decrypted.replace(/\&/, "?");
|
||||
urlParams = new URLSearchParams(session.decrypted);
|
||||
//session.decrypted = true;
|
||||
} else {
|
||||
if (urlEdited !== window.location.search){
|
||||
warnlog(window.location.search + " changed to " + urlEdited);
|
||||
window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString());
|
||||
}
|
||||
}
|
||||
var urlParams = new URLSearchParams(urlEdited);
|
||||
delete urlEdited;
|
||||
|
||||
var isIFrame = false;
|
||||
if ( parent && (window.location !== window.parent.location )) {
|
||||
@ -215,6 +228,8 @@ function saveRoom(ele){
|
||||
}
|
||||
|
||||
function updateURL(param, force = false, cleanUrl = false) {
|
||||
if (session.decrypted){return;}
|
||||
|
||||
param = param.replace("?", "");
|
||||
var para = param.split('=');
|
||||
if (cleanUrl) {
|
||||
@ -438,17 +453,32 @@ function toByteArray(hexString){
|
||||
}
|
||||
|
||||
function playAllVideos(){
|
||||
|
||||
if (session.firstPlayTriggered && (session.audioCtx.state == "suspended")){ // added oct 9th 2022
|
||||
try {
|
||||
session.audioCtx.resume();
|
||||
} catch(e){warnlog(e);}
|
||||
}
|
||||
|
||||
for (var i in session.rpcs){
|
||||
try{
|
||||
if (session.rpcs[i].videoElement){
|
||||
log("I: "+i);
|
||||
if (session.rpcs[i].videoElement.paused){
|
||||
session.rpcs[i].videoElement.play().then(_ => {
|
||||
log("playing 3");
|
||||
setTimeout(function(UUID){
|
||||
session.rpcs[UUID].videoElement.play().then(_ => {
|
||||
log("playing 3 ");
|
||||
if ((session.audioEffects===true) || session.pushLoudness){
|
||||
updateIncomingAudioElement(i);
|
||||
log("updateIncomingAudioElement('"+UUID+"')");
|
||||
updateIncomingAudioElement(UUID);
|
||||
}
|
||||
}).catch(errorlog);
|
||||
},0,i);
|
||||
} else if ((session.audioEffects===true) || session.pushLoudness){
|
||||
updateIncomingAudioElement(i);
|
||||
log("updateIncomingAudioElement('"+i+"')");
|
||||
}
|
||||
|
||||
}
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
@ -3095,7 +3125,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
if (session.infocus===true){
|
||||
soloVideo = true;
|
||||
} else if (session.infocus && (session.infocus!==true) && (session.infocus in session.rpcs)){ // if the infocus stream is connected
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
try {
|
||||
if (session.group.some(item => session.rpcs[session.infocus].group.includes(item))){
|
||||
soloVideo = session.infocus;
|
||||
@ -3203,7 +3233,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
|
||||
for (var j in session.rpcs){
|
||||
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
try {
|
||||
if (!(session.group.some(item => session.rpcs[j].group.includes(item)))){
|
||||
continue;
|
||||
@ -3275,7 +3305,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else if ((soloVideo) && (soloVideo === true)){ // well, fullscreen myself. "true" represents me. UUID would be for others.
|
||||
// already added myself to this as fullscreen
|
||||
for (var j in session.rpcs){
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
try {
|
||||
if (!(session.group.some(item => session.rpcs[j].group.includes(item)))){
|
||||
continue;
|
||||
@ -3303,7 +3333,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
|
||||
for (var i in session.rpcs){
|
||||
if (session.rpcs[i]===null){continue;}
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
try {
|
||||
if (!(session.group.some(item => session.rpcs[i].group.includes(item)))){
|
||||
continue;
|
||||
@ -3432,7 +3462,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
i = RPCSkeys[keyIndex];
|
||||
if (session.rpcs[i]===null){continue;}
|
||||
session.rpcs[i].mutedStateMixer = false;
|
||||
if (session.group.length){ // The MAIN and LAST group filter.
|
||||
if (session.group.length || session.allowNoGroup){ // The MAIN and LAST group filter.
|
||||
try {
|
||||
if (!(session.group.some(item => session.rpcs[i].group.includes(item)))){
|
||||
if (session.scene!==false){
|
||||
@ -3459,6 +3489,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} catch(e){}
|
||||
}
|
||||
applyMuteState(i);
|
||||
var doNotPush = false;
|
||||
|
||||
if (session.rpcs[i].iframeEle){
|
||||
if (session.rpcs[i].iframeEle.style.display=="none"){
|
||||
@ -3546,7 +3577,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
mediaPool.push(session.rpcs[i].imageElement);
|
||||
}
|
||||
|
||||
continue;
|
||||
doNotPush = true;
|
||||
}
|
||||
|
||||
if (session.rpcs[i].videoElement){ // remote feeds
|
||||
@ -3584,17 +3615,18 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
mediaPool.push(session.rpcs[i].canvas);
|
||||
}
|
||||
|
||||
continue;
|
||||
doNotPush = true;
|
||||
//continue;
|
||||
}
|
||||
} else if (session.style==1){
|
||||
if (session.rpcs[i].videoElement.srcObject && ((session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0) || session.rpcs[i].videoMuted)){
|
||||
//if (session.style==1){ // avatars and waveforms might be better done elsewhere? as a canvas effect even?
|
||||
continue;
|
||||
doNotPush = true;
|
||||
//}
|
||||
}
|
||||
} else if (session.rpcs[i].videoElement.srcObject && ((session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0) || session.rpcs[i].videoMuted)){
|
||||
if (session.rpcs[i].screenShareState){
|
||||
continue;
|
||||
doNotPush = true;;
|
||||
}
|
||||
}
|
||||
//} else if (!session.directorList.indexOf(i)>=0){ // director is never audio-only. Video if need, yes, but not visualized-audio.
|
||||
@ -3603,6 +3635,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
session.rpcs[i].opacityMuted = "1";
|
||||
if (session.rpcs[i].opacityDisconnect=="1"){
|
||||
if (session.rpcs[i].videoElement){
|
||||
@ -3659,6 +3692,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
session.requestRateLimit(sceneBitrate, i); // well, screw that. Setting it to room quality.
|
||||
}
|
||||
} else {
|
||||
|
||||
session.requestRateLimit(-1, i); // unlock.
|
||||
}
|
||||
if (session.rpcs[i].order!==false){
|
||||
@ -3672,7 +3706,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else {
|
||||
errorlog("THIS SHOULD NOT HAPPEN; 650");
|
||||
}
|
||||
} else {
|
||||
} else if (!doNotPush){
|
||||
mediaPool.push(session.rpcs[i].videoElement);
|
||||
}
|
||||
} else if (session.roomid!==false){ // guests should see video at low bitrate, ie: 100kbps (not 35kbps like if disabled)
|
||||
@ -3687,7 +3721,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else {
|
||||
errorlog("THIS SHOULD NOT HAPPEN; 665");
|
||||
}
|
||||
} else {
|
||||
} else if (!doNotPush){
|
||||
mediaPool.push(session.rpcs[i].videoElement);
|
||||
}
|
||||
if ((session.roomid==="") && (session.bitrate)){
|
||||
@ -3712,7 +3746,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else {
|
||||
errorlog("THIS SHOULD NOT HAPPEN; 684");
|
||||
}
|
||||
} else {
|
||||
} else if (!doNotPush){
|
||||
mediaPool.push(session.rpcs[i].videoElement);
|
||||
}
|
||||
if (sceneBitrate){
|
||||
@ -4769,15 +4803,15 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
try {
|
||||
if (!(session.cleanOutput && session.cleanish==false)){
|
||||
if (session.firstPlayTriggered===false){ // don't play unless needed; might cause clicking or who knows what else.
|
||||
warnlog("VIDEO IS NOT PLAYING");
|
||||
if (vid.tagName.toLowerCase()=="video"){ // we don't want to try playing an Iframe or Canvas.
|
||||
if (vid.paused){
|
||||
warnlog("VIDEO IS NOT PLAYING");
|
||||
var playPromise = vid.play();
|
||||
if (playPromise !== undefined){
|
||||
playPromise.then(_ => {
|
||||
// playing
|
||||
session.firstPlayTriggered=true; // global tracking. "user gesture obtained", so no longer needed if playing.
|
||||
//session.firstPlayTriggered=true; // global tracking. "user gesture obtained", so no longer needed if playing.
|
||||
}).catch((err)=>{
|
||||
|
||||
var bigPlayButton = document.getElementById("bigPlayButton");
|
||||
if (bigPlayButton){
|
||||
bigPlayButton.innerHTML = '<span class="playButton"></span>';
|
||||
@ -4790,6 +4824,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
var bigPlayButton = document.getElementById("bigPlayButton");
|
||||
if (bigPlayButton){
|
||||
@ -5158,7 +5193,7 @@ function requestKeyframeScene(ele) {
|
||||
}
|
||||
}
|
||||
|
||||
function pokeIframeAPI(action, value = null, UUID = null) {
|
||||
function pokeIframeAPI(action, value = null, UUID = null, SID=null) {
|
||||
if (!isIFrame){return;}
|
||||
try {
|
||||
var data = {};
|
||||
@ -5171,13 +5206,13 @@ function pokeIframeAPI(action, value = null, UUID = null) {
|
||||
if (UUID !== null) {
|
||||
data.UUID = UUID;
|
||||
}
|
||||
|
||||
var SID = null;
|
||||
if (!SID){
|
||||
if (UUID && (UUID in session.rpcs)){
|
||||
if (session.rpcs[UUID].streamID){
|
||||
SID = session.rpcs[UUID].streamID;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!SID){
|
||||
if (UUID && (UUID in session.pcs)){
|
||||
if (session.pcs[UUID].streamID){
|
||||
@ -5185,7 +5220,8 @@ function pokeIframeAPI(action, value = null, UUID = null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UUID){
|
||||
|
||||
if (SID){
|
||||
data.streamID = SID;
|
||||
}
|
||||
|
||||
@ -6364,7 +6400,10 @@ async function makeImages(startup=false){
|
||||
var updateUserListTimeout=null
|
||||
var updateUserListActive = false;
|
||||
function updateUserList(){
|
||||
if ((session.showList!==true) && (session.cleanOutput || (session.scene!==false) || !session.roomid || session.director || (session.showList===false))){return;}
|
||||
if (session.showList===true){
|
||||
// continue
|
||||
}
|
||||
else if ((session.showList!==true) && (session.cleanOutput || (session.scene!==false) || !session.roomid || session.director || (session.showList===false))){return;}
|
||||
clearInterval(updateUserListTimeout);
|
||||
updateUserListTimeout = setTimeout(function(){
|
||||
if (updateUserListActive){return;}
|
||||
@ -6374,14 +6413,16 @@ function updateUserList(){
|
||||
getById("userList").innerHTML = "";
|
||||
|
||||
for (var UUID in session.rpcs){
|
||||
if (session.rpcs[UUID].videoElement && session.rpcs[UUID].streamSrc && session.rpcs[UUID].streamSrc.getTracks().length){
|
||||
if (document.body.contains(session.rpcs[UUID].videoElement)){
|
||||
if ((session.rpcs[UUID].videoElement && session.rpcs[UUID].streamSrc && session.rpcs[UUID].streamSrc.getTracks().length) || (session.rpcs[UUID].canvas) || (session.rpcs[UUID].imageElement)){
|
||||
if (session.rpcs[UUID].videoElement && document.body.contains(session.rpcs[UUID].videoElement)){
|
||||
continue;
|
||||
} else if (session.rpcs[UUID].canvas && document.body.contains(session.rpcs[UUID].canvas)){
|
||||
continue;
|
||||
} else if (session.rpcs[UUID].imageElement && document.body.contains(session.rpcs[UUID].imageElement)){
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if ((session.rpcs[UUID].videoMuted || (!session.rpcs[UUID].imageElement && !session.rpcs[UUID].canvas)) || ( session.infocus && session.infocus!==UUID )){
|
||||
if ((session.rpcs[UUID].videoMuted || (!session.rpcs[UUID].imageElement && !session.rpcs[UUID].canvas)) || ( session.infocus && session.infocus!==UUID ) || (!session.rpcs[UUID].defaultSpeaker && session.activeSpeaker)){
|
||||
|
||||
if (session.directorList.indexOf(UUID)>=0){
|
||||
if (!session.rpcs[UUID].streamSrc){ // director not active yet, so we won't bother showing it.
|
||||
@ -7576,13 +7617,23 @@ function processStats(UUID){
|
||||
|
||||
try {
|
||||
if (session.rpcs[UUID].videoElement.paused){
|
||||
// if (firstPlayTriggered || (session.audioCtx.state == "running")){
|
||||
if (session.firstPlayTriggered){
|
||||
if (session.audioCtx.state == "suspended"){ // added oct 9th 2022
|
||||
try {
|
||||
session.audioCtx.resume();
|
||||
} catch(e){warnlog(e);}
|
||||
}
|
||||
if (session.audioCtx.state == "running"){ // NOTE: I Don't know why this was
|
||||
log("trying to play");
|
||||
session.rpcs[UUID].videoElement.play().then(_ => {
|
||||
log("playing 8");
|
||||
session.firstPlayTriggered = true;
|
||||
|
||||
//if ((session.audioEffects===true) || session.pushLoudness){
|
||||
// updateIncomingAudioElement(UUID);
|
||||
//}
|
||||
}).catch(warnlog);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e){};
|
||||
|
||||
@ -8669,7 +8720,9 @@ function updateLocalStats(){
|
||||
if (stat.encoderImplementation=="ExternalEncoder"){
|
||||
session.mc.stats._hardwareEncoder = true; // I won't set this to false again, just because once I know it has one, I just need to assume it could always be used unexpectednly
|
||||
session.mc.encoder = true;
|
||||
|
||||
} else if (stat.encoderImplementation=="MediaFoundationVideoEncodeAccelerator"){
|
||||
session.mc.stats._hardwareEncoder = true; // I won't set this to false again, just because once I know it has one, I just need to assume it could always be used unexpectednly
|
||||
session.mc.encoder = true;
|
||||
} else {
|
||||
session.mc.encoder = false; // this may not be actually accurate, but lets assume so.
|
||||
}
|
||||
@ -8937,15 +8990,32 @@ function updateLocalStats(){
|
||||
}
|
||||
}
|
||||
|
||||
var miniInfo = {};
|
||||
var sendMini = false;
|
||||
|
||||
if ("encoderImplementation" in stat) {
|
||||
session.pcs[UUID].stats.video_encoder = stat.encoderImplementation;
|
||||
|
||||
if (stat.encoderImplementation=="ExternalEncoder"){
|
||||
session.pcs[UUID].stats._hardwareEncoder = true; // I won't set this to false again, just because once I know it has one, I just need to assume it could always be used unexpectednly
|
||||
if (session.pcs[UUID].encoder !== true){
|
||||
session.pcs[UUID].encoder = true;
|
||||
|
||||
miniInfo.hw_enc = true;
|
||||
sendMini = true;
|
||||
}
|
||||
} else if (stat.encoderImplementation=="MediaFoundationVideoEncodeAccelerator"){
|
||||
session.pcs[UUID].stats._hardwareEncoder = true; // I won't set this to false again, just because once I know it has one, I just need to assume it could always be used unexpectednly
|
||||
if (session.pcs[UUID].encoder !== true){
|
||||
session.pcs[UUID].encoder = true;
|
||||
miniInfo.hw_enc = true;
|
||||
sendMini = true;
|
||||
}
|
||||
} else {
|
||||
session.pcs[UUID].encoder = false; // this may not be actually accurate, but lets assume so.
|
||||
if (session.pcs[UUID].encoder === true){
|
||||
session.pcs[UUID].encoder = false;
|
||||
miniInfo.hw_enc = false;
|
||||
sendMini = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8953,20 +9023,18 @@ function updateLocalStats(){
|
||||
if (session.pcs[UUID].stats.quality_limitation_reason){
|
||||
if (session.pcs[UUID].stats.quality_limitation_reason !== stat.qualityLimitationReason){
|
||||
try{
|
||||
var miniInfo = {};
|
||||
sendMini = true;
|
||||
miniInfo.qlr = stat.qualityLimitationReason;
|
||||
if ("_hardwareEncoder" in session.pcs[UUID].stats){
|
||||
miniInfo.hw_enc = session.pcs[UUID].stats._hardwareEncoder;
|
||||
} else {
|
||||
miniInfo.hw_enc = null;
|
||||
}
|
||||
session.sendMessage({"miniInfo":miniInfo}, UUID);
|
||||
} catch(e){warnlog(e);}
|
||||
}
|
||||
}
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
}
|
||||
|
||||
if (sendMini){
|
||||
session.sendMessage({"miniInfo":miniInfo}, UUID);
|
||||
}
|
||||
|
||||
if ("bytesSent" in stat) {
|
||||
if ("_bytesSentVideo" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp1){
|
||||
@ -10309,21 +10377,61 @@ function syncOtherState(sid){
|
||||
}
|
||||
}
|
||||
|
||||
var groups = session.syncState[sid].group;
|
||||
var elements = document.querySelectorAll('[data-action-type="toggle-group"][data-sid="'+sid+'"]');
|
||||
var UUID = document.querySelector('[data-sid="'+sid+'"][data--u-u-i-d');
|
||||
if (UUID && UUID.dataset.UUID){
|
||||
if (session.syncState[sid].group){
|
||||
session.rpcs[UUID].group = session.syncState[sid].group;
|
||||
syncGroup(groups, UUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function htmlToElement(html) {
|
||||
var template = document.createElement('template');
|
||||
html = html.trim(); // Never return a text node of whitespace as the result
|
||||
template.innerHTML = html;
|
||||
return template.content.firstChild;
|
||||
}
|
||||
|
||||
function syncGroup(groups, UUID){
|
||||
|
||||
groups.forEach(group=>{
|
||||
var ele = getById("container_" + UUID).querySelector('[data-action-type="toggle-group"][data--u-u-i-d="'+UUID+'"][data-group="'+group+'"]');
|
||||
if (!ele){
|
||||
var newGroup = htmlToElement('<button style="margin: 0 5px 10px 5px;" class="pressed" data-sid="'+session.rpcs[UUID].streamID+'" data--u-u-i-d="'+UUID+'" data-action-type="toggle-group" data-group="'+group+'" title="Add to Group: '+group+'" onclick="changeGroup(this, event);"><span ><i class="las la-users" style="color:#060"></i>'+group+'</span></button>');
|
||||
|
||||
var added = false;
|
||||
getById("container_" + UUID).querySelectorAll('.customGroup>[data-group]').forEach(ele=>{
|
||||
log(ele);
|
||||
if (!added && ele.dataset.group>group+""){
|
||||
ele.parentNode.insertBefore(newGroup, ele);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
var newGroupCon = getById("container_" + UUID).querySelector(".customGroup");
|
||||
if (!newGroupCon){
|
||||
newGroupCon = document.createElement("div");
|
||||
newGroupCon.classList.add("customGroup");
|
||||
getById("container_" + UUID).appendChild(newGroupCon);
|
||||
}
|
||||
newGroupCon.appendChild(newGroup);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var elements = document.querySelectorAll('[data-action-type="toggle-group"][data--u-u-i-d="'+UUID+'"][data-group]');
|
||||
if (elements.length){
|
||||
var UUID = elements[0].dataset.UUID;
|
||||
if (UUID){
|
||||
session.rpcs[UUID].group = groups;
|
||||
}
|
||||
for (var i=0;i<elements.length;i++){
|
||||
elements[i].classList.remove("pressed");
|
||||
for (var g=0;g<session.rpcs[UUID].group.length;g++){
|
||||
if (elements[i].value == session.rpcs[UUID].group[g]){
|
||||
if (session.rpcs[UUID].group.includes(elements[i].dataset.group)){
|
||||
elements[i].classList.add("pressed");
|
||||
} else {
|
||||
elements[i].classList.remove("pressed");
|
||||
}
|
||||
}
|
||||
}
|
||||
log("synced group");
|
||||
} else {
|
||||
log("not syncing group buttons; don't exist");
|
||||
}
|
||||
}
|
||||
|
||||
@ -10474,7 +10582,6 @@ async function directPageReload(ele, event) {
|
||||
|
||||
async function directTimer(ele, event=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("directTimer");
|
||||
if (!ele.dataset.UUID){return;}
|
||||
var msg = {};
|
||||
ele.classList.remove("blue");
|
||||
ele.classList.remove("red2");
|
||||
@ -10513,7 +10620,12 @@ async function directTimer(ele, event=false) { // A directing room only is cont
|
||||
ele.classList.add("red2");
|
||||
}
|
||||
}
|
||||
|
||||
if (ele.dataset.UUID){
|
||||
session.sendRequest(msg, ele.dataset.UUID);
|
||||
} else {
|
||||
session.sendRequest(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function updateRemoteTimerButton(UUID, currentTime) {
|
||||
@ -12412,7 +12524,7 @@ function outboundAudioPipeline(){ // this function isn't letting me change the a
|
||||
}
|
||||
|
||||
try {
|
||||
if (webAudio.audioContext.state == "suspended"){
|
||||
if (session.firstPlayTriggered && (webAudio.audioContext.state == "suspended")){
|
||||
webAudio.audioContext.resume();
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
@ -13726,7 +13838,7 @@ async function createDirectorOnlyBox() {
|
||||
|
||||
var buttons = "";
|
||||
if (session.slotmode){
|
||||
var slots = document.querySelectorAll("div.slotsbar[data--u-u-i-d][data-slot]");
|
||||
var slots = document.querySelectorAll("div.slotsbar[data-slot]");
|
||||
var biggestSlot=0;
|
||||
if (session.slotmode==1){
|
||||
for (var i=0;i<slots.length;i++){
|
||||
@ -13741,7 +13853,7 @@ async function createDirectorOnlyBox() {
|
||||
slotName = "unset";
|
||||
}
|
||||
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data--u-u-i-d='"+UUID+"' class='slotsbar'>\
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-sid='"+session.streamID+"' data-slot='"+biggestSlot+"' class='slotsbar'>\
|
||||
<button ondrop='dropSlot(event)' draggable='true' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondragover='allowDropSlot(event)' onclick='changeSlot(event, this);'>"+slotName+"</button></div>";
|
||||
|
||||
}
|
||||
@ -13845,6 +13957,9 @@ async function createDirectorOnlyBox() {
|
||||
labelID.innerText = session.label;
|
||||
}
|
||||
pokeIframeAPI("control-box", true, true);
|
||||
if (session.slotmode){
|
||||
pokeIframeAPI("slot-updated", biggestSlot, null, session.streamID); // need to support self-director
|
||||
}
|
||||
}
|
||||
|
||||
function shiftPC(ele, shift, director=false){
|
||||
@ -14008,8 +14123,8 @@ function dropSlot(event) {
|
||||
|
||||
swapNodes(event.target, origThing);
|
||||
|
||||
pokeIframeAPI("slot-updated", parseInt(event.target.dataset.slot), event.target.dataset.UUID); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(origThing.dataset.slot), origThing.dataset.UUID); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(event.target.dataset.slot), null, event.target.dataset.sid ); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(origThing.dataset.slot), null, origThing.dataset.sid); // need to support self-director
|
||||
} else if (origThing && ("slot" in event.target.parentNode.dataset)){
|
||||
log(event.target.parentNode);
|
||||
|
||||
@ -14019,8 +14134,8 @@ function dropSlot(event) {
|
||||
|
||||
swapNodes(event.target.parentNode, origThing);
|
||||
|
||||
pokeIframeAPI("slot-updated", parseInt(event.target.parentNode.dataset.slot), event.target.parentNode.dataset.UUID); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(origThing.dataset.slot), origThing.dataset.UUID); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(event.target.parentNode.dataset.slot), null, event.target.parentNode.dataset.sid); // need to support self-director
|
||||
pokeIframeAPI("slot-updated", parseInt(origThing.dataset.slot), null, origThing.dataset.sid); // need to support self-director
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -14094,13 +14209,13 @@ function setSlot(ele,slot){
|
||||
getById("slotPicker").classList.add("hidden");
|
||||
if (slot!==null){
|
||||
slot = (parseInt(slot) || 0);
|
||||
var slots = document.querySelectorAll("div.slotsbar[data--u-u-i-d][data-slot]");
|
||||
var slots = document.querySelectorAll("div.slotsbar[data-slot]");
|
||||
for (var i=0;i<slots.length;i++){
|
||||
if (parseInt(slots[i].dataset.slot)==slot){
|
||||
slots[i].dataset.slot = ele.parentNode.dataset.slot;
|
||||
slots[i].querySelector("button").innerText = ele.innerText;
|
||||
warnlog("Slot already existed; setting old one to 0 (unset)");
|
||||
pokeIframeAPI("slot-updated", parseInt(slots[i].dataset.slot), slots[i].dataset.UUID);
|
||||
pokeIframeAPI("slot-updated", parseInt(slots[i].dataset.slot), null, slots[i].dataset.sid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -14110,7 +14225,7 @@ function setSlot(ele,slot){
|
||||
} else {
|
||||
ele.innerText = 'unset';
|
||||
}
|
||||
pokeIframeAPI("slot-updated", slot, ele.parentNode.dataset.UUID);
|
||||
pokeIframeAPI("slot-updated", slot, null, ele.parentNode.dataset.sid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14249,7 +14364,7 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
|
||||
var buttons = "";
|
||||
if (session.slotmode){
|
||||
var slots = document.querySelectorAll("div.slotsbar[data--u-u-i-d][data-slot]");
|
||||
var slots = document.querySelectorAll("div.slotsbar[data-slot]");
|
||||
var biggestSlot=0;
|
||||
if (session.slotmode==1){
|
||||
for (var i=0;i<slots.length;i++){
|
||||
@ -14263,7 +14378,7 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
if (!biggestSlot){
|
||||
slotName = "unset";
|
||||
}
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data--u-u-i-d='"+UUID+"' class='slotsbar'>\
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data--u-u-i-d='"+UUID+"' data-sid='"+streamID+"' class='slotsbar'>\
|
||||
<button ondrop='dropSlot(event)' draggable='true' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondragover='allowDropSlot(event)' onclick='changeSlot(event, this);'>"+slotName+"</button></div>";
|
||||
|
||||
}
|
||||
@ -14362,6 +14477,31 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
videoContainer.appendChild(iframeDetails);
|
||||
container.appendChild(controls);
|
||||
|
||||
session.group.forEach(group=>{
|
||||
var ele = controls.querySelector('[data-action-type="toggle-group"][data--u-u-i-d="'+UUID+'"][data-group="'+group+'"]');
|
||||
if (!ele){
|
||||
var newGroup = htmlToElement('<button style="margin: 0 5px 10px 5px;" data-sid="'+session.rpcs[UUID].streamID+'" data--u-u-i-d="'+UUID+'" data-action-type="toggle-group" data-group="'+group+'" title="Add to Group: '+group+'" onclick="changeGroup(this, event);"><span ><i class="las la-users" style="color:#060"></i>'+group+'</span></button>');
|
||||
|
||||
var added = false;
|
||||
container.querySelectorAll('.customGroup>[data-group]').forEach(ele=>{
|
||||
log(ele);
|
||||
if (!added && ele.dataset.group>group+""){
|
||||
ele.parentNode.insertBefore(newGroup, ele);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
var newGroupCon = container.querySelector(".customGroup");
|
||||
if (!newGroupCon){
|
||||
newGroupCon = document.createElement("div");
|
||||
newGroupCon.classList.add("customGroup");
|
||||
container.appendChild(newGroupCon);
|
||||
}
|
||||
newGroupCon.appendChild(newGroup);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
initSceneList(UUID);
|
||||
syncSceneState(streamID);
|
||||
syncOtherState(streamID);
|
||||
@ -15767,15 +15907,23 @@ function gotDevicesRemote(deviceInfos, UUID) {
|
||||
var videoSelect = document.createElement("select");
|
||||
videoSelect.id = "remoteVideoSelect_"+UUID;
|
||||
videoSelect.style = "max-width:170px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
|
||||
|
||||
|
||||
|
||||
videoSelect.onchange = function(){
|
||||
if (session.rpcs[UUID].stats.info && session.rpcs[UUID].stats.info.consent){
|
||||
getById("requestVideoDevice_"+UUID).innerHTML = '<i class="las la-video"></i> apply';
|
||||
getById("requestVideoDevice_"+UUID).title = "This will update the remote device to the selected one";
|
||||
} else {
|
||||
getById("requestVideoDevice_"+UUID).innerHTML = '<i class="las la-video"></i> request';
|
||||
getById("requestVideoDevice_"+UUID).title = "This will ask the remote guest for permission to change";
|
||||
}
|
||||
}
|
||||
|
||||
var buttonGO = document.createElement("button");
|
||||
buttonGO.innerHTML = '<i class="las la-video"></i> request';
|
||||
buttonGO.innerHTML = '<i class="las la-video"></i> refresh';
|
||||
buttonGO.style = "padding: 5px;";
|
||||
buttonGO.title = "This will ask the remote guest for permission to change";
|
||||
buttonGO.title = "This will refresh the current device";
|
||||
buttonGO.id = "requestVideoDevice_"+UUID;
|
||||
buttonGO.onclick = function(){
|
||||
var data = {}
|
||||
@ -15789,6 +15937,7 @@ function gotDevicesRemote(deviceInfos, UUID) {
|
||||
}
|
||||
|
||||
if (document.getElementById("remoteAudioSelect_"+UUID)){
|
||||
log("remoteAudioSelect_ ");
|
||||
var audioSelect = document.getElementById("remoteAudioSelect_"+UUID);
|
||||
var length = audioSelect.options.length;
|
||||
for (i = length-1; i >= 0; i--) {
|
||||
@ -15798,10 +15947,25 @@ function gotDevicesRemote(deviceInfos, UUID) {
|
||||
var audioSelect = document.createElement("select");
|
||||
audioSelect.id = "remoteAudioSelect_"+UUID;
|
||||
audioSelect.style = "max-width:170px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
|
||||
|
||||
|
||||
audioSelect.onchange = function(){
|
||||
log("ON CHANGE");
|
||||
if (session.rpcs[UUID].stats.info && session.rpcs[UUID].stats.info.consent){
|
||||
getById("requestAudioDevice_"+UUID).innerHTML = '<i class="las la-microphone-alt"></i> apply';
|
||||
getById("requestAudioDevice_"+UUID).title = "This will update the remote device to the selected one";
|
||||
} else {
|
||||
getById("requestAudioDevice_"+UUID).innerHTML = '<i class="las la-microphone-alt"></i> request';
|
||||
getById("requestAudioDevice_"+UUID).title = "This will ask the remote guest for permission to change";
|
||||
}
|
||||
}
|
||||
|
||||
var buttonGO = document.createElement("button");
|
||||
buttonGO.innerHTML = '<i class="las la-microphone-alt"></i> request';
|
||||
buttonGO.innerHTML = '<i class="las la-microphone-alt"></i> refresh';
|
||||
buttonGO.style = "padding: 5px;";
|
||||
buttonGO.title = "This will ask the remote guest for permission to change";
|
||||
buttonGO.title = "This will refresh the current device";
|
||||
buttonGO.id = "requestAudioDevice_"+UUID;
|
||||
|
||||
buttonGO.onclick = function(){
|
||||
var data = {}
|
||||
data.changeMicrophone = audioSelect.value;
|
||||
@ -15825,10 +15989,22 @@ function gotDevicesRemote(deviceInfos, UUID) {
|
||||
var audioOutputSelect = document.createElement("select");
|
||||
audioOutputSelect.id = "remoteAudioOutputSelect_"+UUID;
|
||||
audioOutputSelect.style = "max-width:170px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
|
||||
|
||||
audioOutputSelect.onchange = function(){
|
||||
if (session.rpcs[UUID].stats.info && session.rpcs[UUID].stats.info.consent){
|
||||
getById("requestAudioOutputDevice_"+UUID).innerHTML = '<i class="las la-headphones"></i> apply';
|
||||
getById("requestAudioOutputDevice_"+UUID).title = "This will update the remote device to the selected one";
|
||||
} else {
|
||||
getById("requestAudioOutputDevice_"+UUID).innerHTML = '<i class="las la-headphones"></i> request';
|
||||
getById("requestAudioOutputDevice_"+UUID).title = "This will ask the remote guest for permission to change";
|
||||
}
|
||||
}
|
||||
|
||||
var buttonGO = document.createElement("button");
|
||||
buttonGO.innerHTML = '<i class="las la-headphones"></i> request';
|
||||
buttonGO.innerHTML = '<i class="las la-headphones"></i> refresh';
|
||||
buttonGO.style = "padding: 5px;";
|
||||
buttonGO.title = "This will ask the remote guest for permission to change";
|
||||
buttonGO.title = "This will refresh the current device";
|
||||
buttonGO.id = "requestAudioOutputDevice_"+UUID;
|
||||
buttonGO.onclick = function(){
|
||||
var data = {}
|
||||
data.changeSpeaker = audioOutputSelect.value;
|
||||
@ -16231,7 +16407,7 @@ var playbackReconnectTimeout = null;
|
||||
function reconnectDevices(event) { /// TODO: Perhaps change this to only if there is a DISCONNECT; rather than ON NEW DEVICE?
|
||||
|
||||
try {
|
||||
if (session.audioCtx.state == "suspended"){
|
||||
if (session.firstPlayTriggered && (session.audioCtx.state == "suspended")){
|
||||
session.audioCtx.resume();
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
@ -17425,16 +17601,16 @@ function changeVideoDeviceById(deviceId, UUID=false){
|
||||
}
|
||||
}
|
||||
if (index!==false){
|
||||
if (document.getElementById("videoSource3").selectedIndex === j){ // this is just refreshing the device.
|
||||
if (document.getElementById("videoSource3").selectedIndex === index){ // this is just refreshing the device.
|
||||
activatedPreview=false;
|
||||
grabVideo(0, "videosource", "#videoSource3", callback=UUID);
|
||||
grabVideo(0, "videosource", "#videoSource3", UUID);
|
||||
} else if (UUID && !session.consent){
|
||||
window.focus();
|
||||
confirmAlt("Allow the director to change your video device to:\n\n"+opts[index].text+" ?").then(res=>{
|
||||
if (res){
|
||||
document.getElementById("videoSource3").selectedIndex = j;
|
||||
document.getElementById("videoSource3").selectedIndex = index;
|
||||
activatedPreview=false;
|
||||
grabVideo(0, "videosource", "#videoSource3", callback=UUID);
|
||||
grabVideo(0, "videosource", "#videoSource3", UUID);
|
||||
} else {
|
||||
try {
|
||||
var data = {};
|
||||
@ -17445,20 +17621,37 @@ function changeVideoDeviceById(deviceId, UUID=false){
|
||||
}
|
||||
});
|
||||
} else {
|
||||
document.getElementById("videoSource3").selectedIndex = j;
|
||||
document.getElementById("videoSource3").selectedIndex = index;
|
||||
activatedPreview=false;
|
||||
grabVideo(0, "videosource", "#videoSource3", callback=UUID);
|
||||
grabVideo(0, "videosource", "#videoSource3", UUID);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeAudioDeviceById(deviceId, UUID=false){
|
||||
if (UUID && !session.consent){
|
||||
window.focus();
|
||||
confirmAlt("Allow the director to change your audio mic source").then(res=>{
|
||||
if (res){
|
||||
enumerateDevices().then(gotDevices2).then(function() {
|
||||
var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
|
||||
var matched = false;
|
||||
var exists = false;
|
||||
for (var i = 0; i < audioSelect.length; i++) {
|
||||
if (audioSelect[i].value == deviceId){
|
||||
exists = true;
|
||||
if (audioSelect[i].checked){
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exists){
|
||||
if (matched){ // this is just refreshing the device.
|
||||
activatedPreview=false;
|
||||
grabAudio("#audioSource3", UUID);
|
||||
} else if (UUID && !session.consent){
|
||||
window.focus();
|
||||
confirmAlt("Allow the director to change your audio mic source?").then(res=>{
|
||||
if (res){
|
||||
// enumerateDevices().then(gotDevices2).then(function() {
|
||||
var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
|
||||
for (var i = 0; i < audioSelect.length; i++) {
|
||||
if (audioSelect[i].value == deviceId){
|
||||
@ -17468,8 +17661,8 @@ function changeAudioDeviceById(deviceId, UUID=false){
|
||||
}
|
||||
}
|
||||
activatedPreview=false;
|
||||
grabAudio("#audioSource3", callback=UUID);
|
||||
});
|
||||
grabAudio("#audioSource3", UUID);
|
||||
// });
|
||||
} else {
|
||||
try {
|
||||
var data = {};
|
||||
@ -17480,7 +17673,7 @@ function changeAudioDeviceById(deviceId, UUID=false){
|
||||
}
|
||||
});
|
||||
} else {
|
||||
enumerateDevices().then(gotDevices2).then(function() {
|
||||
//enumerateDevices().then(gotDevices2).then(function() {
|
||||
var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
|
||||
for (var i = 0; i < audioSelect.length; i++) {
|
||||
if (audioSelect[i].value == deviceId){
|
||||
@ -17490,9 +17683,11 @@ function changeAudioDeviceById(deviceId, UUID=false){
|
||||
}
|
||||
}
|
||||
activatedPreview=false;
|
||||
grabAudio("#audioSource3", callback=UUID);
|
||||
});
|
||||
grabAudio("#audioSource3", UUID);
|
||||
// });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeAudioOutputDeviceById(deviceId, UUID=false){ // remote control of the speaker output.
|
||||
@ -17509,7 +17704,12 @@ function changeAudioOutputDeviceById(deviceId, UUID=false){ // remote control of
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UUID && !session.consent){ // UUID just lets us inform the requester
|
||||
if (index!==false){
|
||||
if (document.getElementById("outputSource3").selectedIndex === index){ // this is just refreshing the device.
|
||||
session.sink = deviceId;
|
||||
saveSettings();
|
||||
resetupAudioOut();
|
||||
} else if (UUID && !session.consent){ // UUID just lets us inform the requester
|
||||
window.focus();
|
||||
confirmAlt("Allow the director to change your audio's speaker to:\n\n"+opts[index].text+" ?").then(res=>{
|
||||
if (res){
|
||||
@ -17540,6 +17740,7 @@ function changeAudioOutputDeviceById(deviceId, UUID=false){ // remote control of
|
||||
saveSettings();
|
||||
resetupAudioOut();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
session.sink = deviceId;
|
||||
@ -18405,13 +18606,17 @@ async function grabAudio(selector = "#audioSource", trackid = null, override = f
|
||||
}
|
||||
|
||||
session.toggleSoloChat = function(UUID, event=false){ // ==> applyIsolatedChat -- this should be trigger by the director only I think
|
||||
if (session.director){
|
||||
if (Firefox){
|
||||
warnUser("Sorry, but Firefox does not support solo talk.",2000)
|
||||
return false;
|
||||
} else if (session.director){
|
||||
if (!session.directorEnabledPPT){
|
||||
warnUser("Enable the director's microphone first.");
|
||||
warnUser("Enable the director's microphone first.",2000);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var msg = {};
|
||||
msg.micIsolate = false;
|
||||
|
||||
@ -23321,7 +23526,7 @@ function listCameraSettings() {
|
||||
track0.applyConstraints({
|
||||
advanced: [{[i]:cameraSettings['default'][i]}]
|
||||
}).then(() => {}).catch(e => {
|
||||
errorlog("Failed to reset to defaults: "+i);
|
||||
errorlog("Failed to reset to defaults");
|
||||
failed = true;
|
||||
});
|
||||
}
|
||||
@ -23954,7 +24159,7 @@ function screenshareTypeDecider(sstype=1){
|
||||
}
|
||||
}
|
||||
|
||||
function createScreenShareURL(transparent=true){
|
||||
function createScreenShareURL(transparent=true){ // iframe.src =
|
||||
if (session.screenShareElement) {
|
||||
var iFrameID = session.streamID.substring(0, 12) + "_" + session.generateStreamID(5);
|
||||
} else if (session.screenshareid) {
|
||||
@ -24060,6 +24265,15 @@ function createScreenShareURL(transparent=true){
|
||||
if (session.muted){
|
||||
extras += "&muted";
|
||||
}
|
||||
|
||||
if (session.recordLocal){
|
||||
extras += "&record="+session.recordLocal;
|
||||
}
|
||||
|
||||
if (session.autorecordlocal){
|
||||
extras += "&autorecordlocal";
|
||||
}
|
||||
|
||||
if (transparent){
|
||||
extras += "&transparent&cleanish";
|
||||
}
|
||||
@ -27063,8 +27277,11 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream = createMediaStream();
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream.addTrack(track);
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = createAudioElement();
|
||||
|
||||
if (ChromeVersion && (ChromeVersion<106)){ // I'm going to deprecate this.
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = createAudioElement(); // TODO: I don't know if this mutedAudio thing matters any more, in recent versions of Chrome, since it won't play even if muted.
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true;
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.playsinline = true; // ## Added Oct 9th 2022. Not sure it's does anything, but might help with iPhones?
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.srcObject = session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream; // needs to be added as an streamed element to be usable, even if its hidden
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true;
|
||||
//session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.volume = 0.01;
|
||||
@ -27072,6 +27289,7 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
//session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = false;
|
||||
log("playing 1");
|
||||
}).catch(warnlog);
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaStreamTrackSource
|
||||
var source = session.audioCtx.createMediaStreamSource(session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream);
|
||||
@ -27080,6 +27298,7 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
|
||||
var screwedUp = false;
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].destination = false;
|
||||
|
||||
if (session.sync!==false){
|
||||
log("adding a delay node to audio");
|
||||
source = addDelayNode( source, UUID, trackid);
|
||||
@ -27130,7 +27349,8 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
source.connect(session.rpcs[UUID].inboundAudioPipeline[trackid].destination);
|
||||
|
||||
try {
|
||||
if (session.audioCtx.state == "suspended"){
|
||||
if (session.firstPlayTriggered && (session.audioCtx.state == "suspended")){
|
||||
log("trying to resume..");
|
||||
session.audioCtx.resume();
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
@ -27139,10 +27359,10 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
}
|
||||
|
||||
try {
|
||||
if (session.audioCtx.state == "suspended"){
|
||||
if (session.firstPlayTriggered && (session.audioCtx.state == "suspended")){
|
||||
session.audioCtx.resume();
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed 2");}
|
||||
|
||||
return track;
|
||||
} catch(e) {errorlog(e);}
|
||||
@ -27177,7 +27397,7 @@ function changeGroupDirector(ele, state=null){
|
||||
}
|
||||
}
|
||||
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
session.sendMessage({"group":session.group.join(",")});
|
||||
} else {
|
||||
session.sendMessage({"group":false});
|
||||
@ -27253,7 +27473,7 @@ function changeGroupDirectorAPI(group, state=null, update=true){
|
||||
}
|
||||
}
|
||||
if (update){
|
||||
if (session.group.length){
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
session.sendMessage({"group":session.group.join(",")});
|
||||
} else {
|
||||
session.sendMessage({"group":false});
|
||||
@ -28380,6 +28600,15 @@ function oscClient(){ // api.vdo.ninja api OSC (websocket / https API hotkey sup
|
||||
if ("msg" in data){
|
||||
data = data.msg
|
||||
}
|
||||
|
||||
if ("value" in data){
|
||||
if (("action" in data) && (data.action == "layout")){
|
||||
try {
|
||||
data.value = JSON.parse(data.value) || data.value;
|
||||
} catch(e){}
|
||||
}
|
||||
}
|
||||
|
||||
var resp = processMessage(data);
|
||||
if (resp!==null){
|
||||
var ret = {};
|
||||
@ -28572,9 +28801,9 @@ function setupCommands(){
|
||||
if (!("slot" in session.layout[i])){
|
||||
continue;
|
||||
}
|
||||
var slot = document.querySelector("div.slotsbar[data--u-u-i-d][data-slot='"+(parseInt(session.layout[i].slot)+1)+"']")
|
||||
var slot = document.querySelector("div.slotsbar[data-slot='"+(parseInt(session.layout[i].slot)+1)+"']")
|
||||
if (!slot){continue;}
|
||||
var streamID = session.rpcs[slot.dataset.UUID].streamID;
|
||||
var streamID = slot.dataset.sid;
|
||||
combined[streamID] = session.layout[i];
|
||||
}
|
||||
issueLayout(combined, "0");
|
||||
@ -28610,9 +28839,9 @@ function setupCommands(){
|
||||
if (!("slot" in session.layout[i])){
|
||||
continue;
|
||||
}
|
||||
var slot = document.querySelector("div.slotsbar[data--u-u-i-d][data-slot='"+(parseInt(session.layout[i].slot)+1)+"']")
|
||||
var slot = document.querySelector("div.slotsbar[data-slot='"+(parseInt(session.layout[i].slot)+1)+"']")
|
||||
if (!slot){continue;}
|
||||
var streamID = session.rpcs[slot.dataset.UUID].streamID;
|
||||
var streamID = slot.dataset.sid;
|
||||
combined[streamID] = session.layout[i];
|
||||
}
|
||||
issueLayout(combined, "0");
|
||||
@ -29826,14 +30055,10 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
ele.dataset.sid = streamID;
|
||||
});
|
||||
|
||||
//var buttons = "";
|
||||
//if (session.slotmode){
|
||||
// buttons += "<div draggable='true' title='Drag to swap layout positions' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data--u-u-i-d='"+UUID+"' class='slotsbar'>slot: "+biggestSlot+"</div>";
|
||||
//}
|
||||
|
||||
var buttons = "";
|
||||
if (session.slotmode){
|
||||
var slots = document.querySelectorAll("div.slotsbar[data--u-u-i-d][data-slot]");
|
||||
var slots = document.querySelectorAll("div.slotsbar[data-slot]");
|
||||
var biggestSlot=0;
|
||||
if (session.slotmode==1){
|
||||
for (var i=0;i<slots.length;i++){
|
||||
@ -29847,7 +30072,7 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
if (!biggestSlot){
|
||||
slotName = "unset";
|
||||
}
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data--u-u-i-d='"+UUID+"' class='slotsbar'>\
|
||||
buttons += "<div draggable='true' title='Drag to swap layout positions' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondrop='dropSlot(event)' ondragover='allowDropSlot(event)' data-slot='"+biggestSlot+"' data-sid='"+streamID+"' data--u-u-i-d='"+UUID+"' class='slotsbar'>\
|
||||
<button ondrop='dropSlot(event)' draggable='true' ondragend='dragendSlot(event)' ondragstart='dragSlot(event)' ondragover='allowDropSlot(event)' onclick='changeSlot(event, this);'>"+slotName+"</button></div>";
|
||||
}
|
||||
|
||||
@ -29859,6 +30084,7 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
container.innerHTML = buttons;
|
||||
updateLockedElements();
|
||||
|
||||
|
||||
var videoContainerControlBox = document.createElement("div");
|
||||
videoContainerControlBox.className = "controlVideoBox";
|
||||
container.containerControlBox = videoContainerControlBox
|
||||
@ -29916,6 +30142,32 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
videoContainer.appendChild(iframeDetails);
|
||||
videoContainer.appendChild(session.rpcs[UUID].videoElement);
|
||||
container.appendChild(controls);
|
||||
|
||||
session.group.forEach(group=>{
|
||||
var ele = controls.querySelector('[data-action-type="toggle-group"][data--u-u-i-d="'+UUID+'"][data-group="'+group+'"]');
|
||||
if (!ele){
|
||||
var newGroup = htmlToElement('<button style="margin: 0 5px 10px 5px;" data-sid="'+session.rpcs[UUID].streamID+'" data--u-u-i-d="'+UUID+'" data-action-type="toggle-group" data-group="'+group+'" title="Add to Group: '+group+'" onclick="changeGroup(this, event);"><span ><i class="las la-users" style="color:#060"></i>'+group+'</span></button>');
|
||||
|
||||
var added = false;
|
||||
container.querySelectorAll('.customGroup>[data-group]').forEach(ele=>{
|
||||
log(ele);
|
||||
if (!added && ele.dataset.group>group+""){
|
||||
ele.parentNode.insertBefore(newGroup, ele);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
var newGroupCon = container.querySelector(".customGroup");
|
||||
if (!newGroupCon){
|
||||
newGroupCon = document.createElement("div");
|
||||
newGroupCon.classList.add("customGroup");
|
||||
container.appendChild(newGroupCon);
|
||||
}
|
||||
newGroupCon.appendChild(newGroup);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
initSceneList(UUID);
|
||||
pokeIframeAPI("control-box", true, UUID);
|
||||
}
|
||||
14
main.css
14
main.css
@ -277,7 +277,7 @@ button.white:active {
|
||||
}
|
||||
#header {
|
||||
width: 100%;
|
||||
margin: 1px;
|
||||
padding: 1px;
|
||||
background-color: #0F131D;
|
||||
color: #FFF;
|
||||
-webkit-app-region: drag;
|
||||
@ -1351,7 +1351,9 @@ body {
|
||||
display:block;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
div[data-action-type='toggle-group'] {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.infoblob {
|
||||
color: white;
|
||||
width: 100%;
|
||||
@ -2617,11 +2619,13 @@ button.toggleSettings{
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
|
||||
#minipreview > #videosource {
|
||||
height:auto!important;
|
||||
width:auto!important;
|
||||
max-height:100%!important;
|
||||
max-width:100%!important;
|
||||
border-radius: 0!important;
|
||||
}
|
||||
|
||||
#videoSourceSelect {
|
||||
@ -3787,9 +3791,6 @@ input:checked + .slider:before {
|
||||
margin: 0px auto 10px auto;
|
||||
}
|
||||
|
||||
.darktheme .startupWarning{
|
||||
}
|
||||
|
||||
#alertModal {
|
||||
position: absolute;
|
||||
background-color: rgb(221 221 221);
|
||||
@ -4370,3 +4371,6 @@ body.darktheme .containerGreen{
|
||||
body.darktheme .startupWarning>.las {
|
||||
color:white!important;
|
||||
}
|
||||
body.darktheme .invite_setting_group_links a {
|
||||
color:#d2e5ff!important;
|
||||
}
|
||||
116
main.js
116
main.js
@ -345,10 +345,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
|
||||
// flagship
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('broadcast') || urlParams.has('bc')) {
|
||||
log("Broadcast flag set");
|
||||
session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null;
|
||||
@ -389,6 +385,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.showList = true;
|
||||
}
|
||||
}
|
||||
if (session.showList===true){
|
||||
getById("hideusers").classList.add("hidden");
|
||||
}
|
||||
|
||||
if (urlParams.has('meshcast')) {
|
||||
session.meshcast = urlParams.get('meshcast') || "any";
|
||||
@ -398,6 +397,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
|
||||
var filename = false;
|
||||
try {
|
||||
if (!session.decrypted){
|
||||
filename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1);
|
||||
filename = filename.replace("??", "?");
|
||||
filename2 = filename.split("?")[0];
|
||||
@ -429,6 +429,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
filename = false;
|
||||
}
|
||||
log(filename);
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
@ -454,8 +455,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
session.slotmode = false; // temporary; remove in the future TODO: ## -----------------------
|
||||
if (urlParams.has('slotmode')){
|
||||
session.slotmode = parseInt(urlParams.get('slotmode')) || 1;
|
||||
if (urlParams.has('slotmode') || urlParams.has('slotsmode')){
|
||||
session.slotmode = parseInt(urlParams.get('slotmode')) || parseInt(urlParams.get('slotsmode')) || 1;
|
||||
}
|
||||
|
||||
|
||||
@ -699,6 +700,19 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('layouts')) { // an ordered array of layouts, which can be used to switch between using the API layouts action.
|
||||
// ie: ?layouts=[[{"x":0,"y":0,"w":100,"h":100,"slot":0}],[{"x":0,"y":0,"w":100,"h":100,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"slot":2}],[{"x":0,"y":0,"w":100,"h":100,"slot":3}],[{"x":0,"y":0,"w":50,"h":100,"c":false,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"z":0,"c":false,"slot":1},{"x":70,"y":70,"w":30,"h":30,"z":1,"c":true,"slot":0}],[{"x":0,"y":0,"w":50,"h":50,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":50,"c":true,"slot":1},{"x":0,"y":50,"w":50,"h":50,"c":true,"slot":2},{"x":50,"y":50,"w":50,"h":50,"c":true,"slot":3}],[{"x":0,"y":16.667,"w":66.667,"h":66.667,"c":true,"slot":0},{"x":66.667,"y":0,"w":33.333,"h":33.333,"c":true,"slot":1},{"x":66.667,"y":33.333,"w":33.333,"h":33.333,"c":true,"slot":2},{"x":66.667,"y":66.667,"w":33.333,"h":33.333,"c":true,"slot":3}]]
|
||||
try {
|
||||
session.layouts = JSON.parse(decodeURIComponent(urlParams.get('layouts'))) || JSON.parse(urlParams.get('layouts')) || {};
|
||||
} catch(e){
|
||||
try {
|
||||
session.layouts = JSON.parse(urlParams.get('layouts')) || false;
|
||||
} catch(e){
|
||||
session.layouts = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('deaf') || urlParams.has('deafen')) {
|
||||
session.directorSpeakerMuted=true; // false == true in this case.
|
||||
}
|
||||
@ -1261,6 +1275,28 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (urlParams.has('labelsuggestion') || urlParams.has('ls')) {
|
||||
session.label = urlParams.get('labelsuggestion') || urlParams.get('ls') || null;
|
||||
var updateURLAsNeed = true;
|
||||
window.focus();
|
||||
var label = await promptAlt(miscTranslations["enter-display-name"], true);
|
||||
if (label) {
|
||||
session.label = sanitizeLabel(label); // alphanumeric was too strict.
|
||||
} else {
|
||||
session.label = sanitizeLabel(session.label);
|
||||
updateURLAsNeed = false;
|
||||
}
|
||||
|
||||
document.title = session.label; // what the result is.
|
||||
|
||||
if (updateURLAsNeed) {
|
||||
var label = encodeURIComponent(session.label);
|
||||
if (urlParams.has('l')) {
|
||||
updateURL("l=" + label, true, false);
|
||||
} else {
|
||||
updateURL("label=" + label, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('transparent') || urlParams.has('transparency')) { // sets the window to be transparent - useful for IFRAMES?
|
||||
@ -1779,9 +1815,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
//innerHTML =
|
||||
}
|
||||
|
||||
if (urlParams.has('keyframeinterval') || urlParams.has('keyframeRate') || urlParams.has('keyframe') || urlParams.has('fki')) {
|
||||
if (urlParams.has('keyframeinterval') || urlParams.has('keyframerate') || urlParams.has('keyframe') || urlParams.has('fki')) {
|
||||
log("keyframeRate ENABLED");
|
||||
session.keyframeRate = parseInt(urlParams.get('keyframeinterval') || urlParams.get('keyframeRate') || urlParams.get('keyframe') || urlParams.get('fki')) || 0;
|
||||
session.keyframeRate = parseInt(urlParams.get('keyframeinterval') || urlParams.get('keyframerate') || urlParams.get('keyframe') || urlParams.get('fki')) || 0;
|
||||
}
|
||||
|
||||
if (urlParams.has('obsoff') || urlParams.has('oo') || urlParams.has('disableobs')) {
|
||||
@ -2247,6 +2283,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.groupAudio = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('groupmode') || urlParams.has('gm')) {
|
||||
session.allowNoGroup = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('host')) {
|
||||
session.roomhost = true;
|
||||
}
|
||||
@ -3329,20 +3369,19 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (session.roomid || urlParams.has('roomid') || urlParams.has('r') || urlParams.has('room') || filename || (session.permaid !== false)) {
|
||||
|
||||
var roomid = "";
|
||||
if (urlParams.has('room')) { // needs to be first; takes priority
|
||||
roomid = urlParams.get('room');
|
||||
} else if (filename) {
|
||||
roomid = filename;
|
||||
} else if (urlParams.has('roomid')) {
|
||||
roomid = urlParams.get('roomid');
|
||||
} else if (urlParams.has('r')) {
|
||||
roomid = urlParams.get('r');
|
||||
} else if (session.roomid) {
|
||||
roomid = session.roomid;
|
||||
} else if (filename) {
|
||||
roomid = filename;
|
||||
}
|
||||
session.roomid = sanitizeRoomName(roomid);
|
||||
}
|
||||
@ -3544,6 +3583,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("container-11").style.display = 'none';
|
||||
getById("container-12").style.display = 'none';
|
||||
getById("container-13").style.display = 'none';
|
||||
getById("container-14").style.display = 'none';
|
||||
getById("container-15").style.display = 'none';
|
||||
getById("mainmenu").style.alignSelf = "center";
|
||||
getById("mainmenu").classList.add("mainmenuclass");
|
||||
getById("header").style.alignSelf = "center";
|
||||
@ -4016,6 +4057,58 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
|
||||
if ("groups" in e.data) {
|
||||
if (typeof e.data.groups == "object"){
|
||||
session.group = e.data.groups || [];
|
||||
} else if (!e.data.group){
|
||||
session.group = [];
|
||||
} else {
|
||||
session.group = e.data.groups.split(",");
|
||||
}
|
||||
var eleGroup = getById("groups");
|
||||
eleGroup.querySelectorAll('[data-action-type="toggle-group"][data-group]').forEach(group=>{
|
||||
if (!(session.group && session.group.includes(group))){
|
||||
group.remove("green");
|
||||
}
|
||||
});
|
||||
|
||||
if (session.group){
|
||||
session.group.forEach(group =>{
|
||||
|
||||
var ele = eleGroup.querySelector('[data-action-type="toggle-group"][data-group="'+group+'"');
|
||||
if (!ele){
|
||||
ele = document.createElement("div");
|
||||
ele.dataset.actionType = "toggle-group";
|
||||
ele.dataset.group = group;
|
||||
ele.classList.add('float');
|
||||
ele.style.display = "inline-block";
|
||||
ele.role = "button";
|
||||
ele.innerHTML = '<i class="my-float las la-users" aria-hidden="true"></i><br />'+group;
|
||||
eleGroup.appendChild(ele);
|
||||
ele.onclick = function(){
|
||||
changeGroupDirectorAPI(this.dataset.group);
|
||||
}
|
||||
}
|
||||
ele.classList.add("green");
|
||||
});
|
||||
}
|
||||
|
||||
updateMixer();
|
||||
|
||||
if (session.group.length || session.allowNoGroup){
|
||||
session.sendMessage({"group":session.group.join(",")});
|
||||
if (session.screenShareState && (session.screenshareType ===3)){
|
||||
session.sendMessage({"group":session.group.join(","), altUUID:true});
|
||||
}
|
||||
} else {
|
||||
session.sendMessage({"group":false});
|
||||
if (session.screenShareState && (session.screenshareType ===3)){
|
||||
session.sendMessage({"group":false, altUUID:true});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ("mute" in e.data) {
|
||||
if (e.data.mute === true) { // unmute
|
||||
session.speakerMuted = true; // set
|
||||
@ -4314,7 +4407,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
stats.total_inbound_connections = Object.keys(session.rpcs).length;
|
||||
for (var i in session.rpcs) {
|
||||
stats.inbound_stats[session.rpcs[i].streamID] = session.rpcs[i].stats;
|
||||
console.log(stats);
|
||||
}
|
||||
for (var uuid in session.pcs) {
|
||||
setTimeout(function(UUID) {
|
||||
|
||||
21
mixer.html
21
mixer.html
@ -867,19 +867,19 @@
|
||||
<div class="center-content">
|
||||
<div class="title"><h1 class="main-heading">Mixer App</h1><h2>Video chat with custom <b>layouts</b></h2></div>
|
||||
|
||||
<label for="roomname"><input name="roomname" id="roomname" type="text" placeholder="Room Name" /></label>
|
||||
<label for="roomname"><input name="roomname" autocorrect="off" autocapitalize="off" id="roomname" type="text" placeholder="Room Name" /></label>
|
||||
<font class="tooltip">
|
||||
<button onclick="randomRoomName();" class="randomRoomName"></button><span class="tooltiptext">Generate a random room name</span>
|
||||
</font>
|
||||
<br />
|
||||
<label for="roompassword"><input name="roompassword" id="roompassword" type="text" placeholder="Room Password (optional)"/></label><br />
|
||||
<label for="roompassword"><input name="roompassword" autocorrect="off" autocapitalize="off" id="roompassword" type="text" placeholder="Room Password (optional)"/></label><br />
|
||||
<button onclick="startRoom();">Get started!</button><br /><br />
|
||||
<span id="lastSavedRoom" class="hidden">
|
||||
<br /><br />
|
||||
<label for="savedroomname">
|
||||
<input name="savedroomname" id="savedroomname" type="text" disabled placeholder="Room Name" /></label>
|
||||
<input name="savedroomname" autocorrect="off" autocapitalize="off" id="savedroomname" type="text" disabled placeholder="Room Name" /></label>
|
||||
<label for="savedroompassword" id="savedpasswordlabel"><br />
|
||||
<input name="savedroompassword" id="savedroompassword" disabled type="password" placeholder="Room Password"/></label>
|
||||
<input name="savedroompassword" autocorrect="off" autocapitalize="off" id="savedroompassword" disabled type="password" placeholder="Room Password"/></label>
|
||||
<button onclick="startLastRoom();">Restore last room</button>
|
||||
</span>
|
||||
<br /><br />
|
||||
@ -1068,7 +1068,7 @@
|
||||
var assignSlotToGuest = true;
|
||||
var toggleLabel = false;
|
||||
var toggleBroadcast = true;
|
||||
|
||||
var messageList = [];
|
||||
var password = false;
|
||||
if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) {
|
||||
password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p');
|
||||
@ -1966,7 +1966,7 @@
|
||||
roomname = generateString(10);
|
||||
}
|
||||
|
||||
var iframesrc = "./index.html?novice<b=350&transparent&hideheader&hidetranslate&cleandirector&chatbutton=0&director="+roomname+additional+additional2+"&b64css="+injectCSS;
|
||||
var iframesrc = "./index.html?novice&showdirector<b=350&transparent&hideheader&hidetranslate&cleandirector&chatbutton=0&director="+roomname+additional+additional2+"&b64css="+injectCSS;
|
||||
|
||||
if (roomname!==false){
|
||||
setStorage("savedRoom", {roomname:roomname,password:password}, 9999);
|
||||
@ -2112,6 +2112,15 @@
|
||||
|
||||
//console.log(e.data);
|
||||
|
||||
if ("gotChat" in e.data){
|
||||
messageList.push(e.data.gotChat);
|
||||
messageList = messageList.slice(-100);
|
||||
updateMessages(e.data.gotChat);
|
||||
} else if ("messageList" in e.data){
|
||||
messageList = e.data.messageList;
|
||||
updateMessages();
|
||||
}
|
||||
|
||||
if ("action" in e.data){
|
||||
///var outputWindow = document.createElement("div");
|
||||
//outputWindow.innerHTML = "event: "+e.data.action+"<br />";
|
||||
|
||||
@ -59,6 +59,14 @@
|
||||
Check out <a href="https://youtu.be/je2ljlvLzlY" target="_blank" style='color:#DEF;'>this Youtube video</a> for more details and solutions to reduce packet loss if suffering from any.
|
||||
</li>
|
||||
</ol>
|
||||
<h2>Unsupervised guest check option</h2>
|
||||
<span style="margin:5px;line-height:32px;font-size:110%;">
|
||||
You can also use <a target="_blank" style="color: #CCC;" href='./check.html'>this tool</a> to have a guest perform a system and connection test, with those results being available to you via a result's page for up to a week.<br />
|
||||
You can either ask the remote guest to send you the link to their results page when they complete the test, or you can use <i style="color: #CCF;" >check.html?id=xxx</i> to pre-assign the test ID (ie: xxx), which will have the results then be available at <i style="color: #CCF;" >results.html?id=xxx</i>.
|
||||
<br />If you have questions, <a href="https://discord.vdo.ninja" style="color: #CCC;" target="_blank">join the Discord here</a>.
|
||||
</span>
|
||||
<br />
|
||||
<h3>More testing options below</h3>
|
||||
<div id="screen" style="color: #CCC; margin:10px 0;"><a href="./speedtest?screen" style="color: #CCC;">Test screen-sharing performance here</a></div>
|
||||
<div id="remote"></div>
|
||||
<br />
|
||||
|
||||
29
thirdparty/CodecsHandler.js
vendored
29
thirdparty/CodecsHandler.js
vendored
@ -301,6 +301,8 @@ var CodecsHandler = (function() {
|
||||
return defaultBitrate;
|
||||
}
|
||||
|
||||
var codecDetails = findLine(sdpLines, 'a=fmtp:'+codecPayload);
|
||||
|
||||
var rtxIndex = findLine(sdpLines, 'a=rtpmap', 'rtx/90000');
|
||||
var rtxPayload;
|
||||
if (rtxIndex) {
|
||||
@ -311,7 +313,13 @@ var CodecsHandler = (function() {
|
||||
return defaultBitrate;
|
||||
}
|
||||
|
||||
var rtxFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + rtxPayload.toString());
|
||||
var rtxFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + codecPayload.toString());
|
||||
if (rtxFmtpLineIndex !== null) {
|
||||
try {
|
||||
var maxBitrate = parseInt(sdpLines[rtxFmtpLineIndex].split("x-google-max-bitrate=")[1].split(";")[0]);
|
||||
var minBitrate = parseInt(sdpLines[rtxFmtpLineIndex].split("x-google-min-bitrate=")[1].split(";")[0]);
|
||||
} catch(e){
|
||||
rtxFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + codecPayload.toString());
|
||||
if (rtxFmtpLineIndex !== null) {
|
||||
try {
|
||||
var maxBitrate = parseInt(sdpLines[rtxFmtpLineIndex].split("x-google-max-bitrate=")[1].split(";")[0]);
|
||||
@ -319,6 +327,10 @@ var CodecsHandler = (function() {
|
||||
} catch(e){
|
||||
return defaultBitrate;
|
||||
}
|
||||
} else {
|
||||
return defaultBitrate;
|
||||
}
|
||||
}
|
||||
|
||||
if (minBitrate>maxBitrate){
|
||||
maxBitrate = minBitrate;
|
||||
@ -328,12 +340,9 @@ var CodecsHandler = (function() {
|
||||
} else {
|
||||
return defaultBitrate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setVideoBitrates(sdp, params, codec) { // modified + Improved by Steve.
|
||||
function setVideoBitrates(sdp, params = false, codec=false) { // modified + Improved by Steve.
|
||||
|
||||
if (codec){
|
||||
codec = codec.toUpperCase();
|
||||
@ -358,9 +367,15 @@ var CodecsHandler = (function() {
|
||||
codec = codecName || codec; // Try to find first Codec; else use expected/default
|
||||
|
||||
params = params || {};
|
||||
var min_bitrate = params.min.toString() || '30';
|
||||
var max_bitrate = params.max.toString() || '2500';
|
||||
|
||||
var min_bitrate = "30";
|
||||
if (params.min){
|
||||
min_bitrate = params.min.toString() || '30';
|
||||
}
|
||||
var max_bitrate = "2500";
|
||||
if (params.max){
|
||||
max_bitrate = params.max.toString() || '2500';
|
||||
}
|
||||
|
||||
var codecIndex = findLine(sdpLines, 'a=rtpmap', codec+'/90000');
|
||||
var codecPayload;
|
||||
|
||||
3514
thirdparty/adapter.js
vendored
Normal file
3514
thirdparty/adapter.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11
thirdparty/adapter.min.js
vendored
11
thirdparty/adapter.min.js
vendored
File diff suppressed because one or more lines are too long
2
thirdparty/jeeliz/JeelizThreeHelper.js
vendored
2
thirdparty/jeeliz/JeelizThreeHelper.js
vendored
@ -126,7 +126,7 @@ const JeelizThreeHelper = (function(){
|
||||
|
||||
const videoGeometry = new THREE.BufferGeometry()
|
||||
const videoScreenCorners = new Float32Array([-1,-1, 1,-1, 1,1, -1,1]);
|
||||
videoGeometry.addAttribute( 'position', new THREE.BufferAttribute( videoScreenCorners, 2 ) );
|
||||
videoGeometry.setAttribute( 'position', new THREE.BufferAttribute( videoScreenCorners, 2 ) );
|
||||
videoGeometry.setIndex(new THREE.BufferAttribute(new Uint16Array([0,1,2, 0,2,3]), 1));
|
||||
_threeVideoMesh = new THREE.Mesh(videoGeometry, videoMaterial);
|
||||
that.apply_videoTexture(_threeVideoMesh);
|
||||
|
||||
@ -378,8 +378,8 @@
|
||||
"animate-mixing": "Animate mixing",
|
||||
"prefix-screenshare": "Prefix screenshare IDs",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\nWelcome! You can send text messages directly to connected peers from here.\n",
|
||||
"privacy-disabled": "Privacy warning: The director will be able to remotely access your camera and microphone if you continue.",
|
||||
"welcome-to-vdo-ninja-chat": "\nWelcome! You can send text messages directly to connected peers from here.\n",
|
||||
"privacy-disabled": "Privacy warning: The director will be able to remotely change which camera and microphone is being used while this page is open, if you continue.",
|
||||
"face-mesh": "Face mesh (slow load)",
|
||||
"anonymous-mask": "Anonymous mask",
|
||||
"dog-face": "Dog ears and nose",
|
||||
|
||||
@ -394,7 +394,7 @@
|
||||
"animate-mixing": "动画合成",
|
||||
"prefix-screenshare": "前缀屏幕共享 ID",
|
||||
"more-than-four-can-join": "这四个客人位置仅用于演示。一个房间可以容纳四位以上的客人。",
|
||||
"welcome-to-obs-ninja-chat": "\n欢迎!您可以从此处直接向连接的对等方发送文本信息。\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n欢迎!您可以从此处直接向连接的对等方发送文本信息。\n",
|
||||
"privacy-disabled": "隐私警告:如果您继续,房管将能够远程访问您的摄像头和麦克风。",
|
||||
"face-mesh": "面网格(缓慢加载)",
|
||||
"anonymous-mask": "匿名面具",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Povolit administrátorovi Push-to-Talk mód",
|
||||
"welcome-to-control-room": "Welcome. This is the control-room for the group-chat. There are different things you can use this room for:<br><br>\t<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>\t<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>\t<li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li>\t<li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li>\t<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>\t<li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li>\t<li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li>\t<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li>\t<br>\tAs guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\t<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>\tFor advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "Tyto čtyři sloty pro hosty slouží pouze k předvedení. K místnosti se mohou skutečně připojit více než čtyři hosté.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tVítejte na VDO.Ninja! můžete ihned poslat zprávy ostatním členům této místnosti\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tVítejte na VDO.Ninja! můžete ihned poslat zprávy ostatním členům této místnosti\n",
|
||||
"names-and-labels-coming-soon": "\n\tJména členů bude jedna z budoucích funkcí VDO.ninja.\n",
|
||||
"send-chat": "Poslat",
|
||||
"available-languages": "Dostupné jazyky:",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Audio und Video mit Gästen teilen (Push-to-Talk Mode)",
|
||||
"welcome-to-control-room": "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><li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li><li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li><li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li><li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li><li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li><li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li><br>As guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>For advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\nWillkommen zu VDO.Ninja! Schicken Sie anderen Gästen eine Message.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\nWillkommen zu VDO.Ninja! Schicken Sie anderen Gästen eine Message.\n",
|
||||
"names-and-labels-coming-soon": "\nNames identifying connected peers will be a feature in an upcoming release.\n",
|
||||
"send-chat": "Abschicken",
|
||||
"available-languages": "Verfügbare Sprachen:",
|
||||
|
||||
@ -361,7 +361,7 @@
|
||||
"toggle-control-video": "Toggle control bar",
|
||||
"picture-in-picture": "Picture-in-picture",
|
||||
"chrome-cast": "Cast..",
|
||||
"welcome-to-obs-ninja-chat": "\nWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\nWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"send-chat": "Send",
|
||||
"apply-new-guest-settings": "Apply settings",
|
||||
"cancel": "Cancel",
|
||||
|
||||
@ -384,7 +384,7 @@
|
||||
"application-audio-capture": "Para capturar el audio especifico de una aplicación, <a href=\"https://docs.vdo.ninja/audio\" style=\"color: #007AC8;\">vea aquí</a>",
|
||||
"animate-mixing": "Animar",
|
||||
"prefix-screenshare": "Prefijo de ID de pantalla compartida ",
|
||||
"welcome-to-obs-ninja-chat": "\n\t¡Bienvenido a VDO.Ninja! Desde aquí puede enviar mensajes de texto para conectar mejor a sus amigos.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\t¡Bienvenido a VDO.Ninja! Desde aquí puede enviar mensajes de texto para conectar mejor a sus amigos.\n",
|
||||
"privacy-disabled": "Advertencia de Privacidad: El Director podra acceder a la Cámara y al Microfono si continua",
|
||||
"face-mesh": "Mapeado de la cara (Carga lento)",
|
||||
"anonymous-mask": "Mascara de Anonymous",
|
||||
|
||||
@ -410,7 +410,7 @@
|
||||
"click-start-to-join": "Click Start to Join",
|
||||
"waiting-for-mic-to-load": "Waiting for mic to load",
|
||||
"waiting-for-camera-to-load": "Waiting for Camera to load",
|
||||
"welcome-to-obs-ninja-chat": "\n\tWelcome! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tWelcome! You can send text messages directly to connected peers from here.\n",
|
||||
"please-select-option-to-join": "Please select an option to join.",
|
||||
"show-controls-video": "Show control bar",
|
||||
"hide-controls-video": "Hide control bar",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Permettre à l'administrateur d'utiliser le push-to-talk",
|
||||
"welcome-to-control-room": "Welcome. This is the control-room for the group-chat. There are different things you can use this room for:<br><br>\t<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>\t<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>\t<li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li>\t<li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li>\t<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>\t<li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li>\t<li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li>\t<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li>\t<br>\tAs guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\t<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>\tFor advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"names-and-labels-coming-soon": "\n\tNames identifying connected peers will be a feature in an upcoming release.\n",
|
||||
"send-chat": "Send",
|
||||
"available-languages": "Options de langues disponibles :",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Abilita Director's Push-to-Talk Mode",
|
||||
"welcome-to-control-room": "Benvenuto. Questa è la sala di controllo per la chat di gruppo. Ci sono diverse cose per cui puoi usare questa stanza:<br><br>\t<li>Puoi ospitare una chat di gruppo con gli amici utilizzando una stanza. Condividi il link blu per invitare gli ospiti che si uniranno automaticamente alla chat.</li>\t<li>Una sala per gruppi può ospitare da 4 a 30 persone, a seconda di numerosi fattori, tra cui CPU e larghezza di banda disponibile di tutti gli ospiti nella stanza.</li>\t<li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li>\t<li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li>\t<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>\t<li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li>\t<li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li>\t<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li>\t<br>\tAs guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\t<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>\tFor advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tBenvenuto in VDO.Ninja! Da qui puoi inviare messaggi di testo direttamente ai peer connessi.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tBenvenuto in VDO.Ninja! Da qui puoi inviare messaggi di testo direttamente ai peer connessi.\n",
|
||||
"names-and-labels-coming-soon": "\n\tI nomi che identificano i peer connessi saranno una funzionalità in una prossima versione..\n",
|
||||
"send-chat": "Invia",
|
||||
"available-languages": "Lingue Disponibili:",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Enable Director's Push-to-Talk Mode",
|
||||
"welcome-to-control-room": "Welcome. This is the control-room for the group-chat. There are different things you can use this room for:<br><br>\t<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>\t<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>\t<li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li>\t<li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li>\t<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>\t<li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li>\t<li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li>\t<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li>\t<br>\tAs guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\t<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>\tFor advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"names-and-labels-coming-soon": "\n\tNames identifying connected peers will be a feature in an upcoming release.\n",
|
||||
"send-chat": "Send",
|
||||
"available-languages": "Available Languages:",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Enable Director's Push-to-Talk Mode Zet ",
|
||||
"welcome-to-control-room": "Welcome. This is the control-room for the group-chat. There are different things you can use this room for:<br><br>\t<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>\t<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>\t<li>Solo-views of each video are offered under videos as they load. These can be used within an OBS Browser Source.</li>\t<li>You can use the auto-mixing Group Scene, the green link, to auto arrange multiple videos for you in OBS.</li>\t<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>\t<li>Videos in the Director's room will be of low quality on purpose; to save bandwidth/CPU</li>\t<li>Guest's in the room will see each other's videos at a very limited quality to conserve bandwidth/CPU.</li>\t<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps.</li>\t<br>\tAs guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\t<br>The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br><br>Apple mobile devices, such as iPhones and iPads, do not fully support Video Group Chat. This is a hardware constraint.<br><br>\tFor advanced options and parameters, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">see the Wiki.</a>",
|
||||
"more-than-four-can-join": "Er staan momenteel vier gasten plekken gevuld voor de demonstratie. Het is mogelijk om meer gasten te hebben in een kamer.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"names-and-labels-coming-soon": "\n\tNames identifying connected peers will be a feature in an upcoming release.\n",
|
||||
"send-chat": "Verstuur",
|
||||
"available-languages": "Beschikbare talen:",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": " Enable Director's Push-to-Talk Mode",
|
||||
"welcome-to-control-room": "\n\tErehay ouyay ancay epray-enerategay\n",
|
||||
"more-than-four-can-join": "Erehay ouyay ancay epray-enerategay.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tErehay ouyay ancay epray-enerategay.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tErehay ouyay ancay epray-enerategay.\n",
|
||||
"names-and-labels-coming-soon": "\n\tErehay ouyay ancay epray-enerategay.\n",
|
||||
"send-chat": "Erehay ouyay ancay epray-enerategay",
|
||||
"available-languages": "AErehay ouyay ancay epray-enerategay:",
|
||||
|
||||
@ -218,7 +218,7 @@
|
||||
"waiting-for-camera-to-load": "Aguardando a câmera carregar",
|
||||
"waiting-for-mic-to-load": "Aguardando o microfone carregar",
|
||||
"welcome-to-control-room": "\n<b>Bem-vindo. Esta é a sala de controle do diretor para o bate-papo em grupo.</b><br><br>\nVocê pode hospedar um bate-papo em grupo com amigos usando uma sala. Compartilhe o link azul para convidar as pessoas que participarão do bate-papo automaticamente.\n<br><br>\nUma sala de grupo pode lidar normalmente com cerca de 6 a 20 convidados, dependendo de vários fatores, incluindo CPU e largura de banda disponível de todos os convidados na sala\n",
|
||||
"welcome-to-obs-ninja-chat": "\nBem-vindo! Você pode enviar mensagens de texto diretamente para as pessoas conectadas a partir daqui.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\nBem-vindo! Você pode enviar mensagens de texto diretamente para as pessoas conectadas a partir daqui.\n",
|
||||
"you-are-in-the-control-center": "Centro de controle para sala:",
|
||||
"you-are-using-headphones-earphones": "Você está usando headphones/fones de ouvido",
|
||||
"your-connection-is-hardwired-instead-of-wifi": "Sua conexão é cabeada em vez de Wi-Fi",
|
||||
|
||||
@ -288,7 +288,7 @@
|
||||
"push-to-talk-enable": "🔊 Ativar Push-to-talk do realizador",
|
||||
"welcome-to-control-room": "Bem-vindo. Esta é a sala de controlo para o chat de grupo. Há diferentes coisas que pode fazer aqui:<br><br>\t<li>Pode hospedar um chat de grupo com amigos. Partilhe o link azul para os convidados se juntarem ao chat de forma automática.</li>\t<li>Uma sala de grupo pode hospedar entre 4 a 30 4 to 30 convidados, dependendo de inúmeros factores, incluindo CPU e largura de banda de todos os convidados na sala.</li>\t<li>Visualizações individuais de cada vídeo serão mostradas quando carregam. Estas podem ser usadas em Fontes do tipo Browser no OBS.</li>\t<li>Pode usar a cena de grupo automática, o link verde, para dispôr automaticamente os vídeos por si no OBS.</li>\t<li>Pode usar esta sala de controlo para gravar streams isolados de vídeo ou áudio, mas isto é ainda experimental.</li>\t<li>Vídeos na sala de controle são de baixa qualidade propositadamente; para poupar largura de banda/CPU</li>\t<li>Convidados na sala irão ver-se numa qualidade muito reduzida para conservar largura de banda/CPU.</li>\t<li>OBS tem acesso ao vídeo do convidado em alta qualidade; o bitrate de vídeo por omissão é 2500kbps.</li>\t<br>\tÀ medida que os convidados entram, os seus vídeos são mostrados abaixo. Pode levar os seus sinais para o OBS como cenas individuais ou pode adicioná-los à cena de grupo.\t<br>A Cena de grupo auto-mistura vídeos que lhe forem adicionados. Note que a auto-mistura requer que os convidados sejam manualmente adicionados; não são adicionados automaticamente.<br><br>Dispositivos móveis Apple, como iPhones e iPads, não suportam totalmente o Chat de Grupo. Este é um constrangimento de hardware.<br><br>\tPara opções avançadas e parâmetros, <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">veja o Wiki.</a>",
|
||||
"more-than-four-can-join": "Estes quatro convidados são apenas ilustrativos. Podem juntar-se mais de quatro convidados numa sala.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tBem vindo ao VDO.Ninja! Pode enviar mensagens diretas a quem estiver aqui ligado a partir daqui.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tBem vindo ao VDO.Ninja! Pode enviar mensagens diretas a quem estiver aqui ligado a partir daqui.\n",
|
||||
"names-and-labels-coming-soon": "\n\tNomes a identificar as ligações será uma funcionalidade futura.\n",
|
||||
"send-chat": "Enviar",
|
||||
"available-languages": "Línguas disponíveis:",
|
||||
|
||||
@ -415,7 +415,7 @@
|
||||
"animate-mixing": "Анимированный переход",
|
||||
"prefix-screenshare": "Prefix screenshare IDs",
|
||||
"more-than-four-can-join": "Этот шаблон на 4 гостей только для демонстрации. Гостей может быть больше.",
|
||||
"welcome-to-obs-ninja-chat": "Пожалуйста, сделайте все возможное, чтобы немедленно остановить эту кровавую войну! Иначе завтра может не быть",
|
||||
"welcome-to-vdo-ninja-chat": "Пожалуйста, сделайте все возможное, чтобы немедленно остановить эту кровавую войну! Иначе завтра может не быть",
|
||||
"privacy-disabled": "Ведущий сможет удаленно управлять вашим микрофоном и камерой.",
|
||||
"face-mesh": "Face mesh (slow load)",
|
||||
"anonymous-mask": "Маска анонимуса",
|
||||
|
||||
@ -309,7 +309,7 @@
|
||||
"push-to-talk-enable": "🔊 Yönetmen bas-konuş'u etkinleştir",
|
||||
"welcome-to-control-room": "Hoş geldiniz. Bu grup konuşması için kontrol odasıdır. Bu odayı farklı amaçlar için kullanabilirsiniz:<br><br>\t<li>Arkadaşlarınız ile grup konunşması yapmak için bir oda kullanabilirsiniz. Otomatik olarak gruba dahil etmek için misafirleriniz ile mavi bağlantıyı paylaşın.</li>\t<li>Bir grup odası 4 - 30 sayıda misafir ağırlayabilir. Ancak bu bir çok etkene göre değişebilir, yeterli CPU ve internet bant genişliği gibi.</li>\t<li>Her videonun tekil görüntüsü bağlantıları misafirler bağlandıkça videolarının altında yer alacak. Bunları OBS tarayıcı kaynağı olarak kullanabilirsiniz.</li>\t<li>Otomatik-karıştırma grup sahnesi (yeşil bağlantı) bir çok videoyu OBS'de otomatik ayarlamak için kullanabilirsiniz.</li>\t<li>Bu odayı kullanarak her bir video için ayrı ayrı video ve ses kaynaklarını kaydedebilirsiniz, ancak bu özellik halen deneysel aşamadadır.</li>\t<li>Yönetmen odasında yer alan videolar kasten düşük kalitede tutulmuştur; CPU ve internetbant genişliğinden tasarruf için</li>\t<li>Odada yer alan misafirler, CPU ve internetten tasarruf etmek amacıyla bir birlerinin videolarını düşük kalitede görecek.</li>\t<li>OBS misafirlerin videolarını çok yüksek kalitede alacak, varsayılan kalite 2500kbps'dir.</li>\t<br>\tMisafirler eklendikçe videoları aşağıda belirecek. OBS'ye videolarını tekil sahneler olarak ekleyebilir, ya da grup sahnelerine ekleyebilirsiniz.\t<br>Grup sahnesi, eklenmiş videoları otomatik olarak karıştırır. Otomatik karıştırmanın çalışması için misafirlerin el ile bu sahneye eklenmesi gerektiğini unutmayın; otomatik olarak sahnelere eklenmeyeceklerdir.<br><br>iPhone iPad gibi Apple mobil cihazlar, tam olarak video grup görüşmeyi desteklemiyor. Bu bir donanım sınırlamasıdır.<br><br>\tGekişmiş özellik ve parametreler için <a href=\"https://github.com/steveseguin/vdo.ninja/wiki/Guides-and-How-to's#urlparameters\">Wiki'ye göz atın.</a>",
|
||||
"more-than-four-can-join": "These four guest slots are just for demonstration. More than four guests can actually join a room.",
|
||||
"welcome-to-obs-ninja-chat": "\n\tVDO.Ninja'ya hoş geldin! Bağlı olan kişilere buradan yazılı mesajlar gönderebilirsin.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tVDO.Ninja'ya hoş geldin! Bağlı olan kişilere buradan yazılı mesajlar gönderebilirsin.\n",
|
||||
"names-and-labels-coming-soon": "\n\tBağlanan kişileri tanımlayan isimler ileriki bir geliştirmede yer alacak.\n",
|
||||
"send-chat": "Gönder",
|
||||
"available-languages": "Diller:",
|
||||
|
||||
@ -319,7 +319,7 @@
|
||||
"advanced-camera-settings": "<i class=\"las la-sliders-h\"></i> Відео налаштування",
|
||||
"open-in-new-tab": "Відкрити у новій закладинці",
|
||||
"copy-to-clipboard": "Скопіювати у буфер",
|
||||
"welcome-to-obs-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "\n\tWelcome to VDO.Ninja! You can send text messages directly to connected peers from here.\n",
|
||||
"names-and-labels-coming-soon": "\n\tNames identifying connected peers will be a feature in an upcoming release.\n",
|
||||
"send-chat": "Надіслати",
|
||||
"available-languages": "Доступні мови:",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user