diff --git a/main.js b/main.js index 41302e7..48f902f 100644 --- a/main.js +++ b/main.js @@ -12,6 +12,22 @@ 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(" "); @@ -2838,6 +2854,1069 @@ if (isIFrame) { // reduce CPU load if not needed. }; } +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.className += "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, session.rpcs[uid].stats, session.rpcs[uid].streamID ); + + menu.interval = setInterval(printViewStats,3000, innerMenu, session.rpcs[uid].stats, session.rpcs[uid].streamID); + + + } + 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, session.rpcs[UUID].stats, session.rpcs[UUID].streamID ); + + menu.interval = setInterval(printViewStats,3000, innerMenu, session.rpcs[UUID].stats, session.rpcs[UUID].streamID); + + } + } + + + 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, session.rpcs[uid].stats, session.rpcs[uid].streamID ); + + menu.interval = setInterval(printViewStats,3000, innerMenu, session.rpcs[uid].stats, session.rpcs[uid].streamID); + + + } + 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? + } + } + } + } + + 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; + } + } + + if (session.aspectratio){ + if (session.aspectratio==1){ + var arW = 9.0; + var arH = 16.0; + } else if (session.aspectratio==2){ + var arW = 1.0; + var arH = 1.0; + } + } else { + var arW = 16.0; + var arH = 9.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