From 36a63f615556e4e3104b2630b0f214b73e3797c0 Mon Sep 17 00:00:00 2001 From: Steve Seguin Date: Mon, 31 May 2021 15:46:08 -0400 Subject: [PATCH] bug fixes + rebrand - midiin/out issue with indexing fixed - h264 broadcast support no longer default - vdo.ninja branding --- index.html | 39 +- main.js | 35549 ++++++++++++++++++++++++++------------------------- webrtc.js | 18 +- 3 files changed, 17806 insertions(+), 17800 deletions(-) diff --git a/index.html b/index.html index 541addc..4b43df2 100644 --- a/index.html +++ b/index.html @@ -24,25 +24,25 @@ - OBS.Ninja - - + VDO.Ninja + + - + - - - - + + + + - - + + @@ -73,7 +73,7 @@ - OBS.Ninja + VDO.Ninja
@@ -605,8 +605,7 @@
See the documentation for more options and info.

- Try out the advanced invite generator here also. - + Try out the advanced invite generator here also.
@@ -698,7 +697,7 @@
-

What is OBS.Ninja

+

What is VDO.Ninja


  • 100% free; no downloads; no personal data collection; no sign-in
  • Bring live video from your smartphone, remote computer, or friends directly into OBS or other studio software.
  • @@ -706,7 +705,7 @@
  • Youtube video - Demoing it here + Demoing it here

  • @@ -720,9 +719,12 @@
  • A list of less common issues can be found here.
  • -
    - 🌻 Site Updated on May 28th. The new v18 release notes are here. If new issues occur, the previous version can also be found here. +

    + 👋 👀 Welcome to our new domain! We've started to rebrand to VDO.Ninja. 📼 Nothing else is changing. +

    +
    + 🌻 Site Updated on May 31st. The new v18 release notes are here. If new issues occur, the previous version can also be found here.

    @@ -782,6 +784,7 @@
  • https://invite.cam is a free service provided that can help obfuscuate the URL parameters of an invite link given to guests.
  • Adding &showonly=SOME_OBS_VIRTUALCAM to the guest invite links allows for only a single video to be seen by the guests; this can be output of the OBS Virtual Camera for example

  • + For advanced URL options and parameters, see the Wiki.
    @@ -1476,7 +1479,7 @@
    - Welcome to OBS.Ninja! You can send text messages directly to connected peers from here. + Welcome to VDO.Ninja! You can send text messages directly to connected peers from here.
    diff --git a/main.js b/main.js index 4907de5..676ea4d 100644 --- a/main.js +++ b/main.js @@ -1,17773 +1,17776 @@ -/* -* 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. -* -*/ -/*jshint esversion: 6 */ - -var formSubmitting = true; -var activatedPreview = false; - - -// function log(msg){ // uncomment to enable logging. - // console.log(msg); -// } -// function warnlog(msg, url=false, lineNumber=false){ - // onsole.warn(msg); - // if (lineNumber){ - // console.warn(lineNumber); - // } -// } -// function errorlog(msg, url=false, lineNumber=false){ - // console.error(msg); - // if (lineNumber){ - // console.error(lineNumber); - // } -// } - -function addEventToAll(targets, trigger, callback) { // js helper - const target = document.querySelectorAll(targets); - var triggers = trigger.split(" "); - for (let i = 0; i < target.length; i++) { - for (let j = 0; j < triggers.length; j++) { - setTimeout(function(t1,t2){ - t1.addEventListener(t2, function(e) { - callback(e, t1); - }); - },0,target[i],triggers[j]); - } - } -} - -function mapToAll(targets, callback, parentElement = document) { // js helper - if (!targets) { - return; - } - if (!parentElement) { - return; - } - const target = parentElement.querySelectorAll(targets); - for (let i = 0; i < target.length; i++) { - callback(target[i]); - } -} - -var isIFrame = false; -if ( parent && (window.location !== window.parent.location )) { - isIFrame = true; -} - -function changeParam(url, paramName, paramValue) { - paramName = paramName.replace("?", ""); - var qind = url.indexOf('?'); - url = url.replace("?", "&"); - var params = url.substring(qind + 1).split('&'); - var query = ''; - var match = false; - for (var i = 0; i < params.length; i++) { - var tokens = params[i].split('='); - var name = tokens[0]; - var value = ""; - if (tokens.length > 1 && tokens[1] !== '') { - value = tokens[1]; - } - - if (name == paramName) { - if (match) { - continue; - } // already matched the first time. - match = true; - value = paramValue; - } - if (value !== "") { - value = '=' + value; - } - - if (query == '') { - query = "?" + name + value; - } else { - query = query + '&' + name + value; - } - } - return url.substring(0, qind) + query; -} - -function updateURL(param, force = false, cleanUrl = false) { - param = param.replace("?", ""); - var para = param.split('='); - if (cleanUrl) { - if (history.pushState) { - var href = new URL(cleanUrl); - if (para.length == 1) { - href = changeParam(cleanUrl, para[0], ""); - } else { - href = changeParam(cleanUrl, para[0], para[1]); - } - log("--" + href.toString()); - window.history.pushState({path: href.toString()}, '', href.toString()); - } - } else if (!(urlParams.has(para[0]))) { // don't need to replace as it doesn't exist. - if (history.pushState) { - var href = window.location.href; - href = href.replace("??", "?"); - var arr = href.split('?'); - var newurl; - if (arr.length > 1 && arr[1] !== '') { - newurl = href + '&' + param; - } else { - newurl = href + '?' + param; - } - - window.history.pushState({path: newurl.toString()}, '', newurl.toString()); - } - } else if (force) { - if (history.pushState) { - var href = new URL(window.location.href); - if (para.length == 1) { - href = changeParam(window.location.href, para[0], ""); - } else { - href = changeParam(window.location.href, para[0], para[1]); - } - log("---" + href.toString()); - window.history.pushState({path: href.toString()}, '', href.toString()); - } - } - if (session.sticky) { - setStorage("settings", encodeURI(window.location.href), 90); - } - urlParams = new URLSearchParams(window.location.search); -} - -function changeGuestSettings(ele){ - var eles = ele.querySelectorAll('[data-param]'); - var UUID = ele.dataset.UUID; - var settings = {}; - for (var i = 0;i< eles.length; i++){ - if (eles[i].tagName.toLowerCase() == "input"){ - if (eles[i].checked===true){ - settings[eles[i].dataset.param] = true; - } else if (eles[i].checked===false){ - settings[eles[i].dataset.param] = false; - } else { - settings[eles[i].dataset.param] = eles[i].value; - } - } - } - warnlog(settings); - - if (!settings.changepassword){ - delete settings.password; - } - - delete settings.changepassword; - - if (!settings.changeroom){ - // send Migration message - delete settings.roomid; - } - delete settings.roomid; - delete settings.changeroom; - - warnlog(UUID); - var msg = {}; - msg.changeParams = settings; - session.sendRequest(msg, UUID); - closeModal(); -} - -// proper room migration needs to happen; in sync. -// updateMixer after settings changed -// password needs to be special cased -// room shouldn't be sent - -function applyNewParams(changeParams){ - for (var key in changeParams){ - session[key] = changeParams[key]; - log(key); - } - log(changeParams); - updateMixer(); -} - -function promptUser(eleId, UUID=null){ - if (document.getElementById("modalBackdrop")){ - getById("promptModal").innerHTML = ''; // Delete modal - getById("promptModal").remove(); - getById("modalBackdrop").innerHTML = ''; // Delete modal - getById("modalBackdrop").remove(); - } - - zindex = 30 + document.querySelectorAll('#promptModal').length; - modalTemplate = - `
    -
    - × - -
    -
    -
    `; - document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end - - getById("promptModalMessage").innerHTML = getById(eleId).innerHTML; - if (UUID){ - getById("promptModalMessage").dataset.UUID = UUID; - } - - - document.getElementById("modalBackdrop").addEventListener("click", closeModal); - - getById("promptModal").addEventListener("click", function(e) { - e.stopPropagation(); - return false; - }); - -} -var warnUserTimeout=null; -function warnUser(message, timeout=false){ - // Allows for multiple alerts to stack better. - // Every modal and backdrop has an increasing z-index - // to block the previous modal - if (document.getElementById("modalBackdrop")){ - getById("alertModal").innerHTML = ''; // Delete modal - getById("alertModal").remove(); - getById("modalBackdrop").innerHTML = ''; // Delete modal - getById("modalBackdrop").remove(); - } - - zindex = 31 + document.querySelectorAll('.alertModal').length; - message = message.replace(/\n/g,"
    "); - modalTemplate = - `
    -
    - × - ${message} -
    -
    -
    `; - document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end - - document.getElementById("modalBackdrop").addEventListener("click", closeModal); - - clearTimeout(warnUserTimeout); - if (timeout){ - warnUserTimeout = setTimeout(closeModal, timeout); - } - getById("alertModal").addEventListener("click", function(e) { - e.stopPropagation(); - return false; - }); - -} -function closeModal(){ - getById("modalBackdrop").innerHTML = ''; // Delete modal - getById("modalBackdrop").remove(); - getById("alertModal").innerHTML = ''; // Delete modal - getById("alertModal").remove(); - getById("promptModal").innerHTML = ''; // Delete modal - getById("promptModal").remove(); -} - -var filename = false; -try { - filename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1); - filename = filename.replace("??", "?"); - filename2 = filename.split("?")[0]; - // split at ??? - if (filename.split(".").length == 1) { - if (filename2.length < 2) { // easy win - filename = false; - } else if (filename.startsWith("&")) { // easy win - var tmpHref = window.location.href.substring(0, window.location.href.lastIndexOf('/')) + "/?" + filename.split("&").slice(1).join("&"); - log("TMP " + tmpHref); - updateURL(filename.split("&")[1], true, tmpHref); - filename = false; - } else if (filename2.split("&")[0].includes("=")) { - log("asdf " + filename.split("&")[0]); - if (history.pushState) { - var tmpHref = window.location.href.substring(0, window.location.href.lastIndexOf('/')); - tmpHref = tmpHref + "/?" + filename; - filename = false; - //warnUser("Please ensure your URL is correctly formatted."); - window.history.pushState({path: tmpHref.toString()}, '', tmpHref.toString()); - } - } else { - filename = filename2.split("&")[0]; - if (filename2 != filename) { - warnUser("Warning: Please ensure your URL is correctly formatted."); - } - } - } else { - filename = false; - } - log(filename); -} catch (e) { - errorlog(e); -} - - -(function(w) { - w.URLSearchParams = w.URLSearchParams || function(searchString) { - var self = this; - searchString = searchString.replace("??", "?"); - self.searchString = searchString; - self.get = function(name) { - var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString); - if (results == null) { - return null; - } else { - return decodeURI(results[1]) || 0; - } - }; - }; - -})(window); - -var urlEdited = window.location.search.replace(/\?\?/g, "?"); -urlEdited = urlEdited.replace(/\?/g, "&"); -urlEdited = urlEdited.replace(/\&/, "?"); - -if (urlEdited !== window.location.search){ - warnlog(window.location.search + " changed to " + urlEdited); - window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString()); -} -var urlParams = new URLSearchParams(urlEdited); - -var sanitizeStreamID = function(streamID) { - streamID = streamID.trim(); - - if (streamID.length < 1) { - streamID = session.generateStreamID(8); - if (!(session.cleanOutput)) { - warnUser("No streamID was provided; one will be generated randomily.\n\nStream ID: " + streamID); - } - } - var streamID_sanitized = streamID.replace(/[\W]+/g, "_"); - if (streamID !== streamID_sanitized) { - if (!(session.cleanOutput)) { - warnUser("Info: Only AlphaNumeric characters should be used for the stream ID.\n\nThe offending characters have been replaced by an underscore"); - } - } - if (streamID_sanitized.length > 44) { - streamID_sanitized = streamID_sanitized.substring(0, 44); - if (!(session.cleanOutput)) { - warnUser("The Stream ID should be less than 45 alPhaNuMeric characters long.\n\nWe will trim it to length."); - } - } - return streamID_sanitized; -}; - -var checkStrength = function(string) { - var matcher = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,30}$/; - if (string.match(matcher)) { - return true; - } else if (string.length > 20) { - return true; - } else { - return false; - } -}; - -var checkStrengthRoom = function() { - var result1 = checkStrength(getById('videoname1').value); - var result2 = getById('passwordRoom').value.length; - var target = getById('securityLevelRoom'); - target.style.display = "block"; - if (result1) { - if (result2) { - target.innerHTML = "Share only with those you trust"; - } else { - target.innerHTML = "A password is recommended"; - } - } else { - target.innerHTML = "Insecure room name. Allowed chars: A-Z, a-z, 0-9, _"; - } -}; - -var sanitizeChat = function(string) { - var temp = document.createElement('div'); - temp.innerText = string; - temp.innerText = temp.innerHTML; - temp = temp.textContent || temp.innerText || ""; - temp = temp.substring(0, Math.min(temp.length, 500)); - return temp.trim(); -}; - -var sanitizeString = function(str) { - str = str.replace(/[^a-z0-9áéíóúñü \.,_-]/gim, ""); - return str.trim(); -}; - -var sanitizeLabel = function(string) { - let temp = document.createElement("div"); - temp.innerText = string; - temp.innerText = temp.innerHTML; - temp = temp.textContent || temp.innerText || ""; - temp = temp.substring(0, Math.min(temp.length, 50)); - return temp.trim(); -}; - -var sanitizeRoomName = function(roomid) { - roomid = roomid.trim(); - if (roomid === "") { - return roomid; - } else if (roomid === false) { - return roomid; - } - - var sanitized = roomid.replace(/[\W]+/g, "_"); - if (sanitized !== roomid) { - if (!(session.cleanOutput)) { - warnUser("Info: Only AlphaNumeric characters should be used for the room name.\n\nThe offending characters have been replaced by an underscore"); - } - } - if (sanitized.length > 30) { - sanitized = sanitized.substring(0, 30); - if (!(session.cleanOutput)) { - warnUser("The Room name should be less than 31 alPhaNuMeric characters long.\n\nWe will trim it to length."); - } - } - return sanitized; -}; - -var sanitizePassword = function(passwrd) { - if (passwrd === "") { - return passwrd; - } else if (passwrd === false) { - return passwrd; - } else if (passwrd === null) { - return passwrd; - } - passwrd = passwrd.trim(); - if (passwrd.length < 1) { - if (!(session.cleanOutput)) { - warnUser("The password provided was blank."); - } - } - var sanitized = encodeURIComponent(passwrd);//.replace(/[\W]+/g, "_"); - //if (sanitized !== passwrd) { - // if (!(session.cleanOutput)) { - // warnUser("Info: Only AlphaNumeric characters should be used in the password.\n\nThe offending characters have been replaced by an underscore"); - // } - //} - return sanitized; -}; - -function isOperaGX(){ - return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/75') >= 0; -} - -function getChromeVersion() { - var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); - return raw ? parseInt(raw[2], 10) : false; -} - -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 elements = document.querySelectorAll('[data-effectsNotice]'); - for (let i = 0; i < elements.length; i++) { - elements[i].style.display = "inline-block"; - } -} - -function safariVersion() { - var ver = 0; - try { - ver = navigator.appVersion.split("Version/"); - if (ver.length > 1) { - ver = ver[1].split(" Safari"); - } - if (ver.length > 1) { - ver = ver[0].split("."); - } - if (ver.length > 1) { - ver = parseInt(ver[0]); - } else { - ver = 0; - } - } catch (e) { - return 0; - } - return ver; -} - -if (urlParams.has('optimize')) { - session.optimize = parseInt(urlParams.get('optimize')) || 0; -} -document.addEventListener("visibilitychange", function() { - log(document.hidden, document.visibilityState); - if ((iOS) || (iPad)) { // fixes a bug on iOS devices. Not need with other devices? - if (document.visibilityState === 'visible') { - setTimeout(function() { - resetupAudioOut(); - }, 500); - } - } -}); -function obsSceneChanged(event){ - log(event.detail.name); - window.obsstudio.getCurrentScene(function(scene) { - log("OBS SCENE"); - log(scene); - }); -} -function obsStreamingStarted(event){ - session.obsState.streaming = true; - session.obsStateSync(); -} -function obsStreamingStopped(event){ - session.obsState.streaming = false; - session.obsStateSync(); -} -function obsRecordingStarted(event){ - session.obsState.recording = true; - session.obsStateSync(); -} -function obsRecordingStopped(event){ - session.obsState.recording = false; - session.obsStateSync(); -} -function obsSourceActiveChanged(event){ - warnlog("obsSourceActiveChanged"); - warnlog( event.detail); - - try { - if (typeof event==="boolean"){var sourceActive = event;} - else if (typeof event.detail === "boolean"){var sourceActive = event.detail;} - else if (typeof event.detail.active === "boolean"){var sourceActive = event.detail.active;} - else {var sourceActive = event.detail.active;} - - if (typeof sourceActive === "undefined"){return;} // Just fail. - - if (session.obsState.sourceActive!==sourceActive){ // only move forward if there is a change; the event likes to double fire you see. - session.obsState.sourceActive = sourceActive; - session.obsStateSync(); - } - - } catch (e){errorlog(e);} -} - -function obsSourceVisibleChanged(event){ // accounts for visible in OBS.Ninja scene AND visible in OBS scene - warnlog("obsSourceVisibleChanged"); - warnlog(event.detail); - try { - if (typeof event==="boolean"){var visibility = event;} - else if (typeof event.detail === "boolean"){var visibility = event.detail;} - else if (typeof event.detail.visible === "boolean"){var visibility = event.detail.visible;} - else {var visibility = event.detail.visible;} - - if (typeof visibility === "undefined"){ // fall back - if (typeof document.visibilityState !== "undefined"){ - visibility = document.visibilityState==="visible"; // modern - } else if (typeof document.hidden !== "undefined"){ - visibility = !document.hidden; // legacy - } else { - return; // ... unknown input? fail. - } - } - - errorlog("visibility: "+visibility); - - if (session.obsState.visibility!==visibility){ // only move forward if there is a change; the event likes to double fire you see. - session.obsState.visibility = visibility; - session.obsStateSync(); - } - - } catch (e){errorlog(e);} -} - -if (window.obsstudio) { - session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers? - session.audioMeterGuest = false; - session.audioEffects = false; - session.obsfix = 15; // can be manually set via URL. ; VP8=15, VP9=30. (previous was 20.) - try { - log("OBS VERSION:" + window.obsstudio.pluginVersion); - log("macOS: " + navigator.userAgent.indexOf('Mac OS X') != -1); - log(window.obsstudio); - - if (typeof document.visibilityState !== "undefined"){ - session.obsState.visibility = document.visibilityState==="visible"; - //session.obsState.sourceActive = session.obsState.visibility; - } - - window.obsstudio.getStatus(function(obsStatus) { - log("OBS STATUS:"); - log(obsStatus); - // TODO: update state here - if ("recording" in obsStatus){ - session.obsState.recording = obsStatus.recording; - } - if ("streaming" in obsStatus){ - session.obsState.streaming = obsStatus.streaming; - } - - }); - - if (!(urlParams.has('streamlabs'))) { - - var ver = window.obsstudio.pluginVersion; - ver1 = ver.split("."); - - var cefVersion = getChromeVersion(); - - if (ver1.length == 3) { // Should be 3, but disabled3 - if ((ver1.length == 3) && (parseInt(ver1[0]) == 2) && (cefVersion < 76) && (navigator.userAgent.indexOf('Mac OS X') != -1)) { - updateURL("streamlabs"); - getById("main").innerHTML = "

    Update OBS Studio to v26.1.2 or newer; older versions and StreamLabs OBS are not supported on macOS.\ -
    download here: https://github.com/obsproject/obs-studio/releases/tag/26.1.2\ -



    \ -

    Please use the Electron Capture app if there are further problems or if you wish to use StreamLabs on macOS still.

    \ -
    You can find more details within our wiki guide - https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os\ -
    You can bypass this error message by refreshing, Clicking Here, or by adding &streamlabs to the URL, but it may still not actually work.\ - \ -
    Please report this problem to steve@seguin.email if you feel it is an error.\ -
    "; - } - } - } - - 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); - } -} - -function manageSceneState(data, UUID){ - if (session.disableOBS){return;} - var processNeeded = false - try{ - if ("sceneDisplay" in data){ - processNeeded=true; - session.pcs[UUID].sceneDisplay = data.sceneDisplay; - } - if ("sceneMute" in data){ - processNeeded=true; - session.pcs[UUID].sceneMute = data.sceneMute; - } - if ("obsSourceActive" in data){ - processNeeded=true; - session.pcs[UUID].obsSourceActive = data.obsSourceActive; - } - if ("obsVisibility" in data){ - processNeeded=true; - session.pcs[UUID].obsVisibility = data.obsVisibility; - session.optimizeBitrate(UUID); // &optimize flag; sets video bitrate to target value if this flag == HIDDEN (if optimize=0, disables both audio and video) - } - if ("obsStreaming" in data){ - processNeeded=true; - session.pcs[UUID].obsStreaming = data.obsStreaming; - } - if ("obsRecording" in data){ - processNeeded=true; - session.pcs[UUID].obsRecording = data.obsRecording; - } - } catch(e){} // just in case the client has disconnected. - - if (processNeeded){ - applySceneState(); - } -} - -function applySceneState(){ - - if (session.cleanOutput===false){ - if (document.getElementById("videosource")){ - var visibility = false; - var ondeck = false; - var recording = false; - for (var uid in session.pcs){ - - if (session.pcs[uid].obsSourceActive && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){ - visibility=true; - } else if (session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){ - ondeck=true; - } - if ((session.pcs[uid].obsRecording || session.pcs[uid].obsStreaming) && (session.pcs[uid].obsSourceActive && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false))){ // the scene that is recording must be visible also. - recording=true; - } - } - - if (recording){ - getById("obsState").classList.remove("ondeck"); - getById("obsState").classList.add("recording"); // TODO: this needs to check all peers to make sure it's valid - getById("obsState").innerHTML = "ON AIR"; - } else if (ondeck && !visibility){ - getById("obsState").classList.remove("recording"); - getById("obsState").classList.add("ondeck"); // TODO: this needs to check all peers to make sure it's valid - getById("obsState").innerHTML = "STAND BY"; - } else { - getById("obsState").classList.remove("recording"); - getById("obsState").classList.remove("ondeck"); - getById("obsState").innerHTML = "ACTIVE"; - } - - if (visibility || ondeck){ // BASIC TALLY LIGHT - getById("obsState").classList.add("onair"); // LIVE - } else { - getById("obsState").classList.remove("onair"); - - } - - } - } - -} - -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) { - 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; - } - } - } - } catch (e) {} - //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. - - }); -}; - -getById("credits").innerHTML = "Version: " + session.version + " - " + getById("credits").innerHTML; - -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({}, ''); - } -}); -var Callbacks = []; -var CtrlPressed = false; // global -var AltPressed = false; -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; - } -}); - -window.onpopstate = function() { - if (session.firstPlayTriggered) { - window.location.reload(true); - } -}; - -if (typeof session === 'undefined') { // make sure to init the WebRTC if not exists. - var session = WebRTC.Media; - session.streamID = session.generateStreamID(); - errorlog("Serious error: WebRTC session didn't load in time"); -} - -if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) { - try { - getById("electronDragZone").style.cursor="grab"; - const ipcRenderer = require('electron').ipcRenderer; - window.prompt = function(title, val){ - return ipcRenderer.sendSync('prompt', {title, val}); - }; - } catch(e){} -} - -function makeDraggableElement(elmnt) { - try { - elmnt.dragElement = false; - elmnt.style.bottom = "auto"; - elmnt.style.cursor = "grab"; - elmnt.stashonmouseup = null; - elmnt.stashonmousemove = null; - - } catch (e) { - errorlog(e); - return; - } - - var pos1 = 0; - var pos2 = 0; - var pos3 = 0; - var pos4 = 0; - - function dragMouseDown(e) { - e = e || window.event; - e.preventDefault(); - - pos3 = e.clientX; - pos4 = e.clientY; - elmnt.stashonmouseup = document.onmouseup; // I don't want to interfere with other drag events. - elmnt.stashonmousemove = document.onmousemove; - - document.onmouseup = closeDragElement; - document.onmousemove = elementDrag; - } - - function elementDrag(e) { - e = e || window.event; - e.preventDefault(); - - elmnt.dragElement = true; - pos1 = pos3 - e.clientX; - pos2 = pos4 - e.clientY; - pos3 = e.clientX; - pos4 = e.clientY; - - var topDrag = (elmnt.offsetTop - pos2); - if (topDrag > -3) { - topDrag = -3; - } - elmnt.style.top = topDrag + "px"; - elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; - - } - - elmnt.onmousedown = dragMouseDown; - function closeDragElement() { - document.onmouseup = elmnt.stashonmouseup; - document.onmousemove = elmnt.stashonmousemove; - } -} - -function setStorage(cname, cvalue, exdays=999) { // not actually a cookie - var now = new Date(); - var item = { - value: cvalue, - expiry: now.getTime() + (exdays * 24 * 60 * 60 * 1000), - }; - localStorage.setItem(cname, JSON.stringify(item)); -} - -function getStorage(cname) { - var itemStr = localStorage.getItem(cname); - if (!itemStr) { - return ""; - } - var item = JSON.parse(itemStr); - var now = new Date(); - if (now.getTime() > item.expiry) { - localStorage.removeItem(cname); - return ""; - } - return item.value; -} - -if (!isIFrame){ - if (getStorage("redirect") == "yes") { - setStorage("redirect", "", 0); - session.sticky = true; - } else if (getStorage("settings") != "") { - if (!(session.cleanOutput)){ - window.focus(); - session.sticky = confirm("Would you like you load your previous session's settings?"); - if (!session.sticky) { - setStorage("settings", "", 0); - log("deleting cookie as user said no"); - } else { - var cookieSettings = decodeURI(getStorage("settings")); - setStorage("redirect", "yes", 1); - window.location.replace(cookieSettings); - } - } - } - - if (urlParams.has('sticky')){ // won't work with iframes. - - //if (getStorage("permission") == "") { - // session.sticky = confirm("Would you allow us to store a cookie to keep your session settings persistent?"); - //} else { - session.sticky = true; - //} - //if (session.sticky) { - setStorage("permission", "yes", 999); - setStorage("settings", encodeURI(window.location.href), 90); - //} - } -} - -if (urlParams.has('cleanoutput') || urlParams.has('clean') || urlParams.has('cleanish')) { - session.cleanOutput = true; -} - -if (urlParams.has('retrytimeout')) { - session.retryTimeout = parseInt(urlParams.get('retrytimeout')); -} - -if (urlParams.has('ptz')){ - session.ptz=true; -} - -var screensharebutton = true; -var screensharesupport = true; -if (urlParams.has('nosettings') || urlParams.has('ns')) { - screensharebutton = false; - session.showSettings = false; -} - -if (urlParams.has('nomicbutton') || urlParams.has('nmb')) { - getById("mutebutton").setAttribute('style', "display: none !important"); -} - - -if (urlParams.has('novideobutton') || urlParams.has('nvb')) { - getById("mutevideobutton").setAttribute('style', "display: none !important"); -} - -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); - } -} - -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 (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { - //session.webcamonly = true; - session.mobile = true; - getById("shareScreenGear").style.display = "none"; - screensharebutton = false; - screensharesupport = false; - getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile - getById("dropButton").style.display = "none"; - //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; - -} else if ((iOS) || (iPad)) { - getById("shareScreenGear").style.display = "none"; - session.mobile = true; - screensharebutton = false; - screensharesupport = false; - getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile - getById("dropButton").style.display = "none"; - //session.audiobitrate = false; // iOS devices seem to get distortion with custom audio bitrates. Disable for now. - //session.maxiosbitrate = 10; // this is 10-kbps by default already. - //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; -} else { - log("MAKE DRAGGABLE"); - setTimeout(function(){makeDraggableElement(document.getElementById("subControlButtons"));},100); - - if (safariVersion() && !getChromeVersion()){ - getById("SafariWarning").style.display = "block"; - } -} - - -if ((iOS) || (iPad)) { - window.addEventListener('resize', function() { // Safari is the new IE. - var msg = {}; - msg.requestSceneUpdate = true; - session.sendMessage(msg); - - if ( window.matchMedia("(orientation: portrait)").matches ) { - document.getElementsByTagName("html")[0].style.height = "100vh"; - setTimeout(function(){ - document.getElementsByTagName("html")[0].style.height = "100%"; - }, 1000); - } else if ( window.matchMedia("(orientation: landscape)").matches ) { - document.getElementsByTagName("html")[0].style.height = "100vh"; - setTimeout(function(){ - document.getElementsByTagName("html")[0].style.height = "100%"; - }, 1000); - } - }); -} - -if (/CriOS/i.test(navigator.userAgent) && (iOS || iPad)) { - if (!(session.cleanOutput)) { - try { - navigator.mediaDevices.getUserMedia; - } catch (e) { - warnUser("Chrome on this device does not support the required technology to use this site.\n\nPlease use Safari instead or update your iOS and browser version."); - } - } -} - -if (urlParams.has('tips')){ - getById("guestTips").style.display="flex"; -} - -if (urlParams.has('broadcast') || urlParams.has('bc')) { - log("Broadcast flag set"); - session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null; - //if ((iOS) || (iPad)) { - // session.nopreview = false; - //} else { - // session.nopreview = true; - //} - session.minipreview = 2; // full screen if nothing else on screen. - session.style = 1; - getById("header").style.display = "none"; - getById("header").style.opacity = 0; - session.showList=false; -} - -if (urlParams.has('showlist')) { - session.showList = urlParams.get('showlist'); - if (session.showList === "false") { - session.showList = false; - } else if (session.showList=== "0") { - session.showList = false; - } else if (session.showList === "no") { - session.showList = false; - } else if (session.showList === "off") { - session.showList = false; - } else { - session.showList = true; - } -} - -var directorLanding = false; -if (urlParams.has('director') || urlParams.has('dir')) { - directorLanding = urlParams.get('director') || urlParams.get('dir') || null; - if (directorLanding === null) { - directorLanding = true; - } else if (directorLanding.length === 0) { - directorLanding = true; - } else { - directorLanding = false; - } - session.meterStyle = 1; -} else if (filename === "director") { - directorLanding = true; - filename = false; - session.meterStyle = 1; -} - -if (urlParams.has('rooms')) { - session.rooms = urlParams.get('rooms').split(",").map(function(e) { - return sanitizeRoomName(e); - }); - getById("rooms").classList.remove('advanced'); -} - -if (urlParams.has('showdirector')) { - session.showDirector = true; -} - -if (urlParams.has('midi') || urlParams.has('hotkeys')) { - session.midiHotkeys = urlParams.get('midi') || urlParams.get ('hotkeys') || 1; - session.midiHotkeys = parseInt(session.midiHotkeys); -} - -if (urlParams.has('midipush') || urlParams.has('midiout') || urlParams.has('mo')){ - session.midiOut = urlParams.get('midipush') || urlParams.get('midiout') || urlParams.get('mo') || true; -} - -if (urlParams.has('midipull') || urlParams.has('midiin') || urlParams.has('mi')){ - session.midiIn = urlParams.get('midipull') || urlParams.get('midiin') || urlParams.get('mi') || true; -} - -var loadedQRCode = false; -function loadQR(){ - if (loadedQRCode==false){ - loadedQRCode=true; - var script = document.createElement('script'); - script.src = "./thirdparty/qrcode.min.js"; // dynamically load this only if its needed. Keeps loading time down. - document.head.appendChild(script); - } -} - -if (urlParams.has('webcam') || urlParams.has('wc')) { - session.webcamonly = true; - screensharebutton = false; -} else if (urlParams.has('screenshare') || urlParams.has('ss')) { - session.screenshare = true; -} else if (urlParams.has('fileshare') || urlParams.has('fs')) { - getById("container-5").classList.remove('advanced'); - getById("container-5").classList.add("skip-animation"); - getById("container-5").classList.remove('pointer'); -} else if (directorLanding) { - getById("container-1").classList.remove('advanced'); - getById("container-1").classList.add("skip-animation"); - getById("container-1").classList.remove('pointer'); -} else if (urlParams.has('website') || urlParams.has('iframe')) { - getById("container-6").classList.remove('advanced'); - getById("container-6").classList.add("skip-animation"); - getById("container-6").classList.remove('pointer'); - session.website = urlParams.get('website') || urlParams.get('iframe') || false; - - if (session.website){ - if (session.director){ - setTimeout(function(){shareWebsite(session.website);},100); - } else { - setTimeout(function(){session.publishIFrame(session.website);},100); - - } - } -} - - -if (urlParams.has('ssb')) { - screensharebutton = true; -} - -if (urlParams.has('mute') || urlParams.has('muted') || urlParams.has('m')) { - session.muted = true; -} - -if (urlParams.has('videomute') || urlParams.has('videomuted') || urlParams.has('vm')) { - session.videoMutedFlag = true; -} - - -if (urlParams.has('deaf') || urlParams.has('deafen')) { - session.directorSpeakerMuted=true; // false == true in this case. -} - -if (urlParams.has('blind')) { - session.directorDisplayMuted=true; // false == true in this case. -} - - -if (urlParams.has('dpi') || urlParams.has('dpr')) { - session.devicePixelRatio = urlParams.get('dpi') || urlParams.get('dpr') || 2.0; -} //else if (window.devicePixelRatio && window.devicePixelRatio!==1){ -// session.devicePixelRatio = window.devicePixelRatio; // this annoys me to no end. -//} - -if (urlParams.has('speakermute') || urlParams.has('mutespeaker') || urlParams.has('sm') || urlParams.has('ms')) { - session.speakerMuted = true; - getById("mutespeakertoggle").className = "las la-volume-mute my-float toggleSize"; - //getById("mutespeakerbutton").className="advanced float2 red"; - getById("mutespeakerbutton").classList.add("red"); - getById("mutespeakerbutton").classList.add("float2"); - getById("mutespeakerbutton").classList.remove("float"); - - var sounds = document.getElementsByTagName("video"); - for (var i = 0; i < sounds.length; ++i) { - sounds[i].muted = session.speakerMuted; - } -} - -if (urlParams.has('chatbutton') || urlParams.has('chat') || urlParams.has('cb')) { - session.chatbutton = urlParams.get('chatbutton') || urlParams.get('chat') || urlParams.get('cb') || null; - if (session.chatbutton === "false") { - session.chatbutton = false; - } else if (session.chatbutton === "0") { - session.chatbutton = false; - } else if (session.chatbutton === "no") { - session.chatbutton = false; - } else if (session.chatbutton === "off") { - session.chatbutton = false; - } else { - session.chatbutton = true; - getById("chatbutton").classList.remove("advanced"); - getById("controlButtons").style.display = "inherit"; - } -} - -if (session.screenshare == true) { - getById("container-3").className = 'column columnfade advanced'; // Hide screen share on mobile - getById("container-2").classList.add("skip-animation"); - getById("container-2").classList.remove('pointer'); -} - -if (urlParams.has('manual')) { - session.manual = true; -} - -if (urlParams.has('hands') || urlParams.has('hand')) { - session.raisehands = true; -} - -if (urlParams.has('portrait') || urlParams.has('916') || urlParams.has('vertical')) { - session.aspectratio = 1; // 9:16 (default of 0 is 16:9) -} else if (urlParams.has('square') || urlParams.has('11')) { - session.aspectratio = 2; //1:1 ? -} - -if (urlParams.has('cover')) { - session.cover = true; - document.documentElement.style.setProperty('--fit-style', 'cover'); -} - -if (urlParams.has('record')) { - if (safariVersion()) { - if (!(session.cleanOutput)) { - warnUser("Your browser or device is not supported. Try Chrome if on macOS."); - } - } else { - session.recordLocal = urlParams.get('record'); - - if (session.recordLocal !== parseInt(session.recordLocal)) { - session.recordLocal = 6000; - } else { - session.recordLocal = parseInt(session.recordLocal); - } - } -} -if (urlParams.has('pcm')) { - session.pcm = true; -} - -if (urlParams.has('bigbutton')) { - session.bigmutebutton = true; - getById("mutebutton").style.width = "min(40vh,40vw)"; - getById("mutebutton").style.height = "min(40vh,40vw)"; - getById("mutetoggle").style.width = "min(40vh,40vw)"; - getById("mutetoggle").style.height = "min(40vh,40vw)"; - -} - -if (urlParams.has('scene')) { - session.scene = urlParams.get('scene') || 0; - if (typeof session.scene === "string"){ - session.scene = session.scene.replace(/[\W]+/g, "_"); - } else { - session.scene = (parseInt(session.scene) || 0) + ""; - - } - session.disableWebAudio = true; - session.audioEffects = false; - session.audioMeterGuest = false; -} -if (session.scene!=="1"){ // scene =0 and 1 should load instantly. - session.hiddenSceneViewBitrate = 0; // By default this is ~ 400kbps, but if you have 10 scenes, i don't want to kill things. -} - -if (urlParams.has('scenetype') || urlParams.has('type')) { - session.sceneType = parseInt(urlParams.get('scenetype')) || parseInt(urlParams.get('type')) || false; -} - -if (urlParams.has('mediasettings')) { - session.forceMediaSettings = true; -} - - -if (urlParams.has('transcript') || urlParams.has('transcribe') || urlParams.has('trans')) { - session.transcript = urlParams.get('transcript') || urlParams.get('transcribe') || urlParams.get('trans') || "en-US"; -} - - -if (urlParams.has('cc') || urlParams.has('closedcaptions') || urlParams.has('captions')) { - session.closedCaptions = true; -} - -if (session.webcamonly == true) { - 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'); - setTimeout(function() { - previewWebcam(); - }, 100); -} - -if (urlParams.has('css')){ - var cssURL = urlParams.get('css'); - cssURL = decodeURI(cssURL); - log(cssURL); - var cssStylesheet = document.createElement('link'); - cssStylesheet.rel = 'stylesheet'; - cssStylesheet.type = 'text/css'; - cssStylesheet.media = 'screen'; - cssStylesheet.href = cssURL; - document.getElementsByTagName('head')[0].appendChild(cssStylesheet); - - cssStylesheet.onload = function() { - getById("main").classList.remove('hidden'); - log("loaded remote style sheet"); - }; - - cssStylesheet.onerror = function() { - getById("main").classList.remove('hidden'); - errorlog("REMOTE STYLE SHEET HAD ERROR"); - }; - -} else { - getById("main").classList.remove('hidden'); -} - -if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) { - session.password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p'); - if (!session.password) { - window.focus(); - session.password = prompt("Please enter the password below: \n\n(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)"); - } else if (session.password === "false") { - session.password = false; - session.defaultPassword = false; - } else if (session.password === "0") { - session.password = false; - session.defaultPassword = false; - } else if (session.password === "off") { - session.password = false; - session.defaultPassword = false; - } -} - -if (session.password) { - session.password = sanitizePassword(session.password); - getById("passwordRoom").value = session.password; - session.defaultPassword = false; - getById("addPasswordBasic").style.display = "none"; -} - - -if (urlParams.has('hash') || urlParams.has('crc') || urlParams.has('check')) { // could be brute forced in theory, so not as safe as just not using a hash check. - session.taintedSession = null; // waiting to see if valid or not. - var hash_input = urlParams.get('hash') || urlParams.get('crc') || urlParams.get('check'); - if (session.password === false) { - window.focus(); - session.password = prompt("Please enter the password below: \n\n(Note: Passwords are case-sensitive.)"); - session.password = sanitizePassword(session.password); - getById("passwordRoom").value = session.password; - session.defaultPassword = false; - } - - session.generateHash(session.password + session.salt, 6).then(function(hash) { // million to one error. - log("hash is " + hash); - if (hash.substring(0, 4) !== hash_input) { // hash crc checks are just first 4 characters. - session.taintedSession = true; - if (!(session.cleanOutput)) { - getById("request_info_prompt").innerHTML = "The password was incorrect.\n\nRefresh and try again."; - getById("request_info_prompt").style.display = "block"; - getById("mainmenu").style.display = "none"; - getById("head1").style.display = "none"; - session.cleanOutput = true; - - } else { - getById("request_info_prompt").innerHTML = ""; - getById("request_info_prompt").style.display = "block"; - getById("mainmenu").style.display = "none"; - getById("head1").style.display = "none"; - } - } else { - session.taintedSession = false; - session.hash = hash; - } - }); -} - -if (session.defaultPassword !== false) { - session.password = session.defaultPassword; // no user entered password; let's use the default password if its not disabled. -} - -if (urlParams.has('showlabels') || urlParams.has('showlabel') || urlParams.has('sl')) { - session.showlabels = urlParams.get('showlabels') || urlParams.get('showlabel') || urlParams.get('sl') || ""; - session.showlabels = sanitizeLabel(session.showlabels.replace(/[\W]+/g, "_").replace(/_+/g, '_')); - if (session.showlabels == "") { - session.showlabels = true; - session.labelstyle = false; - } else { - session.labelstyle = session.showlabels; - session.showlabels = true; - } -} - -if (urlParams.has('sizelabel') || urlParams.has('labelsize') || urlParams.has('fontsize')) { - session.labelsize = urlParams.get('sizelabel') || urlParams.get('labelsize') || urlParams.get('fontsize') || 100; - session.labelsize = parseInt(session.labelsize); -} - -if (urlParams.has('label') || urlParams.has('l')) { - session.label = urlParams.get('label') || urlParams.get('l') || null; - var updateURLAsNeed = true; - if (session.label == null || session.label.length == 0) { - window.focus(); - session.label = prompt("Please enter your display name:"); - } else { - var updateURLAsNeed = false; - session.label = decodeURIComponent(session.label); - session.label = session.label.replace(/_/g, " ") - } - if (session.label != null) { - session.label = sanitizeLabel(session.label); // alphanumeric was too strict. - document.title = session.label; // what the result is. - - if (updateURLAsNeed) { - var label = encodeURIComponent(session.label); - if (urlParams.has('l')) { - updateURL("l=" + label, true, false); - } else { - updateURL("label=" + label, true, false); - } - } - } -} - -if (urlParams.has('transparent')) { // sets the window to be transparent - useful for IFRAMES? - getById("main").style.backgroundColor = "rgba(0,0,0,0)"; - document.documentElement.style.setProperty('--container-color', '#0000'); - document.documentElement.style.setProperty('--background-color', '#0000'); - document.documentElement.style.setProperty('--regular-margin', '0'); - document.documentElement.style.setProperty('--director-margin', '0 25px 0 0'); - getById("directorLinksButton").style.color = "black"; - session.transparent=true; -} - -if (urlParams.has('stereo') || urlParams.has('s') || urlParams.has('proaudio')) { // 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 = urlParams.get('stereo') || urlParams.get('s') || urlParams.get('proaudio'); - - if (session.stereo) { - session.stereo = session.stereo.toLowerCase(); - } - - //var supportedConstraints = navigator.mediaDevices.getSupportedConstraints(); - //supportedConstraints.channelCount; - - if (session.stereo === "false") { - session.stereo = 0; - session.audioInputChannels = 1; - } else if (session.stereo === "0") { - session.stereo = 0; - session.audioInputChannels = 1; - } else if (session.stereo === "no") { - session.stereo = 0; - session.audioInputChannels = 1; - } else if (session.stereo === "off") { - session.stereo = 0; - session.audioInputChannels = 1; - - } else if (session.stereo === "1") { - session.stereo = 1; - } else if (session.stereo === "both") { - session.stereo = 1; - } else if (session.stereo === "3") { - session.stereo = 3; - } else if (session.stereo === "out") { - session.stereo = 3; - } else if (session.stereo === "mono") { - session.stereo = 3; - session.audiobitrate = 128; - } else if (session.stereo === "4") { - session.stereo = 4; - } else if (session.stereo === "multi") { - session.stereo = 4; - } else if (session.stereo === "2") { - session.stereo = 2; - } else if (session.stereo === "in") { - session.stereo = 2; - } else { - session.stereo = 5; // guests; no stereo in, no high bitrate in, but otherwise like stereo=1 - } -} - - -if (urlParams.has('pie')){ - session.pie = urlParams.get('pie') || false; // If session.pie == true, then there is no need to set parameters via URL - if (session.pie){ - session.wss = "wss://us-nyc-1.websocket.me/v3/1?api_key="+session.pie; // if URL param is set, it will use the API key. - } -} - -if ((session.stereo == 1) || (session.stereo == 3) || (session.stereo == 4) || (session.stereo == 5)) { - session.echoCancellation = false; - session.autoGainControl = false; - session.noiseSuppression = false; -} - -if (urlParams.has('mono')) { - session.mono = true; - if ((session.stereo == 1) || (session.stereo == 4)) { - session.stereo = 3; - session.audiobitrate = 128; - } else if (session.stereo == 5) { - session.stereo = 3; - session.audiobitrate = 128; - } else if (session.stereo == 2) { - session.stereo = 0; - session.audiobitrate = 128; - } -} - -if (urlParams.has("channelcount") || urlParams.has("ac")) { - session.audioInputChannels = urlParams.get('channelcount') || urlParams.get('ac'); - session.audioInputChannels = parseInt(session.audioInputChannels); - if (!session.audioInputChannels) { - session.audioInputChannels = false; - } -} - - -if (urlParams.has("aec") || urlParams.has("ec")) { - - session.echoCancellation = urlParams.get('aec') || urlParams.get('ec'); - - if (session.echoCancellation) { - session.echoCancellation = session.echoCancellation.toLowerCase(); - } - if (session.echoCancellation == "false") { - session.echoCancellation = false; - } else if (session.echoCancellation == "0") { - session.echoCancellation = false; - } else if (session.echoCancellation == "no") { - session.echoCancellation = false; - } else if (session.echoCancellation == "off") { - session.echoCancellation = false; - } else { - session.echoCancellation = true; - } -} - - -if (urlParams.has("autogain") || urlParams.has("ag")) { - - session.autoGainControl = urlParams.get('autogain') || urlParams.get('ag'); - if (session.autoGainControl) { - session.autoGainControl = session.autoGainControl.toLowerCase(); - } - if (session.autoGainControl == "false") { - session.autoGainControl = false; - } else if (session.autoGainControl == "0") { - session.autoGainControl = false; - } else if (session.autoGainControl == "no") { - session.autoGainControl = false; - } else if (session.autoGainControl == "off") { - session.autoGainControl = false; - } else { - session.autoGainControl = true; - } -} - -if (urlParams.has("denoise") || urlParams.has("dn")) { - - session.noiseSuppression = urlParams.get('denoise') || urlParams.get('dn'); - - if (session.noiseSuppression) { - session.noiseSuppression = session.noiseSuppression.toLowerCase(); - } - if (session.noiseSuppression == "false") { - session.noiseSuppression = false; - } else if (session.noiseSuppression == "0") { - session.noiseSuppression = false; - } else if (session.noiseSuppression == "no") { - session.noiseSuppression = false; - } else if (session.noiseSuppression == "off") { - session.noiseSuppression = false; - } else { - session.noiseSuppression = true; - } -} - - -if (urlParams.has('roombitrate') || urlParams.has('roomvideobitrate') || urlParams.has('rbr')) { - log("Room BITRATE SET"); - session.roombitrate = urlParams.get('roombitrate') || urlParams.get('rbr') || urlParams.get('roomvideobitrate'); - session.roombitrate = parseInt(session.roombitrate); - if (session.roombitrate < 1) { - session.roombitrate = 0; - } -} - -if ( urlParams.has('outboundaudiobitrate') || urlParams.has('oab')) { - session.outboundAudioBitrate = parseInt(urlParams.get('outboundaudiobitrate')) || parseInt(urlParams.get('oab')) || false; -} -if (urlParams.has('outboundvideobitrate') || urlParams.has('ovb')) { - session.outboundVideoBitrate = parseInt(urlParams.get('outboundvideobitrate')) || parseInt(urlParams.get('ovb')) || false; -} - -if (urlParams.has('webp')){ - session.webp = true; -} - -if (urlParams.has('webpquality') || urlParams.has('webpq') || urlParams.has('wq')){ - session.webPquality = parseInt(urlParams.get('webpquality')) || parseInt(urlParams.get('webpq')) || parseInt(urlParams.get('wq')) || 4; -} - - -if (urlParams.has('audiobitrate') || urlParams.has('ab')) { // 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("AUDIO BITRATE SET"); - session.audiobitrate = urlParams.get('audiobitrate') || urlParams.get('ab'); - session.audiobitrate = parseInt(session.audiobitrate); - if (session.audiobitrate < 1) { - session.audiobitrate = false; - } else if (session.audiobitrate > 510) { - session.audiobitrate = 510; - } // this is to just prevent abuse -} -if ((iOS) || (iPad)) { - session.audiobitrate = false; // iOS devices seem to get distortion with custom audio bitrates. Disable for now. -} - -/* if (urlParams.has('whitebalance') || urlParams.has('temp')){ // Need to be applied after the camera is selected. bleh. not enforcible. remove for now. - var temperature = urlParams.get('whitebalance') || urlParams.get('temp'); - try{ - updateCameraConstraints('colorTemperature', parseFloat(temperature)); - } catch (e){errorlog(e);} -} */ - -if (urlParams.has('streamid') || urlParams.has('view') || urlParams.has('v') || urlParams.has('pull')) { // 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') || urlParams.get('v') || urlParams.get('pull') || null; // this value can be comma seperated for multiple streams to pull - - getById("headphonesDiv2").style.display = "inline-block"; - getById("headphonesDiv").style.display = "inline-block"; - getById("addPasswordBasic").style.display = "none"; - - if (session.view == null) { - session.view = ""; - } - if (session.view) { - if (session.view.split(",").length > 1) { - session.view_set = session.view.split(","); - } - } -} - -//if (urlParams.has('directorview') || urlParams.has('dv')){ -// session.directorView = true; -// if (!session.view){ -// session.view = true; -// } -//} - -if (urlParams.has('nopreview') || urlParams.has('np')) { - log("preview OFF"); - session.nopreview = true; -} else if ((urlParams.has('preview')) || (urlParams.has('showpreview'))) { - log("preview ON"); - session.nopreview = false; -} else if ((urlParams.has('minipreview')) || (urlParams.has('mini'))) { - var mini = urlParams.has('minipreview') || urlParams.has('mini') || true; // 2 is a valid option. - log("preview ON"); - session.nopreview = false; - session.minipreview = mini; -} - -if (urlParams.has('obsfix')) { - session.obsfix = urlParams.get('obsfix'); - if (session.obsfix) { - session.obsfix = session.obsfix.toLowerCase(); - } - if (session.obsfix == "false") { - session.obsfix = false; - } else if (session.obsfix == "0") { - session.obsfix = false; - } else if (session.obsfix == "no") { - session.obsfix = false; - } else if (session.obsfix == "off") { - session.obsfix = false; - } else if (parseInt(session.obsfix) > 0) { - session.obsfix = parseInt(session.obsfix); - } else { - session.obsfix = 1; // aggressive. - } -} - -if (urlParams.has('controlroombitrate') || urlParams.has('crb')) { - session.controlRoomBitrate = true; -} - -if (urlParams.has('remote') || urlParams.has('rem')) { - log("remote ENABLED"); - session.remote = urlParams.get('remote') || urlParams.get('rem') || "nosecurity"; - session.remote = session.remote.trim(); -} - -if (urlParams.has('latency') || urlParams.has('al') || urlParams.has('audiolatency')) { - log("latency ENABLED"); - session.audioLatency = urlParams.get('latency') || urlParams.get('al') || urlParams.get('audiolatency'); - session.audioLatency = parseInt(session.audioLatency) || 0; - session.disableWebAudio = false; -} - - - -if (urlParams.has('micdelay') || urlParams.has('delay') || urlParams.has('md')) { - log("audio gain ENABLED"); - session.micDelay = urlParams.get('micdelay') || urlParams.get('delay') || urlParams.get('md'); - session.micDelay = parseInt(session.micDelay) || 0; - session.disableWebAudio = false; -} - -if (urlParams.has('tips')){ - getById("guestTips").style.display="flex"; -} - -if (urlParams.has('audiogain') || urlParams.has('gain') || urlParams.has('g')) { - log("audio gain ENABLED"); - session.audioGain = urlParams.get('audiogain') || urlParams.get('gain') || urlParams.get('g'); - session.audioGain = parseInt(session.audioGain) || 0; - session.disableWebAudio = false; -} -if (urlParams.has('compressor') || urlParams.has('comp')) { - log("audio gain ENABLED"); - session.compressor = 1; - session.disableWebAudio = false; -} else if (urlParams.has('limiter')) { - log("audio gain ENABLED"); - session.compressor = 2; - session.disableWebAudio = false; -} -if ((urlParams.has('equalizer')) || (urlParams.has('eq'))) { - session.equalizer = true; - session.disableWebAudio = false; -} -if ((urlParams.has('lowcut')) || (urlParams.has('lc')) || (urlParams.has('higpass'))) { - session.lowcut = urlParams.get('lowcut') || urlParams.get('lc') || urlParams.get('higpass') || 100; - session.lowcut = parseInt(session.lowcut); - session.disableWebAudio = false; -} - -if (urlParams.has('pip')) { - session.pip = true; // togglePip - //session.manual=true; - //innerHTML = -} - -if (urlParams.has('keyframeinterval') || urlParams.has('keyframerate') || urlParams.has('keyframe') || urlParams.has('fki')) { - log("keyframerate ENABLED"); - session.keyframerate = parseInt(urlParams.get('keyframeinterval') || urlParams.get('keyframerate') || urlParams.get('keyframe') || urlParams.get('fki')) || 0; -} - -if (urlParams.has('tallyoff') || urlParams.has('obsoff') || urlParams.has('oo')) { - log("OBS feedback disabled"); - session.disableOBS = true; -} - - -if (urlParams.has('chroma')) { - log("Chroma ENABLED"); - getById("main").style.backgroundColor = "#" + (urlParams.get('chroma') || "0F0"); -} - -if (urlParams.has('margin')) { - if (urlParams.get('margin') || 10){ - 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('fadein')) { - 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("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'); - setTimeout(function() { - previewWebcam(); - }, 100); - 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 (urlParams.has('autojoin') || urlParams.has('autostart') || urlParams.has('aj') || urlParams.has('as')) { - session.autostart = true; - if (session.screenshare) { - setTimeout(function() { - publishScreen(); - }, 2000); - } -} - -if (urlParams.has('noiframe') || urlParams.has('noiframes') || urlParams.has('nif')) { - - session.noiframe = urlParams.get('noiframe') || urlParams.get('noiframes') || urlParams.get('nif'); - - 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')) { - session.nocursor = true; - log("DISABLE CURSOR"); - var style = document.createElement('style'); - style.innerHTML = ` - video { - margin: 0; - padding: 0; - overflow: hidden; - cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), none; - user-select: none; - } - `; - document.head.appendChild(style); - -} - -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 -} - -var ConfigSettings = getById("main-js"); -var ln_template = false; -var translation = false; -try { - if (ConfigSettings) { - ln_template = ConfigSettings.getAttribute('data-translation'); // Translations - if (typeof ln_template === "undefined") { - ln_template = false; - } else if (ln_template === null) { - ln_template = false; - } - } - - if (urlParams.has('ln')) { - ln_template = urlParams.get('ln'); - } -} catch (e) { - errorlog(e); -} - -if (ln_template) { // checking if manual lanuage override enabled - try { - log("Template: " + ln_template); - fetch("./translations/" + ln_template + '.json').then(function(response) { - if (response.status !== 200) { - log('Looks like there was a problem. Status Code: ' + - response.status); - return; - } - response.json().then(function(data) { - log(data); - translation = data; - var trans = data.innerHTML; - var allItems = document.querySelectorAll('[data-translate]'); - allItems.forEach(function(ele) { - if (ele.dataset.translate in trans) { - ele.innerHTML = trans[ele.dataset.translate]; - } - }); - trans = data.titles; - var allTitles = document.querySelectorAll('[title]'); - allTitles.forEach(function(ele) { - var key = ele.title.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.title = trans[key]; - } - }); - trans = data.placeholders; - var allPlaceholders = document.querySelectorAll('[placeholder]'); - allPlaceholders.forEach(function(ele) { - var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.placeholder = trans[key]; - } - }); - - - getById("mainmenu").style.opacity = 1; - }).catch(function(err) { - errorlog(err); - getById("mainmenu").style.opacity = 1; - }); - }).catch(function(err) { - errorlog(err); - getById("mainmenu").style.opacity = 1; - }); - - } catch (error) { - errorlog(error); - getById("mainmenu").style.opacity = 1; - } -} else if (location.hostname !== "obs.ninja") { - if (location.hostname === "rtc.ninja"){ - try { - if (session.label === false) { - document.title = ""; - } - getById("qos").innerHTML = ""; - getById("logoname").innerHTML = ""; - getById("helpbutton").style.display = "none"; - getById("helpbutton").style.opacity = 0; - getById("reportbutton").style.display = "none"; - getById("reportbutton").style.opacity = 0; - getById("mainmenu").style.opacity = 1; - getById("mainmenu").style.margin = "30px 0"; - getById("translateButton").style.display = "none"; - getById("translateButton").style.opacity = 0; - getById("info").style.display = "none"; - getById("info").style.opacity = 0; - getById("chatBody").innerHTML = ""; - } catch (e) {} - } - try { - fetch("./translations/blank.json").then(function(response) { - if (response.status !== 200) { - log('Looks like there was a problem. Status Code: ' + - response.status); - return; - } - response.json().then(function(data) { - log(data); - - var trans = data.innerHTML; - var allItems = document.querySelectorAll('[data-translate]'); - allItems.forEach(function(ele) { - if (ele.dataset.translate in trans) { - ele.innerHTML = trans[ele.dataset.translate]; - } - }); - trans = data.titles; - var allTitles = document.querySelectorAll('[title]'); - allTitles.forEach(function(ele) { - var key = ele.title.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.title = trans[key]; - } - }); - trans = data.placeholders; - var allPlaceholders = document.querySelectorAll('[placeholder]'); - allPlaceholders.forEach(function(ele) { - var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.placeholder = trans[key]; - } - }); - - if (session.label === false) { - document.title = location.hostname; - } - getById("qos").innerHTML = location.hostname; - getById("logoname").innerHTML = getById("qos").outerHTML; - getById("helpbutton").style.display = "none"; - getById("reportbutton").style.display = "none"; - getById("mainmenu").style.opacity = 1; - }).catch(function(err) { - errorlog(err); - getById("mainmenu").style.opacity = 1; - }); - }).catch(function(err) { - errorlog(err); - getById("mainmenu").style.opacity = 1; - }); - if (session.label === false) { - document.title = location.hostname; - } - getById("qos").innerHTML = location.hostname; - getById("logoname").innerHTML = getById("qos").outerHTML; - getById("helpbutton").style.display = "none"; - getById("reportbutton").style.display = "none"; - getById("chatBody").innerHTML = ""; - } catch (error) { - errorlog(error); - } -} else { // check if automatic language translation is available - getById("mainmenu").style.opacity = 1; -} - -try { - if (location.hostname === "rtc.ninja"){ // an extra-brand-free version of OBS.Ninja - if (session.label === false) { - document.title = ""; - } - getById("qos").innerHTML = ""; - getById("logoname").innerHTML = ""; - getById("helpbutton").style.display = "none"; - getById("helpbutton").style.opacity = 0; - getById("reportbutton").style.display = "none"; - getById("reportbutton").style.opacity = 0; - getById("mainmenu").style.opacity = 1; - getById("mainmenu").style.margin = "30px 0"; - getById("translateButton").style.display = "none"; - getById("translateButton").style.opacity = 0; - getById("info").style.display = "none"; - getById("info").style.opacity = 0; - getById("chatBody").innerHTML = ""; - } else if (location.hostname !== "obs.ninja") { - if (session.label === false) { - document.title = location.hostname; - } - getById("qos").innerHTML = sanitizeLabel(location.hostname); - getById("logoname").innerHTML = getById("qos").outerHTML; - getById("helpbutton").style.display = "none"; - getById("reportbutton").style.display = "none"; - } - -} catch (e) {} - -if (isIFrame) { - getById("helpbutton").style.display = "none"; - getById("helpbutton").style.opacity = 0; - getById("reportbutton").style.display = "none"; - getById("reportbutton").style.opacity = 0; - getById("chatBody").innerHTML = ""; -} - -function miniTranslate(ele, ident = false) { - if (ident) { - ele.dataset.translate = ident; - } else { - ident = ele.dataset.translate; - } - try { - if (ident in translation.innerHTML) { - ele.innerHTML = translation.innerHTML[ident]; - } - } catch (e) {} -} - -function changeLg(lang) { - fetch("./translations/" + lang + '.json').then(function(response) { - if (response.status !== 200) { - logerror('Language translation file not found.' + response.status); - return; - } - response.json().then(function(data) { - log(data); - translation = data; // translation.innerHTML[ele.dataset.translate] - var trans = data.innerHTML; - var allItems = document.querySelectorAll('[data-translate]'); - allItems.forEach(function(ele) { - if (ele.dataset.translate in trans) { - ele.innerHTML = trans[ele.dataset.translate]; - } - }); - trans = data.titles; - var allTitles = document.querySelectorAll('[title]'); - allTitles.forEach(function(ele) { - var key = ele.title.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.title = trans[key]; - } - }); - trans = data.placeholders; - var allPlaceholders = document.querySelectorAll('[placeholder]'); - allPlaceholders.forEach(function(ele) { - var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase(); - if (key in trans) { - ele.placeholder = trans[key]; - } - }); - }); - }).catch(function(err) { - errorlog(err); - }); -} - -if (urlParams.has('beep') || urlParams.has('notify') || urlParams.has('tone')) { - session.beepToNotify = true; -} - -if (urlParams.has('r2d2')) { - getById("testtone").innerHTML = ""; - getById("testtone").src = "./media/robot.mp3"; - session.beepToNotify = 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"; - var style = document.createElement('style'); - style.innerHTML = ` - video { - background-image: none; - } - `; - document.head.appendChild(style); -} - -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)) { - setTimeout(function() { - warnUser("Enhanced Security Mode Enabled."); - }, 100); - } -} - -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 - session.buffer = parseFloat(urlParams.get('buffer')) || 0; - log("buffer Changed: " + session.buffer); - session.sync = 0; - session.audioEffects = true; -} - -if (urlParams.has('sync')) { - 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"; - } else { - session.effects = parseInt(session.effects); - } - - 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 (urlParams.has('activespeaker') || urlParams.has('speakerview') || urlParams.has('sas')){ - session.activeSpeaker = true; - session.audioEffects = true; - session.audioMeterGuest = true; - setInterval(function(){activeSpeaker(false);},100); -} - -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.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 - if (!session.configuration){session.configuration={};} - session.configuration = { - iceServers: [ - { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"]} // more than 4 stun+turn servers will cause firefox issues? (2 + 2 for now then) - ], - 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 = {}; - turn.username = turnstring[0]; // myusername - turn.credential = turnstring[1]; //mypassword - turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"]; - session.configuration = { - iceServers: [ - { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"]} // more than 4 stun+turn servers will cause firefox issues? (2 + 2 for now then) - ], - 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(); // obs.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('queue')) { - session.queue = true; -} - -if (isIFrame) { // reduce CPU load if not needed. - 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 ("sendChat" in e.data) { - sendChat(e.data.sendChat); // sends to all peers; more options down the road - } - // 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 ("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 ("sceneState" in e.data) { // TRUE OR FALSE - tells the connected peers if they are live or not via a tally light change. - - var visibility = e.data.sceneState; - - if (session.obsState.visibility !== visibility) { // 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 ("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 ("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); - } - } - } - }; -} - -function setupIncomingVideoTracking(v, UUID){ // video element. - - if (session.directorUUID===UUID){ - v.muted=false; - } else { - v.muted = session.speakerMuted; - } - - v.onpause = (event) => { // prevent things from pausing; human or other - if (!((event.ctrlKey) || (event.metaKey) )){ - warnlog("Video paused; force it to play again"); - //return; - //session.audioCtx.resume(); - //log("ctx resume"); - - event.currentTarget.play().then(_ => { - log("playing"); - }).catch(error => { - warnlog("didnt play 1"); - }); - - } - } - - v.onplay = function(){ - try { - var bigPlayButton = document.getElementById("bigPlayButton"); - if (bigPlayButton){ - bigPlayButton.parentNode.removeChild(bigPlayButton); - } - } catch(e){} - if (session.pip){ - if (v.readyState >= 3){ - if (!(v.pip)){ - v.pip=true; - toggleSystemPip(v, true); - } - } - } - - } - - if (session.pip){ - v.onloadedmetadata = function(){ - if (!v.paused){ - if (!(v.pip)){ - v.pip=true; - toggleSystemPip(v, true); - } - } - } - } - - - v.addEventListener('resize', (e) => { - log("resize event"); - var aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight); - if (v.dataset.aspectRatio){ - if (aspectRatio != v.dataset.aspectRatio){ - setTimeout(function(){updateMixer();},1); // We don't want to run this on the first resize? just subsequent ones. - } - } else { - log("ASPECT RATIO CHANGED"); - setTimeout(function(){updateMixer();},1); - } - v.dataset.aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight); - }); - - v.volume = 1.0; // play audio automatically - v.autoplay = true; - v.controls = false; - v.classList.add("tile"); - v.setAttribute("playsinline",""); - v.controlTimer = null; - - changeAudioOutputDevice(v); // if enabled, changes to desired output audio device. - - if (document.getElementById("mainmenu")){ - var m = getById("mainmenu"); - m.remove(); - } - - if (session.director){ - v.controls = true; - var container = getById("videoContainer_"+UUID); - v.disablePictureInPicture = false - v.setAttribute("controls","controls") - container.appendChild(v); - session.requestRateLimit(session.directorViewBitrate,UUID); /// limit resolution for director - - if (session.beepToNotify) { - playtone(); - } - - } else if (session.scene!==false){ - v.controls = false; - - if (session.view){ // specific video to be played - v.style.display="block"; - } else if (session.scene==="0"){ - v.style.display="block"; - } else { // group scene I guess; needs to be added manually - v.style.display="none"; - v.muted= true; - } - - setTimeout(function(){updateMixer();},1); - } else if (session.roomid!==false){ - if (session.cleanOutput){ - v.controls = false; - } else if (window.obsstudio) { - v.controls = false; - } else { - v.controls = true; - } - if ((session.roomid==="") && (session.bitrate)){ - // let's keep the default bitrates, since this isn't a real room and bitrates are specified. - } else if (session.novideo !== false){ - if (session.novideo.includes(session.rpcs[UUID].streamID)){ - session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also - } - } else { - session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also - } - setTimeout(function(){updateMixer();},1); - } else { - v.style.display="block"; - if (window.obsstudio) { - v.controls = false; - } - setTimeout(function(){updateMixer();},1); - } - - - v.addEventListener('click', function(e) { // show stats of video if double clicked - log("clicked"); - try { - if ((e.ctrlKey)||(e.metaKey)){ - e.preventDefault(); - var uid = e.currentTarget.dataset.UUID; - if ("stats" in session.rpcs[uid]){ - - var [menu, innerMenu] = statsMenuCreator(); - - printViewStats(innerMenu, uid ); - - menu.interval = setInterval(printViewStats,3000, innerMenu, uid); - - - } - e.stopPropagation(); - return false; - } - } catch(e){errorlog(e);} - }); - - if (session.statsMenu){ - if ("stats" in session.rpcs[UUID]){ - - if (getById("menuStatsBox")){ - clearInterval(getById("menuStatsBox").interval); - getById("menuStatsBox").remove(); - } - - var [menu, innerMenu] = statsMenuCreator(); - - printViewStats(innerMenu, UUID ); - - menu.interval = setInterval(printViewStats,3000, innerMenu, UUID); - - } - } - - - v.touchTimeOut = null; - v.touchLastTap = 0; - v.touchCount = 0; - v.addEventListener('touchend', function(event) { - log("touched"); - - document.ontouchup = null; - document.onmouseup = null; - document.onmousemove = null; - document.ontouchmove = null; - - var currentTime = new Date().getTime(); - var tapLength = currentTime - v.touchLastTap; - clearTimeout(v.touchTimeOut); - if (tapLength < 500 && tapLength > 0) { - /// - log("double touched"); - v.touchCount+=1; - event.preventDefault(); - if (v.touchCount<5){ - v.touchLastTap = currentTime; - return false; - } - v.touchLastTap = 0; - v.touchCount=0; - - log("double touched"); - var uid = event.currentTarget.dataset.UUID; - if ("stats" in session.rpcs[uid]){ - - var [menu, innerMenu] = statsMenuCreator(); - - printViewStats(innerMenu, uid ); - - menu.interval = setInterval(printViewStats,3000, innerMenu, uid); - - - } - event.stopPropagation(); - return false; - ////// - } else { - v.touchCount=1; - v.touchTimeOut = setTimeout(function(vv) { - clearTimeout(vv.touchTimeOut); - vv.touchLastTap = 0; - vv.touchCount=0; - }, 5000, v); - v.touchLastTap = currentTime; - } - - }); - - - if (session.remote){ - v.addEventListener("wheel", session.remoteControl); - } - - if (v.controls == false){ - v.addEventListener("click", function () { - if (v.paused){ - log("PLAYING MANUALLY?"); - v.play().then(_ => { - log("playing"); - }).catch(warnlog); - } - }); - if (session.nocursor==false){ // we do not want to show the controls. This is because MacOS + OBS does not work; so electron app needs this. - if (!(session.cleanOutput)){ - if (!(window.obsstudio)){ - if (v.controlTimer){ - clearInterval(v.controlTimer); - } - v.controlTimer = setTimeout(showControlBar.bind(null,v),3000); - //v.controlTimer = setTimeout(function (){v.controls=true;},3000); // 3 seconds before I enable the controls automatically. This way it doesn't auto appear during loading. 3s enough, right? - } - } - } - } - - if (session.fadein){ - v.classList.add("fadein"); // allows the video to fade in. - } - - setTimeout(session.processStats, 1000, UUID); - -} - -function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a giant function that runs when there are changes to screensize, video track statuses, etc. - if (getById("subControlButtons").dragElement){ - if (parseInt(getById("subControlButtons").style.top) > 0){ - getById("subControlButtons").style.top = "0px"; - } else if (parseInt(getById("subControlButtons").style.top) < parseInt(50 - window.innerHeight) ){ - getById("subControlButtons").style.top = parseInt( 50 - window.innerHeight)+"px"; - } - if (parseInt(getById("subControlButtons").style.left) < 0){ - getById("subControlButtons").style.left = "0px"; - } else if (parseInt(getById("subControlButtons").style.left) > parseInt( window.innerWidth - getById("subControlButtons").offsetWidth) ){ - getById("subControlButtons").style.left = parseInt( window.innerWidth -getById("subControlButtons").offsetWidth )+"px"; - } - } - if (session.director){return;} - if (session.manual === true){return;} - var playarea = getById("gridlayout"); - var header = getById("header"); - - var hi = header.offsetHeight ; - var w = window.innerWidth; - var h = window.innerHeight - hi; - - if ( window.innerHeight<=700 ){ - if (document.getElementById("controlButtons")){ - var h = window.innerHeight - hi - document.getElementById("controlButtons").offsetHeight; - } else { - var h = window.innerHeight - hi; - } - } - - var arW = 16.0; - var arH = 9.0; - - if (session.aspectratio){ - if (session.aspectratio==1){ - arW = 9.0; - arH = 16.0; - } else if (session.aspectratio==2){ - arW = 12.0; // square root; cause why not. - arH = 12.0; - } - } - - var ww = w/arW; - var hh = h/arH; - - var mediaPool = []; - var mediaPool_invisible = []; - - if (session.videoElement){ // I, myself, exist - if (session.videoElement.style.display!="none"){ // local feed - if (session.minipreview && (session.infocus!==true)){ - - session.videoElement.onclick = function(){ - if (session.infocus === true){ - session.infocus = false; - } else { - session.infocus = true; - log("session: myself"); - } - setTimeout(()=>updateMixer(),10); - }; - - } else { - if (session.order!==false){ - session.videoElement.order=session.order; - } else { - session.videoElement.order=0; - } - if (session.activeSpeaker && (!session.activelySpeaking)){ - mediaPool_invisible.push(session.videoElement); - } else { - mediaPool.push(session.videoElement); - } - } - } - } - - if (session.screenShareElement){ // I, myself, exist - if (session.screenShareElement.style.display!="none"){ // local feed - if (session.order!==false){ - session.screenShareElement.order=session.order; - } else { - session.screenShareElement.order=0; - } - - if (session.infocus!==false){ - mediaPool_invisible.push(session.screenShareElement); - } else if (session.activeSpeaker && (!session.activelySpeaking)){ - mediaPool_invisible.push(session.screenShareElement); - } else { - mediaPool.push(session.screenShareElement); - } - } - } - - if (session.iframeEle){ // I, myself, exist - if (session.iframeEle.style.display!="none"){ // local feed - if (session.order!==false){ - session.iframeEle.order=session.order; - } else { - session.iframeEle.order=0; - } - if (session.activeSpeaker && (!session.activelySpeaking)){ - mediaPool_invisible.push(session.iframeEle); - } else { - mediaPool.push(session.iframeEle); - } - } - } - - - if ((session.infocus) && (session.infocus in session.rpcs)){ // remote guest being full screened; infocus == UUID - log(session.infocus+" set fullscreen"); - mediaPool = []; // remove myself from fullscreen - for (var j in session.rpcs){ - if (j != session.infocus){ - session.requestRateLimit(0, j); // disable the video of non-fullscreen videos - try { - if (session.rpcs[j].videoElement.style.display!="none"){ // Add it if not hidden - mediaPool_invisible.push(session.rpcs[j].videoElement); - } - } catch(e){} - } else { // in focus video - //////// - try { - if (session.rpcs[j].order!==false){ - session.rpcs[j].videoElement.order=session.rpcs[j].order; - } else { - session.rpcs[j].videoElement.order=0; - } - /////////// - if (session.activeSpeaker && (!session.rpcs[j].activelySpeaking)){ - mediaPool_invisible.push(session.rpcs[j].videoElement); - } else { - mediaPool.push(session.rpcs[j].videoElement); - } - - session.rpcs[j].videoElement.style.visibility = "visible"; - if ((session.rpcs[j].targetBandwidth!==-1) && (session.rpcs[j].targetBandwidth