mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-13 06:38:29 +00:00
mixer updates + &relay fix
This commit is contained in:
parent
d1ff359c60
commit
b66a7ac3f3
134
index.html
134
index.html
@ -56,7 +56,7 @@
|
||||
<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=314" />
|
||||
<link rel="stylesheet" href="./main.css?ver=324" />
|
||||
<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" /> -->
|
||||
@ -83,7 +83,7 @@
|
||||
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=47"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=625"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=631"></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">
|
||||
@ -248,7 +248,7 @@
|
||||
id="reportbutton"
|
||||
title="Submit any error logs"
|
||||
onclick="submitDebugLog();"
|
||||
style="cursor: pointer; display:none;z-index:3;"
|
||||
style="cursor: pointer;z-index:3;display:none;"
|
||||
class="hidden"
|
||||
>
|
||||
<i style="cursor: pointer; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-bug" aria-hidden="true"></i>
|
||||
@ -369,6 +369,7 @@
|
||||
<ul style="max-width: 500px; display: none; text-align: left;" class="roomnotes" id="roomnotes">
|
||||
<span data-translate="added-notes" >
|
||||
<i>Important Tips:</i>
|
||||
<br><br>
|
||||
<li>Disabling video sharing between guests will improve performance</li>
|
||||
<li>Invite only guests to the room that you trust.</li>
|
||||
<li>The "Recording" option is considered experimental.</li>
|
||||
@ -425,7 +426,7 @@
|
||||
<div class="title">
|
||||
<i class="las la-video"></i><span data-translate="video-source"> Video Source </span>
|
||||
</div>
|
||||
<span style="display:flex;align-items: center;">
|
||||
<span style="display:inline-block;padding-top: 5px;">
|
||||
<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>
|
||||
@ -486,7 +487,7 @@
|
||||
<div id="headphonesDiv" class="audioMenu">
|
||||
<div class="title">
|
||||
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination
|
||||
</span><button onclick="playtone()" class="white" style="padding: 2px 10px;" type="button">Test</button></div>
|
||||
</span><button id="testtonebutton" onclick="playtone()" class="white" type="button">Test</button></div>
|
||||
<select id="outputSource" alt="Audio output device" ></select>
|
||||
<div id="headphoneTip1" class="cameraTip hidden">
|
||||
<i class="las la-info-circle"></i>
|
||||
@ -586,7 +587,7 @@
|
||||
<video id="screenshare" autoplay="true" muted="true" loop src="./media/screenshare.webm" class="lazy" style='background-image: unset;'></video>
|
||||
</span>
|
||||
<br />
|
||||
<button class='gobutton' style="padding: 10px; font-size: 120%;" alt="clilck to select you screen to share" onclick="publishScreen()">
|
||||
<button class='gobutton' style="padding: 10px; font-size: 120%;animation: pulsate 2s ease-out infinite;" alt="clilck to select you screen to share" onclick="publishScreen()">
|
||||
<span data-translate="select-screen-to-share">SELECT SCREEN TO SHARE</span>
|
||||
</button>
|
||||
<span id="gear_screen" style="display: inline-block; cursor: pointer;" onclick="toggle(document.getElementById('videoSettings2'));">
|
||||
@ -821,7 +822,7 @@
|
||||
|
||||
<div id="container-6" class="column columnfade pointer rounded card hidden" style=" overflow-y: auto;">
|
||||
<h2><span data-translate="share-website-iframe">Share Website</span></h2>
|
||||
<i style="margin-top:30px;font-size:560%;overflow:hidden;" class="las la-broadcast-tower"></i>
|
||||
<i style="margin-top:30px;font-size:560%;overflow:hidden;" class="largeDarkIcon las la-broadcast-tower"></i>
|
||||
<div class="container-inner">
|
||||
<br />
|
||||
<div id="previewIframe"></div>
|
||||
@ -852,47 +853,47 @@
|
||||
|
||||
<div id="container-7" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = './speedtest.html';">
|
||||
<h2><span data-translate="run-a-speed-test">Run a Speed Test</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-tachometer-alt"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-tachometer-alt"></i>
|
||||
</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">Custom Mixed Layouts</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-blender"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon 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">Multi-Stream Monitor</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-gamepad"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-gamepad"></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">Group Voice Comms</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-comments"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-comments"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-9" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://guides.vdo.ninja';">
|
||||
<h2><span data-translate="read-the-guides">Basic Usage Guides</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-book-open"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-book-open"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-13" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://linkgen.vdo.ninja';">
|
||||
<h2><span data-translate="wizard-link-generator">Wizard Link Generator</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-hat-wizard"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-hat-wizard"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-10" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://docs.vdo.ninja';">
|
||||
<h2><span data-translate="get-full-documentation">Full Documentation</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-info"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-info"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-11" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://github.vdo.ninja';">
|
||||
<h2><span data-translate="get-the-source-code">Source Code</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-code-branch"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-code-branch"></i>
|
||||
</div>
|
||||
|
||||
<div id="container-12" class="column columnfade pointer rounded card hidden" style="overflow: hidden;" onclick="window.location = 'https://docs.vdo.ninja/getting-started/sponsor';">
|
||||
<h2><span data-translate="show-your-support">Show Your Support</span></h2>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="las la-heartbeat"></i>
|
||||
<i style="margin-top:30px;font-size:600%;overflow:hidden;" class="largeDarkIcon las la-heartbeat"></i>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
@ -1001,8 +1002,8 @@
|
||||
</label>
|
||||
<span data-translate="guests-hear-others" style="line-height:0;position:relative;top:-3px;">Guests hear others</span>
|
||||
</span>
|
||||
<button class='pull-right' style='font-size:1.15em' onclick='copyFunction(getById("director_block_1"),event)'><i class='las la-copy'></i><span data-translate="copy-link">Copy link</span></button>
|
||||
<button class='pull-right' style='font-size:1.15em' id="showCustomizerButton1" onclick='showCustomizer(1,this)'><i class='las la-tools'></i><span data-translate="customize">Customize</span></button>
|
||||
<button class='pull-right' onclick='copyFunction(getById("director_block_1"),event)'><i class='las la-copy'></i><span data-translate="copy-link">Copy link</span></button>
|
||||
<button class='pull-right' id="showCustomizerButton1" onclick='showCustomizer(1,this)'><i class='las la-tools'></i><span data-translate="customize">Customize</span></button>
|
||||
<span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1353,7 +1354,7 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<br />
|
||||
<div id="hiddenElements"></div>
|
||||
<div id='guestFeeds' style="display:none">
|
||||
<div id='deleteme'>
|
||||
<div class='vidcon directorMargins' id='fakeguest1' style='min-height: 300px;text-align: center;'><h2><span data-translate="guest-1">Guest 1</span></h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
@ -1429,7 +1430,7 @@
|
||||
<span data-translate="disconnect-guest">Hangup</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flexBreak"><span data-translate="guest-toggle">Guest Toggle</span></div>
|
||||
<div class="flexBreak"></div>
|
||||
<div class="row three">
|
||||
<button data-action-type="solo-chat" class="mainonly advanced" title="Toggle solo voice chat or hold CTRL/CMD when selecting to make it two-way private." onclick="session.toggleSoloChat(this.dataset.UUID, event);">
|
||||
<i class="las la-microphone"></i>
|
||||
@ -1439,7 +1440,7 @@
|
||||
<i class="las la-user"></i>
|
||||
<span data-translate="solo-video">Highlight</span>
|
||||
</button>
|
||||
<button data-action-type="mute-video-guest" title="Disable this guest's video track" onclick="remoteMuteVideo(this, event);">
|
||||
<button data-action-type="mute-video-guest" class="advanced" title="Disable this guest's video track" onclick="remoteMuteVideo(this, event);">
|
||||
<i class="las la-video-slash"></i>
|
||||
<span data-translate="mute-video-guest">Video off</span>
|
||||
</button>
|
||||
@ -1450,38 +1451,25 @@
|
||||
<i class="las la-user-slash"></i>
|
||||
<span data-translate="hide-guest">Hide</span>
|
||||
</button>
|
||||
<button class="mainonly" data-action-type="toggle-remote-display" title="Toggle the remote guest's display output" onclick="remoteDisplayMute(this, event);">
|
||||
<button class="mainonly advanced" data-action-type="toggle-remote-display" title="Toggle the remote guest's display output" onclick="remoteDisplayMute(this, event);">
|
||||
<i class="las la-eye-slash"></i> <span data-translate="toggle-remote-display">Blind</span>
|
||||
</button>
|
||||
<button data-action-type="addToScene" class="advanced" title="Add this Video to any remote '&scene=1'" data-scene="1" onclick="directEnable(this, event);">
|
||||
<i class="las la-plus-square"></i>
|
||||
<span data-translate="add-to-scene">add to scene 1</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flexBreak"><span data-translate="settings">Settings</span></div>
|
||||
<div class="row two">
|
||||
<!-- Further Audio/Video Settings -->
|
||||
<div class="row two settingsWrapper" data-cluster="3">
|
||||
<button data-action-type="advanced-audio-settings" data-active="false" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
|
||||
<i class="las la-sliders-h"></i>
|
||||
<span data-translate="advanced-audio-settings">Audio</span>
|
||||
</button>
|
||||
<button class="mainonly" data-action-type="advanced-camera-settings" data-active="false" title="Advanced Video Settings" onclick="requestVideoSettings(this);">
|
||||
<i class="las la-sliders-h"></i>
|
||||
<span data-translate="advanced-camera-settings">Video</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class='row one hidden advancedAudioSettings'></div>
|
||||
<div class='row one hidden advancedVideoSettings'></div>
|
||||
<div class="flexBreak"><span data-translate="more">More</span></div>
|
||||
<button class="hideDropMenu" onclick="toggleByDataset('1');getById('chevarrow3').classList.toggle('bottom');getById('chevarrow3').classList.toggle('right');">
|
||||
<i id="chevarrow3" style="padding:0px 7px 0 3px;" class="chevron right" aria-hidden="true"></i>
|
||||
<i id="chevarrow3" class="chevron right" aria-hidden="true"></i>
|
||||
<span data-translate="scene-options">Scene options</span>
|
||||
</button>
|
||||
<div class="group hidden" data-cluster="1">
|
||||
<!-- Scene Controls -->
|
||||
<div class="row two">
|
||||
<button data-action-type="addToScene" class="advanced" title="Add this Video to any remote '&scene=1'" data-scene="1" onclick="directEnable(this, event);">
|
||||
<i class="las la-plus-square"></i>
|
||||
<span data-translate="add-to-scene">add to scene 1</span>
|
||||
</button>
|
||||
<button data-action-type="addToScene" class="advanced" title="Add this Video to any remote '&scene=2'" data-scene="2" onclick="directEnable(this, event);">
|
||||
<i class="las la-plus-square"></i>
|
||||
<span data-translate="add-to-scene2">add to scene 2</span>
|
||||
</button>
|
||||
<button data-action-type="mute-scene" title="Remotely Mute this Audio in all remote '&scene' views" onclick="directMute(this, event);">
|
||||
<i class="las la-microphone-slash"></i>
|
||||
<span data-translate="mute-scene">mute in scenes</span>
|
||||
@ -1490,24 +1478,24 @@
|
||||
|
||||
<!-- Row of Scenes -->
|
||||
<div class="row six advanced">
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="2" title="Add to Scene 2" onclick="directEnable(this, event);">
|
||||
<span>S2</span>
|
||||
</button>
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="3" title="Add to Scene 3" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" data-scene="3" title="Add to Scene 3" onclick="directEnable(this, event);">
|
||||
<span>S3</span>
|
||||
</button>
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="4" title="Add to Scene 4" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" data-scene="4" title="Add to Scene 4" onclick="directEnable(this, event);">
|
||||
<span>S4</span>
|
||||
</button>
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="5" title="Add to Scene 5" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" data-scene="5" title="Add to Scene 5" onclick="directEnable(this, event);">
|
||||
<span>S5</span>
|
||||
</button>
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="6" title="Add to Scene 6" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" data-scene="6" title="Add to Scene 6" onclick="directEnable(this, event);">
|
||||
<span>S6</span>
|
||||
</button>
|
||||
<button class="btn-HL-peach" data-action-type="addToScene" data-scene="7" title="Add to Scene 7" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" data-scene="7" title="Add to Scene 7" onclick="directEnable(this, event);">
|
||||
<span>S7</span>
|
||||
</button>
|
||||
<button data-action-type="addToScene" data-scene="8" title="Add to Scene 8" onclick="directEnable(this, event);">
|
||||
<span>S8</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button data-action-type="stats-remote" title="Request the statistics of this video in any active scene" onclick="toggleSceneStats(this);">
|
||||
@ -1532,8 +1520,8 @@
|
||||
</div>
|
||||
|
||||
<button class="hideDropMenu" onclick="toggleByDataset('2');getById('chevarrow4').classList.toggle('bottom');getById('chevarrow4').classList.toggle('right');">
|
||||
<i id="chevarrow4" class="chevron right" aria-hidden="true" style="padding:0px 7px 0 3px;" ></i>
|
||||
<span data-translate="additional-controls">Controls</span>
|
||||
<i id="chevarrow4" class="chevron right" aria-hidden="true" ></i>
|
||||
<span data-translate="additional-controls">Additional Controls</span>
|
||||
</button>
|
||||
<div class="group hidden" data-cluster="2">
|
||||
<!-- General Controls -->
|
||||
@ -1621,6 +1609,21 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row two">
|
||||
<!-- Further Audio/Video Settings -->
|
||||
<div class="row two settingsWrapper" data-cluster="3">
|
||||
<button data-action-type="advanced-audio-settings" data-active="false" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
|
||||
<i class="las la-sliders-h"></i>
|
||||
<span data-translate="advanced-audio-settings">Audio settings</span>
|
||||
</button>
|
||||
<button class="mainonly" data-action-type="advanced-camera-settings" data-active="false" title="Advanced Video Settings" onclick="requestVideoSettings(this);">
|
||||
<i class="las la-sliders-h"></i>
|
||||
<span data-translate="advanced-camera-settings">Video settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class='row one hidden advancedAudioSettings'></div>
|
||||
<div class='row one hidden advancedVideoSettings'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1715,12 +1718,14 @@
|
||||
<div class="title">
|
||||
<i class="las la-video"></i><span data-translate="video-source"> Video Source: </span>
|
||||
</div>
|
||||
<select id="videoSource3" ></select>
|
||||
<span id="refreshVideoButton" title="Activate or Reload this video device.">
|
||||
<i style="cursor: pointer; font-size: 120%;" class="las la-sync-alt"></i>
|
||||
</span>
|
||||
<span id="gear_webcam3" style="display: none; cursor:pointer;" onclick="toggleQualityGear3();">
|
||||
<i class="las la-cog" style="font-size: 135%; top:1px; vertical-align: middle;" aria-hidden="true"></i>
|
||||
<span style="display:inline-block;">
|
||||
<select id="videoSource3" ></select>
|
||||
<span id="refreshVideoButton" title="Activate or Reload this video device.">
|
||||
<i class="las la-sync-alt"></i>
|
||||
</span>
|
||||
<span id="gear_webcam3" style="display: none; cursor:pointer;" onclick="toggleQualityGear3();">
|
||||
<i class="las la-cog" style="font-size: 135%; top:1px; vertical-align: middle;" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span id="videoSettings3" style="display: none;">
|
||||
<center>
|
||||
@ -2345,12 +2350,9 @@
|
||||
<u>
|
||||
<br />
|
||||
<a onclick="addToGoogleCalendar();" style="cursor: pointer;" data-translate='add-to-google-calendar'>Add to Google Calendar</a>
|
||||
<br />
|
||||
<a onclick="addToOutlookCalendar();" style="cursor: pointer;" data-translate='add-to-outlook-calendar'>Add to Outlook Calendar</a>
|
||||
<br />
|
||||
<a onclick="addToYahooCalendar();" style="cursor: pointer;" data-translate='add-to-yahoo-calendar'>Add to Yahoo Calendar</a>
|
||||
<br />
|
||||
<br />
|
||||
</u>
|
||||
</div>
|
||||
<span class="hidden" id="hangupTemplate">
|
||||
@ -2374,7 +2376,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 = "23.2b";
|
||||
session.version = "23.3b";
|
||||
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
|
||||
@ -2487,11 +2489,11 @@
|
||||
// session.hidehome = true; // If used, 'hide home' will make the landing page inaccessible, along with hiding a few go-home elements.
|
||||
// session.record = false; // uncomment to block users from being able to record via vdo.ninja's built in recording function
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=773"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=788"></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=609"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=617"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
364
lib.js
364
lib.js
@ -343,7 +343,7 @@ function applyNewParams(changeParams){
|
||||
updateMixer();
|
||||
}
|
||||
|
||||
function submitDebugLog(msg){
|
||||
function submitDebugLog(msg=false){
|
||||
try {
|
||||
appendDebugLog({"connection_type": session.stats.network_type});
|
||||
if (navigator.userAgent){
|
||||
@ -358,11 +358,18 @@ function submitDebugLog(msg){
|
||||
var res = confirm(miscTranslations["submit-error-report"]);
|
||||
if (res){
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('POST', "https://reports.vdo.ninja/"); // php, well, whatever.
|
||||
|
||||
var recordResults = session.streamID + "_"+parseInt(Date.now());
|
||||
request.open('POST', "https://reports.vdo.ninja/?name="+recordResults); // php, well, whatever.
|
||||
if (!session.cleanOutput){
|
||||
warnUser("Report any details of your bug report to steve@seguin.email, along with the following link: <a target='_blank' onclick='copyFunction(this, event)' href='https://reports.vdo.ninja/?name="+recordResults+"'>https://reports.vdo.ninja/?name="+recordResults+"</a>", false, false);
|
||||
}
|
||||
console.log("Report any details of your bug report to steve@seguin.email, along with the following ID: "+recordResults);
|
||||
|
||||
request.send(JSON.stringify(errorReport));
|
||||
errorReport = [];
|
||||
if (document.getElementById("reportbutton")){
|
||||
getById("reportbutton").style.visibility = "hidden";
|
||||
getById("reportbutton").classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1236,6 +1243,48 @@ function checkConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
function combinedLayout(layout){
|
||||
var combined = {};
|
||||
for (var i=0;i<layout.length;i++){
|
||||
if (!layout[i]){continue;}
|
||||
var streamID = null;
|
||||
if ("slot" in layout[i]){
|
||||
try {
|
||||
streamID = session.currentSlots[parseInt(layout[i].slot)+1]; // slot 1 is index of 0, but slot 0 is considered NULL; I need to stream line this a bit
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
streamID = null;
|
||||
}
|
||||
}
|
||||
if (!streamID){
|
||||
if (combined[""]){
|
||||
combined[""].push(layout[i]);
|
||||
} else {
|
||||
combined[""] = [layout[i]];
|
||||
}
|
||||
} else {
|
||||
combined[streamID] = layout[i];
|
||||
}
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
session.obsSceneSync = function(){
|
||||
if (session.layouts && session.obsSceneTriggers && session.obsState && session.obsState.details && session.obsState.details.currentScene.name && session.obsSceneTriggers.includes(session.obsState.details.currentScene.name)){
|
||||
var idx = session.obsSceneTriggers.indexOf(session.obsState.details.currentScene.name);
|
||||
if (idx>=0){
|
||||
if (session.layouts[idx]){
|
||||
var layout = combinedLayout(session.layouts[idx]);
|
||||
if (layout){
|
||||
session.layout = layout;
|
||||
updateMixer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
session.sceneSync = function(UUID){
|
||||
if (!session.rpcs[UUID].videoElement){return;} // i'll want to consider other things, such as canvas at some point.
|
||||
|
||||
@ -1270,6 +1319,8 @@ session.obsStateSync = function(data2send=false, uid=false){
|
||||
if (!window.obsstudio){return;} // this isn't OBS
|
||||
// they can disable remote control via OBS brower source drop-down itself.
|
||||
|
||||
log(data2send);
|
||||
|
||||
var needOptimize = false;
|
||||
if (session.obsState.visibility!==null){
|
||||
if (session.obsState.visibility===false){ /////////////////// I need to change tis to .state or whatever, anc catch/handle these events to update the buttons in the pop up menu
|
||||
@ -1277,6 +1328,8 @@ session.obsStateSync = function(data2send=false, uid=false){
|
||||
}
|
||||
}
|
||||
|
||||
session.obsSceneSync();
|
||||
|
||||
for (var UUID in session.rpcs){
|
||||
if (uid && (uid!==UUID)){continue;} // target just a single connection.
|
||||
|
||||
@ -1573,6 +1626,7 @@ function manageSceneState(data, UUID){ // incoming obs details
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
|
||||
if (processNeeded){
|
||||
log(data);
|
||||
applySceneState();
|
||||
@ -5186,32 +5240,24 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
// do not dynamically scale the screen share feed.
|
||||
} else if (session.dynamicScale){
|
||||
if (vid.dataset.UUID){
|
||||
if (wrw && hrh){
|
||||
|
||||
let targetWidth = wrw;
|
||||
let targetHeight = hrh;
|
||||
|
||||
if (maxWidth>targetWidth){
|
||||
targetWidth = maxWidth;
|
||||
}
|
||||
if (maxHeight>targetHeight){
|
||||
targetHeight = maxHeight;
|
||||
}
|
||||
|
||||
targetWidth -= (borderOffset + videoMargin)*2;
|
||||
targetHeight -= (borderOffset + videoMargin)*2
|
||||
|
||||
if (targetWidth<0){targetWidth=0;}
|
||||
if (targetHeight<0){targetHeight=0;}
|
||||
|
||||
if (session.devicePixelRatio){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
} else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true);
|
||||
} else {
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true);
|
||||
}
|
||||
let targetWidth = wrw;
|
||||
let targetHeight = hrh;
|
||||
|
||||
targetWidth -= (borderOffset + videoMargin)*2;
|
||||
targetHeight -= (borderOffset + videoMargin)*2
|
||||
|
||||
if (targetWidth<0){targetWidth=0;}
|
||||
if (targetHeight<0){targetHeight=0;}
|
||||
|
||||
if (session.devicePixelRatio){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true, false, cover); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
} else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true, false, cover);
|
||||
} else {
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true, false, cover);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -5349,8 +5395,8 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else if (session.dynamicScale){
|
||||
if (vid.dataset.UUID){
|
||||
|
||||
let targetWidth = Math.ceil(hsw);
|
||||
let targetHeight = Math.ceil(hsh);
|
||||
let targetWidth = wrw;
|
||||
let targetHeight = hrh;
|
||||
|
||||
targetWidth -= (borderOffset + videoMargin)*2;
|
||||
targetHeight -= (borderOffset + videoMargin)*2
|
||||
@ -5359,11 +5405,11 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
if (targetHeight<0){targetHeight=0;}
|
||||
|
||||
if (session.devicePixelRatio){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true, false, cover); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
} else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true);
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true, false, cover);
|
||||
} else {
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true);
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true, false, cover);
|
||||
}
|
||||
|
||||
}
|
||||
@ -5381,34 +5427,24 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
// do not dynamically scale the screen share feed.
|
||||
} else if (session.dynamicScale){
|
||||
if (vid.dataset.UUID){
|
||||
if (wrw && hrh){
|
||||
|
||||
let targetWidth = wrw;
|
||||
let targetHeight = hrh;
|
||||
|
||||
if (cover){
|
||||
if (maxWidth>targetWidth){
|
||||
targetWidth = maxWidth;
|
||||
}
|
||||
if (maxHeight>targetHeight){
|
||||
targetHeight = maxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
targetWidth -= (borderOffset + videoMargin)*2;
|
||||
targetHeight -= (borderOffset + videoMargin)*2
|
||||
|
||||
if (targetWidth<0){targetWidth=0;}
|
||||
if (targetHeight<0){targetHeight=0;}
|
||||
|
||||
if (session.devicePixelRatio){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
} else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true);
|
||||
} else {
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true);
|
||||
}
|
||||
|
||||
let targetWidth = wrw;
|
||||
let targetHeight = hrh;
|
||||
|
||||
targetWidth -= (borderOffset + videoMargin)*2;
|
||||
targetHeight -= (borderOffset + videoMargin)*2
|
||||
|
||||
if (targetWidth<0){targetWidth=0;}
|
||||
if (targetHeight<0){targetHeight=0;}
|
||||
|
||||
if (session.devicePixelRatio){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth * session.devicePixelRatio, targetHeight * session.devicePixelRatio, true, false, cover); // snap=true; if resolution close to 100%, send 100%. screenshare only
|
||||
} else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth*window.devicePixelRatio, targetHeight*window.devicePixelRatio, true, false, cover);
|
||||
} else {
|
||||
session.requestResolution(vid.dataset.UUID, targetWidth, targetHeight, true, false, cover);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
///////////////
|
||||
@ -12587,12 +12623,12 @@ function remoteMute(ele, event=false, skipSend=false) {
|
||||
if (val == 1){
|
||||
ele.value = 0;
|
||||
ele.classList.remove("pressed"); ele.ariaPressed = "false";
|
||||
ele.innerHTML = '<i class="las la-microphone-slash" style="color:#900"></i>';
|
||||
ele.innerHTML = '<i class="las la-microphone-slash"></i>';
|
||||
ele.innerHTML += miscTranslations["mute"] || "Mute";
|
||||
} else {
|
||||
ele.value = 1;
|
||||
ele.classList.add("pressed"); ele.ariaPressed = "true";
|
||||
ele.innerHTML = '<i class="las la-microphone-slash" style="color:#900"></i>';
|
||||
ele.innerHTML = '<i class="las la-microphone-slash"></i>';
|
||||
ele.innerHTML += miscTranslations["unmute"] || "Unmute";
|
||||
}
|
||||
}
|
||||
@ -12827,9 +12863,15 @@ function remoteVolumeUI(ele){
|
||||
remoteSliderTimeout = Date.now();
|
||||
remoteVolume(ele);
|
||||
}
|
||||
//setVolumeColor(ele);
|
||||
return ele.value;
|
||||
}
|
||||
|
||||
/* function setVolumeColor(ele){
|
||||
var vol1 = 200-parseInt(ele.value);
|
||||
if (vol1<0){vol1=0};
|
||||
ele.style.backgroundColor = "hsl("+vol1+", 100%, 50%)";
|
||||
} */
|
||||
|
||||
function remoteVolume(ele) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("volume: "+session.rpcs[ele.dataset.UUID].directorMutedState);
|
||||
@ -13063,20 +13105,37 @@ async function publishScreen() {
|
||||
}
|
||||
|
||||
try {
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints(); // cursor hidding isn't supported by most browsers anyways.
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
|
||||
if (supportedConstraints.cursor) {
|
||||
constraints.video.cursor = "never";
|
||||
if (session.screensharecursor){
|
||||
constraints.video.cursor = ["always", "motion"];
|
||||
} else {
|
||||
constraints.video.cursor = "never";
|
||||
}
|
||||
}
|
||||
if (session.suppressLocalAudioPlayback && supportedConstraints.suppressLocalAudioPlayback){
|
||||
constraints.audio.suppressLocalAudioPlayback = true;
|
||||
}
|
||||
//
|
||||
if (session.preferCurrentTab){
|
||||
constraints.preferCurrentTab = true;
|
||||
}
|
||||
if (session.selfBrowserSurface){
|
||||
constraints.selfBrowserSurface = session.selfBrowserSurface; // exclude or include
|
||||
}
|
||||
if (session.surfaceSwitching){
|
||||
constraints.surfaceSwitching = session.surfaceSwitching; // exclude or include
|
||||
}
|
||||
if (session.systemAudio){
|
||||
constraints.systemAudio = session.systemAudio; // exclude or include
|
||||
}
|
||||
if (session.displaySurface && supportedConstraints.displaySurface){
|
||||
constraints.video.displaySurface = session.displaySurface; // monitor, window, or browser
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
|
||||
}
|
||||
|
||||
//if (session.nocursor) { // we assume no cursor on screen share anyways. maybe make a different flag for screenshare cursor
|
||||
// constraints.video.cursor = {
|
||||
// exact: "none"
|
||||
// }; // Not sure this does anything, but whatever.
|
||||
//}
|
||||
|
||||
var overrideFramerate = false;
|
||||
if ((session.frameRate !== false) && (session.maxframeRate != false)){
|
||||
overrideFramerate = session.frameRate;
|
||||
@ -14042,7 +14101,7 @@ session.publishIFrame = function(iframeURL){
|
||||
getById("hangupbutton").className="float";
|
||||
getById("controlButtons").classList.remove("hidden");
|
||||
getById("helpbutton").style.display = "inherit";
|
||||
//getById("reportbutton").style.display = "";
|
||||
getById("reportbutton").style.display = "";
|
||||
} else {
|
||||
getById("controlButtons").classList.add("hidden");
|
||||
}
|
||||
@ -14861,11 +14920,11 @@ function audioMeter(mediaStreamSource, audioContext) {
|
||||
|
||||
function audioCompressor(mediaStreamSource, audioContext) {
|
||||
var compressor = audioContext.createDynamicsCompressor();
|
||||
compressor.threshold.value = -50;
|
||||
compressor.knee.value = 40;
|
||||
compressor.ratio.value = 12;
|
||||
compressor.attack.value = 0;
|
||||
compressor.release.value = 0.25;
|
||||
compressor.threshold.value = -40;
|
||||
compressor.knee.value = 10;
|
||||
compressor.ratio.value = 4; // 3
|
||||
compressor.attack.value = 0.002; // 0.001
|
||||
compressor.release.value = 0.1; // 0.06
|
||||
mediaStreamSource.connect(compressor);
|
||||
return compressor;
|
||||
}
|
||||
@ -16083,13 +16142,21 @@ function requestInfocus(ele, evt=null, value=null) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var fixScrollReset = null;
|
||||
var fixScrollResetValue = null;
|
||||
|
||||
function requestAudioSettings(ele) {
|
||||
|
||||
var UUID = ele.dataset.UUID;
|
||||
|
||||
try {
|
||||
clearTimeout(fixScrollReset);
|
||||
fixScrollResetValue = getById("directorlayout").scrollTop;
|
||||
fixScrollReset = setTimeout(function(scrollpos){
|
||||
fixScrollReset = null;
|
||||
getById("directorlayout").scrollTop = scrollpos;
|
||||
}, 1000, fixScrollResetValue);
|
||||
|
||||
query("#container_"+UUID+" [data-action-type='advanced-camera-settings']").value = 0;
|
||||
query("#container_"+UUID+" [data-action-type='advanced-camera-settings']").classList.remove("pressed");
|
||||
query("#container_"+UUID+" [data-action-type='advanced-camera-settings']").ariaPressed = "false";
|
||||
@ -16118,6 +16185,13 @@ function requestVideoSettings(ele) {
|
||||
var UUID = ele.dataset.UUID;
|
||||
|
||||
try {
|
||||
clearTimeout(fixScrollReset);
|
||||
fixScrollResetValue = getById("directorlayout").scrollTop;
|
||||
fixScrollReset = setTimeout(function(scrollpos){
|
||||
fixScrollReset = null;
|
||||
getById("directorlayout").scrollTop = scrollpos;
|
||||
}, 1000, fixScrollResetValue);
|
||||
|
||||
query("#container_"+UUID+" [data-action-type='advanced-audio-settings']").value = 0;
|
||||
query("#container_"+UUID+" [data-action-type='advanced-audio-settings']").classList.remove("pressed");
|
||||
query("#container_"+UUID+" [data-action-type='advanced-audio-settings']").ariaPressed = "false";
|
||||
@ -16212,7 +16286,7 @@ async function createDirectorOnlyBox() {
|
||||
controls.innerHTML += "<div class='soloButton' title='A direct solo view of the video/audio stream with nothing else'> \
|
||||
<a class='soloLink advanced task' data-menu='context-menu' data-sololink='true' data-drag='1' draggable='true' onclick='copyFunction(this,event)' \
|
||||
value='" + soloLink + "' href='" + soloLink + "'/>" + sanitizeChat(soloLink) + "</a>\
|
||||
<button class='pull-right' style='width:100%;' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
<button class='pull-right controlsGrid' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
</div>\
|
||||
<div id='groups'></div>";
|
||||
if (session.directorUUID){
|
||||
@ -16303,6 +16377,28 @@ async function createDirectorOnlyBox() {
|
||||
if (session.slotmode){
|
||||
pokeIframeAPI("slot-updated", biggestSlot, null, session.streamID); // need to support self-director
|
||||
session.pastSlots[session.streamID] = biggestSlot;
|
||||
|
||||
createSlotUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
function createSlotUpdate(UUID=false){
|
||||
try {
|
||||
var newSlots = {};
|
||||
document.querySelectorAll("[data--u-u-i-d][data-slot]").forEach(ele=>{
|
||||
newSlots[ele.dataset.slot] = ele.dataset.sid;
|
||||
});
|
||||
if (!UUID){
|
||||
for (var uid in session.pcs){
|
||||
if (session.pcs[uid].layout){
|
||||
session.sendMessage({slotsUpdate:newSlots}, uid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
session.sendMessage({slotsUpdate:newSlots}, UUID);
|
||||
}
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -16375,7 +16471,7 @@ async function createDirectorScreenshareOnlyBox() { // sstype=3
|
||||
controls.innerHTML += "<div style='padding:5px;word-wrap: break-word; overflow:hidden; white-space: nowrap; overflow: hidden; font-size:0.7em; text-overflow: ellipsis;' title='A direct solo view of the video/audio stream with nothing else'> \
|
||||
<a class='soloLink advanced task' data-menu='context-menu' data-sololink='true' data-drag='1' draggable='true' onclick='copyFunction(this,event)' \
|
||||
value='" + soloLink + "' href='" + soloLink + "'/>" + sanitizeChat(soloLink) + "</a>\
|
||||
<button class='pull-right' style='width:100%;' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
<button class='pull-right controlsGrid' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
</div>\
|
||||
<div id='groups'></div>";
|
||||
if (session.directorUUID){
|
||||
@ -16466,6 +16562,8 @@ async function createDirectorScreenshareOnlyBox() { // sstype=3
|
||||
if (session.slotmode){
|
||||
pokeIframeAPI("slot-updated", biggestSlot, null, session.streamID+":s"); // need to support self-director
|
||||
session.pastSlots[session.streamID+":s"] = biggestSlot;
|
||||
|
||||
createSlotUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -16633,6 +16731,7 @@ function dropSlot(event) {
|
||||
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
|
||||
|
||||
|
||||
session.pastSlots[event.target.dataset.sid] = parseInt(event.target.dataset.slot);
|
||||
session.pastSlots[origThing.dataset.sid] = parseInt(origThing.dataset.slot);
|
||||
} else if (origThing && ("slot" in event.target.parentNode.dataset)){
|
||||
@ -16651,7 +16750,7 @@ function dropSlot(event) {
|
||||
session.pastSlots[origThing.dataset.sid] = parseInt(origThing.dataset.slot);
|
||||
}
|
||||
|
||||
|
||||
createSlotUpdate();
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -16743,6 +16842,8 @@ function setSlot(ele,slot){
|
||||
}
|
||||
pokeIframeAPI("slot-updated", slot, null, ele.parentNode.dataset.sid);
|
||||
session.pastSlots[ele.parentNode.dataset.sid] = slot;
|
||||
|
||||
createSlotUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -16858,13 +16959,13 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
|
||||
var handsID = "hands_" + UUID;
|
||||
|
||||
controls.innerHTML += "<div class='flexBreak'><span data-translate='links'>Links</span></div>"; //Seems to create an empty div.
|
||||
// controls.innerHTML += "<div class='flexBreak'><span data-translate='links'>Links</span></div>"; //Seems to create an empty div.
|
||||
|
||||
if (session.hidesololinks==false){
|
||||
controls.innerHTML += "<div class='soloButton' title='A direct solo view of the video/audio stream with nothing else. Its audio can be remotely controlled from here'> \
|
||||
<a class='soloLink advanced task' data-menu='context-menu' data-sololink='true' data-drag='1' draggable='true' onclick='copyFunction(this,event)' \
|
||||
value='" + soloLink + "' href='" + soloLink + "'/>" + sanitizeChat(soloLink) + "</a>\
|
||||
<button class='pull-right' style='width:100%;' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
<button class='pull-right controlsGrid' onclick='copyFunction(this.previousElementSibling,event)'><i class='las la-user'></i><span translate='copy-solo-view-link'>copy solo view link</span></button>\
|
||||
</div>";
|
||||
}
|
||||
|
||||
@ -17041,6 +17142,8 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
if (session.slotmode){
|
||||
pokeIframeAPI("slot-updated", biggestSlot, UUID); // need to support self-director
|
||||
session.pastSlots[streamID] = biggestSlot;
|
||||
|
||||
createSlotUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -20122,19 +20225,39 @@ async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
|
||||
//,cursor: {exact: "none"}
|
||||
};
|
||||
|
||||
if (session.screensharecursor){
|
||||
constraints.video.cursor = ["always", "motion"];
|
||||
} else {
|
||||
try {
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
|
||||
if (supportedConstraints.cursor) {
|
||||
|
||||
try {
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
|
||||
if (supportedConstraints.cursor) {
|
||||
if (session.screensharecursor){
|
||||
constraints.video.cursor = ["always", "motion"];
|
||||
} else {
|
||||
constraints.video.cursor = "never";
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
|
||||
}
|
||||
if (session.suppressLocalAudioPlayback && supportedConstraints.suppressLocalAudioPlayback){
|
||||
constraints.audio.suppressLocalAudioPlayback = true;
|
||||
}
|
||||
if (session.preferCurrentTab){
|
||||
constraints.preferCurrentTab = true;
|
||||
}
|
||||
if (session.selfBrowserSurface){
|
||||
constraints.selfBrowserSurface = session.selfBrowserSurface; // exclude or include
|
||||
}
|
||||
if (session.surfaceSwitching){
|
||||
constraints.surfaceSwitching = session.surfaceSwitching; // exclude or include
|
||||
}
|
||||
if (session.systemAudio){
|
||||
constraints.systemAudio = session.systemAudio; // exclude or include
|
||||
}
|
||||
if (session.displaySurface && supportedConstraints.displaySurface){
|
||||
constraints.video.displaySurface = session.displaySurface; // monitor, window, or browser
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (session.echoCancellation === true) {
|
||||
constraints.audio.echoCancellation = true;
|
||||
}
|
||||
@ -23457,7 +23580,7 @@ session.hostFile = function(ele, event){ // webcam stream is used to generated a
|
||||
getById("hangupbutton").className="float";
|
||||
getById("controlButtons").classList.remove("hidden");
|
||||
getById("helpbutton").style.display = "inherit";
|
||||
//getById("reportbutton").style.display = "";
|
||||
getById("reportbutton").style.display = "";
|
||||
} else {
|
||||
getById("controlButtons").classList.add("hidden");
|
||||
}
|
||||
@ -24958,7 +25081,7 @@ function updateDirectorsAudio(dataN, UUID) {
|
||||
input.dataset.track = n;
|
||||
input.dataset.UUID = UUID;
|
||||
input.id = "constraints_" + i + "_"+UUID;
|
||||
input.style = "display:block; width:100%; margin: 2px 0px 5px;";
|
||||
input.classList.add("inputConstraint");
|
||||
input.name = "constraints_" + i;
|
||||
|
||||
manualInput.onchange = function(e) {
|
||||
@ -25374,6 +25497,12 @@ function updateDirectorsAudio(dataN, UUID) {
|
||||
|
||||
query("#container_"+UUID+" .advancedAudioSettings").appendChild(audioEle);
|
||||
}
|
||||
|
||||
if (fixScrollReset){
|
||||
clearTimeout(fixScrollReset);
|
||||
fixScrollReset = null;
|
||||
getById("directorlayout").scrollTop = fixScrollResetValue;
|
||||
}
|
||||
}
|
||||
|
||||
var remoteSliderTimeout = 0;
|
||||
@ -25543,7 +25672,7 @@ function updateDirectorsVideo(data, UUID) {
|
||||
input.dataset.UUID = UUID;
|
||||
input.id = "constraints_" + i + "_" + UUID;
|
||||
input.name = input.id;
|
||||
input.style = "display:block; width:100%; margin: 2px 0px 5px;";
|
||||
input.classList.add("inputConstraint");
|
||||
input.manualMode = manualMode;
|
||||
|
||||
|
||||
@ -25766,6 +25895,12 @@ function updateDirectorsVideo(data, UUID) {
|
||||
query("#container_"+UUID+" .advancedVideoSettings").innerHTML = "";
|
||||
query("#container_"+UUID+" .advancedVideoSettings").appendChild(videoEle);
|
||||
query("#container_"+UUID+" .advancedVideoSettings").classList.remove("hidden");
|
||||
|
||||
if (fixScrollReset){
|
||||
clearTimeout(fixScrollReset);
|
||||
fixScrollReset = null;
|
||||
getById("directorlayout").scrollTop = fixScrollResetValue;
|
||||
}
|
||||
}
|
||||
|
||||
///////
|
||||
@ -28404,7 +28539,7 @@ async function requestBasicPermissions(constraint = {video: true, audio: true},
|
||||
}).catch(function(err) {
|
||||
clearTimeout(timerBasicCheck);
|
||||
warnlog("some error with GetUSERMEDIA");
|
||||
errorlog(err); /* handle the error */
|
||||
console.warn(err); /* handle the error */
|
||||
if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
|
||||
//required track is missing
|
||||
} else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
|
||||
@ -28435,7 +28570,7 @@ async function requestBasicPermissions(constraint = {video: true, audio: true},
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
errorlog("trying to list webcam again");
|
||||
warnlog("trying to list webcam again");
|
||||
|
||||
if (callback){
|
||||
callback(miconly);
|
||||
@ -28443,7 +28578,7 @@ async function requestBasicPermissions(constraint = {video: true, audio: true},
|
||||
|
||||
});
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
console.warn(e);
|
||||
if (!(session.cleanOutput)) {
|
||||
if (window.isSecureContext) {
|
||||
warnUser("An error has occured when trying to access the webcam or microphone. The reason is not known.");
|
||||
@ -31509,7 +31644,7 @@ function updateIncomingVideoElement(UUID, video=true, audio=true){
|
||||
}
|
||||
}
|
||||
session.rpcs[UUID].videoElement.srcObject.addTrack(trk);
|
||||
mediaVideoTrackUpdated(UUID, session.rpcs[UUID].streamID);
|
||||
mediaVideoTrackUpdated(UUID, session.rpcs[UUID].streamID);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -35600,17 +35735,36 @@ async function createSecondStream() { //////////////////////////// &sstype=3 ?
|
||||
//,cursor: {exact: "none"}
|
||||
};
|
||||
|
||||
if (session.screensharecursor){
|
||||
constraints.video.cursor = ["always", "motion"];
|
||||
} else {
|
||||
try {
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
|
||||
if (supportedConstraints.cursor) {
|
||||
try {
|
||||
let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
|
||||
if (supportedConstraints.cursor) {
|
||||
if (session.screensharecursor){
|
||||
constraints.video.cursor = ["always", "motion"];
|
||||
} else {
|
||||
constraints.video.cursor = "never";
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
|
||||
}
|
||||
if (session.suppressLocalAudioPlayback && supportedConstraints.suppressLocalAudioPlayback){
|
||||
constraints.audio.suppressLocalAudioPlayback = true;
|
||||
}
|
||||
//
|
||||
if (session.preferCurrentTab){
|
||||
constraints.preferCurrentTab = true;
|
||||
}
|
||||
if (session.selfBrowserSurface){
|
||||
constraints.selfBrowserSurface = session.selfBrowserSurface; // exclude or include
|
||||
}
|
||||
if (session.surfaceSwitching){
|
||||
constraints.surfaceSwitching = session.surfaceSwitching; // exclude or include
|
||||
}
|
||||
if (session.systemAudio){
|
||||
constraints.systemAudio = session.systemAudio; // exclude or include
|
||||
}
|
||||
if (session.displaySurface && supportedConstraints.displaySurface){
|
||||
constraints.video.displaySurface = session.displaySurface; // monitor, window, or browser
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
|
||||
}
|
||||
|
||||
if (session.echoCancellation === false) {
|
||||
|
||||
38
main.js
38
main.js
@ -44,6 +44,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
if (location.hostname !== "vdo.ninja" && location.hostname !== "backup.vdo.ninja" && location.hostname !== "proxy.vdo.ninja" && location.hostname !== "obs.ninja") {
|
||||
|
||||
errorReport = false;
|
||||
|
||||
if (location.hostname === "rtc.ninja"){
|
||||
try {
|
||||
if (session.label === false) {
|
||||
@ -780,6 +783,25 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.screenshareType = parseInt(session.screenshareType) || false;
|
||||
}
|
||||
|
||||
if (urlParams.has('suppresslocalaudio')){
|
||||
session.suppressLocalAudioPlayback = true;
|
||||
}
|
||||
if (urlParams.has('prefercurrenttab')){
|
||||
session.preferCurrentTab = true;
|
||||
}
|
||||
if (urlParams.has('selfbrowsersurface')){ // exclude
|
||||
session.selfBrowserSurface = urlParams.get('selfbrowsersurface') || "exclude";
|
||||
}
|
||||
if (urlParams.has('surfaceswitching')){
|
||||
session.surfaceSwitching = urlParams.get('surfaceswitching') || "exclude";
|
||||
}
|
||||
if (urlParams.has('systemaudio')){ // exclude or exclude
|
||||
session.systemAudio = urlParams.get('systemaudio') || "exclude";
|
||||
}
|
||||
if (urlParams.has('displaysurface')){ // browser, window, or monitor (which is default selected)
|
||||
session.displaySurface = urlParams.get('displaysurface') || "monitor";
|
||||
}
|
||||
|
||||
if (urlParams.has('intro') || urlParams.has('ib')) {
|
||||
session.introButton = true;
|
||||
}
|
||||
@ -3640,13 +3662,13 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warnlog("Bitrate being throttled to max of 3000 kbps");
|
||||
warnlog("Bitrate being throttled to max of 4000 kbps");
|
||||
if (session.maxvideobitrate !== false) {
|
||||
if (session.maxvideobitrate > 4000) {
|
||||
session.maxvideobitrate = 4000; // Please feel free to get rid of this if using your own TURN servers...
|
||||
}
|
||||
} else {
|
||||
session.maxvideobitrate = 4000; // don't let people pull more than 3000 from you
|
||||
session.maxvideobitrate = 4000; // don't let people pull more than 4000 from you
|
||||
}
|
||||
if (session.bitrate !== false) {
|
||||
if (session.bitrate > 4000) {
|
||||
@ -4870,6 +4892,18 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
|
||||
if ("layouts" in e.data) {
|
||||
session.layouts = e.data.layouts;
|
||||
if ("obsSceneTriggers" in e.data) {
|
||||
session.obsSceneTriggers = e.data.obsSceneTriggers;
|
||||
} else {
|
||||
session.obsSceneTriggers = false;
|
||||
}
|
||||
for (var uid in session.pcs){
|
||||
if (session.pcs[uid].layout){
|
||||
session.sendMessage(e.data, uid);
|
||||
}
|
||||
}
|
||||
// session.obsSceneSync(); // not sure I need to trigger this?
|
||||
log(e.data);
|
||||
}
|
||||
|
||||
if ("sendMessage" in e.data) { // webrtc send to viewers
|
||||
|
||||
94
mixer.html
94
mixer.html
@ -952,7 +952,7 @@
|
||||
<div id='sceneSettings' class="hidden modal">
|
||||
<div class="modal-content">
|
||||
<span class="close-btn">×</span>
|
||||
<h2>General Settings</h2>
|
||||
<h2>General Mixer Settings</h2>
|
||||
<h3>Aspect Ratio</h3>
|
||||
<input type="checkbox" checked class="aspectbutton" data-value="169" onchange="changeAspectRatio(16/9.0, this);">16:9
|
||||
<input type="checkbox" class="aspectbutton" data-value="0.5625" onchange="changeAspectRatio(9.0/16, this);">9:16
|
||||
@ -969,8 +969,12 @@
|
||||
|
||||
<h3>Layout switching</h3>
|
||||
<input type="checkbox" title="When a user is assigned a slot or switches slots, the last active layout is re-applied automatically" id="updateOnSlotChange" checked onchange="submitChange(this)";>Update layout on a slot change
|
||||
<h3>Linked OBS scenes</h3>
|
||||
<input type="checkbox" title="When a user is assigned a slot or switches slots, the last active layout is re-applied automatically" id="syncOBS" onchange="submitChange3(this)";>Activate linked OBS scene on layout change
|
||||
|
||||
<h3>Trigger OBS scenes change on layout change</h3>
|
||||
<input type="checkbox" title="" id="syncOBS" onchange="submitChange3(this)";>Activate linked OBS scene on layout change
|
||||
<h3>Switch layouts to match selected OBS scene</h3>
|
||||
<input type="checkbox" title="" id="remoteSyncOBS" onchange="submitChange5(this)";>Activate the linked layout on remote OBS scene change
|
||||
|
||||
<h3>Slot assignment</h3>
|
||||
<input type="checkbox" title="A guest is assigned a slot when they join, automatically. If disabled, they must be assigned a slot manually." id="assignSlotToGuest" checked onchange="submitChange2(this)";>Assign a slot to new guests automatically
|
||||
<h3>Show advanced controls</h3>
|
||||
@ -1158,6 +1162,7 @@
|
||||
var messageList = [];
|
||||
var password = false;
|
||||
var syncOBS = false;
|
||||
var remoteSyncOBS = false;
|
||||
var showDirector = true;
|
||||
|
||||
var currentOBSState = false;
|
||||
@ -1757,6 +1762,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (savedSession.settings && ("remoteSyncOBS" in savedSession.settings)){
|
||||
remoteSyncOBS = savedSession.settings.remoteSyncOBS;
|
||||
if (!remoteSyncOBS){
|
||||
getById("remoteSyncOBS").value = "off";
|
||||
getById("remoteSyncOBS").checked = false;
|
||||
getById("remoteSyncOBS").removeAttribute('checked');
|
||||
} else {
|
||||
getById("remoteSyncOBS").value = "on";
|
||||
getById("remoteSyncOBS").checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (savedSession.settings && ("showDirector" in savedSession.settings)){
|
||||
showDirector = savedSession.settings.showDirector;
|
||||
if (!showDirector){
|
||||
@ -1876,7 +1893,11 @@
|
||||
}
|
||||
|
||||
if (iframe){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
if (remoteSyncOBS){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts , obsSceneTriggers: savedSession.obsScenes}, "*");
|
||||
} else {
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
}
|
||||
}
|
||||
|
||||
var guestPositions = {};
|
||||
@ -1913,6 +1934,22 @@
|
||||
saveSession();
|
||||
}
|
||||
|
||||
function submitChange5(element){
|
||||
if (element.checked){
|
||||
remoteSyncOBS=true;
|
||||
if (iframe){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts , obsSceneTriggers: savedSession.obsScenes}, "*");
|
||||
}
|
||||
} else { // do not assign guests to slots automatically
|
||||
if (iframe){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts , obsSceneTriggers: false}, "*");
|
||||
}
|
||||
element.removeAttribute('checked');
|
||||
remoteSyncOBS=false
|
||||
}
|
||||
saveSession();
|
||||
}
|
||||
|
||||
function submitChange4(element){
|
||||
if (element.checked){
|
||||
showDirector=true;
|
||||
@ -2270,12 +2307,7 @@
|
||||
<!-- button.classList.add("menuButton"); -->
|
||||
<!-- document.getElementById("sources").appendChild(button); -->
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Settings ⚙︎";
|
||||
button.onclick = showSettings;
|
||||
button.id = "showSettings";
|
||||
button.classList.add("menuButton");
|
||||
document.getElementById("sources").appendChild(button);
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Switch Modes ↻";
|
||||
@ -2303,6 +2335,12 @@
|
||||
};
|
||||
document.getElementById("sources").appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Mixer Settings ⚙︎";
|
||||
button.onclick = showSettings;
|
||||
button.id = "showSettings";
|
||||
button.classList.add("menuButton");
|
||||
document.getElementById("sources").appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Add Stream ID";
|
||||
@ -2382,7 +2420,11 @@
|
||||
document.getElementById("chatModule").classList.remove("hidden");
|
||||
|
||||
iframe.onload = function(){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
if (remoteSyncOBS){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts , obsSceneTriggers: savedSession.obsScenes}, "*");
|
||||
} else {
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
}
|
||||
}
|
||||
|
||||
iframe.src = iframesrc;
|
||||
@ -2494,7 +2536,6 @@
|
||||
if (updateOnSlotChange){
|
||||
remoteActivate(false, lastLayoutRaw);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -2518,17 +2559,23 @@
|
||||
if (currentOBSState.currentScene && currentOBSState.currentScene.name){
|
||||
console.log("Current OBS scene: " + currentOBSState.currentScene.name);
|
||||
|
||||
if (syncOBS){
|
||||
|
||||
if (remoteSyncOBS){
|
||||
var layouts = document.querySelectorAll(".canvasContainer>canvas");
|
||||
|
||||
for (var i=0;i<layouts.length;i++){
|
||||
if (!layouts[i].layout){continue;}
|
||||
if (!layouts[i].layout){
|
||||
console.log("no layout");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
var obs = layouts[i].obsSceneName || false;
|
||||
if (obs && obs == currentOBSState.currentScene.name){
|
||||
console.log("Syncing with OBS");
|
||||
layouts[i].click();
|
||||
console.log("obs scene names:"+obs+ " vs "+currentOBSState.currentScene.name);
|
||||
if (obs && obs.toLowerCase().trim() == currentOBSState.currentScene.name.toLowerCase().trim()){
|
||||
if (layouts[i].parentNode && layouts[i].parentNode.classList.contains("pressed")){
|
||||
console.log("Matched scene already active");
|
||||
} else {
|
||||
console.log("Syncing with OBS; matched");
|
||||
layouts[i].click(); // triggers for everyone else.
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch(e){
|
||||
@ -2536,6 +2583,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("No current scene in OBS's output");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3754,6 +3803,7 @@
|
||||
savedSession.settings.toggleLabel = toggleLabel;
|
||||
savedSession.settings.toggleBroadcast = toggleBroadcast;
|
||||
savedSession.settings.syncOBS = syncOBS;
|
||||
savedSession.settings.remoteSyncOBS = remoteSyncOBS;
|
||||
savedSession.settings.aspectRatio = aspectRatio;
|
||||
savedSession.settings.pixelDensity = pixelDensity;
|
||||
savedSession.settings.absolutePixel = absolutePixel;
|
||||
@ -3777,7 +3827,11 @@
|
||||
setStorage("savedSession", JSON.stringify(savedSession));
|
||||
|
||||
if (iframe){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
if (remoteSyncOBS){
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts , obsSceneTriggers: savedSession.obsScenes}, "*");
|
||||
} else {
|
||||
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
|
||||
}
|
||||
}
|
||||
log(getStorage("savedSession"));
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@
|
||||
"push-to-talk-enable": " enable director`s microphone or video<br>(only guests can see this feed)",
|
||||
"hide-the-links": " LINKS (GUEST INVITES & SCENES)",
|
||||
"click-here-for-help": "Click Here for a quick overview and help",
|
||||
"welcome-to-control-room": "\n<b>Welcome. This is the director's control-room for the group-chat.</b><br><br>\nYou can host a group chat with friends using a room. Share the blue link to invite guests who will join the chat automatically.\n<br><br>\nA group room can handle normally around 6 to 20 guests, depending on numerous factors, including CPU and available bandwidth of all guests in the room\n",
|
||||
"welcome-to-control-room": "<b>Welcome. This is the director's control-room for the group-chat.</b><br><br>You can host a group chat with friends using a room. Share the blue link to invite guests who will join the chat automatically.<br><br>A group room can handle normally around 6 to 20 guests, depending on numerous factors, including CPU and available bandwidth of all guests in the room",
|
||||
"invite-users-to-join": "Guests can use the link to join the group room",
|
||||
"guests-hear-others": "Guests hear others",
|
||||
"capture-a-group-scene": "CAPTURE A GROUP SCENE",
|
||||
@ -298,7 +298,7 @@
|
||||
"mute": "Mute",
|
||||
"More-scene-options": "Scene options",
|
||||
"add-to-scene2": "add to scene 2",
|
||||
"mute-scene": "mute in scene",
|
||||
"mute-scene": "mute in scenes",
|
||||
"force-keyframe": "Rainbow Puke Fix",
|
||||
"stats-remote": " Scene Stats",
|
||||
"additional-controls": "Additional controls",
|
||||
@ -310,8 +310,8 @@
|
||||
"change-params": "URL Params",
|
||||
"record-local": " Record Local",
|
||||
"record-remote": " Record Remote",
|
||||
"advanced-audio-settings": "Audio",
|
||||
"advanced-camera-settings": "Video",
|
||||
"advanced-audio-settings": "Audio Settings",
|
||||
"advanced-camera-settings": "Video Settings",
|
||||
"user-raised-hand": "Lower Raised Hand",
|
||||
"unmute": "unmute",
|
||||
"unhide-guest": "unhide",
|
||||
@ -325,8 +325,8 @@
|
||||
"balanced": "Balanced",
|
||||
"smooth-cool": "Smooth and Cool",
|
||||
"select-audio-source": " Audio Source(s) ",
|
||||
"select-output-source": " Audio Output Destination: ",
|
||||
"select-digital-effect": " Digital Video Effects: ",
|
||||
"select-output-source": " Audio Output Destination ",
|
||||
"select-digital-effect": " Digital Video Effects ",
|
||||
"no-effects-applied": "No effects applied",
|
||||
"blurred-background": "Blurred background",
|
||||
"digital-greenscreen": "Digital greenscreen",
|
||||
@ -340,32 +340,29 @@
|
||||
"apply-new-guest-settings": "Apply settings",
|
||||
"cancel": "Cancel",
|
||||
"invisible-guests": "Not Visible",
|
||||
"available-languages": "Available Languages:",
|
||||
"available-languages": "Available Languages",
|
||||
"add-more-here": "Add More Here!",
|
||||
"add-to-calendar": "Add details to your Calendar:",
|
||||
"add-to-google-calendar": "Add to Google Calendar",
|
||||
"add-to-outlook-calendar": "Add to Outlook Calendar",
|
||||
"add-to-yahoo-calendar": "Add to Yahoo Calendar",
|
||||
"logo-header": "\n<font id=\"qos\">V</font>DO.Ninja \n",
|
||||
"logo-header": "<font id=\"qos\">V</font>DO.Ninja ",
|
||||
"only-director-can-hear-you": "Only the director can hear you currently.",
|
||||
"director-muted-you": "The director has muted you.",
|
||||
"add-group-chat": "Create a Room",
|
||||
"rooms-allow-for": "Rooms allow for group-chat and the tools to manage multiple guests.",
|
||||
"room-name": "Room Name",
|
||||
"password-input-field": "Password",
|
||||
"guests-only-see-director": "Guests can only see the Director's Video",
|
||||
"scenes-can-see-director": "Director will also be a performer",
|
||||
"default-codec-select": "Preferred Video Codec: ",
|
||||
"enter-the-rooms-control": "Enter the Room's Control Center",
|
||||
"show-tips": "Show me some tips..",
|
||||
"added-notes": "\n<u>\n<i>Important Tips:</i><br>\n</u>\n<li>Disabling video sharing between guests will improve performance</li>\n<li>Invite only guests to the room that you trust.</li>\n<li>The \"Recording\" option is considered experimental.</li>",
|
||||
"added-notes": "<u><i>Important Tips:</i><br><br></u><li>Disabling video sharing between guests will improve performance</li><li>Invite only guests to the room that you trust.</li><li>The \"Recording\" option is considered experimental.</li>",
|
||||
"back": "Back",
|
||||
"add-your-camera": "Add your Camera",
|
||||
"ask-for-permissions": "Allow Access to Camera/Microphone",
|
||||
"waiting-for-camera": "Waiting for Camera to Load",
|
||||
"no-audio": "No Audio",
|
||||
"add-a-password": " Add a Password:",
|
||||
"use-chrome-instead": "Consider using a Chromium-based browser instead.<br>\n Safari is more prone to having audio issues",
|
||||
"add-a-password": " Add a Password",
|
||||
"use-chrome-instead": "Consider using a Chromium-based browser instead.<br> Safari is more prone to having audio issues",
|
||||
"remote-screenshare-obs": "Remote Screenshare",
|
||||
"select-screen-to-share": "SELECT SCREEN TO SHARE",
|
||||
"audio-sources": "Audio Sources",
|
||||
@ -394,11 +391,11 @@
|
||||
"enter-the-website-URL-you-wish-to-share": "Enter the URL website you wish to share.",
|
||||
"run-a-speed-test": "Run a Speed Test",
|
||||
"read-the-guides": "Browse the Guides",
|
||||
"info-blob": "\n<h2>What is VDO.Ninja</h2>\n<br>\n<li>100% <b>free</b>; no downloads; no personal data collection; no sign-in</li>\n<li>Bring live video from your smartphone, remote computer, or friends directly into OBS or other studio software.</li>\n<li>We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency</li>\n<br>\n<li>Youtube video \n<i class=\"lab la-youtube\"></i>\n<a href=\"https://www.youtube.com/watch?v=QaA_6aOP9z8&list=PLWodc2tCfAH1WHjl4WAOOoRSscJ8CHACe&index=1\" alt=\"Youtube video demoing VDO.Ninja\">Demoing it here</a>\n</li>\n<br><h3>\n 🛠 For support, see the <a href=\"https://www.reddit.com/r/VDONinja/\">sub-reddit <i class=\"lab la-reddit-alien\"></i></a> or join the <a href=\"https://discord.vdo.ninja/\">Discord <i class=\"lab la-discord\"></i></a>. The <a href=\"https://docs.vdo.ninja/\">documentation is here</a> and my personal email is <i>steve@seguin.email</i>\n</h3> \n\n",
|
||||
"info-blob": "<h2>What is VDO.Ninja</h2><br><li>100% <b>free</b>; no downloads; no personal data collection; no sign-in</li><li>Bring live video from your smartphone, remote computer, or friends directly into OBS or other studio software.</li><li>We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency</li><br><li>Youtube video <i class=\"lab la-youtube\"></i><a href=\"https://www.youtube.com/watch?v=QaA_6aOP9z8&list=PLWodc2tCfAH1WHjl4WAOOoRSscJ8CHACe&index=1\" alt=\"Youtube video demoing VDO.Ninja\">Demoing it here</a></li><br><h3> 🛠 For support, see the <a href=\"https://www.reddit.com/r/VDONinja/\">sub-reddit <i class=\"lab la-reddit-alien\"></i></a> or join the <a href=\"https://discord.vdo.ninja/\">Discord <i class=\"lab la-discord\"></i></a>. The <a href=\"https://docs.vdo.ninja/\">documentation is here</a> and my personal email is <i>steve@seguin.email</i></h3> ",
|
||||
"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-vdo-ninja-chat": "\nWelcome! You can send text messages directly to connected peers from here.\n",
|
||||
"welcome-to-vdo-ninja-chat": "Welcome! You can send text messages directly to connected peers from here.",
|
||||
"privacy-disabled": "Privacy warning: The director will be able to remotely change your camera, microphone, and URL while this page is open, if you continue.",
|
||||
"face-mesh": "Face mesh (slow load)",
|
||||
"anonymous-mask": "Anonymous mask",
|
||||
@ -412,7 +409,6 @@
|
||||
"toggle-control-video": "Toggle control bar",
|
||||
"picture-in-picture": "Picture-in-picture",
|
||||
"chrome-cast": "Cast..",
|
||||
"join-the-room-basic": "Join room as participant",
|
||||
"allow-effects-invite": "Allow video effects to be used",
|
||||
"show-welcome-message": "Show welcome message",
|
||||
"please-select-option-to-join": "Please select an option to join.",
|
||||
@ -471,7 +467,7 @@
|
||||
"digital-zoom": "Digital zoom",
|
||||
"face-tracker": "Face tracker",
|
||||
"add-your-microphone": "Add your Microphone to OBS",
|
||||
"1080p-screen-capture-guide": "For achieving 1080p60 game-capture, <a href=\"https://docs.vdo.ninja/guides/how-to-screen-share-in-1080p\" target=\"_blank\">see here</a>",
|
||||
"1080p-screen-capture-guide": "",
|
||||
"quality-paramaters": "Quality settings",
|
||||
"general-paramaters": "User options",
|
||||
"interview-paramaters": "Two-way chat",
|
||||
@ -517,38 +513,38 @@
|
||||
"new-display-name": "Enter a new Display Name for this stream",
|
||||
"submit-error-report": "Press OK to submit any error logs. Error logs may contain private information.",
|
||||
"director-redirect-1": "The director wishes to redirect you to the URL: ",
|
||||
"director-redirect-2": "\n\nPress OK to be redirected.",
|
||||
"director-redirect-2": "Press OK to be redirected.",
|
||||
"add-a-label": "Add a label",
|
||||
"audio-processing-disabled": "Audio processing is disabled with this guest. Can't mute or change volume",
|
||||
"not-the-director": "<font color='red'>You are not the director of this room. You will have limited to no control.</font>",
|
||||
"room-is-claimed": "The room is already claimed by someone else.\n\nOnly the first person to join a room is the assigned director.\n\nRefresh after the first director leaves to claim.",
|
||||
"token-room-is-claimed": "The room is claimed by someone else.\n\nJoin as a guest or co-director instead.",
|
||||
"room-is-claimed-codirector": "The room is already claimed by someone else.\n\nTrying to join as a co-director...",
|
||||
"streamid-already-published": "The stream ID you are publishing to is already in use.\n\nPlease try with a different invite link or refresh to retry again.\n\nYou will now be disconnected.",
|
||||
"room-is-claimed": "The room is already claimed by someone else.Only the first person to join a room is the assigned director.Refresh after the first director leaves to claim.",
|
||||
"token-room-is-claimed": "The room is claimed by someone else.Join as a guest or co-director instead.",
|
||||
"room-is-claimed-codirector": "The room is already claimed by someone else.Trying to join as a co-director...",
|
||||
"streamid-already-published": "The stream ID you are publishing to is already in use.Please try with a different invite link or refresh to retry again.You will now be disconnected.",
|
||||
"director": "Director",
|
||||
"unknown-user": "Unknown User",
|
||||
"room-test-not-good": "The room name 'test' is very commonly used and may not be secure.\n\nAre you sure you wish to proceed?",
|
||||
"room-test-not-good": "The room name 'test' is very commonly used and may not be secure.Are you sure you wish to proceed?",
|
||||
"load-previous-session": "Would you like to load your previous session's settings?",
|
||||
"enter-password": "Please enter the password below: \n\n(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)",
|
||||
"enter-password-2": "Please enter the password below: \n\n(Note: Passwords are case-sensitive.)",
|
||||
"enter-director-password": "Please enter the director's password:\n\n(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)",
|
||||
"password-incorrect": "The password was incorrect.\n\nRefresh and try again.",
|
||||
"enter-password": "Please enter the password below: (Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)",
|
||||
"enter-password-2": "Please enter the password below: (Note: Passwords are case-sensitive.)",
|
||||
"enter-director-password": "Please enter the director's password:(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)",
|
||||
"password-incorrect": "The password was incorrect.Refresh and try again.",
|
||||
"enter-display-name": "Please enter your display name:",
|
||||
"enter-new-display-name": "Enter a new Display Name for this stream",
|
||||
"what-bitrate": "What bitrate would you like to record at? (kbps)\n(note: This feature is experimental, so have backup recordings going)",
|
||||
"what-bitrate": "What bitrate would you like to record at? (kbps)(note: This feature is experimental, so have backup recordings going)",
|
||||
"enter-website": "Enter a website URL to share",
|
||||
"press-ok-to-record": "Press OK to start recording. Press again to stop and download.\n\nWarning: Keep this browser tab active to continue recording.\n\nYou can change the default video bitrate if desired below (kbps)",
|
||||
"no-streamID-provided": "No streamID was provided; one will be generated randomily.\n\nStream ID: ",
|
||||
"alphanumeric-only": "Info: Only AlphaNumeric characters should be used for the stream ID.\n\nThe offending characters have been replaced by an underscore",
|
||||
"stream-id-too-long": "The Stream ID should be less than 45 alPhaNuMeric characters long.\n\nWe will trim it to length.",
|
||||
"press-ok-to-record": "Press OK to start recording. Press again to stop and download.Warning: Keep this browser tab active to continue recording.You can change the default video bitrate if desired below (kbps)",
|
||||
"no-streamID-provided": "No streamID was provided; one will be generated randomily.Stream ID: ",
|
||||
"alphanumeric-only": "Info: Only AlphaNumeric characters should be used for the stream ID.The offending characters have been replaced by an underscore",
|
||||
"stream-id-too-long": "The Stream ID should be less than 45 alPhaNuMeric characters long.We will trim it to length.",
|
||||
"share-with-trusted": "Share only with those you trust",
|
||||
"pass-recommended": "A password is recommended",
|
||||
"insecure-room-name": "Insecure room name.",
|
||||
"allowed-chars": "Allowed chars",
|
||||
"transfer": "transfer",
|
||||
"armed": "armed",
|
||||
"transfer-guest-to-room": "Transfer guests to room:\n\n(Please note rooms must share the same password)",
|
||||
"transfer-guest-to-url": "Transfer guests to new website URL.\n\nGuests will be prompted to accept unless they are using &consent",
|
||||
"transfer-guest-to-room": "Transfer guests to room:(Please note rooms must share the same password)",
|
||||
"transfer-guest-to-url": "Transfer guests to new website URL.Guests will be prompted to accept unless they are using &consent",
|
||||
"change-url": "change URL",
|
||||
"mute-in-scene": "mute in scene",
|
||||
"unmute-guest": "unmute guest",
|
||||
@ -578,29 +574,29 @@
|
||||
"camera-tip-c922": "<i>Tip:</i> To achieve 60-fps with a C922 webcam, low-light compensation needs to be turned off, exposure set to auto, and 720p used.",
|
||||
"camera-tip-camlink": "<i>Tip:</i> A Cam Link may glitch green/purple if accessed elsewhere while already in use.",
|
||||
"samsung-a-series": "Samsung A-series phones may have issues with Chrome; if so, try Firefox Mobile instead or switch video codecs.",
|
||||
"screen-permissions-denied": "Permission to capture denied. Ensure your browser has screen record system permissions\n\n1.On your Mac, choose Apple menu > System Preferences, click Security & Privacy , then click Privacy.\n2.Select Screen Recording.\n3.Select the checkbox next to your browser to allow it to record your screen.",
|
||||
"change-audio-output-device": "Audio could not be captured. Please make sure you have an audio output device available.\n\nSome gaming headsets (ie: Corsair) may need to be set to 2-channel output to work, as surround sound drivers may cause problems.",
|
||||
"screen-permissions-denied": "Permission to capture denied. Ensure your browser has screen record system permissions1.On your Mac, choose Apple menu > System Preferences, click Security & Privacy , then click Privacy.2.Select Screen Recording.3.Select the checkbox next to your browser to allow it to record your screen.",
|
||||
"change-audio-output-device": "Audio could not be captured. Please make sure you have an audio output device available.Some gaming headsets (ie: Corsair) may need to be set to 2-channel output to work, as surround sound drivers may cause problems.",
|
||||
"prompt-access-request": " is trying to view your stream. Allow them?",
|
||||
"confirm-reload-user": "Are you sure you wish to reload this user's browser?",
|
||||
"webrtc-is-blocked": "⚠ This browser has either blocked WebRTC or does not support it.\n\nThis site will not work without it.\n\nDisable any browser extensions or privacy settings that may be blocking WebRTC, or try a different browser.",
|
||||
"not-clean-session": "Video effects or canvas rendering failed.\n\nCheck to ensure any remotely hosted images are cross-origin allowed.",
|
||||
"webrtc-is-blocked": "⚠ This browser has either blocked WebRTC or does not support it.This site will not work without it.Disable any browser extensions or privacy settings that may be blocking WebRTC, or try a different browser.",
|
||||
"not-clean-session": "Video effects or canvas rendering failed.Check to ensure any remotely hosted images are cross-origin allowed.",
|
||||
"ios-no-screen-share": "Sorry, but your iOS browser does not support screen-sharing.",
|
||||
"android-no-screen-share": "Sorry, your mobile browser does not support screen-sharing.",
|
||||
"no-screen-share-supported": "Sorry, your browser does not support screen-sharing.\n\nPlease use the desktop versions of Firefox or Chrome instead.",
|
||||
"no-screen-share-supported": "Sorry, your browser does not support screen-sharing.Please use the desktop versions of Firefox or Chrome instead.",
|
||||
"speech-not-suppoted": "⚠ Speech Recognition is not supported by this browser",
|
||||
"blue-yeti-tip": "<i>Tip:</i> Blue Yeti microphones may experience issues being overly loud. <a href='https://support.google.com/chrome/thread/7542181?hl=en&msgid=79691143'>Please see here</a> for a solution or disable auto-gain.",
|
||||
"site-not-responsive": "<h3>Notice: The system cannot be accessed or is currently slow to respond.</h3>\n\nCheck your connection or contact support.\n\nThis service requires the use of Websockets over port 443.",
|
||||
"site-not-responsive": "<h3>Notice: The system cannot be accessed or is currently slow to respond.</h3>Check your connection or contact support.This service requires the use of Websockets over port 443.",
|
||||
"no-audio-source-detected": "Notice: No Audio Source was detected",
|
||||
"viewer-count": "Total outbound p2p connections of this remote stream",
|
||||
"enter-url-for-widget": "Enter a URL for a page to embed as a sidebar",
|
||||
"director-password": "Enter the main director's password",
|
||||
"vision-disabled": "The Director has disabled your vision temporarily<br /><br ><center><i style='font-size:500%;' class='las la-eye-slash'></i></center>",
|
||||
"invalid-remote-code": "Invalid remote control code.\n\nUse the field below to try again with a different passcode.",
|
||||
"invalid-remote-code-obs": "Invalid remote control code.\n\nThe remote OBS system needs a matching passcode set using &remote.\n\nSee the documentation for help..",
|
||||
"request-rejected-obs": "The request was rejected.\n\nThe remote OBS system needs a matching passcode set using &remote.\n\nSee the documentation for help.",
|
||||
"invalid-remote-code": "Invalid remote control code.Use the field below to try again with a different passcode.",
|
||||
"invalid-remote-code-obs": "Invalid remote control code.The remote OBS system needs a matching passcode set using &remote.See the documentation for help..",
|
||||
"request-rejected-obs": "The request was rejected.The remote OBS system needs a matching passcode set using &remote.See the documentation for help.",
|
||||
"remote-token-rejected": "The remote request failed; the &remote token did not match or the remote user does not allow remote control.",
|
||||
"remote-control-failed": "The remote control request failed.",
|
||||
"remote-peer-connected": "Remote peer connected to video stream.\n\nConnection to handshake server being killed on request. This increases security, but the peer will not be able to reconnect automatically on connection failure.\n\nPress OK to start the stream!",
|
||||
"remote-peer-connected": "Remote peer connected to video stream.Connection to handshake server being killed on request. This increases security, but the peer will not be able to reconnect automatically on connection failure.Press OK to start the stream!",
|
||||
"director-denied": "The main director denied you as a co-director",
|
||||
"only-main-director": "Only the main director can transfer this guest",
|
||||
"request-failed": "The request failed; you can't apply this action",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user