fixing my last commit. :/

This commit is contained in:
Steve Seguin 2020-05-12 05:02:21 -04:00 committed by GitHub
parent ac34971a50
commit 3263cbd684
2 changed files with 239 additions and 178 deletions

View File

@ -2,47 +2,47 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta name="copyright" content="&copy; 2020 Stephen Seguin" />
<meta content="utf-8" http-equiv="encoding">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" href="favicon.ico" />
<link rel="icon" type="image/png" sizes="32x32" href="./images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./images/favicon-16x16.png">
<link rel="icon" href="./images/favicon.ico" />
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="font-awesome.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script type="text/javascript" src="qrcode.min.js"></script>
<script type="text/javascript" src="./thirdparty/qrcode.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<link rel="stylesheet" href="./main.css" />
</head>
<body id="main" class="cat">
<script language="javascript" type="text/javascript" src="./CodecsHandler.js"></script>
<script language="javascript" type="text/javascript" src="./thirdparty/CodecsHandler.js"></script>
<script language="javascript" type="text/javascript" src="./webrtc.js?version=12"></script>
<input id='zoomSlider'type="range" style="display:none">
<div id="header">
<font style="font-size:130%;">
<a href="./" style="text-decoration:none;color:white;margin: 2px;" id="logoname"><font id="qos">O</font>BS.Ninja </a>
<a href="./" style="text-decoration:none;color:white;margin: 2px;" id="logoname">
<span data-translate="logo-header"><font id="qos">O</font>BS.Ninja </a></span>
<div id="head1" style="display:inline-block;position:relative;">
<input id="joinroomID" name="joinroomID" size=26 placeholder=" Join by Room Name here"></input>
<button style="padding:0px;margin: 0 0" onclick="jumptoroom();">&nbspGO&nbsp</button>
<button style="padding:0px;margin: 0 0" onclick="jumptoroom();">&nbsp;<span data-translate="GO">GO</span>&nbsp;</button>
</div>
<div id="head3" style="display:inline-block" class='advanced'>
<font style='font-size:80%;color:#888' id="copythisurl"> &nbsp Copy this URL into an OBS "Browser Source" => &nbsp </font>
<font style='font-size:80%;color:#888' id="copythisurl"> &nbsp; <span data-translate="copy-this-url">Copy this URL into an OBS "Browser Source"</span> => &nbsp; </font>
<input id="reshare" data-drag="1" onclick="popupMessage(event);copyFunction(this)" class="task" onmousedown="copyFunction(this)" style="font-weight:bold; color:#AFA; cursor:grab; background-color:#202;border: 2px solid black; padding:5px; font-size:115%; min-width:550px;max-width:700px;" />
<i class="fa fa-paperclip task" aria-hidden="true" onclick="popupMessage(event);copyFunction(document.getElementById('reshare'));" onmouseover="this.style.cursor='pointer'"></i>
</div>
<div id="head4" style="display:inline-block" class='advanced'>
<font style="font-size:68%;color:white;"> &nbsp You are in the room's control center:&nbsp <div id="dirroomid" style="font-size:140%;color:#99C;display:inline-block"></div></font>
<font style="font-size:68%;color:white;" > &nbsp; <span data-translate="you-are-in-the-control-center">You are in the room's control center</span>:&nbsp; <div id="dirroomid" style="font-size:140%;color:#99C;display:inline-block"></div></font>
</div>
<div id="head2" class="advanced" style="display:inline-block;text-decoration:none;font-size:60%;color:white;">
You are joining room: <div id="roomid" style="display:inline-block"></div>
<span data-translate="joining-room">You are joining room</span>: <div id="roomid" style="display:inline-block"></div>
</div>
</font>
@ -58,60 +58,64 @@
<div id="mainmenu" class="row" style="align:center;">
<div id="container-1" class="column columnfade" style="background-color:#ddd;">
<h2>Add Group Chat to OBS</h2>
<h2><span data-translate="add-group-chat">Add Group Chat to OBS</span></h2>
<div class="container-inner">
<br /><br />Rooms allow for simplified group-chat and the advanced management of multiple streams at once.<br /><br />
<p><b>Room Name: </b><input id="videoname1" placeholder="Enter a Room Name here" onkeyup="enterPressed(event, createRoom);" size=30 maxlength=50 style="font-size:110%;padding:5px;" /></br ><br /></p>
<br /><br /><span data-translate="rooms-allow-for">Rooms allow for simplified group-chat and the advanced management of multiple streams at once.</span><br /><br />
<p><b><span data-translate="room-name">Room Name</span>: </b><input id="videoname1" placeholder="Enter a Room Name here" onkeyup="enterPressed(event, createRoom);" size=30 maxlength=50 style="font-size:110%;padding:5px;" /></br ><br /></p>
<br />
<button onclick="createRoom()" class="gowebcam">Enter the Room's Control Center</button><br />
<button onclick="createRoom()" class="gowebcam"><span data-translate="enter-the-rooms-control">Enter the Room's Control Center</span></button><br />
<button onclick="toggle(document.getElementById('roomnotes'),this);">Show me some tips..</button>
<button onclick="toggle(document.getElementById('roomnotes'),this);"><span data-translate="show-tips">Show me some tips..</span></button>
<ul style="padding:10px;margin:auto auto;max-width:500px; display:none; text-align:left;" id="roomnotes">
<br /><u><i>Added Notes:</i></u>
<br />
<span data-translate="added-notes">
<u><i>Added Notes:</i></u>
<li>Anyone can enter a room if they know the name, so keep it unique</li>
<li>Having more than four (4) people in a room is not advisable due to performance reasons, but it depends on your hardware.</li>
<li>iOS devices are limited to group sizes of no more than two (2) people. This is a hardware limitation.</li>
<li>The "Recording" option is new and is considered experimental.</li>
<li>You must "Add" a video feed to the "Group Scene" for it to appear there.</li>
<li>There is a new "enhanced fullscreen" button added to the Guest's view.</li>
</span>
</ul>
</div>
<div class="outer close">
<div class="inner">
<label class="labelclass">Back</label>
<label class="labelclass"><span data-translate="back">Back<span></label>
</div>
</div>
</div>
<div id="container-3" class="column columnfade" onclick="previewWebcam()" style="background-color:#ddd;">
<h2 id="add_camera">Add your Camera to OBS</h2>
<h2 id="add_camera"><span data-translate="add-your-camera">Add your Camera to OBS</span></h2>
<div class="container-inner"><br />
<p>Select the audio/video source below</p>
<button onclick="publishWebcam()" id="gowebcam" class="gowebcam">Waiting for Camera to Load</button>
<p><span data-translate="select-audio-video">Select the audio/video source below</span></p>
<button onclick="publishWebcam()" id="gowebcam" class="gowebcam"><span data-translate="waiting-for-camera">Waiting for Camera to Load</span></button>
<p><video id="previewWebcam" oncanplay="updateStats();" muted controls autoplay playsinline style="max-width:640px; max-width:83vw; max-height:30vh"></video>
</p>
<div id="infof"></div>
<br/>
<p>Video source: <select id="videoSource"></select></p><br/>
<p><span data-translate="video-source">Video source</span>: <select id="videoSource"></select></p><br/>
<form id="webcamquality">
<input type="radio" id="fullhd" name="resolution" value="0">
<label for="fullhd">Max Resolution </label> |
<label for="fullhd"><span data-translate="max-resolution">Max Resolution</span> </label> |
<input type="radio" checked id="halfhd" name="resolution" value="1">
<label for="halfhd">Balanced </label> |
<label for="halfhd"><span data-translate="balanced">Balanced</span> </label> |
<input type="radio" id="nothd" name="resolution" value="3">
<label for="nothd">Smooth and Cool</label>
<label for="nothd"><span data-translate="smooth-cool">Smooth and Cool</span></label>
</form>
<center><div id="webcamstats" ></div></center><br/>
<div class="form-group multiselect">
<a class="form-control multiselect-trigger" tabindex="3">
<div id="audioTitle" class="title">Select Audio Sources:<i class="fa fa-chevron-down" aria-hidden="true"></i> </span></div>
<div id="audioTitle" class="title"><span data-translate="select-audio-source">Select Audio Sources</span>:<i class="fa fa-chevron-down" aria-hidden="true"></i> </div>
</a>
<ul id="audioSource" class="multiselect-contents">
<li><input type="checkbox" id="multiselect1" name="multiselect1" style="display:none" checked value="ZZZ"> <label for="multiselect1">No Audio</label></li>
<li><input type="checkbox" id="multiselect1" name="multiselect1" style="display:none" checked value="ZZZ"> <label for="multiselect1">
<span data-translate="no-audio">No Audio</span></label></li>
</ul>
</div>
@ -119,53 +123,54 @@
</div>
<div class="outer close">
<div class="inner">
<label class="labelclass">Back</label>
<label class="labelclass"><span data-translate="back">Back</span></label>
</div>
</div>
</div>
<div id="container-2" class="column columnfade" style="background-color:#ddd;">
<h2 id="add_screen">Remote Screenshare into OBS</h2>
<h2 id="add_screen"><span data-translate="remote-screenshare-obs">Remote Screenshare into OBS</span></h2>
<div class="container-inner">
<p><b>note</b>: Do not forget to click "Share audio" in Chrome.<br />(Firefox does not support audio sharing.)</p>
<p><img src="share.jpg" style="max-height:55vh"/></p>
<p><span data-translate="note-share-audio">
<b>note</b>: Do not forget to click "Share audio" in Chrome.<br />(Firefox does not support audio sharing.)</p>
<p><img src="./images/share.jpg" style="max-height:55vh"/></p>
</span>
<br />
<button style="padding:10px;border:3px solid #CCC; cursor:pointer; background-color:#FFF" onclick="publishScreen()" >SELECT SCREEN TO SHARE</button>
<button style="padding:10px;border:3px solid #CCC; cursor:pointer; background-color:#FFF" onclick="publishScreen()" ><span data-translate="select-screen-to-share">SELECT SCREEN TO SHARE</span></button>
<br /><br />
<p>Audio Sources:<br />
<p><span data-translate="audio-sources">Audio Sources</span>:<br />
<select id="audioSourceScreenshare" multiple style="height:60px;width:200px; resize: both; overflow: auto; padding:5px" onchange="requestAudioStream();">
<option value="screenshare" selected>Screen Share Audio (default)</option>
<option value="microphones" >Other Audio Sources</option>
<option value="screenshare" selected><span data-translate="screen-shrae-audio">Screen Share Audio (default)</span></option>
<option value="microphones" ><span data-translate="other-audio-sources">Other Audio Sources</span></option>
</select></p>
</div>
<div class="outer close">
<div class="inner">
<label class="labelclass">Back</label>
<label class="labelclass"><span data-translate="back">Back</span></label>
</div>
</div>
</div>
<div id="container-4" class="column columnfade" style="background-color:#ddd;">
<h2>Create Reusable Invite</h2>
<h2><span data-translate="create-reusable-invite">Create Reusable Invite</span></h2>
<div id="gencontent" class="container-inner">
<br /><br />
Here you can pre-generate a reusable Browser Source link and a related guest invite link.<br /><br />
<span data-translate="here-you-can-pre-generate">Here you can pre-generate a reusable Browser Source link and a related guest invite link.</span><br /><br />
<p><input style="padding:5px;font-size:120%;" id="videoname4" onkeyup="enterPressed(event, generateQRPage);" placeholder="Give this media source a name (optional)" size=35 maxlength=70 style="padding:5px;" /></br ><br /></p>
<button style="padding:20px;" onclick="generateQRPage()" >GENERATE THE INVITE LINK</button><br /><br /><br />
<button style="padding:20px;" onclick="generateQRPage()" ><span data-translate="generate-invite-link">GENERATE THE INVITE LINK</span></button><br /><br /><br />
<div style="margin:20px;max-width:330px;text-align:left;margin:auto auto;;">
<h5 style="padding:0 0 10px 0"><i>Advanced Parameters</i></h5>
<input type="checkbox" id="invite_bitrate" /><label for="invite_bitrate"> Unlock Video Bitrate (20mbps)</label><br />
<input type="checkbox" id="invite_vp9" /><label for="invite_vp9"> Force VP9 Video Codec (less artifacting)</label><br />
<input type="checkbox" id="invite_stereo" /><label for="invite_stereo"> Enable Stereo and Pro HD Audio</label><br />
<input type="checkbox" id="invite_secure" /><label for="invite_secure"> High Security Mode</label><br /><br />
<h5 style="padding:0 0 10px 0"><i><span data-translate="advanced-paramaters">Advanced Parameters</span></i></h5>
<input type="checkbox" id="invite_bitrate" /><label for="invite_bitrate"> <span data-translate="unlock-video-bitrate">Unlock Video Bitrate (20mbps)</span></label><br />
<input type="checkbox" id="invite_vp9" /><label for="invite_vp9"> <span data-translate="force-vp9-video-codec">Force VP9 Video Codec (less artifacting)</span></label><br />
<input type="checkbox" id="invite_stereo" /><label for="invite_stereo"> <span data-translate="enable-stereo-and-pro">Enable Stereo and Pro HD Audio</span></label><br />
<input type="checkbox" id="invite_secure" /><label for="invite_secure"> <span data-translate="high-security-mode">High Security Mode</span></label><br /><br />
<div>See the <a style="text-decoration:none;color:blue;" target="_blank" href="https://docs.obs.ninja/advanced">documentation</a> for more options.</div>
</div>
</div>
<div class="outer close">
<div class="inner">
<label class="labelclass">Back</label>
<label class="labelclass"><span data-translate="back">Back</span></label>
</div>
</div>
@ -174,26 +179,27 @@
<p><div id="info" class="fullcolumn columnfade">
<center>
<div class="infoblob" align="left">
<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, laptop, computer, or from your friends directly into your OBS video stream</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="fa fa-youtube-play" aria-hidden="true"></i> <a href="https://www.youtube.com/watch?v=6R_sQKxFAhg">Demoing it here</a> </li>
<li>Code is available here: <i class="fa fa-github" aria-hidden="true"></i> <a href="https://github.com/steveseguin/obsninja">https://github.com/steveseguin/obsninja</a> </li>
<li>You can also check out <a href="https://steves.app">my other video app</a> designed for sharing video with friends and family</li>
<br />
<i><font style="color:red">Known issues:</font></i><br />
<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, laptop, computer, or from your friends directly into your OBS video stream</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="fa fa-youtube-play" aria-hidden="true"></i> <a href="https://www.youtube.com/watch?v=6R_sQKxFAhg">Demoing it here</a> </li>
<li>Code is available here: <i class="fa fa-github" aria-hidden="true"></i> <a href="https://github.com/steveseguin/obsninja">https://github.com/steveseguin/obsninja</a> </li>
<li>You can also check out <a href="https://steves.app">my other video app</a> designed for sharing video with friends and family</li>
<br />
<i><font style="color:red">Known issues:</font></i><br />
<li><i class="fa fa-apple" aria-hidden="true"></i> MacOS users need to use OBS v23 or resort to <i>Window Capturing</i> a Chrome Browser with OBS v25</li>
<li>Some users will have "pixelation" problems with videos. Please add the URL parameter <b>&codec=vp9</b> to the OBS Links to correct it.</li>
<br />
Site last updated: <a href='https://www.reddit.com/r/OBSNinja/comments/gf5pd3/new_version_released_today_along_with_new/'>May 7th, 2020.</a> The previous version can be found at <a href="https://obs.ninja/v3/">https://obs.ninja/v3/</a> if you are having new issues.
<li><i class="fa fa-apple" aria-hidden="true"></i> MacOS users need to use OBS v23 or resort to <i>Window Capturing</i> a Chrome Browser with OBS v25</li>
<li>Some users will have "pixelation" problems with videos. Please add the URL parameter <b>&codec=vp9</b> to the OBS Links to correct it.</li>
<br />
Site last updated: <a href='https://www.reddit.com/r/OBSNinja/comments/gf5pd3/new_version_released_today_along_with_new/'>May 7th, 2020.</a> The previous version can be found at <a href="https://obs.ninja/v3/">https://obs.ninja/v3/</a> if you are having new issues.
<br /><br />
<i><h3>Check out the <a href="https://www.reddit.com/r/OBSNinja/">sub-reddit</a> <i class="fa fa-reddit-alien" aria-hidden="true"></i> for help and advanced info. I'm also on <a href="https://discord.gg/EksyhGA">Discord</a> and you can email me at steve@seguin.email</i></h3>
<br /><br />
<i><h3>Check out the <a href="https://www.reddit.com/r/OBSNinja/">sub-reddit</a> <i class="fa fa-reddit-alien" aria-hidden="true"></i> for help and advanced info. I'm also on <a href="https://discord.gg/EksyhGA">Discord</a> and you can email me at steve@seguin.email</i></h3>
</span>
</div>
</center>
</p></div>
@ -208,27 +214,27 @@
<div id="gridlayout"></div>
<div id="controls_blank" style="display:none">
<center><br />
<b>Remote Control for OBS</b><br />
<button data-value="0" style="font-size:112%" onclick="directEnable(this);">Add to Group Scene</button>
<button style="font-size:112%" onclick="directMute(this);">Mute</button>
<button style="font-size:112%" onclick="var video = document.getElementById('videosource_'+this.parentNode.parentNode.dataset.UUID);video.recorder=recordVideo(event,video,this.parentNode.parentNode.dataset.UUID);">Record</button>
<br />Volume:<input type="range" min="1" max="100" value="100" onclick="directVolume(this);"><br />
<b><span data-translate="remote-control-for-obs">Remote Control for OBS</span></b><br />
<button data-value="0" style="font-size:112%" onclick="directEnable(this);"><span data-translate="add-to-group">Add to Group Scene</span></button>
<button style="font-size:112%" onclick="directMute(this);"><span data-translate="mute">Mute</span></button>
<button style="font-size:112%" onclick="var video = document.getElementById('videosource_'+this.parentNode.parentNode.dataset.UUID);video.recorder=recordVideo(event,video,this.parentNode.parentNode.dataset.UUID);"><span data-translate="record">Record</span></button>
<br /><span data-translate="volume">Volume</span>:<input type="range" min="1" max="100" value="100" onclick="directVolume(this);"><br />
<br /><hr /></center>
</div>
<nav id="context-menu" class="context-menu">
<ul class="context-menu__items">
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Open"><i class="fa fa-external-link"></i> Open in new Tab</a>
<a href="#" class="context-menu__link" data-action="Open"><i class="fa fa-external-link"></i> <span data-translate="open-in-new-tab">Open in new Tab</span></a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Copy"><i class="fa fa-paperclip"></i> Copy to Clipboard</a>
<a href="#" class="context-menu__link" data-action="Copy"><i class="fa fa-paperclip"></i> <span data-translate="copy-to-clipboard">Copy to Clipboard</span></a>
</li>
</ul>
</nav>
<div id="messagePopup" class="popup-message">
</div>
<script type="text/javascript" src="./main.js?ver=12"></script>
<script type="text/javascript" src="./template.js"></script>
<script type="text/javascript" src="./animations.js"></script>
</body>

265
main.js
View File

@ -1,8 +1,11 @@
/////////////
// Some browsers partially implement mediaDevices. We can't just assign an object
// with getUserMedia as it would overwrite existing properties.
// Here, we will just add the getUserMedia property if it's missing.
/*
* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
*
* Use of this source code is governed by the APGLv3 open-source license
* that can be found in the LICENSE file in the root of the source
* tree. Alternative licencing options can be made available on request.
*
*/
var VIS = vis;
var formSubmitting = true;
@ -13,7 +16,6 @@ window.onload = function() { // This just keeps people from killing the live str
if (formSubmitting) {
return undefined;
}
var confirmationMessage = 'Leaving the page now will terminate your stream ';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
@ -43,11 +45,10 @@ window.onpopstate = function() {
}
};
var session = Ooblex.Media;
var session = WebRTC.Media;
session.streamID = session.generateStreamID();
(function (w) {
(function (w) {
w.URLSearchParams = w.URLSearchParams || function (searchString) {
var self = this;
self.searchString = searchString;
@ -60,9 +61,9 @@ session.streamID = session.generateStreamID();
return decodeURI(results[1]) || 0;
}
};
}
};
})(window)
})(window);
var urlParams = new URLSearchParams(window.location.search);
var isMobile = false;
@ -77,9 +78,18 @@ if ((urlParams.has('permaid')) || (urlParams.has('push'))){
document.getElementById("container-4").className = 'column columnfade advanced';
}
if (urlParams.has('stereo')){
if (urlParams.has('stereo')){ // both peers need this enabled for HD stereo to be on. If just pub, you get no echo/noise cancellation. if just viewer, you get high bitrate mono
log("STEREO ENABLED");
session.stereo = true;
session.stereo = true;
}
if ((urlParams.has('streamid')) || (urlParams.has('view'))){ // the streams we want to view; if set, but let blank, we will request no streams to watch.
session.view = urlParams.get('streamid') || urlParams.get('view'); // this value can be comma seperated for multiple streams to pull
}
if (urlParams.has('remote')){
log("remote ENABLED");
session.remote = parseInt(urlParams.get('remote'));
}
if (urlParams.has('nocursor')){
@ -104,6 +114,52 @@ if (urlParams.has('codec')){
session.codec = urlParams.get('codec');
}
if (urlParams.has('ln')){ // checking if manual lanuage override enabled
try {
fetch("./translations/"+urlParams.get('ln')+'.json').then(function(response){
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
response.json().then(function(data) {
log(data);
document.querySelectorAll('[data-translate]').forEach(function(ele){
//log(ele.dataset.translate);
//log(translations[ele.dataset.translate]);
ele.innerHTML = data[ele.dataset.translate];
});
});
}).catch(function(err){
errorlog(err);
});
} catch (error){
errorlog(error);
}
} else { // check if automatic language translation is available
if (window.navigator.language.slice(0, 2) !== 'en'){
fetch("./translations/"+window.navigator.language.slice(0, 2)+'.json').then(function(response){
if (response.status !== 200) {
logerror('Language translation file not found.' + response.status);
return;
}
response.json().then(function(data) {
log(data);
document.querySelectorAll('[data-translate]').forEach(function(ele){
//log(ele.dataset.translate);
//log(translations[ele.dataset.translate]);
ele.innerHTML = data[ele.dataset.translate];
});
});
}).catch(function(err){
errorlog(err);
});
}
}
if (urlParams.has('bitrate')){
session.bitrate = parseInt(urlParams.get('bitrate'));
log("BITRATE ENABLED");
@ -118,6 +174,11 @@ if (urlParams.has('width')){
session.width = parseInt(urlParams.get('width'));
}
if (urlParams.has('sink')){
session.sink = urlParams.get('sink');
}
if (urlParams.has('secure')){
session.security = true;
setTimeout(function() {alert("Enhanced Security Mode Enabled.");}, 100);
@ -164,8 +225,12 @@ if (urlParams.has('turn')){
turn.credential = "justtesting";
turn.urls = ["turn:turn.obs.ninja:443"]; // main TURN server. Do not abuse. I pay out of pocket.
session.configuration.iceServers.push(turn);
turn.urls = ["turn:turn2.obs.ninja:443"]; // backup TURN server. Do not abuse. I pay out of pocket.
session.configuration.iceServers.push(turn);
var turn = {};
turn.username = "steve";
turn.credential = "justtesting";
turn.urls = ["turn:turn2.obs.ninja:443"]; // main TURN server. Do not abuse. I pay out of pocket.
session.configuration.iceServers.push(turn);
}
function updateURL(param) {
@ -188,7 +253,6 @@ function updateURL(param) {
}
function jumptoroom(){
document.getElementById("joinroomID").value;
var arr = window.location.href.split('?');
if (arr.length > 1 && arr[1] !== '') {
window.location+="&room="+document.getElementById("joinroomID").value;
@ -263,10 +327,12 @@ if ( (urlParams.has('roomid')) || (filename) || (urlParams.has('room')) ){
function checkConnection(){
if (session.ws.readyState === WebSocket.OPEN) {
document.getElementById("qos").style.color = "white";
} else {
document.getElementById("qos").style.color = "red";
if (document.getElementById("qos")){
if (session.ws.readyState === WebSocket.OPEN) {
document.getElementById("qos").style.color = "white";
} else {
document.getElementById("qos").style.color = "red";
}
}
}
setInterval(function(){checkConnection();},5000);
@ -281,7 +347,7 @@ function updateStats(){
log(track.getSettings());
log(track.getSettings().frameRate);
//log(track.getSettings().frameRate);
document.getElementById("webcamstats").innerHTML = "Current Video Settings: "+(track.getSettings().width|0) +"x"+(track.getSettings().height|0)+"@"+(parseInt(track.getSettings().frameRate*10)/10)+"fps";
document.getElementById("webcamstats").innerHTML = "Current Video Settings: "+(track.getSettings().width||0) +"x"+(track.getSettings().height||0)+"@"+(parseInt(track.getSettings().frameRate*10)/10)+"fps";
}
);
}
@ -328,7 +394,7 @@ function directEnable(ele){ // A directing room only is controlled by the Direct
var msg = {};
msg.request = "sendroom";
msg.roomid = session.roomid;
msg.director = "1" // scene
msg.director = "1"; // scene
msg.action = "display";
msg.value = ele.parentNode.parentNode.dataset.enable;
msg.target = ele.parentNode.parentNode.dataset.UUID;
@ -414,7 +480,7 @@ function publishScreen(){
};
if (session.framerate){
constraints.video.frameRate = {exact: session.framerate};
constraints.video.frameRate = session.framerate;
}
var audioSelect = document.querySelector('select#audioSourceScreenshare');
@ -472,10 +538,10 @@ function joinRoom(roomname, maxbitrate=false){
session.joinRoom(roomname,maxbitrate).then(function(response){ // callback from server; we've joined the room
log("Members in Room");
log(response);
for (i in response){
for (var i in response){
if ("UUID" in response[i]){
if ("streamID" in response[i]){
if (response[i]['UUID'] in session.pcs){
if (response[i].UUID in session.pcs){
log("RTC already connected"); /// lets just say instead of Stream, we have
} else {
//var title = ""; // TODO: Assign labels
@ -483,17 +549,17 @@ function joinRoom(roomname, maxbitrate=false){
// title = response[i]["title"];
//}
if ((urlParams.has('streamid')) || (urlParams.has('view'))){
play(response[i]['streamID']);
if (session.view){ // if they want to watch specific streams only; perhaps from a list even
play(response[i].streamID);
} else {
session.watchStream(response[i]['streamID']); // How do I make sure they aren't requesting the same movie twice as a race condition?
session.watchStream(response[i].streamID); // How do I make sure they aren't requesting the same movie twice as a race condition?
}
}
}
}
}
},function(error){return {}});
},function(error){return {};});
} else {
errorlog("Room name not long enough or contained all bad characaters");
}
@ -513,12 +579,6 @@ function createRoom(){
var gridlayout = document.getElementById("gridlayout");
gridlayout.classList.add("directorsgrid");
// var sheet = document.createElement('style');
// sheet.innerHTML = ".tile{object-fit:contain }";
// document.body.appendChild(sheet);
var roomname = document.getElementById("videoname1").value;
log(roomname);
session.roomid = roomname;
formSubmitting = false;
@ -539,12 +599,12 @@ function createRoom(){
session.director = true;
document.getElementById("reshare").parentNode.removeChild(document.getElementById("reshare"));
gridlayout.innerHTML = "<br /><div style='display:inline-block'><font style='font-size:130%;color:white;'></font><input onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#78F; width:400px; font-size:100%; padding:10px; border:2px solid black; margin:5px;' class='task' value='https://"+location.host+location.pathname+"?room="+session.roomid+"' /><font style='font-size:130%;color:white;'><i class='fa fa-video-camera' style='font-size:2em;' aria-hidden='true'></i> - Invite link to add guests to the group. These guests will see every camera feed, so more than 4 is not recommended.</font></div>";
gridlayout.innerHTML = "<br /><div style='display:inline-block'><font style='font-size:130%;color:white;'></font><input onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#78F; width:400px; font-size:100%; padding:10px; border:2px solid black; margin:5px;' class='task' value='https://"+location.host+location.pathname+"?room="+session.roomid+"' /><font style='font-size:130%;color:white;'><i class='fa fa-video-camera' style='font-size:2em;' aria-hidden='true'></i> - Invites users to join the group and broadcast their feed to it. These users will see every feed, so a limit of 4 is recommended.</font></div>";
gridlayout.innerHTML += "<br /><font style='font-size:130%;color:white;'></font><input class='task' onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#F45;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?room="+session.roomid+"&view' /><font style='font-size:130%;color:white;'><i class='fa fa-video-camera' style='font-size:2em;' aria-hidden='true'></i> - Link to add a camera to the group. This source will not be able to see or hear any other guest in the group.</font><br />";
gridlayout.innerHTML += "<br /><font style='font-size:130%;color:white;'></font><input class='task' onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#F45;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?room="+session.roomid+"&view' /><font style='font-size:130%;color:white;'><i class='fa fa-video-camera' style='font-size:2em;' aria-hidden='true'></i> - Link to Invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.</font><br />";
gridlayout.innerHTML += "<font style='font-size:130%;color:white'></font><input class='task' onmousedown='copyFunction(this)' data-drag='1' onclick='popupMessage(event);copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#5F4;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?scene=1&room="+session.roomid+"' /><font style='font-size:130%;color:white'><i class='fa fa-th-large' style='font-size:2em;' aria-hidden='true'></i> - This is a OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.</font><br />";
gridlayout.innerHTML += "<font style='font-size:130%;color:white'></font><input class='task' onmousedown='copyFunction(this)' data-drag='1' onclick='popupMessage(event);copyFunction(this)' style='cursor:grab;font-weight:bold;background-color:#5F4;width:400px;font-size:100%;padding:10px;border:2px solid black;margin:5px;' value='https://"+location.host+location.pathname+"?scene=1&room="+session.roomid+"' /><font style='font-size:130%;color:white'><i class='fa fa-th-large' style='font-size:2em;' aria-hidden='true'></i> - This is an OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.</font><br />";
gridlayout.innerHTML += '<button style="margin:10px;padding:5px" onclick="toggle(document.getElementById(\'roomnotes2\'),this);">Click Here for a quick overview and help</button>';
@ -557,7 +617,7 @@ function createRoom(){
<li>You can use it to record video streams independently</li>\
<br />\
As guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\
<br />The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br />The Group Scene includes all audio sources by default, but they can be muted manually.<br /><Br />Apple mobile devices, such as iPhones and iPads, do not support Group Chat. This is a hardware constraint.<br /><br /></font></div><hr />";
<br />The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.<br /><Br />Apple mobile devices, such as iPhones and iPads, do not support Group Chat. This is a hardware constraint.<br /><br /></font></div><hr />";
gridlayout.innerHTML += "<div id='deleteme'><br /><br /><center>\
<div style='display:inline-block;width:300px;height:350px;border:2px solid white;background-color:#999;margin:40px;'><br /><br />GUEST SLOT #1<br /><br />(A video will appear here when a guest joins)<br /><br /><i class='fa fa-user ' style='font-size:8em;' aria-hidden='true'></i><br /><br />A Solo-Link for OBS will appear here.</div>\
@ -638,10 +698,10 @@ function requestAudioStream(){
var temp = {};
for (let i = 0; i !== deviceInfos.length; ++i) {
if (deviceInfos[i].kind === 'audioinput') {
if (deviceInfos[i].groupId in temp){
if (deviceInfos[i].deviceId in temp){
deviceInfos[i] = null;
} else {
temp[deviceInfos[i].groupId]=true;
temp[deviceInfos[i].deviceId]=true;
}
}
}
@ -688,10 +748,10 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
var temp = {};
for (let i = 0; i !== deviceInfos.length; ++i) {
if (deviceInfos[i].kind === 'audioinput') {
if (deviceInfos[i].groupId in temp){
if (deviceInfos[i].deviceId in temp){
deviceInfos[i] = null;
} else {
temp[deviceInfos[i].groupId]=true;
temp[deviceInfos[i].deviceId]=true;
}
}
}
@ -1081,7 +1141,7 @@ function dragElement(elmnt) {
// Check whether zoom is supported or not.
if (!('zoom' in capabilities)) {
log('Zoom is not supported by ' + track0.label);
return
return;
}
// Map zoom to a slider element.
@ -1091,7 +1151,7 @@ function dragElement(elmnt) {
input.value = settings.zoom;
} catch(e){errorlog(e);return}
} catch(e){errorlog(e);return;}
@ -1100,7 +1160,7 @@ function dragElement(elmnt) {
elmnt.onclick = onvideoclick;
elmnt.ontouchstart = function (e) {
dragMouseDown(e)
dragMouseDown(e);
};
var pos0 = 1;
@ -1157,8 +1217,8 @@ function dragElement(elmnt) {
var zoom = parseFloat((pos4-pos2)*2/elmnt.offsetHeight);
if (zoom>1){zoom =1.0}
else if (zoom<-1){zoom=-1.0}
if (zoom>1){zoom =1.0;}
else if (zoom<-1){zoom=-1.0;}
//zoom=(zoom+1)/2;
input.value = zoom*(input.max - input.min) + input.min;
@ -1272,7 +1332,7 @@ function previewWebcam(){
if (window.isSecureContext) {
alert("An error has occured when trying to access the webcam. The reason is not known.");
} else {
alert("Error acessing webcam./n/nWebsite is loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
alert("Error acessing webcam.\n\nWebsite is loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
}
}
@ -1308,11 +1368,9 @@ function checkOBS(){
function play(streamid=null){ // play whatever is in the URL params; or filter by a streamID option
log("play stream");
if ((urlParams.has('streamid')) || (urlParams.has('view'))){
var streamlist = urlParams.get('streamid') || urlParams.get('view');
log(streamlist);
streamlist = streamlist.split(",");
for (j in streamlist){
if (session.view){
var streamlist = session.view.split(",");
for (var j in streamlist){
if (streamid===null){
session.watchStream(streamlist[j]);
} else if (streamid === streamlist[j]){
@ -1431,7 +1489,7 @@ function recordVideo(event, video, UUID, videoKbps=2500){
console.log('MediaRecorder started', mediaRecorder);
return this
return this;
}
function copyFunction(copyText) {
copyText.select();
@ -1489,13 +1547,13 @@ function generateQRPage(){
}
if ((urlParams.has('streamid')) || (urlParams.has('view'))){
if (session.view){
document.getElementById("main").className = "";
document.getElementById("credits").style.display = 'none';
}
if (((urlParams.has('streamid')) || (urlParams.has('view'))) && (session.roomid==false)){
if ((session.view) && (session.roomid==false)){
document.getElementById("container-4").className = 'column columnfade';
document.getElementById("container-3").className = 'column columnfade';
document.getElementById("container-2").className = 'column columnfade';
@ -1517,7 +1575,7 @@ if (((urlParams.has('streamid')) || (urlParams.has('view'))) && (session.roomid=
setTimeout(function(){
try{
if ((urlParams.has('streamid')) || (urlParams.has('view'))){
if (session.view){
if (document.getElementById("mainmenu")){
document.getElementById("mainmenu").innerHTML = '<font style="color:#666"><h1>Attempting to load video stream.</h1></font>';
document.getElementById("mainmenu").innerHTML += '<font style="color:#EEE">The stream is not available yet or an error occured.</font><br/><button onclick="location.reload();">Retry Manually</button><br/>';
@ -1527,7 +1585,7 @@ if (((urlParams.has('streamid')) || (urlParams.has('view'))) && (session.roomid=
} else {
clearInterval(retry);
}
},10000)
},10000);
}}
} catch(e){
errorlog("Error handling QR Code failure");
@ -1583,18 +1641,18 @@ function updateMixer(){
log(session.infocus+" set fullscreen");
session.requestRateLimit(1200, session.infocus); // 1.2mbps is decent, no?
mediaPool.push(session.rpcs[session.infocus].videoElement);
for (j in session.rpcs){
for (var j in session.rpcs){
if (j != session.infocus){
session.requestRateLimit(40, j);
}
}
} else if ((session.infocus) && (session.infocus === true)){
log("myself set fullscreen");
for (j in session.rpcs){
for (var j in session.rpcs){
session.requestRateLimit(40, j);
}
} else {
for (i in session.rpcs){
for (var i in session.rpcs){
if (session.rpcs[i].videoElement){ // remote feeds
session.rpcs[i].targetBandwidth = -1;
@ -1612,7 +1670,6 @@ function updateMixer(){
} else {
session.requestRateLimit(40, i); // w/e This is not in OBS, so we just set it as low as possible.
}
} else if (session.single){ // max
} else if (session.scene){ // max
} else if (session.roomid){ // guests should see video at low bitrate, ie: 100kbps (not 40kbps like if disabled)
session.requestRateLimit(100, i);
@ -1620,16 +1677,16 @@ function updateMixer(){
// only set to 300 if not a guest, or if zoomed in.
}
};
}
}
if (session.director){return;} // director view says go no further :)
if (mediaPool.length>1){
var mod = Math.pow((ww*hh)/(mediaPool.length),0.5) // 80
var mod = Math.pow((ww*hh)/(mediaPool.length),0.5); // 80
var rw = Math.ceil(ww/mod); // 80/80
var rh = Math.ceil(hh/mod);
} else { rw=1; rh=1;}
} else { var rw=1; var rh=1;}
//log(mod+","+rw+","+rh); //80,1,1
playarea.innerHTML = "";
@ -1690,7 +1747,7 @@ function updateMixer(){
target.innerHTML = "<i class='fa fa-compress' style='font-size:50px' aria-hidden='true'></i>";
}
setTimeout(()=>updateMixer(),10);
}
};
} else {
button.dataset.UUID = vid.dataset.UUID;
button.onclick = function(event){
@ -1707,7 +1764,7 @@ function updateMixer(){
}
setTimeout(()=>updateMixer(),10);
}
};
}
button.onmouseenter = function(){
@ -1724,31 +1781,6 @@ function updateMixer(){
});
}
document.addEventListener("dragstart", e => {
var url = e.target.href || e.target.value;
if (!url || !url.startsWith('http')) return;
if (e.target.dataset.drag!="1"){
return;
}
var streamId = url.split('view=');
var label = url.split('label=');
url += '&layer-name=OBS.Ninja';
if (streamId.length>1) url += ': ' + streamId[1].split('&')[0];
if (label.length>1) url += ' - ' + decodeURI(label[1].split('&')[0]);
try{
var video = document.getElementById('videosource');
url += '&layer-width=' + video.videoWidth; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=' + video.videoHeight;
} catch(e){
url += '&layer-width=1280'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=720';
}
e.dataTransfer.setData("text/uri-list", encodeURI(url));
});
var vis = (function(){
var stateKey, eventKey, keys = {
hidden: "visibilitychange",
@ -1769,7 +1801,7 @@ var vis = (function(){
//document.addEventListener("focus", c);
}
return !document[stateKey];
}
};
})();
(function() { // right click menu
@ -1798,24 +1830,24 @@ var vis = (function(){
* @param {Object} e The event passed in
* @return {Object} Returns the x and y position
*/
function getPosition(e) {
function getPosition(event2) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (!event2) var event = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
if (event2.pageX || event2.pageY) {
posx = event2.pageX;
posy = event2.pageY;
} else if (event2.clientX || event2.clientY) {
posx = event2.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = event2.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
x: posx,
y: posy
}
};
}
var contextMenuClassName = "context-menu";
@ -1897,7 +1929,7 @@ var vis = (function(){
if ( e.keyCode === 27 ) {
toggleMenuOff();
}
}
};
}
/**
@ -1980,6 +2012,29 @@ var vis = (function(){
})();
document.addEventListener("dragstart", event => {
var url = event.target.href || event.target.value;
if (!url || !url.startsWith('https://')) return;
if (event.target.dataset.drag!="1"){
return;
}
var streamId = url.split('view=');
var label = url.split('label=');
url += '&layer-name=OBS.Ninja';
if (streamId.length>1) url += ': ' + streamId[1].split('&')[0];
if (label.length>1) url += ' - ' + decodeURI(label[1].split('&')[0]);
try{
var video = document.getElementById('videosource');
url += '&layer-width=' + video.videoWidth; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=' + video.videoHeight;
} catch(error){
url += '&layer-width=1280'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=720';
}
event.dataTransfer.setData("text/uri-list", encodeURI(url));
});
function popupMessage(e, message="Copied to Clipboard"){ // right click menu
@ -2042,4 +2097,4 @@ function popupMessage(e, message="Copied to Clipboard"){ // right click menu
}
}
setTimeout(function(){toggleMenuOff();},1000);
};
}