";
}
}
}
if (navigator.userAgent.indexOf('Mac OS X') != -1) {
session.codec = "h264"; // default the codec to h264 if OBS is on macOS (that's all it supports with hardware)
}
if (session.disableOBS===false){
window.addEventListener("obsSourceVisibleChanged", obsSourceVisibleChanged);
window.addEventListener("obsSourceActiveChanged", obsSourceActiveChanged);
window.addEventListener("obsSceneChanged", obsSceneChanged);
window.addEventListener("obsStreamingStarted", obsStreamingStarted);
window.addEventListener("obsStreamingStopped", obsStreamingStopped);
window.addEventListener("obsRecordingStarted", obsRecordingStarted);
window.addEventListener("obsRecordingStopped", obsRecordingStopped);
}
} catch (e) {
errorlog(e);
}
}
if (urlParams.has('chroma')) {
log("Chroma ENABLED");
getById("main").style.backgroundColor = "#" + (urlParams.get('chroma') || "0F0");
}
if (urlParams.has('margin')) {
try {
var videoMargin = urlParams.get('margin') || 10;
videoMargin = parseInt(videoMargin);
videoMargin+="px";
document.querySelector(':root').style.setProperty('--video-margin', videoMargin);
} catch(e){errorlog("variable css failed");}
}
if (urlParams.has('rounded')) {
try {
var videoRounded = urlParams.get('rounded') || 50;
videoRounded = parseInt(videoRounded);
videoRounded+="px";
document.querySelector(':root').style.setProperty('--video-rounded', videoRounded);
} catch(e){errorlog("variable css failed");}
}
var darkmode=false;
try {
if (urlParams.has("darkmode") || urlParams.has("nightmode")){
darkmode = urlParams.get("darkmode") || urlParams.get("nightmode") || null;
if ((darkmode===null) || (darkmode === "")){
darkmode=true;
} else if ((darkmode=="false") || (darkmode == "0") || (darkmode == 0) || (darkmode == "off")){
darkmode=false;
}
} else if (urlParams.has("lightmode") || urlParams.has("lightmode")){
darkmode = false;
} else {
darkmode = getComputedStyle(document.querySelector(':root')).getPropertyValue('--color-mode').trim();
if (darkmode == "dark"){
darkmode = true;
} else {
darkmode = false;
}
}
if (darkmode){
document.body.classList.add("darktheme");
document.querySelector(':root').style.setProperty('--background-color',"#02050c" );
} else {
document.body.classList.remove("darktheme");
document.querySelector(':root').style.setProperty('--background-color',"#141926" );
}
} catch(e){errorlog(e);}
if (urlParams.has("videodevice") || urlParams.has("vdevice") || urlParams.has('vd') || urlParams.has('device') || urlParams.has('d')) {
session.videoDevice = urlParams.get("videodevice") || urlParams.get("vdevice") || urlParams.get("vd") || urlParams.get("device") || urlParams.get("d");
if (session.videoDevice === null) {
session.videoDevice = "1";
} else if (session.videoDevice) {
session.videoDevice = session.videoDevice.toLowerCase().replace(/[\W]+/g, "_");
}
if (session.videoDevice == "false") {
session.videoDevice = 0;
} else if (session.videoDevice == "0") {
session.videoDevice = 0;
} else if (session.videoDevice == "no") {
session.videoDevice = 0;
} else if (session.videoDevice == "off") {
session.videoDevice = 0;
} else if (session.videoDevice == "snapcam") {
session.videoDevice = "snap_camera";
} else if (session.videoDevice == "canon") {
session.videoDevice = "eos";
} else if (session.videoDevice == "camlink") {
session.videoDevice = "cam_link";
} else if (session.videoDevice == "ndi") {
session.videoDevice = "newtek_ndi_video";
} else if (session.videoDevice == "") {
session.videoDevice = 1;
} else if (session.videoDevice == "1") {
session.videoDevice = 1;
} else if (session.videoDevice == "default") {
session.videoDevice = 1;
} else {
// whatever the user entered I guess, santitized.
session.videoDevice = session.videoDevice.replace(/[\W]+/g, "_").toLowerCase();
}
if (session.videoDevice === 0) {
getById("add_camera").innerHTML = "Share your Microphone";
miniTranslate(getById("add_camera"), "share-your-mic");
}
getById("videoMenu").style.display = "none";
log("session.videoDevice:" + session.videoDevice);
}
// audioDevice
if (urlParams.has('audiodevice') || urlParams.has('adevice') || urlParams.has('ad') || urlParams.has('device') || urlParams.has('d')) {
session.audioDevice = urlParams.get("audiodevice") || urlParams.get("adevice") || urlParams.get("ad") || urlParams.get("device") || urlParams.get("d");
if (session.audioDevice === null) {
session.audioDevice = "1";
} else if (session.audioDevice) {
session.audioDevice = session.audioDevice.toLowerCase().replace(/[\W]+/g, "_");
}
if (session.audioDevice == "false") {
session.audioDevice = 0;
} else if (session.audioDevice == "0") {
session.audioDevice = 0;
} else if (session.audioDevice == "no") {
session.audioDevice = 0;
} else if (session.audioDevice == "off") {
session.audioDevice = 0;
} else if (session.audioDevice == "") {
session.audioDevice = 1;
} else if (session.audioDevice == "1") {
session.audioDevice = 1;
} else if (session.audioDevice == "default") {
session.audioDevice = 1;
} else if (session.audioDevice == "ndi") {
session.audioDevice = "line_newtek_ndi_audio";
} else {
// whatever the user entered I guess
session.audioDevice = session.audioDevice.replace(/[\W]+/g, "_").toLowerCase();
}
if (session.videoDevice === 0) {
if (session.audioDevice === 0) {
getById("add_camera").innerHTML = "Click Start to Join";
miniTranslate(getById("add_camera"), "click-start-to-join");
getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
getById("container-3").classList.add("skip-animation");
getById("container-3").classList.remove('pointer');
delayedStartupFuncs.push([previewWebcam]);
session.webcamonly = true;
}
}
log("session.audioDevice:" + session.audioDevice);
getById("audioMenu").style.display = "none";
getById("headphonesDiv").style.display = "none";
getById("headphonesDiv2").style.display = "none";
getById("audioScreenShare1").style.display = "none";
}
if (session.mobile){
getById("shareScreenGear").style.display = "none";
getById("dropButton").style.display = "none";
getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
screensharebutton = false;
screensharesupport = false;
if (session.audioDevice!==0){
getById("flipcamerabutton").classList.remove("advanced");
}
}
if (urlParams.has('consent')){
session.consent = true;
getById("consentWarning").classList.remove("advanced");
getById("consentWarning2").classList.remove("advanced");
}
if (urlParams.has('autojoin') || urlParams.has('autostart') || urlParams.has('aj') || urlParams.has('as')) {
session.autostart = true;
if (session.screenshare!==false) {
delayedStartupFuncs.push([publishScreen]);
}
if (session.consent){
setTimeout(function(){
warnUser("⚠ Privacy warning: The director of this room can remotely switch your camera or microphone without permission.", 8000);
}, 1500);
}
}
if (urlParams.has('noiframe') || urlParams.has('noiframes') || urlParams.has('nif') || urlParams.has('nowebsite') ) {
session.noiframe = urlParams.get('noiframe') || urlParams.get('noiframes') || urlParams.get('nif') || urlParams.get('nowebsite');
if (!(session.noiframe)) {
session.noiframe = [];
} else {
session.noiframe = session.noiframe.split(",");
}
log("disable iframe playback");
log(session.noiframe);
}
if (urlParams.has('exclude') || urlParams.has('ex')) {
session.exclude = urlParams.get('exclude') || urlParams.get('ex');
if (!(session.exclude)) {
session.exclude = false;
} else {
session.exclude = session.exclude.split(",");
}
log("exclude video playback");
log(session.exclude);
}
if (urlParams.has('novideo') || urlParams.has('nv') || urlParams.has('hidevideo') || urlParams.has('showonly')) {
session.novideo = urlParams.get('novideo') || urlParams.get('nv') || urlParams.get('hidevideo') || urlParams.get('showonly');
if (!(session.novideo)) {
session.novideo = [];
} else {
session.novideo = session.novideo.split(",");
}
log("disable video playback");
log(session.novideo);
}
if (urlParams.has('noaudio') || urlParams.has('na') || urlParams.has('hideaudio')) {
session.noaudio = urlParams.get('noaudio') || urlParams.get('na') || urlParams.get('hideaudio');
if (!(session.noaudio)) {
session.noaudio = [];
} else {
session.noaudio = session.noaudio.split(",");
}
log("disable audio playback");
}
if (urlParams.has('forceios')) {
log("allow iOS to work in video group chat; for this user at least");
session.forceios = true;
}
if (urlParams.has('nocursor')) { // on the screen, not in screen share
session.nocursor = true;
log("DISABLE CURSOR");
var styletmp = document.createElement('style');
styletmp.innerHTML = `
video {
margin: 0;
padding: 0;
overflow: hidden;
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), none;
user-select: none;
}
`;
document.head.appendChild(styletmp);
}
if (urlParams.has('cursor') || urlParams.has('screensharecursor')) {
session.screensharecursor = true;
}
if (urlParams.has('vbr')) {
session.cbr = 0;
}
if (urlParams.has('order')) {
session.order = parseInt(urlParams.get('order')) || 0;
}
if (urlParams.has('sensors') || urlParams.has('sensor') || urlParams.has('gyro') || urlParams.has('gyros') || urlParams.has('accelerometer')) {
session.sensorData = urlParams.get('sensors') || urlParams.get('sensor') || urlParams.get('gyro') || urlParams.get('gyros') || urlParams.get('accelerometer') || 30;
session.sensorData = parseInt(session.sensorData);
}
if (urlParams.has('minptime')) {
session.minptime = parseInt(urlParams.get('minptime')) || 10;
if (session.minptime < 10) {
session.minptime = 10;
}
if (session.minptime > 300) {
session.minptime = 300;
}
}
if (urlParams.has('maxptime')) {
session.maxptime = parseInt(urlParams.get('maxptime')) || 60;
if (session.maxptime < 10) {
session.maxptime = 10;
}
if (session.maxptime > 300) {
session.maxptime = 300;
}
}
if (urlParams.has('ptime')) {
session.ptime = parseInt(urlParams.get('ptime')) || 20;
if (session.minptime < 10) {
session.ptime = 10;
}
if (session.minptime > 300) {
session.ptime = 300;
}
}
if (urlParams.has('codec')) {
log("CODEC CHANGED");
session.codec = urlParams.get('codec').toLowerCase();
if (session.codec=="webp"){
session.webp = true;
session.codec = false;
}
} else if (isOperaGX()){
session.codec = "vp8";
warnlog("Defaulting to VP8 manually, as H264 with remote iOS devices is not supported");
}
if (urlParams.has('nonacks')){ // disables error control / throttling.
session.noNacks = true;
}
if (urlParams.has('nopli')){ // disables error control / throttling.
session.noPLIs = true;
}
if (urlParams.has('noremb')){ // disables error control / throttling.
session.noREMB = true;
}
if (urlParams.has('scale')) {
if (urlParams.get('scale') == "false") {} else if (urlParams.get('scale') == "0") {} else if (urlParams.get('scale') == "no") {} else if (urlParams.get('scale') == "off") {} else {
log("Resolution scale requested");
session.scale = parseInt(urlParams.get('scale')) || 100;
}
session.dynamicScale = false; // default true
}
if (isIFrame) {
getById("helpbutton").style.display = "none";
getById("helpbutton").style.opacity = 0;
getById("reportbutton").style.display = "none";
getById("reportbutton").style.opacity = 0;
getById("calendarButton").style.display = "none";
getById("calendarButton").style.opacity = 0;
getById("chatBody").innerHTML = "";
}
if (urlParams.has('beep') || urlParams.has('notify') || urlParams.has('tone')) {
session.beepToNotify = true;
var addtone = createAudioElement();
addtone.id = "jointone";
addtone.src = "./media/join.mp3";
getById("testtone").parentNode.insertBefore(addtone, getById("testtone").nextSibling)
var addtone = createAudioElement();
addtone.id = "leavetone";
addtone.src = "./media/leave.mp3";
getById("testtone").parentNode.insertBefore(addtone, getById("testtone").nextSibling)
}
if (urlParams.has('r2d2')) {
getById("testtone").innerHTML = "";
getById("testtone").src = "./media/robot.mp3";
session.beepToNotify = true;
}
if (urlParams.has('easyexit') || urlParams.has('ee')) {
session.noExitPrompt = true;
}
if (urlParams.has('videobitrate') || urlParams.has('bitrate') || urlParams.has('vb')) {
session.bitrate = urlParams.get('videobitrate') || urlParams.get('bitrate') || urlParams.get('vb');
if (session.bitrate) {
if ((session.view_set) && (session.bitrate.split(",").length > 1)) {
session.bitrate_set = session.bitrate.split(",");
session.bitrate = parseInt(session.bitrate_set[0]);
} else {
session.bitrate = parseInt(session.bitrate);
}
if (session.bitrate < 1) {
session.bitrate = false;
}
log("BITRATE ENABLED");
log(session.bitrate);
}
}
if (urlParams.has('maxvideobitrate') || urlParams.has('maxbitrate') || urlParams.has('mvb')) {
session.maxvideobitrate = urlParams.get('maxvideobitrate') || urlParams.get('maxbitrate') || urlParams.get('mvb');
session.maxvideobitrate = parseInt(session.maxvideobitrate);
if (session.maxvideobitrate < 1) {
session.maxvideobitrate = false;
}
log("maxvideobitrate ENABLED");
log(session.maxvideobitrate);
}
if (urlParams.has('totalroombitrate') || urlParams.has('totalroomvideobitrate') || urlParams.has('trb')) {
session.totalRoomBitrate = urlParams.get('totalroombitrate') || urlParams.get('totalroomvideobitrate') || urlParams.get('trb');
session.totalRoomBitrate = parseInt(session.totalRoomBitrate);
if (session.totalRoomBitrate < 1) {
session.totalRoomBitrate = false;
}
log("totalRoomBitrate ENABLED");
log(session.totalRoomBitrate);
}
if (session.totalRoomBitrate===false){
session.totalRoomBitrate = session.totalRoomBitrate_default;
} else {
session.totalRoomBitrate_default = session.totalRoomBitrate; // trb_default doesn't change dynamically, but trb can (per director I guess)
}
if (urlParams.has('limittotalbitrate') || urlParams.has('ltb')){
session.limitTotalBitrate = urlParams.get('limittotalbitrate') || urlParams.get('ltb') || 2500;
session.limitTotalBitrate = parseInt(session.limitTotalBitrate);
}
if (urlParams.has('height') || urlParams.has('h')) {
session.height = urlParams.get('height') || urlParams.get('h');
session.height = parseInt(session.height);
}
if (urlParams.has('width') || urlParams.has('w')) {
session.width = urlParams.get('width') || urlParams.get('w');
session.width = parseInt(session.width);
}
if (urlParams.has('quality') || urlParams.has('q')) {
try {
session.quality = urlParams.get('quality') || urlParams.get('q') || 0;
session.quality = parseInt(session.quality);
getById("gear_screen").parentNode.removeChild(getById("gear_screen"));
getById("gear_webcam").parentNode.removeChild(getById("gear_webcam"));
} catch (e) {
errorlog(e);
}
}
if (urlParams.has('sink')) {
session.sink = urlParams.get('sink');
} else if (urlParams.has('outputdevice') || urlParams.has('od') || urlParams.has('audiooutput')) {
session.outputDevice = urlParams.get('outputdevice') || urlParams.get('od') || urlParams.get('audiooutput') || null;
if (session.outputDevice) {
session.outputDevice = session.outputDevice.toLowerCase().replace(/[\W]+/g, "_");
} else {
session.outputDevice = null;
getById("headphonesDiv3").style.display = "none"; //
}
if (session.outputDevice) {
try {
enumerateDevices().then(function(deviceInfos) {
for (let i = 0; i !== deviceInfos.length; ++i) {
if (deviceInfos[i].kind === 'audiooutput') {
if (deviceInfos[i].label.replace(/[\W]+/g, "_").toLowerCase().includes(session.outputDevice)) {
session.sink = deviceInfos[i].deviceId;
log("AUDIO OUT DEVICE: " + deviceInfos[i].deviceId);
break;
}
}
}
});
} catch (e) {}
}
getById("headphonesDiv").style.display = "none";
getById("headphonesDiv2").style.display = "none";
}
if (window.obsstudio || (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1)){
session.fullscreen = true;
} else if (urlParams.has('fullscreen')) {
session.fullscreen = true;
}
if (urlParams.has('stats')) {
session.statsMenu = true;
}
if (urlParams.has('cleandirector') || urlParams.has('cdv')) {
session.cleanDirector = true;
}
if (session.cleanOutput){
getById("translateButton").style.display = "none";
getById("credits").style.display = "none";
getById("header").style.display = "none";
getById("controlButtons").style.display = "none";
getById("helpbutton").style.display = "none";
getById("helpbutton").style.opacity = 0;
getById("reportbutton").style.display = "none";
getById("reportbutton").style.opacity = 0;
getById("calendarButton").style.display = "none";
getById("calendarButton").style.opacity = 0;
var styleTmp = document.createElement('style');
styleTmp.innerHTML = `
video {
background-image: none;
}
`;
document.head.appendChild(styleTmp);
}
getById("credits").innerHTML = "Version: " + session.version + " - " + getById("credits").innerHTML;
if (urlParams.has('minidirector')) {
try {
var cssStylesheet = document.createElement('link');
cssStylesheet.rel = 'stylesheet';
cssStylesheet.type = 'text/css';
cssStylesheet.media = 'screen';
cssStylesheet.href = 'minidirector.css';
document.getElementsByTagName('head')[0].appendChild(cssStylesheet);
} catch (e) {
errorlog(e);
}
}
if (urlParams.has('cleanish')) {
session.cleanish = true;
}
if (urlParams.has('channels')) { // must be loaded before channelOffset
session.audioChannels = parseInt(urlParams.get('channels'));
session.offsetChannel = 0;
log("max channels is 32; channels offset");
session.audioEffects = true;
}
if (urlParams.has('channeloffset')) {
session.offsetChannel = parseInt(urlParams.get('channeloffset'));
log("max channels is 32; channels offset");
session.audioEffects = true;
}
if (urlParams.has('enhance')) {
//if (parseInt(urlParams.get('enhance')>0){
session.enhance = true; //parseInt(urlParams.get('enhance'));
//}
}
if (urlParams.has('maxviewers') || urlParams.has('mv')) {
session.maxviewers = urlParams.get('maxviewers') || urlParams.get('mv');
if (session.maxviewers.length == 0) {
session.maxviewers = 1;
} else {
session.maxviewers = parseInt(session.maxviewers);
}
log("maxviewers set");
}
if (urlParams.has('maxpublishers') || urlParams.has('mp')) {
session.maxpublishers = urlParams.get('maxpublishers') || urlParams.get('mp');
if (session.maxpublishers.length == 0) {
session.maxpublishers = 1;
} else {
session.maxpublishers = parseInt(session.maxpublishers);
}
log("maxpublishers set");
}
if (urlParams.has('maxconnections') || urlParams.has('mc')) {
session.maxconnections = urlParams.get('maxconnections') || urlParams.get('maxconnections');
if (session.maxconnections.length == 0) {
session.maxconnections = 1;
} else {
session.maxconnections = parseInt(session.maxconnections);
}
log("maxconnections set");
}
if (urlParams.has('secure')) {
session.security = true;
if (!(session.cleanOutput)) {
delayedStartupFuncs.push([warnUser, "Enhanced Security Mode Enabled."]);
}
}
if (urlParams.has('random') || urlParams.has('randomize')) {
session.randomize = true;
}
if (urlParams.has('framerate') || urlParams.has('fr') || urlParams.has('fps')) {
session.framerate = urlParams.get('framerate') || urlParams.get('fr') || urlParams.get('fps');
session.framerate = parseInt(session.framerate);
log("framerate Changed");
log(session.framerate);
}
if (urlParams.has('maxframerate') || urlParams.has('mfr') || urlParams.has('mfps')) {
session.maxframerate = urlParams.get('maxframerate') || urlParams.get('mfr') || urlParams.get('mfps');
session.maxframerate = parseInt(session.maxframerate);
log("max framerate assigned");
log(session.maxframerate);
}
if (urlParams.has('buffer')) { // needs to be before sync
if ((getChromeVersion() > 50) && (getChromeVersion()< 78)){
} else {
session.buffer = parseFloat(urlParams.get('buffer')) || 0;
log("buffer Changed: " + session.buffer);
session.sync = 0;
session.audioEffects = true;
}
}
if (urlParams.has('panning') || urlParams.has('pan')) {
session.panning=true;
if (urlParams.get('panning') || urlParams.get('pan')){
session.panning = urlParams.get('panning') || urlParams.get('pan');
}
session.audioEffects = true;
}
if (urlParams.has('sync')) {
if ((getChromeVersion() > 50) && (getChromeVersion()< 78)){
} else {
session.sync = parseFloat(urlParams.get('sync'));
log("sync Changed; in milliseconds. If not set, defaults to auto.");
log(session.sync);
session.audioEffects = true;
if (session.buffer === false) {
session.buffer = 0;
}
}
}
if (urlParams.has('mirror')) {
if (urlParams.get('mirror') == "3") {
getById("main").classList.add("mirror");
} else if (urlParams.get('mirror') == "2") {
session.mirrored = 2;
} else if (urlParams.get('mirror') == "0") {
session.mirrored = 0;
} else if (urlParams.get('mirror') == "false") {
session.mirrored = 0;
} else if (urlParams.get('mirror') == "off") {
session.mirrored = 0;
} else {
session.mirrored = 1;
}
}
if (urlParams.has('flip')) {
if (urlParams.get('flip') == "0") {
session.flipped = false;
} else if (urlParams.get('flip') == "false") {
session.flipped = false;
} else if (urlParams.get('flip') == "off") {
session.flipped = false;
} else {
session.flipped = true;
}
}
if ((session.mirrored) && (session.flipped)) {
try {
log("Mirror all videos");
var mirrorStyle = document.createElement('style');
mirrorStyle.innerHTML = "video {transform: scaleX(-1) scaleY(-1); }";
document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
} catch (e) {
errorlog(e);
}
} else if (session.mirrored) { // mirror the video horizontally
try {
log("Mirror all videos");
var mirrorStyle = document.createElement('style');
mirrorStyle.innerHTML = "video {transform: scaleX(-1);}";
document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
} catch (e) {
errorlog(e);
}
} else if (session.flipped) { // mirror the video vertically
try {
log("Mirror all videos");
var mirrorStyle = document.createElement('style');
mirrorStyle.innerHTML = "video {transform: scaleY(-1);}";
document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
} catch (e) {
errorlog(e);
}
}
if (urlParams.has('icefilter')) {
log("ICE FILTER ENABLED");
session.icefilter = urlParams.get('icefilter');
}
if (urlParams.has('effects') || urlParams.has('effect')) {
session.effects = urlParams.get('effects') || urlParams.get('effect') || null;
if (session.effects === null){
getById("effectsDiv").style.display = "block";
session.effects = "0";
} else if (session.effects === "0" || session.effects === "false" || session.effects === "off"){
session.effects = false;
getById("effectSelector3").style.display = "none";
getById("effectsDiv3").style.display = "none";
getById("effectSelector").style.display = "none";
getById("effectsDiv").style.display = "none";
}
if (session.effects === "5"){
getById("selectImageTFLITE").style.display = "block";
getById("selectImageTFLITE3").style.display = "block";
getById("effectSelector").style.display = "none";
getById("effectsDiv").style.display = "block";
}
// mirror == 2
// face == 1
// blur = 3
// green = 4
// image = 5
}
if (!(getChromeVersion()>=57)){
getById("effectSelector").disabled=true;
getById("effectSelector3").disabled=true;
getById("effectSelector").title = "Effects are only support on Chromium-based browsers";
getById("effectSelector3").title = "Effects are only support on Chromium-based browsers";
var elementsTmp = document.querySelectorAll('[data-effectsNotice]');
for (let i = 0; i < elementsTmp.length; i++) {
elementsTmp[i].style.display = "inline-block";
}
}
if (urlParams.has('viewereffect') || urlParams.has('viewereffects') || urlParams.has('ve')) {
session.viewereffects = parseInt(urlParams.get('viewereffect')) || parseInt(urlParams.get('ve')) || false;
}
if (urlParams.has('activespeaker') || urlParams.has('speakerview') || urlParams.has('sas')){
session.activeSpeaker = true;
session.audioEffects = true;
session.audioMeterGuest = true;
//session.animatedMoves = false;
session.fadein=true;
document.querySelector(':root').style.setProperty('--fadein-speed', 0.5);
setInterval(function(){activeSpeaker(false);},100);
} else if (urlParams.has('noisegate')){
session.quietOthers = true;
session.audioEffects = true;
session.audioMeterGuest = true;
setInterval(function(){activeSpeaker(false);},100);
}
if (urlParams.has('fadein')) {
session.fadein=true;
if (urlParams.get('fadein') || 0){
try {
var fadeinspeed = parseInt(urlParams.get('fadein') || 0)/1000.0;
fadeinspeed+="s";
document.querySelector(':root').style.setProperty('--fadein-speed', fadeinspeed);
} catch(e){errorlog("variable css failed");}
} else {
try {
var fadeinspeed = 0.5;
fadeinspeed+="s";
document.querySelector(':root').style.setProperty('--fadein-speed', fadeinspeed);
} catch(e){errorlog("variable css failed");}
}
}
if (urlParams.has('animated') || urlParams.has('animate')){
session.animatedMoves = urlParams.get('animated') || urlParams.get('animate');
if (session.animatedMoves === "false") {
session.animatedMoves = false;
} else if (session.animatedMoves === "0") {
session.animatedMoves = false;
} else if (session.animatedMoves === "no") {
session.animatedMoves = false;
} else if (session.animatedMoves === "off") {
session.animatedMoves = false;
} else {
session.animatedMoves=true;
}
} else if (session.mobile){
session.animatedMoves=false;
}
if (urlParams.has('meter') || urlParams.has('meterstyle')){
session.meterStyle = urlParams.get('meter') || urlParams.get('meterstyle') || 1;
}
if (urlParams.has('directorchat') || urlParams.has('dc')){
session.directorChat = true;
}
if (urlParams.has('style') || urlParams.has('st')) {
session.style = urlParams.get('style') || urlParams.get('st') || 1;
if ((parseInt(session.style) == 1) || (session.style == "justvideo")) { // no audio only
session.style = 1;
} else if ((parseInt(session.style) == 2) || (session.style == "waveform")) { // audio waveform
session.style = 2;
session.audioEffects = true; ////!!!!!!! Do I want to enable the audioEffects myself? or do it here?
} else if ((parseInt(session.style) == 3) || (session.style == "volume")) { // photo is taken? upload option? canvas?
session.style = 3;
session.audioEffects = true;
} else {
session.style = 1;
}
}
if (urlParams.has('samplerate') || urlParams.has('sr')) {
session.sampleRate = parseInt(urlParams.get('samplerate')) || parseInt(urlParams.get('samplerate')) || 48000;
if (session.audioCtx) {
session.audioCtx.close(); // close the default audio context.
}
session.audioCtx = new AudioContext({ // create a new audio context with a higher sample rate.
sampleRate: session.sampleRate
});
session.audioEffects = true;
}
if (urlParams.has('noaudioprocessing') || urlParams.has('noap')) {
session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers?
session.audioEffects = false; // disable audio inbound effects also.
session.audioMeterGuest = false;
}
if (urlParams.has('tcp')){ // forces the TURN servers to use TCP mode; still need to add &private to force TURN also tho
session.forceTcpMode = true;
}
if (urlParams.has('speedtest')){ // forces essentially UDP mode, unless TCP is specified, and some other stuff
session.speedtest = true;
if (urlParams.get('speedtest')){
session.speedtest = urlParams.get('speedtest').toLowerCase();
}
}
var iceServers = [{ urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"]}]; // google stun servers.
if (urlParams.has('stun')) {
var stunstring = urlParams.get('stun');
stunstring = stunstring.split(";");
if (stunstring !== "false") { // false disables the TURN server. Useful for debuggin
var stun = {};
if (stunstring.length==3){
stun.username = stunstring[0]; // myusername
stun.credential = stunstring[1]; //mypassword
stun.urls = [stunstring[2]]; // ["turn:turn.obs.ninja:443"];
} else if (stunstring.length==1){
stun.urls = [stunstring[0]];
}
iceServers = [stun];
} else {
iceServers = [];
}
}
if (urlParams.has('addstun')) {
var stunstring = urlParams.get('addstun');
stunstring = stunstring.split(";");
var stun = {};
if (stunstring.length==3){
stun.username = stunstring[0]; // myusername
stun.credential = stunstring[1]; //mypassword
stun.urls = [stunstring[2]]; // ["turn:turn.obs.ninja:443"];
} else if (stunstring.length==1){
stun.urls = [stunstring[0]];
}
iceServers = iceServers.concat(stun);
}
if (urlParams.has('turn')) {
var turnstring = urlParams.get('turn');
if (turnstring == "twilio") { // a sample function on loading remote credentials for TURN servers.
try {
session.ws = false; // prevents connection
var twillioRequest = new XMLHttpRequest();
twillioRequest.onreadystatechange = function() {
if (twillioRequest.status === 200) {
try{
var res = JSON.parse(twillioRequest.responseText);
} catch(e){return;}
session.configuration = {
iceServers: [{
"username": res["1"],
"credential": res["2"],
"url": "turn:global.turn.twilio.com:3478?transport=tcp",
"urls": "turn:global.turn.twilio.com:3478?transport=tcp"
},
{
"username": res["1"],
"credential": res["2"],
"url": "turn:global.turn.twilio.com:443?transport=tcp",
"urls": "turn:global.turn.twilio.com:443?transport=tcp"
}
],
sdpSemantics: 'unified-plan' // future-proofing
};
if (session.ws===false){
session.ws=null; // allows connection (clears state)
session.connect(); // connect if not already connected.
}
}
// system does not connect if twilio API does not respond.
};
twillioRequest.open('GET', 'https://api.obs.ninja:1443/twilio', true); // `false` makes the request synchronous
twillioRequest.send();
} catch (e) {
errorlog("Twilio Failed");
}
} else if (turnstring == "nostun") { // disable TURN servers
session.configuration = {
sdpSemantics: 'unified-plan' // future-proofing
};
} else if ((turnstring == "false") || (turnstring == "off") || (turnstring == "0")) { // disable TURN servers
session.configuration = {
iceServers: iceServers,
sdpSemantics: 'unified-plan' // future-proofing
};
} else {
try {
//session.configuration = {iceServers: [], sdpSemantics: 'unified-plan'};
turnstring = turnstring.split(";");
if (turnstring !== "false") { // false disables the TURN server. Useful for debuggin
var turn = {};
if (turnstring.length==3){
turn.username = turnstring[0]; // myusername
turn.credential = turnstring[1]; //mypassword
turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"];
} else if (turnstring.length==1){
turn.urls = [turnstring[0]];
}
session.configuration = {
iceServers: iceServers,
sdpSemantics: 'unified-plan' // future-proofing
};
session.configuration.iceServers.push(turn);
}
} catch (e) {
if (!(session.cleanOutput)) {
warnUser("TURN server parameters were wrong.");
}
errorlog(e);
}
}
} else {
chooseBestTURN(iceServers); // vdo.ninja turn servers, if needed.
}
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) {
if (!(session.cleanOutput)) {
warnUser("Privacy mode failed to configure.");
}
errorlog(e);
}
if (session.speedtest){
if (session.maxvideobitrate !== false) {
if (session.maxvideobitrate > 6000) {
session.maxvideobitrate = 6000; // Please feel free to get rid of this if using your own TURN servers...
}
} else {
session.maxvideobitrate = 6000; // don't let people pull more than 2500 from you
}
if (session.bitrate !== false) {
if (session.bitrate > 6000) {
session.bitrate = 6000; // Please feel free to get rid of this if using your own TURN servers...
}
}
} else {
if (session.maxvideobitrate !== false) {
if (session.maxvideobitrate > 2500) {
session.maxvideobitrate = 2500; // Please feel free to get rid of this if using your own TURN servers...
}
} else {
session.maxvideobitrate = 2500; // don't let people pull more than 2500 from you
}
if (session.bitrate !== false) {
if (session.bitrate > 2500) {
session.bitrate = 2500; // Please feel free to get rid of this if using your own TURN servers...
}
}
}
}
if (urlParams.has('wss')) {
if (urlParams.get('wss')) {
session.wss = "wss://" + urlParams.get('wss');
}
}
if (urlParams.has('osc') || urlParams.has('api')) {
if (urlParams.get('osc') || urlParams.get('api')) {
session.api = urlParams.get('osc') || urlParams.get('api');
setTimeout(function(){oscClient();},1000);
}
}
if (urlParams.has('queue')) {
session.queue = true;
}
if (urlParams.has('permaid') || urlParams.has('push')) {
session.permaid = urlParams.get('push') || urlParams.get('permaid');
if (session.permaid) {
session.streamID = sanitizeStreamID(session.permaid);
} else {
session.permaid = null;
}
if (urlParams.has('permaid')) {
updateURL("permaid=" + session.streamID, true, false); // I'm not deleting the permaID first tho...
} else {
updateURL("push=" + session.streamID, true, false); // I'm not deleting the permaID first tho...
}
if (urlParams.has('director') || urlParams.has('dir')) { // if I do a short form of this, it will cause duplications in the code elsewhere.
//var director_room_input = urlParams.get('director');
//director_room_input = sanitizeRoomName(director_room_input);
//createRoom(director_room_input);
session.permaid = false; // used to avoid a trigger later on.
} else {
getById("container-1").className = 'column columnfade advanced';
getById("container-4").className = 'column columnfade advanced';
getById("dropButton").className = 'column columnfade advanced';
getById("info").innerHTML = "";
if (session.videoDevice === 0) {
getById("add_camera").innerHTML = "Share your Microphone";
miniTranslate(getById("add_camera"), "share-your-mic");
} else {
getById("add_camera").innerHTML = "Share your Camera";
miniTranslate(getById("add_camera"), "share-your-camera");
}
getById("add_screen").innerHTML = "Share your Screen";
miniTranslate(getById("add_screen"), "share-your-screen");
getById("passwordRoom").value = "";
getById("videoname1").value = "";
getById("dirroomid").innerHTML = "";
getById("roomid").innerHTML = "";
getById("mainmenu").style.alignSelf = "center";
getById("mainmenu").classList.add("mainmenuclass");
getById("header").style.alignSelf = "center";
if ((iOS) || (iPad)) {
getById("header").style.display = "none"; // just trying to free up space.
}
if (session.webcamonly == true) { // mobile or manual flag 'webcam' pflag set
getById("head1").innerHTML = '- Please accept any camera permissions';
} else {
getById("head1").innerHTML = ' - Please select which you wish to share';
}
}
}
if (urlParams.has('hidescreenshare') || urlParams.has('hidess') || urlParams.has('sshide') || urlParams.has('screensharehide')) { // this way I don't need to remember what it's called. I can just guess. :D
session.screenShareElementHidden = true;
}
if (urlParams.has('zoomedbitrate') || urlParams.has('zb')) { // this way I don't need to remember what it's called. I can just guess. :D
session.zoomedBitrate = urlParams.get('zoomedbitrate') || urlParams.get('zb') || 2500;
session.zoomedBitrate = parseInt(session.zoomedBitrate) ;
}
if (urlParams.has('screenshareid') || urlParams.has('ssid')) {
if (urlParams.get('screenshareid') || urlParams.get('ssid')) {
session.screenshareid = urlParams.get('screenshareid') || urlParams.get('ssid');
session.screenshareid = sanitizeStreamID(session.screenshareid);
} else {
session.screenshareid = session.streamID + "_screenshare";
}
}
if (urlParams.has('screensharefps') || urlParams.has('ssfps')) {
if (urlParams.get('screensharefps') || urlParams.get('ssfps')) {
session.screensharefps = urlParams.get('screensharefps') || urlParams.get('ssfps');
session.screensharefps = parseInt(session.screensharefps) || 2;
}
}
if (urlParams.has('screensharequality') || urlParams.has('ssq')) {
if (urlParams.get('screensharequality') || urlParams.get('ssq')) {
session.screensharequality = urlParams.get('screensharequality') || urlParams.get('ssq');
session.screensharequality = parseInt(session.screensharequality) || 1;
}
}
if ((session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (urlParams.has('room')) || (filename) || (session.permaid !== false)) {
var roomid = "";
if (filename) {
roomid = filename;
} else if (urlParams.has('room')) {
roomid = urlParams.get('room');
} else if (urlParams.has('roomid')) {
roomid = urlParams.get('roomid');
} else if (urlParams.has('r')) {
roomid = urlParams.get('r');
} else if (session.roomid) {
roomid = session.roomid;
}
session.roomid = sanitizeRoomName(roomid);
if (!(session.cleanOutput)) {
if (session.roomid === "test") {
if (session.password === session.defaultPassword) {
window.focus();
var testRoomResponse = confirm(miscTranslations["room-test-not-good"]);
if (testRoomResponse == false) {
hangup();
throw new Error("User requested to not enter room 'room'.");
}
}
}
}
if (session.audioDevice === false && session.outputDevice === false) {
getById("headphonesDiv2").style.display = "inline-block";
getById("headphonesDiv").style.display = "inline-block";
}
getById("addPasswordBasic").style.display = "none";
getById("info").innerHTML = "";
getById("info").style.color = "#CCC";
getById("videoname1").value = session.roomid;
getById("dirroomid").innerText = session.roomid;
getById("roomid").innerText = session.roomid;
getById("container-1").className = 'column columnfade advanced';
getById("container-4").className = 'column columnfade advanced';
getById("container-7").style.display = 'none';
getById("container-8").style.display = 'none';
getById("mainmenu").style.alignSelf = "center";
getById("mainmenu").classList.add("mainmenuclass");
getById("header").style.alignSelf = "center";
if (session.webcamonly == true) { // mobile or manual flag 'webcam' pflag set
getById("head1").innerHTML = '';
} else {
getById("head1").innerHTML = 'Please select an option to join.';
}
if (session.roomid.length > 0) {
if (session.videoDevice === 0) {
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");
}
getById("add_screen").innerHTML = "Screenshare with Room";
miniTranslate(getById("add_screen"), "share-screen-with-room");
} else {
if (session.videoDevice === 0) {
getById("add_camera").innerHTML = "Share your Microphone";
miniTranslate(getById("add_camera"), "share-your-mic");
} else {
getById("add_camera").innerHTML = "Share your Camera";
miniTranslate(getById("add_camera"), "share-your-camera");
}
getById("add_screen").innerHTML = "Share your Screen";
miniTranslate(getById("add_screen"), "share-your-screen");
}
getById("head3").classList.add('advanced');
getById("head3a").classList.add('advanced');
if (session.scene !== false) {
getById("container-4").className = 'column columnfade';
getById("container-3").className = 'column columnfade';
getById("container-2").className = 'column columnfade';
getById("container-1").className = 'column columnfade';
getById("header").className = 'advanced';
getById("info").className = 'advanced';
getById("head1").className = 'advanced';
getById("head2").className = 'advanced';
getById("mainmenu").style.display = "none";
getById("translateButton").style.display = "none";
log("Update Mixer Event on REsize SET");
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
joinRoom(session.roomid); // this is a scene, so we want high resolutions
getById("main").style.overflow = "hidden";
if (session.chatbutton === true) {
getById("chatbutton").classList.remove("advanced");
getById("controlButtons").style.display = "inherit";
} else if (session.chatbutton === false) {
getById("chatbutton").classList.add("advanced");
}
} else {
if ((session.permaid === null) && (session.roomid == "")) {
if (!(session.cleanOutput)) {
getById("head3").classList.remove('advanced');
getById("head3a").classList.remove('advanced');
}
}
}
} else if (urlParams.has('director') || urlParams.has('dir')) { // if I do a short form of this, it will cause duplications in the code elsewhere.
if (directorLanding == false) {
var director_room_input = urlParams.get('director') || urlParams.get('dir');
director_room_input = sanitizeRoomName(director_room_input);
log("director_room_input:" + director_room_input);
if (urlParams.has('codirector') || urlParams.has('directorpassword') || urlParams.has('dirpass') || urlParams.has('dp')) {
session.directorPassword = urlParams.get('codirector') || urlParams.get('directorpassword') || urlParams.get('dirpass') || urlParams.get('dp');
if (!session.directorPassword) {
window.focus();
session.directorPassword = await promptAlt(miscTranslations["enter-director-password"], true);
}
if (session.directorPassword){
await generateHash(session.directorPassword + session.salt + "abc123", 12).then(function(hash) { // million to one error.
log("dir room hash is " + hash);
session.directorHash = hash;
return;
}).catch(errorlog);
} else {
session.directorPassword = false;
}
}
createRoom(director_room_input);
}
if (session.chatbutton === true) {
getById("chatbutton").classList.remove("advanced");
getById("controlButtons").style.display = "inherit";
} else if (session.chatbutton === false) {
getById("chatbutton").classList.add("advanced");
}
} else if ((session.view) && (session.permaid === false)) {
//if (!session.activeSpeaker){
session.audioMeterGuest = false;
//}
if (session.audioEffects === null) {
session.audioEffects = false;
}
log("Update Mixer Event on REsize SET");
getById("translateButton").style.display = "none";
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
getById("main").style.overflow = "hidden";
if (session.chatbutton === true) {
getById("chatbutton").classList.remove("advanced");
getById("controlButtons").style.display = "inherit";
} else if (session.chatbutton === false) {
getById("chatbutton").classList.add("advanced");
}
}
if (urlParams.has('nofileshare') || urlParams.has('nodownloads') || urlParams.has('nofiles')){
session.hostedFiles = false;
session.nodownloads = true;
getById('sharefilebutton').style.display = "none";
getById('sharefilebutton').classList.add("advanced");
} else if (session.mobile){
getById('sharefilebutton').style.display = "none";
getById('sharefilebutton').classList.add("advanced");
} else if (session.roomid==false){
getById('sharefilebutton').style.display = "none";
getById('sharefilebutton').classList.add("advanced");
}
if (session.audioEffects === null) {
session.audioEffects = true;
}
if (session.audioEffects) {
getById("channelGroup1").style.display = "block";
getById("channelGroup2").style.display = "block";
}
if (urlParams.has('hidemenu') || urlParams.has('hm')) { // needs to happen the room and permaid applications
getById("mainmenu").style.display = "none";
getById("header").style.display = "none";
getById("mainmenu").style.opacity = 0;
getById("header").style.opacity = 0;
}
if (urlParams.has('hideheader') || urlParams.has('noheader') || urlParams.has('hh')) { // needs to happen the room and permaid applications
getById("header").style.display = "none";
getById("header").style.opacity = 0;
}
if (session.view) {
getById("main").className = "";
getById("credits").style.display = 'none';
try {
if (session.label === false) {
if (document.title == "") {
document.title = "View=" + session.view.toString();
} else {
document.title += ", View=" + session.view.toString();
}
}
} catch (e) {
errorlog(e);
};
}
if ((session.view) && (session.roomid === false)) {
getById("container-4").className = 'column columnfade';
getById("container-3").className = 'column columnfade';
getById("container-2").className = 'column columnfade';
getById("container-1").className = 'column columnfade';
//getById("header").className = 'advanced';
getById("info").className = 'advanced';
getById("header").className = 'advanced';
getById("head1").className = 'advanced';
getById("head2").className = 'advanced';
getById("head3").classList.add('advanced');
getById("head3a").classList.add('advanced');
getById("mainmenu").style.backgroundRepeat = "no-repeat";
getById("mainmenu").style.backgroundPosition = "bottom center";
getById("mainmenu").style.minHeight = "300px";
getById("mainmenu").style.backgroundSize = "100px 100px";
getById("mainmenu").innerHTML = '';
setTimeout(function() {
try {
if ((session.view) && (!(session.cleanOutput))) {
if (document.getElementById("mainmenu")) {
getById("mainmenu").style.backgroundImage = "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K')";
getById("mainmenu").innerHTML = '
Attempting to load video stream.
';
getById("mainmenu").innerHTML += 'The stream is not available yet or an error occured.
';
}
}
} catch (e) {
errorlog("Error handling QR Code failure");
}
}, 15000);
log("auto playing");
var SafariVer = safariVersion();
if ((iPad || iOS) && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1 && SafariVer > 13) { // Modern iOS doesn't need pop up
play();
} else if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { // Safari on Desktop does require pop up
if (!(session.cleanOutput)) {
warnUser("Safari requires us to ask for an audio permission to use peer-to-peer technology. You will need to accept it in a moment if asked to view this live video", 20000);
}
navigator.mediaDevices.getUserMedia({
audio: true
}).then(function() {
closeModal();
play();
}).catch(function() {
play();
});
} else { // everything else is OK.
play();
}
} else if (session.roomid) {
try {
if (session.label === false) {
if (document.title == "") {
document.title = "Room=" + session.roomid.toString();
} else {
document.title += ": " + session.roomid.toString();
}
}
} catch (e) {
errorlog(e);
};
}
setTimeout(function(){
for (var i in delayedStartupFuncs) {
var cb = delayedStartupFuncs[i];
log(cb.slice(1));
cb[0](...cb.slice(1)); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#A_better_apply
}
delayedStartupFuncs = [];
},50);
if ((session.effects=="3") || (session.effects=="4") || (session.effects=="5")){
attemptTFLiteJsFileLoad();
} else if (session.effects=="6"){
loadTensorflowJS();
} else if (session.effects=="9"){
var script = document.createElement('script');
script.onload = function() {
effectsEngine();
}
script.src = "./filters/sample.js";
document.head.appendChild(script);
warnUser("Loading custom effects model...",1000);
} else if (session.effects=="10"){
var script = document.createElement('script');
script.onload = function() {
effectsEngine();
}
script.src = "./filters/cube.js";
document.head.appendChild(script);
warnUser("Loading custom effects model...",1000);
} else if (session.effects=="11"){
session.effects="anon";
//loadEffect(session.effects);
}
if (location.protocol !== 'https:') {
if (!(session.cleanOutput)) {
warnUser("SSL (https) is not enabled. This site will not work without it!
Try accessing the site from here instead.");
}
}
if (session.sensorData) {
setupSensorData(parseInt(session.sensorData));
}
try {
navigator.mediaDevices.ondevicechange = reconnectDevices;
} catch (e) {
errorlog(e);
}
if (isIFrame) { // reduce CPU load if not needed. //iframe API
window.onmessage = function(e) { // iFRAME support
log(e);
try {
if ("function" in e.data) { // these are calling in-app functions, with perhaps a callback -- TODO: add callbacks
var ret = null;
if (e.data.function === "previewWebcam") {
ret = previewWebcam();
} else if (e.data.function === "changeHTML") {
ret = getById(e.data.target);
ret.innerHTML = e.data.value;
} else if (e.data.function === "publishScreen") {
ret = publishScreen();
} else if (e.data.function === "eval") {
eval(e.data.value); // eval == evil ; feedback welcomed
}
}
} catch (err) {
errorlog(err);
}
if ("sendData" in e.data) { // send generic data via p2p. Send whatever you want I guess; there is a max chunk size of course. Use filetransfer for large files?
var UUID = false;
var streamID = false;
var type = false;
if (e.data.UUID){
UUID = e.data.UUID;
} else if (e.data.streamID){
streamID = e.data.streamID;
}
if (e.data.type){
type = e.data.type;
}
var ret = session.sendGenericData(e.data.sendData, UUID, streamID, type); // comes out the other side as: ("dataReceived", data, UUID);
if (!ret){warnlog("Not connected yet or no peers available");}
return;
}
if ("sendChat" in e.data) {
sendChat(e.data.sendChat); // sends to all peers; more options down the road
return;
}
// Chat out gets called via getChatMessage function
// Related code: parent.postMessage({"chat": {"msg":-----,"type":----,"time":---} }, "*");
if ("mic" in e.data) { // this should work for the director's mic mute button as well. Needs to be manually enabled the first time still tho.
if (e.data.mic === true) { // unmute
session.muted = false; // set
log(session.muted);
toggleMute(true); // apply
} else if (e.data.mic === false) { // mute
session.muted = true; // set
log(session.muted);
toggleMute(true); // apply
} else if (e.data.mic === "toggle") { // toggle
toggleMute();
}
}
if ("camera" in e.data) { // this should work for the director's mic mute button as well. Needs to be manually enabled the first time still tho.
if (e.data.camera === true) { // unmute
session.videoMuted = false; // set
log(session.videoMuted);
toggleVideoMute(true); // apply
} else if (e.data.camera === false) { // mute
session.videoMuted = true; // set
log(session.videoMuted);
toggleVideoMute(true); // apply
} else if (e.data.camera === "toggle") { // toggle
toggleVideoMute();
}
}
if ("keyframe" in e.data) {
session.sendKeyFrameScenes();
}
if ("mute" in e.data) {
if (e.data.mute === true) { // unmute
session.speakerMuted = true; // set
toggleSpeakerMute(true); // apply
} else if (e.data.mute === false) { // mute
session.speakerMuted = false; // set
toggleSpeakerMute(true); // apply
} else if (e.data.mute === "toggle") { // toggle
toggleSpeakerMute();
}
} else if ("speaker" in e.data) { // same thing as mute.
if (e.data.speaker === true) { // unmute
session.speakerMuted = false; // set
toggleSpeakerMute(true); // apply
} else if (e.data.speaker === false) { // mute
session.speakerMuted = true; // set
toggleSpeakerMute(true); // apply
} else if (e.data.speaker === "toggle") { // toggle
toggleSpeakerMute();
}
}
if ("record" in e.data) {
if (e.data.record == false) { // mute
if ("recording" in session.videoElement) {
recordLocalVideo("stop");
}
} else if (e.data.record == true){
if ("recording" in session.videoElement) {
// already recording
} else {
recordLocalVideo("start");
}
}
}
if ("volume" in e.data) {
for (var i in session.rpcs) {
try {
session.rpcs[i].videoElement.volume = parseFloat(e.data.volume);
} catch (e) {
errorlog(e);
}
}
}
if ("panning" in e.data){
if ("UUID" in e.data){
try {
adjustPan(UUID, e.data.panning);
} catch (e) {
errorlog(e);
}
} else {
for (var i in session.rpcs) {
try {
adjustPan(i, e.data.panning);
} catch (e) {
errorlog(e);
}
}
}
}
if ("bitrate" in e.data) {
for (var i in session.rpcs) {
try {
session.requestRateLimit(parseInt(e.data.bitrate), i);
} catch (e) {
errorlog(e);
}
}
}
if ("audiobitrate" in e.data) {
for (var i in session.rpcs) {
try {
session.requestAudioRateLimit(parseInt(e.data.audiobitrate), i);
} catch (e) {
errorlog(e);
}
}
}
if ("changeVideoDevice" in e.data) {
warnlog(e.data.changeVideoDevice);
changeVideoDevice(e.data.changeVideoDevice);
}
if ("changeAudioDevice" in e.data) {
warnlog(e.data.changeAudioDevice);
changeAudioDevice(e.data.changeAudioDevice);
}
if ("changeAudioOutputDevice" in e.data) {
warnlog(e.data.changeAudioOutputDevice);
changeAudioOutputDeviceById(e.data.changeAudioOutputDevice);
}
if ("getDeviceList" in e.data) {
warnlog(e.data.getDeviceList);
enumerateDevices().then(function(deviceInfos) {
parent.postMessage({
"deviceList": deviceInfos
}, "*");
});
}
if ("sceneState" in e.data) { // TRUE OR FALSE - tells the connected peers if they are live or not via a tally light change.
if (session.obsState.visibility !== e.data.sceneState) { // only move forward if there is a change; the event likes to double fire you see.
session.obsStateSync();
}
}
if ("sendMessage" in e.data) { // webrtc send to viewers
session.sendMessage(e.data);
}
if ("sendRequest" in e.data) { // webrtc send to publishers
session.sendRequest(e.data);
}
if ("sendPeers" in e.data) { // webrtc send message to every connected peer; like send and request; a hammer vs a knife.
session.sendPeers(e.data);
}
if ("reload" in e.data) {
location.reload();
}
if ("getStats" in e.data) {
var stats = {};
stats.total_outbound_connections = Object.keys(session.pcs).length;
stats.total_inbound_connections = Object.keys(session.rpcs).length;
stats.inbound_stats = {};
for (var i in session.rpcs) {
stats.inbound_stats[session.rpcs[i].streamID] = session.rpcs[i].stats;
}
for (var uuid in session.pcs) {
setTimeout(function(UUID) {
session.pcs[UUID].getStats().then(function(stats) {
stats.forEach(stat => {
if (stat.type == "outbound-rtp") {
if (stat.kind == "video") {
if ("qualityLimitationReason" in stat) {
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
}
if ("framesPerSecond" in stat) {
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight + " @ " + stat.framesPerSecond;
}
if ("encoderImplementation" in stat) {
session.pcs[UUID].stats.encoder = stat.encoderImplementation;
}
}
} else if (stat.type == "remote-candidate") {
if ("relayProtocol" in stat) {
if ("ip" in stat) {
session.pcs[UUID].stats.remote_relay_IP = stat.ip;
}
session.pcs[UUID].stats.remote_relayProtocol = stat.relayProtocol;
}
if ("candidateType" in stat) {
session.pcs[UUID].stats.remote_candidateType = stat.candidateType;
}
} else if (stat.type == "local-candidate") {
if ("relayProtocol" in stat) {
if ("ip" in stat) {
session.pcs[UUID].stats.local_relayIP = stat.ip;
}
session.pcs[UUID].stats.local_relayProtocol = stat.relayProtocol;
}
if ("candidateType" in stat) {
session.pcs[UUID].stats.local_candidateType = stat.candidateType;
}
} else if ((stat.type == "candidate-pair" ) && (stat.nominated)) {
if ("availableOutgoingBitrate" in stat){
session.pcs[UUID].stats.available_outgoing_bitrate_kbps = parseInt(stat.availableOutgoingBitrate/1024);
}
if ("totalRoundTripTime" in stat){
if ("responsesReceived" in stat){
session.pcs[UUID].stats.average_roundTripTime_ms = parseInt((stat.totalRoundTripTime/stat.responsesReceived)*1000);
}
}
}
return;
});
return;
});
}, 0, uuid);
}
setTimeout(function() {
stats.outbound_stats = {};
for (var i in session.pcs) {
stats.outbound_stats[i] = session.pcs[i].stats;
}
parent.postMessage({
"stats": stats
}, "*");
}, 1000);
}
if ("getRemoteStats" in e.data) {
session.sendRequest({"requestStats":true, "remote":session.remote});
}
if ("getLoudness" in e.data) {
log("GOT LOUDNESS REQUEST");
if (e.data.getLoudness == true) {
session.pushLoudness = true;
var loudness = {};
for (var i in session.rpcs) {
loudness[session.rpcs[i].streamID] = session.rpcs[i].stats.Audio_Loudness;
}
parent.postMessage({
"loudness": loudness
}, "*");
} else {
session.pushLoudness = false;
}
}
if ("getEffectsData" in e.data) {
log("GOT getEffects Data REQUESTed"); // face tracking info, etc.
if (e.data.getEffectsData !== false) {
session.pushEffectsData = e.data.getEffectsData; // which effect do you want the data from? it won't enable the effect necessarily; just the ML pipeline
//parent.postMessage({
// "effectsData": effectsData,
// "effectsID": session.pushEffectsData
//}, "*");
} else {
session.pushEffectsData = false;
}
}
if ("getStreamIDs" in e.data) {
if (e.data.getStreamIDs == true) {
var streamIDs = {};
for (var i in session.rpcs) {
streamIDs[session.rpcs[i].streamID] = session.rpcs[i].label;
}
parent.postMessage({
"streamIDs": streamIDs
}, "*");
}
}
if ("close" in e.data) {
for (var i in session.rpcs) {
try {
session.rpcs[i].close();
} catch (e) {
errorlog(e);
}
}
}
if ("style" in e.data) {
try {
const style = document.createElement('style');
style.textContent = e.data.style;
document.head.append(style);
log(style);
} catch (e) {
errorlog(e);
}
}
if ("automixer" in e.data) {
if (e.data.automixer == true) {
session.manual = false;
try {
updateMixer();
} catch (e) {}
} else if (e.data.automixer == false) {
session.manual = true;
}
}
if (("action" in e.data) && (e.data.action!="null")) { /////////////// reuse the Companion API
processMessage(e.data); // reuse the companion API
} else if ("target" in e.data) {
log(e.data);
for (var i in session.rpcs) {
try {
if ("streamID" in session.rpcs[i]) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) {
try {
if ("settings" in e.data) {
for (const property in e.data.settings) {
session.rpcs[i].videoElement[property] = e.data.settings[property];
}
}
if ("add" in e.data) {
getById("gridlayout").appendChild(session.rpcs[i].videoElement);
} else if ("remove" in e.data) {
try {
session.rpcs[i].videoElement.parentNode.removeChild(session.rpcs[i].videoElement);
} catch (e) {
try {
session.rpcs[i].videoElement.parentNode.parentNode.removeChild(session.rpcs[i].videoElement.parentNode);
} catch (e) {}
}
}
} catch (e) {
errorlog(e);
}
}
}
} catch (e) {
errorlog(e);
}
}
}
};
}
if (session.midiHotkeys || session.midiOut!==false) {
var script = document.createElement('script');
script.onload = function() {
WebMidi.enable(function(err) { // hotkeys
if (err) {
errorlog(err);
}
WebMidi.addListener("connected", function(e) {
log(e);
});
WebMidi.addListener("disconnected", function(e) {
log(e);
});
console.log(WebMidi.inputs);
if (session.midiOut===true){
for (var i = 0; i < WebMidi.inputs.length; i++) {
var input = WebMidi.inputs[i];
input.addListener("midimessage", "all", function(e) {
log(e);
var msg = {};
msg.midi = {};
msg.midi.d = e.data;
msg.midi.s = e.timestamp;
msg.midi.t = e.type;
for (var UUID in session.pcs){
if (session.pcs[UUID].allowMIDI){
session.sendMessage(msg, UUID);
}
}
});
}
} else if (session.midiOut==parseInt(session.midiOut)){
try{
var input = WebMidi.inputs[parseInt(session.midiOut)-1];
input.addListener("midimessage", "all", function(e) {
log(e);
var msg = {};
msg.midi = {};
msg.midi.d = e.data;
msg.midi.s = e.timestamp;
msg.midi.t = e.type;
for (var UUID in session.pcs){
if (session.pcs[UUID].allowMIDI){
session.sendMessage(msg, UUID);
}
}
});
} catch(e){errorlog(e);};
}
for (var i = 0; i < WebMidi.inputs.length; i++) {
var input = WebMidi.inputs[i];
input.addListener('noteon', "all", function(e) {
log(e);
var note = e.note.name + e.note.octave;
var velocity = e.velocity || false;
midiHotkeysNote(node,velocity);
});
input.addListener('controlchange', "all", function(e) {
if (session.midiHotkeys==4){
/* channel: 1
controller: {number: 110, name: undefined}
data: Uint8Array(3) [176, 110, 3]
target: Input {_userHandlers: {…}, _midiInput: MIDIInput, …}
timestamp: 98235.34000001382
type: "controlchange"
value: 3 */
log(e);
if (e.channel!==1){
errorlog("VDO.Ninja is currently configured for use on channel 1 for MIDI hotkeys");
return;
} // channel 1?
var command = e.controller.number;
var value = e.value;
midiHotkeys(command, value)
}
});
}
});
};
script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
document.head.appendChild(script);
} else if (session.midiIn){
var script = document.createElement('script');
script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
script.onload = function() {
WebMidi.enable(function(err) { // hotkeys
if (err) {
errorlog(err);
}
console.log(WebMidi.outputs);
});
}
document.head.appendChild(script);
}
var languages = getById('languagesList').querySelectorAll('li a');
var timezones = [];
languages.forEach(language => {
if (language.dataset.tz) {
var languageTimezones = language.dataset.tz.split(';'); // each link can have multiple timezones separated by ;
languageTimezones.forEach(element => {
timezones.push(element);
});
}
});
var currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (timezones.includes(currentTimezone)) {
var el = getById('languagesList').querySelector("li a[data-tz*='" + currentTimezone +"']"); // select language li
el.parentElement.removeChild(el); // remove it
getById('languagesList').insertBefore(el, getById('languagesList').querySelector('li:nth-child(2)')); // insert it after English
}
var visAudioTimeout = null
document.addEventListener("visibilitychange", function() {
//log("hidden : " +document.hidden);
log("vis : "+document.visibilityState);
if ((iOS) || (iPad)) { // fixes a bug on iOS devices. Not need with other devices?
clearTimeout(visAudioTimeout);
if (document.visibilityState === 'visible') {
visAudioTimeout = setTimeout(function() {
resetupAudioOut();
activatedPreview=false;
grabAudio("videosource", "#audioSource3");
}, 500);
}
}
});
// Warns user about network going down
window.addEventListener("offline", function (e) {
if ((session.view) && (session.permaid === false)) {
log("VDO.Ninja has no network connectivity and can't work properly." );
} else if (session.scene !== false) {
log("VDO.Ninja has no network connectivity and can't work properly." );
} else if (!session.cleanOutput) {
warnUser("Network connection lost.");
} else {
log("VDO.Ninja has no network connectivity and can't work properly.");
}
});
window.addEventListener("online", function (e) {
closeModal();
});
function updateConnectionStatus() {
try{
warnlog("Connection type changed from " + session.stats.network_type + " to " + Connection.effectiveType);
session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
session.ping();
} catch(e){warnlog(e);};
}
try {
var Connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (Connection){
session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
Connection.addEventListener('change', updateConnectionStatus);
}
} catch (e) {log(e);} // effectiveType is not yet supported by Firefox or Safari; 2021
setInterval(function() {
checkConnection();
}, 5000);
// Remove modal if network comes back up
window.addEventListener("online", function (e) {
if (!session.cleanOutput) {
// Remove last inserted modal; Could be improved by tagging the
// modal elements and only removing modals tagged 'offline'
userWarnings = document.querySelectorAll('.alertModal');
closeModal(userWarnings[userWarnings.length- 1]);
} else {
log(
"Network connectivity has been restored."
);
}
});
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;
}
//event.target.ondragend = function(){event.target.blur();}
var streamId = url.split('view=');
var label = url.split('label=');
if (session.label !== false) {
url += '&layer-name=' + session.label;
} else {
url += '&layer-name=VDO.Ninja';
}
if (streamId.length > 1) url += ': ' + streamId[1].split('&')[0];
if (label.length > 1) url += ' - ' + decodeURI(label[1].split('&')[0]);
try {
if (document.getElementById("videosource")) {
var video = getById('videosource');
if (typeof(video.videoWidth) == "undefined") {
url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=1080';
} else if ((parseInt(video.videoWidth) < 360) || (video.videoHeight < 640)) {
url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=1080';
} else {
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;
}
} else {
url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=1080';
}
} catch (error) {
url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
url += '&layer-height=1080';
}
event.dataTransfer.setDragImage( getById('dragImage'), 24, 24);
event.dataTransfer.setData("text/uri-list", encodeURI(url));
//event.dataTransfer.setData("url", encodeURI(url));
});
window.onload = function winonLoad() { // This just keeps people from killing the live stream accidentally. Also give me a headsup that the stream is ending
window.addEventListener("beforeunload", function(e) {
if (!session.noExitPrompt && !session.cleanOutput && (session.permaid!==false || session.director)){
(e || window.event).returnValue = "Are you sure you want to exit?"; //Gecko + IE
return "Are you sure you want to exit?";
} else {
//setTimeout(function(){session.hangup();},0);
return undefined; // ADDED OCT 29th; get rid of popup. Just close the socket connection if the user is refreshing the page. It's one or the other.
}
});
window.addEventListener("unload", function(e) {
try {
session.ws.close();
if (session.videoElement.recording) {
session.videoElement.recorder.writer.close();
session.videoElement.recording = false;
}
for (var i in session.rpcs) {
if (session.rpcs[i].videoElement) {
if (session.rpcs[i].videoElement.recording) {
session.rpcs[i].videoElement.recorder.writer.close();
session.rpcs[i].videoElement.recording = false;
}
}
}
session.hangup();
} catch (e) {}
});
};
var lastTouchEnd = 0;
document.addEventListener('touchend', function(event) {
var now = (new Date()).getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
document.addEventListener('click', function(event) {
if (session.firstPlayTriggered == false) {
playAllVideos();
session.firstPlayTriggered = true;
history.pushState({}, '');
}
});
document.addEventListener("keydown", event => {
if ((event.ctrlKey) || (event.metaKey)) { // detect if CTRL is pressed
CtrlPressed = true;
} else {
CtrlPressed = false;
}
if (event.altKey) {
AltPressed = true;
} else {
AltPressed = false;
}
if (CtrlPressed && event.keyCode) {
if (event.keyCode == 77) { // m
if (event.metaKey) {
if (AltPressed) {
toggleMute(); // macOS
}
} else {
toggleMute(); // Windows
}
// } else if (event.keyCode == 69) { // e
// hangup();
} else if (event.keyCode == 66) { // b
toggleVideoMute();
}
}
});
document.addEventListener("keyup", event => {
if (!((event.ctrlKey) || (event.metaKey))) {
if (CtrlPressed) {
CtrlPressed = false;
for (var i in Callbacks) {
var cb = Callbacks[i];
log(cb.slice(1));
cb[0](...cb.slice(1)); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#A_better_apply
}
Callbacks = [];
}
}
if (!(event.altKey)) {
AltPressed = false;
}
if (event.altKey && event.shiftKey && event.keyCode === 67 /* C */) {
toggleControlBar();
}
});
}
main(); // asyncronous load
setTimeout(function(){ // lazy load
var script = document.createElement('script');
document.head.appendChild(script);
script.onload = function() {
var script = document.createElement('script');
document.head.appendChild(script);
script.src = "./thirdparty/StreamSaver.js"; // dynamically load this only if its needed. Keeps loading time down.
};
script.src = "./thirdparty/polyfill.min.js"; // dynamically load this only if its needed. Keeps loading time down.
},0);