mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-16 16:18:30 +00:00
commit
b36b52ad8b
131
index.html
131
index.html
@ -55,7 +55,7 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
|
||||
<link rel="stylesheet" href="./main.css?ver=46" />
|
||||
<link rel="stylesheet" href="./main.css?ver=48" />
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.min.js"></script>
|
||||
</head>
|
||||
<body id="main" class="hidden">
|
||||
@ -66,8 +66,8 @@
|
||||
<span itemprop="thumbnail" itemscope itemtype="http://schema.org/ImageObject">
|
||||
<link itemprop="url" href="./media/obsNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=26"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=177"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=29"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=179"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
<a id="logoname" href="./" style="text-decoration: none; color: white; margin: 2px;">
|
||||
@ -103,7 +103,6 @@
|
||||
</div>
|
||||
<div id="head2" class="advanced" style="display: inline-block; text-decoration: none; font-size: 60%; color: white;">
|
||||
<span data-translate="joining-room">You are in room</span>:
|
||||
|
||||
<div id="roomid" style="display: inline-block;"></div>
|
||||
</div>
|
||||
|
||||
@ -165,7 +164,7 @@
|
||||
<span
|
||||
id="helpbutton"
|
||||
title="Show Help Info"
|
||||
onclick="alert('Email steve@seguin.email if the system breaks or check https://reddit.com/r/obsninja for support.\n\nThe Wiki contains many help guides and advanced settings.\n\nAccess the debug menu by pressing CTRL (command) and Left-Clicking on a video.\n\nMost issues can be fixed by using Wired Internet instead of Wi-Fi.')"
|
||||
onclick="alert('For support, please browse https://reddit.com/r/obsninja or join the live chat on Discord at https://discord.obs.ninja.\n\nThe Wiki also contains many help guides and advanced settings, located at https://wiki.obs.ninja.\n\nTo access the video stats menu, hold CTRL (command) and Left-Click on a video. Most video issues can be fixed by using Wired Internet instead of Wi-Fi.')"
|
||||
style="cursor: pointer; display:none;"
|
||||
alt="How to Use This with OBS"
|
||||
>
|
||||
@ -563,7 +562,8 @@
|
||||
<input id="fileselector" onchange="session.publishFile(this,event);" type="file" accept="video/*,audio/*" alt="Hold CTRL (or CMD) to select multiple files" title="Hold CTRL (or CMD) to select multiple files" multiple/>
|
||||
<br /><br />
|
||||
<p style="margin:10px">Keep this tab visible if using Chrome, else the video playback will stop</p>
|
||||
<p style="margin:10px">(Media file streaming is still quite experimental)</p>
|
||||
<p style="margin:10px">(Media file streaming is still quite experimental)</p><br />
|
||||
<p style="margin:10px">File Sharing seems to be broken on Chrome v88. <br />Using The Electron Capture app instead of Chrome should work: <a href="https://github.com/steveseguin/electroncapture/releases/tag/1.1.3" style="color:blue"><u>GET IT HERE</u></a><br />You can also <a href="https://github.com/aws/amazon-chime-sdk-js/issues/1031" style="color:blue">turn off hardware-accleration</a> in Chrome/Edge to fix the issue.</p>
|
||||
</div>
|
||||
|
||||
<div class="outer close">
|
||||
@ -587,9 +587,9 @@
|
||||
<button onclick="previewIframe(getById('iframeURL').value);" >Preview</button>
|
||||
<button onclick="this.innerHTML = 'Update'; session.publishIFrame(getById('iframeURL').value);" >Share</button><br />
|
||||
<small class="iframeblob">
|
||||
<li>Remote website must be CORS/IFrame compatible with full SSL-encryption enabled.</li>
|
||||
<li>Not all websites will work with this feature and many will actively not allow embedding like this.</li>
|
||||
<li>If sharing a Youtube video, try using the embeddable link version and ensure that the video is set to allow embedding.</li>
|
||||
<li>Not all websites will work with this feature as some sites disallow embedding.</li>
|
||||
<li>The site will try to auto-optimize standard Youtube or Twitch links.</li>
|
||||
<li>Remote websites must be CORS/IFrame compatible with full SSL-encryption enabled.</li>
|
||||
</small>
|
||||
<div id="iFramePreview" style=" width: 1280px; height: 720px; margin: auto; padding: 10px;"></div>
|
||||
</div>
|
||||
@ -603,7 +603,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div id="container-7" class="column columnfade pointer card advanced" style="overflow: hidden;" onclick="window.location = './speedtest';">
|
||||
<div id="container-7" class="column columnfade pointer card advanced" 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>
|
||||
</div>
|
||||
@ -620,10 +620,8 @@
|
||||
<span data-translate="info-blob">
|
||||
<h2>What is OBS.Ninja</h2>
|
||||
<br />
|
||||
<li>100%
|
||||
<b>free</b>; no downloads; no personal data collection; no sign-in
|
||||
</li>
|
||||
<li>Bring video from your smartphone, computer, or friends directly into your OBS video stream</li>
|
||||
<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
|
||||
@ -631,41 +629,32 @@
|
||||
<a href="https://www.youtube.com/watch?v=vLpRzMjUDaE&list=PLWodc2tCfAH1WHjl4WAOOoRSscJ8CHACe&index=2" alt="Youtube video demoing OBS.Ninja">Demoing it here</a>
|
||||
</li>
|
||||
<br />
|
||||
|
||||
🥳 Over 350,000 streamers have used OBS.Ninja this month alone, including major TV networks and some of the biggest Youtube/Twitch stars.
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<i>
|
||||
<font style="color: red;">Known issues:</font>
|
||||
</i>
|
||||
<br />
|
||||
<li>
|
||||
MacOS users using OBS will need to update to <a href="https://github.com/obsproject/obs-studio/releases/tag/26.1.2">OBS Studio 26.1.2</a> or resort to
|
||||
window-capturing with the provided <a href="https://github.com/steveseguin/electroncapture">Electron-Capture app</a>.
|
||||
|
||||
</li>
|
||||
<li>If you have <a href="https://github.com/steveseguin/obsninja/wiki/FAQ#video-is-pixelated">"pixel smearing"</a> or corrupted video, try adding <b>&codec=vp9</b> or &codec=h264 to the OBS view link. Using Wi-Fi will make the issue worse.
|
||||
</li>
|
||||
<li>
|
||||
iOS devices may have occasional audio or camera issues, such as no sound or distorted sound. <a href="https://bugs.webkit.org/show_bug.cgi?id=218762">Partially fixed in iOS 14.3</a>
|
||||
If you have <a href="https://github.com/steveseguin/obsninja/wiki/FAQ#video-is-pixelated">"pixel smearing"</a> or corrupted video, try adding <i>&codec=h264</i> or <i>&codec=vp9</i> to the OBS view link. Using Wi-Fi will make the issue worse.
|
||||
</li>
|
||||
<li>
|
||||
Chrome on Android 11 has an issue with the browser freezing at times. To unfreeze it, background the browser and then foreground it again.
|
||||
</li>
|
||||
<li>
|
||||
The VP9 codec on Chromium-based browsers seems to lag when screen-sharing at the moment. Use the OBS Virtual Camera as a capture source instead.
|
||||
</li>
|
||||
<br />
|
||||
🥳 Site Updated: <a href="https://github.com/steveseguin/obsninja/wiki/v16-release-notes">Fed 3rd, 2021</a>. The previous version can be found at
|
||||
<a href="https://obs.ninja/v15/">https://obs.ninja/v15/</a> if you are having new issues.
|
||||
Site Updated: <a href="https://github.com/steveseguin/obsninja/wiki/v16.3-update-notes">Feb 24th, 2021</a> (v16.3). The previous version can be found at <a href="https://obs.ninja/v16/">https://obs.ninja/v16/</a> if you are having issues with this minor update.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<h3>
|
||||
<i>
|
||||
Check out the
|
||||
<a href="https://www.reddit.com/r/OBSNinja/">sub-reddit
|
||||
<i class="lab la-reddit-alien"></i> </a>for help and see the <a href="https://github.com/steveseguin/obsninja/wiki/">Wiki for advanced info</a>. I'm also on
|
||||
<a href="https://discord.gg/T4xpQVv">Discord <i class="lab la-discord"></i></a> or email me at steve@seguin.email
|
||||
🛠 For support, see the <a href="https://www.reddit.com/r/OBSNinja/">sub-reddit <i class="lab la-reddit-alien"></i></a> or join the <a href="https://discord.gg/T4xpQVv">Discord <i class="lab la-discord"></i></a>. The <a href="https://github.com/steveseguin/obsninja/wiki/">Wiki is here</a> and my personal email is <i>steve@seguin.email</i>
|
||||
</h3>
|
||||
|
||||
</i>
|
||||
</h3>
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</center>
|
||||
@ -933,7 +922,7 @@
|
||||
<span data-translate="send-direct-chat"><i class="las la-envelope"></i> Message</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="addToScene" style="grid-column: 1;" data-value="0" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event);">
|
||||
<button data-action-type="addToScene" style="grid-column: 1;" data-value="0" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event, 1);">
|
||||
<i class="las la-plus-square"></i>
|
||||
<span data-translate="add-to-scene">Add to Scene</span>
|
||||
</button>
|
||||
@ -942,9 +931,33 @@
|
||||
<span data-translate="mute-scene" >mute in scene</span>
|
||||
</button>
|
||||
|
||||
<font class="tooltip" style="height: 0; border: 0;">
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" onclick="remoteVolume(this);" style="grid-column: 1; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span></font>
|
||||
<span id="sceneGroup1" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-scene-2" title="Add to Scene 2" onclick="directEnable(this, event, 2);">
|
||||
<span >S2</span>
|
||||
</button>
|
||||
<button style="width:35.2px;" data-action-type="add-scene-3" title="Add to Scene 3" onclick="directEnable(this, event, 3);">
|
||||
<span >S3</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-4" title="Add to Scene 4" onclick="directEnable(this, event, 4);">
|
||||
<span >S4</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
|
||||
<font class="tooltip" style="height: 0; border: 0;">
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" onclick="remoteVolume(this);" style="grid-column: 2; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span>
|
||||
</font>
|
||||
<span id="sceneGroup2" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-scene-5" title="Add to Scene 5" onclick="directEnable(this, event, 5);">
|
||||
<span >S5</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-6" title="Add to Scene 6" onclick="directEnable(this, event, 6);">
|
||||
<span >S6</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-scene-7" title="Add to Scene 7" onclick="directEnable(this, event, 7);">
|
||||
<span >S7</span>
|
||||
</button>
|
||||
</span>
|
||||
<button data-action-type="mute-guest" style="grid-column: 2;" title="Mute this guest everywhere" onclick="remoteMute(this, event);">
|
||||
<i class="las la-microphone-slash"></i>
|
||||
<span data-translate="mute-guest" >mute guest</span>
|
||||
@ -992,13 +1005,51 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="toggle-remote-speaker" style="grid-column: 1;" title="Toggle the remote guest's speaker output" onclick="remoteSpeakerMute(this, event);">
|
||||
<span id="channelGroup1" style="display:none">
|
||||
<button style="width: 35.2px" data-action-type="add-channel" class="pressed" title="Set to Default Audio Channel" onclick="changeChannelOffset(this.dataset.UUID, false);">
|
||||
<span >00</span>
|
||||
</button>
|
||||
<button style="width:35.2px;" data-action-type="add-channel" title="Set to Audio Channel 1" onclick="changeChannelOffset(this.dataset.UUID, 0);">
|
||||
<span >C1</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 2" onclick="changeChannelOffset(this.dataset.UUID, 1);">
|
||||
<span >C2</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="toggle-remote-speaker" title="Toggle the remote guest's speaker output" onclick="remoteSpeakerMute(this, event);">
|
||||
<i class="las la-volume-off"></i> <span data-translate="toggle-remote-speaker">Deafen Guest</span>
|
||||
</button>
|
||||
|
||||
<span id="channelGroup2" style="display:none" >
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 3" onclick="changeChannelOffset(this.dataset.UUID, 2);">
|
||||
<span >C3</span>
|
||||
</button>
|
||||
<button style="width:35.2px;" data-action-type="add-channel" title="Set to Audio Channel 4" onclick="changeChannelOffset(this.dataset.UUID,3);">
|
||||
<span >C4</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 5" onclick="changeChannelOffset(this.dataset.UUID, 4);">
|
||||
<span >C5</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button data-action-type="toggle-remote-display" style="grid-column: 2;" title="Toggle the remote guest's display output" onclick="remoteDisplayMute(this, event);">
|
||||
<i class="las la-eye-slash"></i> <span data-translate="toggle-remote-display">Blind Guest</span>
|
||||
</button>
|
||||
|
||||
|
||||
<span id="channelGroup3" style="display:none" >
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 6" onclick="changeChannelOffset(this.dataset.UUID, 5);">
|
||||
<span >C6</span>
|
||||
</button>
|
||||
<button style="width:35.2px;" data-action-type="add-channel" title="Set to Audio Channel 7" onclick="changeChannelOffset(this.dataset.UUID, 6);">
|
||||
<span >C7</span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="add-channel" title="Set to Audio Channel 8" onclick="changeChannelOffset(this.dataset.UUID, 7);">
|
||||
<span >C8</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button class="" data-action-type="advanced-audio-settings" data-active="false" style="grid-column: 1;" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
|
||||
<span data-translate="advanced-audio-settings"><i class="las la-sliders-h"></i> Audio Settings</span>
|
||||
</button>
|
||||
@ -1158,7 +1209,7 @@
|
||||
}
|
||||
|
||||
var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js.
|
||||
session.version = "16.2";
|
||||
session.version = "16.3";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Disabling improves compatibility and is helpful for debugging.
|
||||
@ -1223,7 +1274,7 @@
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="mixer-js" src="./mixer.js?ver=2"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=163"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=168"></script>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){ // lazy load
|
||||
var script = document.createElement('script');
|
||||
|
||||
90
main.css
90
main.css
@ -486,9 +486,9 @@ button.glyphicon-button.active.focus {
|
||||
#container.vidcon {
|
||||
height:100%;
|
||||
}
|
||||
@media only screen and (max-width: 700px){
|
||||
@media only screen and (max-width: 640px){
|
||||
#controlButtons {
|
||||
transform: scale(0.8) translateY(20%);
|
||||
transform: scale(0.9) translateY(10%);
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 400px){
|
||||
@ -521,10 +521,21 @@ button.btnArmTransferRoom.selected{
|
||||
|
||||
@media only screen and (max-height: 540px){
|
||||
#subControlButtons {
|
||||
transform: scale(0.90);
|
||||
transform: scale(0.88);
|
||||
}
|
||||
#gridlayout>#container.vidcon {
|
||||
height:90%
|
||||
height:88%
|
||||
}
|
||||
#controlButtons {
|
||||
height:54px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 500px){
|
||||
#subControlButtons {
|
||||
transform: scale(0.87);
|
||||
}
|
||||
#gridlayout>#container.vidcon {
|
||||
height:87%
|
||||
}
|
||||
#controlButtons {
|
||||
height:54px;
|
||||
@ -534,7 +545,16 @@ button.btnArmTransferRoom.selected{
|
||||
#subControlButtons {
|
||||
transform: scale(0.85);
|
||||
}
|
||||
#header{
|
||||
#logoname{
|
||||
display:none;
|
||||
}
|
||||
#head1{
|
||||
display:none;
|
||||
}
|
||||
#head4{
|
||||
display:none;
|
||||
}
|
||||
#head2{
|
||||
display:none;
|
||||
}
|
||||
#gridlayout>#container.vidcon {
|
||||
@ -544,6 +564,20 @@ button.btnArmTransferRoom.selected{
|
||||
height:50px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 300px){
|
||||
#gridlayout>#container.vidcon {
|
||||
height:81%
|
||||
}
|
||||
#subControlButtons {
|
||||
transform: scale(0.81);
|
||||
}
|
||||
#controlButtons {
|
||||
height:46.2px;
|
||||
}
|
||||
#head2 {
|
||||
display:none !important;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 240px){
|
||||
#gridlayout>#container.vidcon {
|
||||
height:78%
|
||||
@ -589,6 +623,9 @@ button.btnArmTransferRoom.selected{
|
||||
}
|
||||
}
|
||||
|
||||
#header:empty{
|
||||
display:none;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
@ -949,6 +986,18 @@ input[type=range]:focus::-ms-fill-upper {
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 355px) {
|
||||
#popupSelector {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 330px) {
|
||||
#popupSelector {
|
||||
padding: 0 !important;
|
||||
font-size: 92%;
|
||||
}
|
||||
}
|
||||
|
||||
.popupSelector_constraints{
|
||||
margin:30px 9% 0 7%;
|
||||
}
|
||||
@ -2160,36 +2209,21 @@ span#guestTips {
|
||||
|
||||
|
||||
.video-label.zoom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 0px;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
.video-label.teams {
|
||||
position: absolute;
|
||||
bottom: 0.6vh;
|
||||
left: 0.5vh;
|
||||
margin: 0px;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
background: rgba(0, 0, 0, .4);
|
||||
pointer-events:none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.video-label.skype {
|
||||
position: absolute;
|
||||
bottom: 2vh;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin: 0px;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
background: rgba(0, 0, 0, .8);
|
||||
pointer-events:none;
|
||||
border-radius: 5px;
|
||||
@ -2197,7 +2231,6 @@ span#guestTips {
|
||||
}
|
||||
|
||||
.video-label.ninjablue {
|
||||
position: absolute;
|
||||
bottom: 5%;
|
||||
left: 0;
|
||||
background: #141926;
|
||||
@ -2205,7 +2238,6 @@ span#guestTips {
|
||||
}
|
||||
|
||||
.video-label.toprounded {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: unset;
|
||||
background: rgb(0 0 0 / 70%);
|
||||
@ -2223,11 +2255,10 @@ span#guestTips {
|
||||
}
|
||||
|
||||
.video-label.fire {
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0 -1px 4px #FFF, 0 -2px 10px #ff0, 0 -10px 20px #ff8000, 0 -18px 40px #F00;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
bottom: 2vh;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@ -2237,22 +2268,25 @@ span#guestTips {
|
||||
display:block;
|
||||
width:0.5vh;
|
||||
height:0.5vh;
|
||||
min-width:10px;
|
||||
min-height:10px;
|
||||
top: 2vh;
|
||||
right: 2vh;
|
||||
background-color:green;
|
||||
position:absolute;
|
||||
display:none;
|
||||
border-radius: 1vh;
|
||||
border-radius: 2vh;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
.video-mute-state {
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
top: 2vh;
|
||||
right: 2vh;
|
||||
position: absolute;
|
||||
color:white;
|
||||
border-radius: 1vh;
|
||||
border-radius: 2vh;
|
||||
background-color:#b11313;
|
||||
padding: 2px 2px 2px 1px;
|
||||
}
|
||||
|
||||
#help_directors_room{
|
||||
|
||||
273
main.js
273
main.js
@ -669,6 +669,23 @@ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(naviga
|
||||
}
|
||||
|
||||
|
||||
if ((iOS) || (iPad)) {
|
||||
window.addEventListener('resize', function() { // Safari is the new IE.
|
||||
|
||||
if ( window.matchMedia("(orientation: portrait)").matches ) {
|
||||
document.getElementsByTagName("html")[0].style.height = "100vh";
|
||||
setTimeout(function(){
|
||||
document.getElementsByTagName("html")[0].style.height = "100%";
|
||||
}, 1000);
|
||||
} else if ( window.matchMedia("(orientation: landscape)").matches ) {
|
||||
document.getElementsByTagName("html")[0].style.height = "100vh";
|
||||
setTimeout(function(){
|
||||
document.getElementsByTagName("html")[0].style.height = "100%";
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (/CriOS/i.test(navigator.userAgent) && (iOS || iPad)) {
|
||||
if (!(session.cleanOutput)) {
|
||||
try {
|
||||
@ -682,11 +699,11 @@ if (/CriOS/i.test(navigator.userAgent) && (iOS || iPad)) {
|
||||
if (urlParams.has('broadcast') || urlParams.has('bc')) {
|
||||
log("Broadcast flag set");
|
||||
session.broadcast = urlParams.get('broadcast') || urlParams.get('bc');
|
||||
if ((iOS) || (iPad)) {
|
||||
session.nopreview = false;
|
||||
} else {
|
||||
session.nopreview = true;
|
||||
}
|
||||
//if ((iOS) || (iPad)) {
|
||||
// session.nopreview = false;
|
||||
//} else {
|
||||
// session.nopreview = true;
|
||||
//}
|
||||
session.style = 1;
|
||||
getById("header").style.display = "none";
|
||||
getById("header").style.opacity = 0;
|
||||
@ -774,9 +791,9 @@ if (urlParams.has('blind')) {
|
||||
|
||||
if (urlParams.has('dpi') || urlParams.has('dpr')) {
|
||||
session.devicePixelRatio = urlParams.get('dpi') || urlParams.get('dpr') || 2.0;
|
||||
} else if (window.devicePixelRatio && window.devicePixelRatio!==1){
|
||||
session.devicePixelRatio = window.devicePixelRatio; // this annoys me to no end.
|
||||
}
|
||||
} //else if (window.devicePixelRatio && window.devicePixelRatio!==1){
|
||||
// session.devicePixelRatio = window.devicePixelRatio; // this annoys me to no end.
|
||||
//}
|
||||
|
||||
if (urlParams.has('speakermute') || urlParams.has('mutespeaker') || urlParams.has('sm') || urlParams.has('ms')) {
|
||||
session.speakerMuted = true;
|
||||
@ -861,6 +878,11 @@ if (urlParams.has('scene')) {
|
||||
session.audioMeterGuest = false;
|
||||
}
|
||||
|
||||
if (urlParams.has('scenes')) {
|
||||
getById("sceneGroup1").style.display = "block";
|
||||
getById("sceneGroup2").style.display = "block";
|
||||
}
|
||||
|
||||
if (urlParams.has('mediasettings')) {
|
||||
session.forceMediaSettings = true;
|
||||
}
|
||||
@ -1897,6 +1919,14 @@ if (urlParams.has('channeloffset')) {
|
||||
log("max channels is 32; channels offset");
|
||||
session.audioEffects = true;
|
||||
}
|
||||
if (urlParams.has('showchannels')) {
|
||||
getById("channelGroup1").style.display = "block";
|
||||
getById("channelGroup2").style.display = "block";
|
||||
getById("channelGroup3").style.display = "block";
|
||||
session.audioEffects = true;
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('enhance')) {
|
||||
//if (parseInt(urlParams.get('enhance')>0){
|
||||
session.enhance = true; //parseInt(urlParams.get('enhance'));
|
||||
@ -2147,6 +2177,8 @@ if (urlParams.has('turn')) {
|
||||
|
||||
|
||||
if (urlParams.has('privacy') || urlParams.has('private') || urlParams.has('relay')) { // please only use if you are also using your own TURN service.
|
||||
session.privacy = true;
|
||||
|
||||
try {
|
||||
session.configuration.iceTransportPolicy = "relay"; // https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/address
|
||||
} catch (e) {
|
||||
@ -2916,8 +2948,13 @@ if ((session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (ur
|
||||
|
||||
if (session.roomid.length > 0) {
|
||||
if (session.videoDevice === 0) {
|
||||
getById("add_camera").innerHTML = "Join room with Microphone";
|
||||
miniTranslate(getById("add_camera"), "join-room-with-mic");
|
||||
if (session.audioDevice === 0) {
|
||||
getById("add_camera").innerHTML = "Join room";
|
||||
miniTranslate(getById("add_camera"), "join-room");
|
||||
} else {
|
||||
getById("add_camera").innerHTML = "Join room with Microphone";
|
||||
miniTranslate(getById("add_camera"), "join-room-with-mic");
|
||||
}
|
||||
} else {
|
||||
getById("add_camera").innerHTML = "Join Room with Camera";
|
||||
miniTranslate(getById("add_camera"), "join-room-with-camera");
|
||||
@ -3723,10 +3760,10 @@ function lowerhand() {
|
||||
var previousRoom = "";
|
||||
var stillNeedRoom = true;
|
||||
var transferCancelled = false;
|
||||
var armedTransfer = true;
|
||||
var armedTransfer = false;
|
||||
|
||||
function directMigrate(ele, event) { // everyone in the room will hangup this guest also? I like that idea. What about the STREAM ID? I suppose we don't kick out if the viewID matches.
|
||||
|
||||
log("directMigrate");
|
||||
if (event === false) {
|
||||
if (previousRoom === null) { // user cancelled in previous callback
|
||||
ele.innerHTML = '<i class="las la-paper-plane"></i> <span data-translate="forward-to-room">Transfer</span>';
|
||||
@ -3743,6 +3780,7 @@ function directMigrate(ele, event) { // everyone in the room will hangup this gu
|
||||
ele.innerHTML = '<i class="las la-check"></i> <span data-translate="forward-to-room">Armed</span>';
|
||||
ele.style.backgroundColor = "#BF3F3F";
|
||||
transferCancelled = false;
|
||||
armedTransfer=true;
|
||||
Callbacks.push([directMigrate, ele, stillNeedRoom]);
|
||||
stillNeedRoom = false;
|
||||
log("Migrate queued");
|
||||
@ -3826,28 +3864,33 @@ function directHangup(ele, event) { // everyone in the room will hangup this gue
|
||||
}
|
||||
}
|
||||
|
||||
function directEnable(ele, event) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
function directEnable(ele, event, scene=1) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
if (!((event.ctrlKey) || (event.metaKey))) {
|
||||
if (ele.dataset.enable == 1) {
|
||||
ele.dataset.enable = 0;
|
||||
ele.className = "";
|
||||
ele.children[1].innerHTML = "Add to Scene";
|
||||
getById("container_" + ele.dataset.UUID).style.backgroundColor = null;
|
||||
if (ele.children[1]){
|
||||
ele.children[1].innerHTML = "Add to Scene";
|
||||
getById("container_" + ele.dataset.UUID).style.backgroundColor = null;
|
||||
}
|
||||
} else {
|
||||
getById("container_" + ele.dataset.UUID).style.backgroundColor = "#649166";
|
||||
ele.dataset.enable = 1;
|
||||
ele.className = "pressed";
|
||||
ele.children[1].innerHTML = "Remove";
|
||||
if (ele.children[1]){
|
||||
ele.children[1].innerHTML = "Remove";
|
||||
getById("container_" + ele.dataset.UUID).style.backgroundColor = "#649166";
|
||||
}
|
||||
}
|
||||
}
|
||||
var msg = {};
|
||||
msg.request = "sendroom";
|
||||
//msg.roomid = session.roomid;
|
||||
msg.scene = "1"; // scene
|
||||
msg.scene = scene;
|
||||
msg.action = "display";
|
||||
msg.value = ele.dataset.enable;
|
||||
msg.target = ele.dataset.UUID;
|
||||
|
||||
//session.anysend(msg);
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
|
||||
@ -4916,6 +4959,8 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
codecGroupFlag = "&codec=h264";
|
||||
} else if (codecGroupFlag.value === "vp8") {
|
||||
codecGroupFlag = "&codec=vp8";
|
||||
} else if (codecGroupFlag.value === "av1") {
|
||||
codecGroupFlag = "&codec=av1";
|
||||
} else {
|
||||
codecGroupFlag = "";
|
||||
}
|
||||
@ -4939,11 +4984,7 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
|
||||
try {
|
||||
if (session.label === false) {
|
||||
if (document.title == "") {
|
||||
document.title = "Control Room";
|
||||
} else {
|
||||
document.title += " - Control Room";
|
||||
}
|
||||
document.title = "Control Room";
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
@ -5022,7 +5063,14 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
getById("chatbutton").classList.add("advanced");
|
||||
}
|
||||
|
||||
joinRoom(session.roomid);
|
||||
if (session.autostart){
|
||||
press2talk(true);
|
||||
} else {
|
||||
session.seeding=true;
|
||||
session.seedStream();
|
||||
}
|
||||
|
||||
joinRoom(session.roomid);
|
||||
|
||||
}
|
||||
/**
|
||||
@ -5474,12 +5522,17 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
if ((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice))) {
|
||||
tmp.push(deviceInfo);
|
||||
log("A DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
|
||||
} else if (deviceInfo.deviceId === session.audioDevice){
|
||||
tmp.push(deviceInfo);
|
||||
log("EXACT A DEVICE FOUND");
|
||||
}
|
||||
}
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
if (!((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice)))) {
|
||||
tmp.push(deviceInfo);
|
||||
if (deviceInfo.deviceId !== session.audioDevice){
|
||||
tmp.push(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5496,12 +5549,17 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice))) {
|
||||
tmp.push(deviceInfo);
|
||||
log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
|
||||
} else if (deviceInfo.deviceId === session.videoDevice){
|
||||
tmp.push(deviceInfo);
|
||||
log("EXACT V DEVICE FOUND");
|
||||
}
|
||||
}
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
if (!((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice)))) {
|
||||
tmp.push(deviceInfo);
|
||||
if (deviceInfo.deviceId !== session.videoDevice){
|
||||
tmp.push(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
deviceInfos = tmp;
|
||||
@ -7854,6 +7912,36 @@ function previewIframe(iframesrc) { // this is pretty important if you want to a
|
||||
iframesrc = "./";
|
||||
}
|
||||
|
||||
|
||||
if (iframesrc.startsWith("https://") || iframesrc.startsWith("http://")){
|
||||
var domain = (new URL(iframesrc));
|
||||
domain = domain.hostname;
|
||||
log(domain);
|
||||
if ((domain=="www.youtube.com") || (domain=="youtube.com")){
|
||||
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
|
||||
var match = iframesrc.match(regExp);
|
||||
var vidid = (match&&match[7].length==11)? match[7] : false;
|
||||
|
||||
if(vidid){
|
||||
iframesrc = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
|
||||
log(iframesrc);
|
||||
}
|
||||
} else if (domain=="www.twitch.tv"){
|
||||
var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
|
||||
if (vidid){
|
||||
iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
|
||||
log(iframesrc);
|
||||
}
|
||||
} else if (domain=="twitch.tv"){
|
||||
var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
|
||||
if (vidid){
|
||||
iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
|
||||
log(iframesrc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iframe.src = iframesrc;
|
||||
getById("previewIframe").innerHTML = "";
|
||||
getById("previewIframe").style.width = "640px";
|
||||
@ -9481,42 +9569,7 @@ function createIframePopup() {
|
||||
getById("screenshare2button").classList.remove("float2");
|
||||
return;
|
||||
}
|
||||
|
||||
//var iframeContainer = document.createElement("div");
|
||||
//iframeContainer.className="popup";
|
||||
//iframeContainer.style.zIndex = ""+22;
|
||||
//iframeContainer.style.width="640px";
|
||||
//iframeContainer.style.height="480px";
|
||||
//iframeContainer.style.position = "fixed";
|
||||
//iframeContainer.style.top = "60px";
|
||||
//iframeContainer.style.left = "0";
|
||||
//iframeContainer.style.border = "dotted 3px #777";
|
||||
//iframeContainer.style.overflow="auto";
|
||||
//iframeContainer.style.resize="both";
|
||||
//session.screenShareElement = iframeContainer;
|
||||
//session.screenShareElement.dataset.doNotMove = true;
|
||||
|
||||
//var button1 = document.createElement("button");
|
||||
//button1.innerHTML = "<i class='las la-arrows-alt'></i> Move";
|
||||
//button1.className = "popup-header menu";
|
||||
//iframeContainer.appendChild(button1);
|
||||
|
||||
//var button2 = document.createElement("button");
|
||||
//button2.innerHTML = "<i class='las la-times'></i> Close";
|
||||
//button2.className = "menu";
|
||||
//button2.onclick = function(){
|
||||
// iframe.contentWindow.postMessage({"close":true}, '*');
|
||||
// iframe.parentNode.parentNode.removeChild(iframeContainer);
|
||||
// session.screenShareElement = false;
|
||||
//}
|
||||
//iframeContainer.appendChild(button2);
|
||||
|
||||
//var button3 = document.createElement("button");
|
||||
//button3.innerHTML = "<i class='las la-sync'></i> Reload";
|
||||
//button3.className = "menu reload";
|
||||
//button3.onclick = function(){iframe.contentWindow.postMessage({"reload":true}, '*');}
|
||||
//iframeContainer.appendChild(button3);
|
||||
|
||||
|
||||
if (session.screenshareid) {
|
||||
var iFrameID = session.screenshareid;
|
||||
} else {
|
||||
@ -9533,15 +9586,26 @@ function createIframePopup() {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay";
|
||||
iframe.allowtransparency = "true";
|
||||
var pass = "";
|
||||
if (session.password) {
|
||||
pass = "&password=" + session.password; // encodeURIComponent(
|
||||
|
||||
var extras = "";
|
||||
if (session.password){
|
||||
extras += "&password=" + session.password; // encodeURIComponent(
|
||||
}
|
||||
|
||||
if (session.privacy){
|
||||
extras += "&privacy";
|
||||
}
|
||||
|
||||
if (session.quality){
|
||||
extras += "&q="+session.quality;
|
||||
} else {
|
||||
extras += "&q=0";
|
||||
}
|
||||
|
||||
if (session.muted){
|
||||
iframe.src = "./?screenshare&transparent&cleanoutput&noheader&autostart&view&muted&room=" + session.roomid + "&push=" + iFrameID + pass;
|
||||
iframe.src = "./?ad=1&screenshare&transparent&cleanoutput&noheader&autostart&view&muted&room=" + session.roomid + "&push=" + iFrameID + extras;
|
||||
} else {
|
||||
iframe.src = "./?screenshare&transparent&cleanoutput&noheader&autostart&view&room=" + session.roomid + "&push=" + iFrameID + pass;
|
||||
iframe.src = "./?ad=1&screenshare&transparent&cleanoutput&noheader&autostart&view&room=" + session.roomid + "&push=" + iFrameID + extras;
|
||||
}
|
||||
|
||||
iframe.style.width = "100%";
|
||||
@ -9549,8 +9613,6 @@ function createIframePopup() {
|
||||
iframe.style.overflow = "hidden";
|
||||
iframe.id = "screensharesource";
|
||||
|
||||
//iframeContainer.appendChild(iframe);
|
||||
|
||||
|
||||
session.screenShareElement = iframe;
|
||||
session.screenShareElement.dataset.doNotMove = true;
|
||||
@ -10081,7 +10143,7 @@ if ((session.view) && (session.roomid === false)) {
|
||||
if (document.title == "") {
|
||||
document.title = "Room=" + session.roomid.toString();
|
||||
} else {
|
||||
document.title += ", Room=" + session.roomid.toString();
|
||||
document.title += ": " + session.roomid.toString();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@ -10461,7 +10523,7 @@ function toggleQualityDirector(bitrate, UUID, ele = null) { // ele is specific t
|
||||
function createPopoutChat() {
|
||||
var randid = session.generateStreamID(8);
|
||||
log(randid);
|
||||
window.open('./popout?id=' + randid, 'popup', 'width=600,height=480,toolbar=no,menubar=no,resizable=yes');
|
||||
window.open('./popout.html?id=' + randid, 'popup', 'width=600,height=480,toolbar=no,menubar=no,resizable=yes');
|
||||
session.broadcastChannel = new BroadcastChannel(randid);
|
||||
session.broadcastChannel.onmessage = function(e) {
|
||||
if ("loaded" in e.data) {
|
||||
@ -10496,9 +10558,10 @@ function getChatMessage(msg, label = false, director = false, overlay = false) {
|
||||
} else {
|
||||
data.label = "<b>" + data.label + ":</b> ";
|
||||
}
|
||||
label = label+":";
|
||||
} else if (director) {
|
||||
data.label = "<b><i>Director:</i></b> ";
|
||||
label = "Director";
|
||||
label = "Director:";
|
||||
} else {
|
||||
data.label = "";
|
||||
label = "";
|
||||
@ -10512,20 +10575,22 @@ function getChatMessage(msg, label = false, director = false, overlay = false) {
|
||||
}
|
||||
updateMessages();
|
||||
|
||||
if (overlay && director) {
|
||||
var textOverlay = getById("overlayMsgs");
|
||||
if (textOverlay) {
|
||||
var spanOverlay = document.createElement("span");
|
||||
spanOverlay.innerHTML = "<b><i>" + label + ":</i></b> " + msg + "<br />";
|
||||
textOverlay.appendChild(spanOverlay);
|
||||
textOverlay.style.display = "block";
|
||||
var showtime = msg.length * 200 + 3000;
|
||||
if (showtime > 8000) {
|
||||
showtime = 8000;
|
||||
if (overlay) {
|
||||
if (!(session.cleanOutput)){
|
||||
var textOverlay = getById("overlayMsgs");
|
||||
if (textOverlay) {
|
||||
var spanOverlay = document.createElement("span");
|
||||
spanOverlay.innerHTML = "<b><i>" + label + "</i></b> " + msg + "<br />";
|
||||
textOverlay.appendChild(spanOverlay);
|
||||
textOverlay.style.display = "block";
|
||||
var showtime = msg.length * 200 + 3000;
|
||||
if (showtime > 8000) {
|
||||
showtime = 8000;
|
||||
}
|
||||
setTimeout(function(ele) {
|
||||
ele.parentNode.removeChild(ele);
|
||||
}, showtime, spanOverlay);
|
||||
}
|
||||
setTimeout(function(ele) {
|
||||
ele.parentNode.removeChild(ele);
|
||||
}, showtime, spanOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11337,10 +11402,15 @@ function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
source = audioMeterGuest(source, UUID, trackid);
|
||||
}
|
||||
|
||||
if (session.offsetChannel !==false){ // proably better to do this last.
|
||||
if (session.rpcs[UUID].channelOffset !== false){
|
||||
log("custom offset set");
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
|
||||
source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.rpcs[UUID].channelOffset);
|
||||
screwedUp = true;
|
||||
} else if (session.offsetChannel !== false){ // proably better to do this last.
|
||||
log("adding offset channels");
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
|
||||
source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source);
|
||||
source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.offsetChannel);
|
||||
screwedUp = true;
|
||||
}
|
||||
|
||||
@ -11364,7 +11434,28 @@ function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
return stream;
|
||||
}
|
||||
|
||||
function offsetChannel( destination, source){
|
||||
function changeChannelOffset(UUID, channel){
|
||||
session.rpcs[UUID].channelOffset = channel;
|
||||
var tracks = session.rpcs[UUID].streamSrc.getAudioTracks();
|
||||
if (tracks.length){
|
||||
var track = tracks[0];
|
||||
session.rpcs[UUID].videoElement.srcObject = addAudioPipeline(session.rpcs[UUID].streamSrc, UUID, track);
|
||||
}
|
||||
|
||||
var ele = document.querySelectorAll('[data-action-type="add-channel"][data--u-u-i-d="' + UUID + '"]');
|
||||
for (var i=0;i<ele.length;i++){
|
||||
if ((i==0) && (channel===false)){
|
||||
ele[i].classList.add("pressed");
|
||||
} else if (channel===i-1){
|
||||
ele[i].classList.add("pressed");
|
||||
} else {
|
||||
ele[i].classList.remove("pressed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function offsetChannel( destination, source, offset){
|
||||
session.audioCtx.destination.channelCountMode = 'explicit';
|
||||
session.audioCtx.destination.channelInterpretation = 'discrete';
|
||||
destination.channelCountMode = 'explicit';
|
||||
@ -11375,13 +11466,13 @@ function offsetChannel( destination, source){
|
||||
} catch (e){errorlog("Max channels: "+destination.channelCount);}
|
||||
|
||||
var splitter = session.audioCtx.createChannelSplitter(2);
|
||||
var merger = session.audioCtx.createChannelMerger(2+session.offsetChannel);
|
||||
var merger = session.audioCtx.createChannelMerger(2+offset);
|
||||
|
||||
source.connect(splitter);
|
||||
splitter.connect(merger, 0,session.offsetChannel);
|
||||
splitter.connect(merger, 0,offset);
|
||||
|
||||
if ((session.stereo) && (session.stereo!=3)){
|
||||
splitter.connect(merger, 1, 1+session.offsetChannel);
|
||||
splitter.connect(merger, 1, 1+offset);
|
||||
}
|
||||
return merger;
|
||||
}
|
||||
|
||||
@ -1,2 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="65" height="64"><style> .a{stroke-width:10;stroke:#000;}</style><title> background</title><rect height="66" width="67" y="-1" x="-1" fill="#0000"/><g height="100" width="100"><rect y="28.56" x="29.5" height="600" width="800" fill="url(#gridpattern)"/></g><title> Layer 1</title><rect height="3" width="1" y="27.02" x="302" style="fill:#0000;stroke-width:2;stroke:#0000"/><rect height="43" width="48" y="10.8" x="8.38" style="fill-opacity:null;fill:#0000;stroke-opacity:null;stroke-width:2;stroke:#FFF"/>
|
||||
<text font-family="Helvetica, Arial, sans-serif" font-size="24" y="40.49" x="15.38" style="fill:#FFF;font-weight:bold"> HQ</text></svg>
|
||||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="white" x="0px" y="0px" viewBox="0 0 122.88 122.87" style="enable-background:new 0 0 122.88 122.87" xml:space="preserve"><g><path d="M122.88,77.63v41.12c0,2.28-1.85,4.12-4.12,4.12H77.33v-9.62h35.95c0-12.34,0-23.27,0-35.62H122.88L122.88,77.63z M77.39,9.53V0h41.37c2.28,0,4.12,1.85,4.12,4.12v41.18h-9.63V9.53H77.39L77.39,9.53z M9.63,45.24H0V4.12C0,1.85,1.85,0,4.12,0h41 v9.64H9.63V45.24L9.63,45.24z M45.07,113.27v9.6H4.12c-2.28,0-4.12-1.85-4.12-4.13V77.57h9.63v35.71H45.07L45.07,113.27z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 650 B |
@ -1,2 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="65" height="64"><style> .a{stroke-width:10;stroke:#000;}</style><title> background</title><rect height="66" width="67" y="-1" x="-1" fill="#0000"/><g height="100" width="100"><rect y="28.56" x="29.5" height="600" width="800" fill="url(#gridpattern)"/></g><title> Layer 1</title><rect height="3" width="1" y="27.02" x="302" style="fill:#0000;stroke-width:5;stroke:#0000"/><rect height="43" width="48" y="10.8" x="8.38" style="fill-opacity:null;fill:#0000;stroke-opacity:null;stroke-width:5;stroke:#FFF"/>
|
||||
<text font-family="Helvetica, Arial, sans-serif" font-size="24" y="40.49" x="15.38" style="fill:#FFF;font-weight:bold"> LQ</text></svg>
|
||||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" fill="white" width="122.88px" height="122.871px" viewBox="0 0 122.88 122.871" enable-background="new 0 0 122.88 122.871" xml:space="preserve"><g><path d="M122.88,35.775v9.529H81.515c-2.278,0-4.125-1.847-4.125-4.125V0h9.63v35.775H122.88L122.88,35.775z M35.499,0h9.63v41.118 c0,2.278-1.847,4.125-4.125,4.125H0v-9.644h35.499V0L35.499,0z M0,87.164v-9.598h40.942c2.277,0,4.125,1.846,4.125,4.125v41.18 h-9.633V87.164H0L0,87.164z M77.328,122.871V81.752c0-2.277,1.847-4.125,4.125-4.125h41.427v9.625H86.931 c0,12.338-0.003,23.271-0.003,35.619H77.328L77.328,122.871z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 733 B |
2
media/svg.md
Normal file
2
media/svg.md
Normal file
@ -0,0 +1,2 @@
|
||||
https://uxwing.com/collapse-icon/
|
||||
https://uxwing.com/expand-icon/
|
||||
@ -6,6 +6,15 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>OBSN Speed Test</title>
|
||||
<script>
|
||||
|
||||
function getChromeVersion() {
|
||||
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
|
||||
return raw ? parseInt(raw[2], 10) : false;
|
||||
}
|
||||
if (!getChromeVersion()){
|
||||
alert("This speedtest is optimized for Chromium-based browsers; graphs will not work for Firefox or Safari browsers.");
|
||||
}
|
||||
|
||||
(function (w) {
|
||||
w.URLSearchParams =
|
||||
w.URLSearchParams ||
|
||||
|
||||
35
thirdparty/CodecsHandler.js
vendored
35
thirdparty/CodecsHandler.js
vendored
@ -31,17 +31,13 @@ var CodecsHandler = (function() {
|
||||
|
||||
if (!info.videoCodecNumbers) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'vp8' && info.vp8LineNumber === info.videoCodecNumbers[0]) {
|
||||
} else if (codecName === 'vp8' && info.vp8LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'vp9' && info.vp9LineNumber === info.videoCodecNumbers[0]) {
|
||||
} else if (codecName === 'vp9' && info.vp9LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'h264' && info.h264LineNumber === info.videoCodecNumbers[0]) {
|
||||
} else if (codecName === 'h264' && info.h264LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
} else if (codecName === 'av1' && info.av1LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
@ -58,21 +54,24 @@ var CodecsHandler = (function() {
|
||||
return sdp;
|
||||
}
|
||||
preferCodecNumber = info.vp8LineNumber;
|
||||
}
|
||||
|
||||
if (codec === 'vp9') {
|
||||
|
||||
} else if (codec === 'vp9') {
|
||||
if (!info.vp9LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
preferCodecNumber = info.vp9LineNumber;
|
||||
}
|
||||
|
||||
if (codec === 'h264') {
|
||||
|
||||
} else if (codec === 'h264') {
|
||||
if (!info.h264LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
preferCodecNumber = info.h264LineNumber;
|
||||
|
||||
} else if (codec === 'av1') {
|
||||
if (!info.av1LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
preferCodecNumber = info.av1LineNumber;
|
||||
}
|
||||
|
||||
var newLine = info.videoCodecNumbersOriginal.split('SAVPF')[0] + 'SAVPF ';
|
||||
@ -117,6 +116,10 @@ var CodecsHandler = (function() {
|
||||
|
||||
if (line.indexOf('H264/90000') !== -1 && !info.h264LineNumber) {
|
||||
info.h264LineNumber = line.replace('a=rtpmap:', '').split(' ')[0];
|
||||
}
|
||||
|
||||
if (line.indexOf('AV1X/90000') !== -1 && !info.av1LineNumber) {
|
||||
info.av1LineNumber = line.replace('a=rtpmap:', '').split(' ')[0];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
182
zoom.html
Normal file
182
zoom.html
Normal file
@ -0,0 +1,182 @@
|
||||
|
||||
<html>
|
||||
<head><style>
|
||||
span{margin:10px 0 0 0;display:block;}
|
||||
body {
|
||||
|
||||
background-color:#cdf;
|
||||
padding:0;
|
||||
width;100%;height:100%
|
||||
}
|
||||
|
||||
input{padding:5px;}
|
||||
|
||||
button {margin:10px 3px;}
|
||||
|
||||
#stream{
|
||||
display:block;
|
||||
}
|
||||
|
||||
</style></head>
|
||||
<body id="main" style="margin:5%;"
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
<video id="video" autoplay="true" muted="true" playsinline style='height:420px;background-color:black;display:block;margin:0 0 10px 0;'></video>
|
||||
<div id="devices">
|
||||
<div class="select">
|
||||
<label for="videoSource">Video source: </label><select id="videoSource"></select>
|
||||
</div>
|
||||
<div class="select">
|
||||
<label for="audioSource">Audio source: </label><select id="audioSource"></select>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="fullwindow()">FULL WINDOW</button>
|
||||
<script>
|
||||
window.onerror = function backupErr(errorMsg, url=false, lineNumber=false) {
|
||||
console.error(errorMsg);
|
||||
console.error(lineNumber);
|
||||
console.error("Unhandeled Error occured"); //or any message
|
||||
return false;
|
||||
};
|
||||
|
||||
function fullwindow(){
|
||||
videoElement.style.width="100%";
|
||||
videoElement.style.padding= "0";
|
||||
videoElement.style.margin="0";
|
||||
videoElement.style.height="100%";
|
||||
videoElement.style.zIndex="5";
|
||||
videoElement.style.position = "absolute";
|
||||
videoElement.style.top="0px";
|
||||
videoElement.style.left="0px";
|
||||
document.getElementById("main").style.overflow = "hidden";
|
||||
videoElement.style.overflow = "hidden"
|
||||
document.getElementById("main").style.backgroundColor="#000";
|
||||
videoElement.style.cursor="none";
|
||||
document.getElementById("main").style.cursor="none";
|
||||
}
|
||||
|
||||
var videoElement = document.getElementById("video");
|
||||
var gotDev = false;
|
||||
async function gotDevices() {
|
||||
if (gotDev){return;}
|
||||
gotDev=true;
|
||||
await navigator.mediaDevices.getUserMedia({audio:true, video:true}); // is needed to ask for permissinos.
|
||||
navigator.mediaDevices.enumerateDevices().then((deviceInfos)=>{
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
var deviceInfo = deviceInfos[i];
|
||||
var option = document.createElement("option");
|
||||
option.value = deviceInfo.deviceId;
|
||||
|
||||
if (deviceInfo.kind === "audioinput") {
|
||||
option.text = deviceInfo.label || "microphone " + (audioSelect.length + 1);
|
||||
audioSelect.appendChild(option);
|
||||
if (option.text.startsWith("CABLE")){
|
||||
option.selected =true;
|
||||
}
|
||||
} else if (deviceInfo.kind === "videoinput") {
|
||||
option.text = deviceInfo.label || "camera " + (videoSelect.length + 1);
|
||||
if (option.text.startsWith("NewTek")){
|
||||
continue;
|
||||
}
|
||||
videoSelect.appendChild(option);
|
||||
if (option.text.startsWith("OBS")){
|
||||
option.selected =true;
|
||||
}
|
||||
}
|
||||
}
|
||||
getStream();
|
||||
});
|
||||
}
|
||||
|
||||
function getStream() {
|
||||
if (window.stream) {
|
||||
window.stream.getTracks().forEach(function (track) {
|
||||
track.stop();
|
||||
log("TRack stopping");
|
||||
});
|
||||
}
|
||||
|
||||
const constraints = {
|
||||
audio: {
|
||||
deviceId: { exact: audioSelect.value },
|
||||
echoCancellation : false,
|
||||
autoGainControl : false,
|
||||
noiseSuppression : false
|
||||
},
|
||||
video: {
|
||||
deviceId: { exact: videoSelect.value },
|
||||
width: { min: 1280, ideal: 1920, max: 1920 },
|
||||
height: { min: 720, ideal: 1080, max: 1080 }
|
||||
}
|
||||
};
|
||||
return navigator.mediaDevices.getUserMedia(constraints)
|
||||
.then(gotStream)
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
|
||||
function gotStream(stream) {
|
||||
if (window.stream) {
|
||||
window.stream = stream; // make stream available to console
|
||||
videoElement.srcObject = stream;
|
||||
var senders = session.pc.getSenders();
|
||||
videoElement.srcObject.getVideoTracks().forEach((track)=>{
|
||||
var added = false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track) {
|
||||
if (sender.track && sender.track.kind == "video") {
|
||||
sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
|
||||
track.enabled = notCensored;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (added==false){
|
||||
session.pc.addTrack(track);
|
||||
log("ADDED NOT REPLACED?");
|
||||
}
|
||||
});
|
||||
|
||||
videoElement.srcObject.getAudioTracks().forEach((track)=>{
|
||||
var added = false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track) {
|
||||
if (sender.track && sender.track.kind == "audio") {
|
||||
sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
|
||||
track.enabled = notCensored;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (added==false){
|
||||
session.pc.addTrack(track);
|
||||
log("ADDED NOT REPLACED?");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.stream = stream; // make stream available to console
|
||||
videoElement.srcObject = stream;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var audioSelect = document.querySelector("select#audioSource");
|
||||
var videoSelect = document.querySelector("select#videoSource");
|
||||
audioSelect.onchange = getStream;
|
||||
videoSelect.onchange = getStream;
|
||||
gotDevices();
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user