diff --git a/360.html b/360.html new file mode 100644 index 0000000..14120d7 --- /dev/null +++ b/360.html @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/devices.css b/devices.css index 26db120..251253b 100644 --- a/devices.css +++ b/devices.css @@ -1,3 +1,9 @@ +body { + position:inherit; + height:unset; + padding-bottom:100px; +} + #devices { max-width: 80%; width: fit-content; diff --git a/devices.html b/devices.html index 3c24de2..dc4ca2e 100644 --- a/devices.html +++ b/devices.html @@ -2,7 +2,7 @@ - + diff --git a/index.html b/index.html index ef1281d..b3bbfab 100644 --- a/index.html +++ b/index.html @@ -58,7 +58,7 @@ - + @@ -2567,7 +2567,7 @@ // if (!window.location.search){document.body.innerHTML = "";} // uncomment this line, if you wish to try it. var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js. - session.version = "24.5"; + session.version = "24.6"; session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed session.defaultPassword = "someEncryptionKey123"; // Change this password if self-deploying for added security/privacy @@ -2684,11 +2684,11 @@ // session.decrypted = session.decodeInvite("U2FsdGVkX1+d58DFIHoO3EQZSuX86ch4PqW2ouztnJ0="); // get a code from invite.cam - + - + diff --git a/lib.js b/lib.js index ac39717..ac73446 100644 --- a/lib.js +++ b/lib.js @@ -118,6 +118,7 @@ var miscTranslations = { // i can replace this list from time to time from the g "signal-meter": "Video packet loss indicator of video preview; green is good, red is bad. Flame implies CPU is overloaded. May not reflect the packet loss seen by scenes or other guests.", "waiting-for-the-stream": "Waiting for the stream. Tip: Adding &cleanoutput to the URL will hide this spinner, or click to retry, which will also hide it.", "main-director": "Main Director", + "co-director": "Co-Director", "share-a-screen": "Share a screen", "stop-screen-sharing": "Stop screen sharing", "you-have-been-transferred": "You've been transferred to a different room", @@ -154,7 +155,7 @@ var miscTranslations = { // i can replace this list from time to time from the g "remote-token-rejected": "The remote request failed; the &remote token did not match or the remote user does not allow remote control.", "remote-control-failed": "The remote control request failed.", "remote-peer-connected": "Remote peer connected to video stream.\n\nConnection to handshake server being killed on request. This increases security, but the peer will not be able to reconnect automatically on connection failure.\n\nPress OK to start the stream!", - "director-denied": "The main director denied you as a co-director", + "director-denied": "⚠️ The main director denied you as a co-director\n\nYou will only be able to preview streams; you will not be able to control or change anything.", "only-main-director": "Only the main director can transfer this guest", "request-failed": "The request failed; you can't apply this action", "tokens-did-not-match": "The remote request failed; the remote token did not match or the remote user does not allow remote control.", @@ -6256,7 +6257,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a return; } - if (!session.cleanOutput && !session.nocursor){ + if (!session.cleanOutput && !session.nocursor && !session.nofullwindowbutton){ if ((session.roomid!==false) && (session.scene===false)){ if (!((vid.id === "videosource") && miniPreview) && !session.infocusForceMode){ @@ -6271,7 +6272,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a button.id = "button_"+vid.id; button.dataset.button = true; if (soloVideo){ - button.innerHTML = ""; + button.innerHTML = ""; button.title = "Show all active videos togethers"; button.style.visibility = "visible"; } else if ((mpl>1) || session.fullscreenButton){ // with session.fullscreenButton we hide the actuall full screen button, so this replaces it @@ -9290,10 +9291,18 @@ function digitalZoom(reinit=false) { function getNativeOutputResolution(){ - var tracks = session.videoElement.srcObject.getVideoTracks(); - if (tracks.length && tracks[0].getSettings){ - return tracks[0].getSettings(); - } else { + try{ + if (session.videoElement && session.videoElement.srcObject){ + var tracks = session.videoElement.srcObject.getVideoTracks(); + if (tracks.length && tracks[0].getSettings){ + return tracks[0].getSettings(); + } else { + return false; + } + } else if (session.videoElement && session.videoElement.videoWidth && session.videoElement.videoHeight){ + return {width: session.videoElement.videoWidth, height: session.videoElement.videoHeight}; + } + } catch(e){ return false; } } @@ -15987,19 +15996,19 @@ function disabledWebAudioPathway(){ // if (session.disableWebAudio) { then run t return newStream; } -function outboundAudioPipeline(){ // this function isn't letting me change the audio source +function outboundAudioPipeline(sourceStream=false){ // this function isn't letting me change the audio source if (session.disableWebAudio) { return disabledWebAudioPathway(); // safemode } - if (!session.streamSrc){ + if (!session.streamSrc && !sourceStream){ errorlog("STREAM DOES NOT EXIST. This is a problem"); checkBasicStreamsExist(); return session.streamSrc; } - var streamSrc = session.streamSrc; + var streamSrc = sourceStream || session.streamSrc; if (iOS || iPad){ @@ -16783,6 +16792,9 @@ function activeSpeaker(border=false) { if ((session.activeSpeaker>2) && !(session.rpcs[UUID].videoElement && session.rpcs[UUID].videoElement.srcObject && session.rpcs[UUID].videoElement.srcObject.getVideoTracks().length && !session.rpcs[UUID].videoMuted)){ session.rpcs[UUID].activelySpeaking = false; // we're not showing audio-only sources in this mode. + if (session.rpcs[UUID].defaultSpeaker && (session.rpcs[UUID].defaultSpeaker!==true)){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } session.rpcs[UUID].defaultSpeaker = false; continue; } @@ -16829,7 +16841,7 @@ function activeSpeaker(border=false) { if (session.rpcs[UUID].activelySpeaking){ anyoneIsSpeaking=true; } - if (session.rpcs[UUID].defaultSpeaker){ + if (session.rpcs[UUID].defaultSpeaker===true){ defaultSpeaker=true; } } @@ -16842,27 +16854,51 @@ function activeSpeaker(border=false) { if (defaultSpeaker){ // already good to go. } else if (lastActiveSpeaker){ + if (session.rpcs[lastActiveSpeaker].defaultSpeaker!==false){ + clearTimeout(session.rpcs[lastActiveSpeaker].defaultSpeaker); + } else { + changed=true; + log("lastActiveSpeaker is default"); + } session.rpcs[lastActiveSpeaker].defaultSpeaker=true; - changed=true; + } else if (session.scene===false || (session.nopreview===false && session.minipreview!==1)){ // we don't need to care. } else { for (var UUID in session.rpcs) { if (session.rpcs[UUID].videoElement && session.rpcs[UUID].videoElement.srcObject && session.rpcs[UUID].videoElement.srcObject.getVideoTracks().length && !session.rpcs[UUID].videoMuted){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + log(UUID + " is speaker now"); + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; + break } } if (!changed && (session.activeSpeaker<=2)){ // switch to streams that have no video track for (var UUID in session.rpcs) { if (session.rpcs[UUID].label){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + log(UUID + " is speaker now"); + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; + break } else if (!changed){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + log(UUID + " is speaker now"); + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; + } } } @@ -16882,23 +16918,46 @@ function activeSpeaker(border=false) { if (!loudestActive){ loudestActive = UUID; } else if (session.rpcs[UUID].stats._Audio_Loudness_average > session.rpcs[loudestActive].stats._Audio_Loudness_average){ - if (session.rpcs[loudestActive].defaultSpeaker){ - session.rpcs[loudestActive].defaultSpeaker=false; - changed=true + if (session.rpcs[loudestActive].defaultSpeaker===true){ + //session.rpcs[loudestActive].defaultSpeaker=false; + if (!session.activeSpeakerTimeout){ + session.rpcs[loudestActive].defaultSpeaker=false; + changed=true + log(loudestActive + " is loudest but not speaker anymore"); + } else { + session.rpcs[loudestActive].defaultSpeaker = setTimeout(function(uuid){session.rpcs[uuid].defaultSpeaker = false;updateMixer();},session.activeSpeakerTimeout,loudestActive); + } } loudestActive = UUID; - } else if (session.rpcs[UUID].defaultSpeaker){ - session.rpcs[UUID].defaultSpeaker=false; - changed=true; + } else if (session.rpcs[UUID].defaultSpeaker === true){ + //session.rpcs[UUID].defaultSpeaker=false; + if (!session.activeSpeakerTimeout){ + session.rpcs[UUID].defaultSpeaker=false; + changed=true + log(UUID + " is not speaker anymore"); + } else { + session.rpcs[UUID].defaultSpeaker = setTimeout(function(uuid){session.rpcs[uuid].defaultSpeaker = false;updateMixer();},session.activeSpeakerTimeout,UUID); + } } - } else if (session.rpcs[UUID].defaultSpeaker){ - session.rpcs[UUID].defaultSpeaker=false; - changed=true + } else if (session.rpcs[UUID].defaultSpeaker === true){ + if (!session.activeSpeakerTimeout){ + session.rpcs[UUID].defaultSpeaker=false; + changed=true + log(UUID + " is not speaker anymore"); + } else { + session.rpcs[UUID].defaultSpeaker = setTimeout(function(uuid){session.rpcs[uuid].defaultSpeaker = false;updateMixer();},session.activeSpeakerTimeout,UUID); + } + } } - if (loudestActive && !session.rpcs[loudestActive].defaultSpeaker){ + if (loudestActive && (session.rpcs[loudestActive].defaultSpeaker!==true)){ + if (session.rpcs[loudestActive].defaultSpeaker){ + clearTimeout(session.rpcs[loudestActive].defaultSpeaker); + } else { + changed = true; + log(UUID + " is loudestActive now"); + } session.rpcs[loudestActive].defaultSpeaker = true; - changed = true; } } } else if ((session.activeSpeaker===2) || (session.activeSpeaker===4)){ // will show whoever is talking; mixed together; if no one is talking, just shows yourself @@ -16907,27 +16966,45 @@ function activeSpeaker(border=false) { if (defaultSpeaker){ // already good to go. } else if (lastActiveSpeaker){ + if (session.rpcs[lastActiveSpeaker].defaultSpeaker!==false){ + clearTimeout(session.rpcs[lastActiveSpeaker].defaultSpeaker); + } else { + changed=true; + } session.rpcs[lastActiveSpeaker].defaultSpeaker=true; - changed=true; + } else if (session.scene===false || (session.nopreview===false && session.minipreview!==1)){ // we don't need to care. } else { for (var UUID in session.rpcs) { if (session.rpcs[UUID].videoElement && session.rpcs[UUID].videoElement.srcObject && session.rpcs[UUID].videoElement.srcObject.getVideoTracks().length && !session.rpcs[UUID].videoMuted){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; break } } if (!changed && (session.activeSpeaker<=2)){ for (var UUID in session.rpcs) { if (session.rpcs[UUID].label){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; break } else if (!changed){ + if (session.rpcs[UUID].defaultSpeaker!==false){ + clearTimeout(session.rpcs[UUID].defaultSpeaker); + } else { + changed=true; + } session.rpcs[UUID].defaultSpeaker=true; - changed=true; + } } } @@ -16937,9 +17014,13 @@ function activeSpeaker(border=false) { if (session.rpcs[UUID].activelySpeaking && !session.rpcs[UUID].defaultSpeaker){ session.rpcs[UUID].defaultSpeaker = true; changed = true; - } else if (!session.rpcs[UUID].activelySpeaking && session.rpcs[UUID].defaultSpeaker){ - session.rpcs[UUID].defaultSpeaker = false; - changed=true + } else if (!session.rpcs[UUID].activelySpeaking && (session.rpcs[UUID].defaultSpeaker)){ + if (!session.activeSpeakerTimeout){ + session.rpcs[UUID].defaultSpeaker=false; + changed=true + } else if (session.rpcs[UUID].defaultSpeaker===true){ + session.rpcs[UUID].defaultSpeaker = setTimeout(function(uuid){session.rpcs[uuid].defaultSpeaker = false;updateMixer();},session.activeSpeakerTimeout,UUID); + } } } } @@ -25683,12 +25764,22 @@ function stickyMessage(message){ var spanOverlay = document.createElement("span"); spanOverlay.innerHTML = message; var closeBtn = document.createElement("button"); - closeBtn.className = "overlayCloseBtn"; - closeBtn.innerText = "X"; + closeBtn.className = "overlayCloseBtn red"; + closeBtn.innerHTML = "❌"; + closeBtn.title = "Close this message"; closeBtn.onclick = function(){this.parentNode.remove();}; textOverlay.appendChild(spanOverlay); spanOverlay.appendChild(closeBtn); textOverlay.classList.remove("hidden"); + setTimeout(function(spanOverlay){ + if (spanOverlay){ + spanOverlay.style.animation = "fadeout 1s"; + spanOverlay.style.opacity = "0"; + setTimeout(function(spanOverlay){ + spanOverlay.remove(); + },900,spanOverlay) + } + },30000,spanOverlay); } } @@ -26551,18 +26642,23 @@ function nextFilePlaylist(vid) { } else { session.streamSrc = vid.captureStream(); // gaaaaaaaaaaaahhhhhhhh! } + updateMixer(); var tracks = session.streamSrc.getVideoTracks(); if (tracks.length){ pushOutVideoTrack(tracks[0]); // video only } + + session.streamSrc = outboundAudioPipeline(session.streamSrc); var tracks = session.streamSrc.getAudioTracks(); - senderAudioUpdate(false, tracks); // don't apply audio effects + + senderAudioUpdate(false, tracks); // don't apply audio effects } session.applySoloChat(); // mute streams that should be muted if a director session.applyIsolatedChat(); + toggleMute(true); vid.load(); vid.play().then(_ => { @@ -26664,20 +26760,10 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate v.loop = false; // triggers the complex track/rtc logic. } - v.setAttribute("playsinline",""); - v.src = fileURL; - - - try { - if (Firefox){ - session.streamSrc = v.mozCaptureStream(); - } else { - session.streamSrc = v.captureStream(); // gaaaaaaaaaaaahhhhhhhh! - } - toggleMute(true); - } catch (e){ - errorlog(e); - return; + function myHandler(e) { + log("MY HANDLER TRIGGERED"); + var vid = getById("videosource"); + nextFilePlaylist(vid); } v.id = "videosource"; // could be set to UUID in the future @@ -26685,14 +26771,8 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate v.playlist = files; v.addEventListener('ended',myHandler,false); // only fires if the video doesn't loop. - - function myHandler(e) { - log("MY HANDLER TRIGGERED"); - var vid = getById("videosource"); - nextFilePlaylist(vid); - } - - // no preview doesn't work, so just stop it from doing its thing. + v.setAttribute("playsinline",""); + v.src = fileURL; v.className = "tile clean fileshare"; session.videoElement = v; @@ -26701,52 +26781,6 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate session.mirrorExclude=true; - if (session.director){ - } else if (session.scene!==false){ - - } else if (session.roomid!==false){ - if (session.roomid===""){ - if (!session.view || (session.view==="")){ - if (session.fullscreen){ - session.windowed = false; - } else { - v.className = "myVideo clean fileshare"; - container.classList.add("vidcon"); - session.windowed = true; - } - getById("mutespeakerbutton").classList.add("hidden"); - container.style.width="100%"; - container.style.alignItems = "center"; - container.backgroundColor = "#666"; - play(); - } else { - session.windowed = false; - play(); - } - } else { - //session.cbr=0; // we're just going to override it - if (session.stereo==5){ - session.stereo=3; - } - session.windowed = false; - } - applyMirror(session.mirrorExclude); - } else { - if (session.fullscreen){ - session.windowed = false; - } else { - v.className = "myVideo clean fileshare"; - container.classList.add("vidcon"); - session.windowed = true; - } - getById("mutespeakerbutton").classList.add("hidden"); - container.style.width="100%"; - container.style.alignItems = "center"; - container.backgroundColor = "#666"; - applyMirror(session.mirrorExclude); - } - - v.addEventListener('click', function(e){ log("click"); try { @@ -26808,26 +26842,89 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate }, 5000, v); v.touchLastTap = currentTime; } - }); - - updateReshareLink(); - pokeIframeAPI('started-fileshare'); // depreciated - pokeIframeAPI('file-share', true); - - clearInterval(session.updateLocalStatsInterval); - session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},session.statsInterval); - - session.seeding=true; - - if (session.videoMutedFlag){ - session.videoMuted = true; - toggleVideoMute(true); + v.onerror = function(){ + if (session.cleanOutput){ + errorlog("File failed to load.\n\nSelect a compatible media file."); + } else { + warnUser("File failed to load.\n\nSelect a compatible media file."); + } } - session.seedStream(); + v.onloadeddata = function(){ + if (Firefox){ + session.streamSrc = v.mozCaptureStream(); + } else { + session.streamSrc = v.captureStream(); // gaaaaaaaaaaaahhhhhhhh! + } + toggleMute(true); + session.streamSrc = outboundAudioPipeline(session.streamSrc); + updateMixer(); + + + if (session.director){ + } else if (session.scene!==false){ + + } else if (session.roomid!==false){ + if (session.roomid===""){ + if (!session.view || (session.view==="")){ + if (session.fullscreen){ + session.windowed = false; + } else { + v.className = "myVideo clean fileshare"; + container.classList.add("vidcon"); + session.windowed = true; + } + getById("mutespeakerbutton").classList.add("hidden"); + container.style.width="100%"; + container.style.alignItems = "center"; + container.backgroundColor = "#666"; + play(); + } else { + session.windowed = false; + play(); + } + } else { + //session.cbr=0; // we're just going to override it + if (session.stereo==5){ + session.stereo=3; + } + session.windowed = false; + } + applyMirror(session.mirrorExclude); + } else { + if (session.fullscreen){ + session.windowed = false; + } else { + v.className = "myVideo clean fileshare"; + container.classList.add("vidcon"); + session.windowed = true; + } + getById("mutespeakerbutton").classList.add("hidden"); + container.style.width="100%"; + container.style.alignItems = "center"; + container.backgroundColor = "#666"; + applyMirror(session.mirrorExclude); + } + + updateReshareLink(); + pokeIframeAPI('started-fileshare'); // depreciated + pokeIframeAPI('file-share', true); + + clearInterval(session.updateLocalStatsInterval); + session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},session.statsInterval); + + session.seeding=true; + + if (session.videoMutedFlag){ + session.videoMuted = true; + toggleVideoMute(true); + } + + session.seedStream(); + } }; // publishFile @@ -29981,17 +30078,18 @@ function listCameraSettings() { try { if (track0.getSettings) { session.currentCameraConstraints = track0.getSettings(); - - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait")){ + if (session.mobile){ + if (screen && screen.orientation && screen.orientation.type){ + if (!screen.orientation.type.includes("portrait")){ + if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ + session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; + } + } + } else if (!window.matchMedia("(orientation: portrait)").matches){ if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; } } - } else if (!window.matchMedia("(orientation: portrait)").matches){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } } } else { session.currentCameraConstraints = {}; @@ -30000,6 +30098,28 @@ function listCameraSettings() { errorlog(e); } + var orderedConstraints = {}; + if (session.cameraConstraints.torch) { + orderedConstraints.torch = session.cameraConstraints.torch; + } + if (session.cameraConstraints.aspectRatio) { + orderedConstraints.aspectRatio = session.cameraConstraints.aspectRatio; + } + if (session.cameraConstraints.width) { + orderedConstraints.width = session.cameraConstraints.width; + } + if (session.cameraConstraints.height) { + orderedConstraints.height = session.cameraConstraints.height; + } + if (session.cameraConstraints.zoom) { + orderedConstraints.zoom = session.cameraConstraints.zoom; + } + for (var key in session.cameraConstraints) { + if (session.cameraConstraints.hasOwnProperty(key) && key !== 'width' && key !== 'height') { + orderedConstraints[key] = session.cameraConstraints[key]; + } + } + session.cameraConstraints = orderedConstraints; for (var i in session.cameraConstraints) { try { @@ -30534,19 +30654,19 @@ function applySavedAudioSettings(track0){ // just applies any saved settings. Th function applySavedVideoSettings(track0){ // just applies any saved settings. This then assumes there are already default settings saved, as saved won't be there without the default also. if (track0.getSettings) { session.currentCameraConstraints = track0.getSettings(); - - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait")){ + if (session.mobile){ + if (screen && screen.orientation && screen.orientation.type){ + if (!screen.orientation.type.includes("portrait")){ + if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ + session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; + } + } + } else if (!window.matchMedia("(orientation: portrait)").matches){ if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; } } - } else if (!window.matchMedia("(orientation: portrait)").matches){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } } - if ("deviceId" in session.currentCameraConstraints){ var deviceId = session.currentCameraConstraints.deviceId; if (getStorage("camera_"+deviceId)){ @@ -30674,7 +30794,7 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI var cameraSettings = {}; session.currentCameraConstraints = track0.getSettings(); - if (screen && screen.orientation && screen.orientation.type){ + /* if (screen && screen.orientation && screen.orientation.type){ if (!screen.orientation.type.includes("portrait")){ if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; @@ -30684,7 +30804,7 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; } - } + } */ if (session.currentCameraConstraints.deviceId){ if (!getStorage("camera_"+session.currentCameraConstraints.deviceId)){ cameraSettings['default'] = JSON.parse(JSON.stringify(session.currentCameraConstraints)); @@ -30698,191 +30818,179 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI if (constraint=="width"){ - var constraits = {"width": value}; + var constraints = {"width": value}; if (session.currentCameraConstraints && session.currentCameraConstraints.frameRate){ - constraits.frameRate = session.currentCameraConstraints.frameRate; + constraints.frameRate = session.currentCameraConstraints.frameRate; } - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait") && session.currentCameraConstraints){ - if (!ctrl && session.currentCameraConstraints.height){ - constraits.height = session.currentCameraConstraints.height; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches && session.currentCameraConstraints){ - if (!ctrl && session.currentCameraConstraints.height){ - constraits.height = session.currentCameraConstraints.height; - } + if (!ctrl && session.currentCameraConstraints.height){ + constraints.height = session.currentCameraConstraints.height; } } else if (constraint=="height"){ - var constraits = {"height": value}; + var constraints = {"height": value}; if (session.currentCameraConstraints && session.currentCameraConstraints.frameRate){ - constraits.frameRate = session.currentCameraConstraints.frameRate; + constraints.frameRate = session.currentCameraConstraints.frameRate; } - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait") && session.currentCameraConstraints){ - if (!ctrl && session.currentCameraConstraints.width){ - constraits.width = session.currentCameraConstraints.width; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches && session.currentCameraConstraints){ - - if (!ctrl && session.currentCameraConstraints.width){ - constraits.width = session.currentCameraConstraints.width; - } + if (!ctrl && session.currentCameraConstraints.width){ + constraints.width = session.currentCameraConstraints.width; } } else if (!ctrl && (constraint=="frameRate")){ - var constraits = {"frameRate": value}; + var constraints = {"frameRate": value}; - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait") && session.currentCameraConstraints){ - if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ - constraits.height = session.currentCameraConstraints.height; - constraits.width = session.currentCameraConstraints.width; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches && session.currentCameraConstraints){ - if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ - constraits.height = session.currentCameraConstraints.height; - constraits.width = session.currentCameraConstraints.width; - } + if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ + constraints.height = session.currentCameraConstraints.height; + constraints.width = session.currentCameraConstraints.width; } } else if ((constraint=="exposureMode") && (value=="manual")){ - var constraits = {}; // try to force the current focus, to get the actual current value. + var constraints = {}; // try to force the current focus, to get the actual current value. if (session.currentCameraConstraints && session.currentCameraConstraints.exposureTime){ // just requested a second a go - constraits.exposureTime = session.currentCameraConstraints.exposureTime; // needs the focus set for the manual to activate. + constraints.exposureTime = session.currentCameraConstraints.exposureTime; // needs the focus set for the manual to activate. } await track0.applyConstraints({ // apply what we have on record, to try to force it. - advanced: [constraits] + advanced: [constraints] }) session.currentCameraConstraints = track0.getSettings(); // now get the actual focus distance; solves a bug - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait")){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } + if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ + constraints.height = session.currentCameraConstraints.height; + constraints.width = session.currentCameraConstraints.width; } - var constraits = {[constraint]: value}; // now we can set things to manual; if we don't set the focusDistance, it won't work otherwise. + var constraints = {[constraint]: value}; // now we can set things to manual; if we don't set the focusDistance, it won't work otherwise. if (session.currentCameraConstraints && session.currentCameraConstraints.exposureTime){ - constraits.exposureTime = session.currentCameraConstraints.exposureTime; // needs the focus set for the manual to activate. + constraints.exposureTime = session.currentCameraConstraints.exposureTime; // needs the focus set for the manual to activate. } } else if (constraint=="exposureTime"){ - var constraits = {[constraint]: value}; - constraits.exposureMode = "manual"; + var constraints = {[constraint]: value}; + constraints.exposureMode = "manual"; } else if ((constraint=="focusMode") && (value=="manual")){ - var constraits = {}; // try to force the current focus, to get the actual current value. + var constraints = {}; // try to force the current focus, to get the actual current value. if (session.currentCameraConstraints && session.currentCameraConstraints.focusDistance){ // just requested a second a go - constraits.focusDistance = session.currentCameraConstraints.focusDistance; // needs the focus set for the manual to activate. + constraints.focusDistance = session.currentCameraConstraints.focusDistance; // needs the focus set for the manual to activate. } await track0.applyConstraints({ // apply what we have on record, to try to force it. - advanced: [constraits] + advanced: [constraints] }) session.currentCameraConstraints = track0.getSettings(); // now get the actual focus distance; solves a bug - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait")){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches){ // legacy - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } + if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ + constraints.height = session.currentCameraConstraints.height; + constraints.width = session.currentCameraConstraints.width; } - var constraits = {[constraint]: value}; // now we can set things to manual; if we don't set the focusDistance, it won't work otherwise. + var constraints = {[constraint]: value}; // now we can set things to manual; if we don't set the focusDistance, it won't work otherwise. if (session.currentCameraConstraints && session.currentCameraConstraints.focusDistance){ - constraits.focusDistance = session.currentCameraConstraints.focusDistance; // needs the focus set for the manual to activate. + constraints.focusDistance = session.currentCameraConstraints.focusDistance; // needs the focus set for the manual to activate. } } else if (constraint=="focusDistance"){ - var constraits = {[constraint]: value}; - constraits.focusMode = "manual"; + var constraints = {[constraint]: value}; + constraints.focusMode = "manual"; } else if ((constraint=="whiteBalanceMode") && (value=="manual")){ - var constraits = {}; // try to force the current colorTemperature, to get the actual current value. + var constraints = {}; // try to force the current colorTemperature, to get the actual current value. if (session.currentCameraConstraints && session.currentCameraConstraints.colorTemperature){ // just requested a second a go - constraits.colorTemperature = session.currentCameraConstraints.colorTemperature; // needs the colorTemperature set for the manual to activate. + constraints.colorTemperature = session.currentCameraConstraints.colorTemperature; // needs the colorTemperature set for the manual to activate. } await track0.applyConstraints({ // apply what we have on record, to try to force it. - advanced: [constraits] + advanced: [constraints] }) session.currentCameraConstraints = track0.getSettings(); // now get the actual colorTemperature; solves a bug - if (screen && screen.orientation && screen.orientation.type){ - if (!screen.orientation.type.includes("portrait")){ - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } - } - } else if (!window.matchMedia("(orientation: portrait)").matches){ // legacy - if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ - session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; - } + if (session.currentCameraConstraints.height && session.currentCameraConstraints.width){ + constraints.height = session.currentCameraConstraints.height; + constraints.width = session.currentCameraConstraints.width; } - var constraits = {[constraint]: value}; + var constraints = {[constraint]: value}; if (session.cameraConstraints.colorTemperature && ("max" in session.cameraConstraints.colorTemperature) && ("min" in session.cameraConstraints.colorTemperature)){ if (session.currentCameraConstraints && session.currentCameraConstraints.colorTemperature){ - constraits.colorTemperature = session.currentCameraConstraints.colorTemperature; + constraints.colorTemperature = session.currentCameraConstraints.colorTemperature; } else if ((5000>=session.cameraConstraints.colorTemperature.min) && (5000<=session.cameraConstraints.colorTemperature.max)){ - constraits.colorTemperature = 5000; // whiteBalanceMode won't work unless a colorTemperature is set. 5000 is a good default. + constraints.colorTemperature = 5000; // whiteBalanceMode won't work unless a colorTemperature is set. 5000 is a good default. } else { - constraits.colorTemperature = session.cameraConstraints.colorTemperature.max; + constraints.colorTemperature = session.cameraConstraints.colorTemperature.max; } } } else if ((constraint=="whiteBalanceMode") && (value=="continuous")){ - var constraits = {[constraint]: value}; + var constraints = {[constraint]: value}; if (session.mobile && ChromiumVersion){ // trying to fix the issue that chrome mobile has. - constraits.colorTemperature = 5000; + constraints.colorTemperature = 5000; } } else if (constraint=="colorTemperature"){ - var constraits = {[constraint]: value}; - constraits.whiteBalanceMode = "manual"; + var constraints = {[constraint]: value}; + constraints.whiteBalanceMode = "manual"; } else if (constraint=="aspectRatio"){ - var constraits = {[constraint]: value}; + var constraints = {[constraint]: value}; if (session.currentCameraConstraints && session.currentCameraConstraints.frameRate){ - constraits.frameRate = session.currentCameraConstraints.frameRate; + constraints.frameRate = session.currentCameraConstraints.frameRate; } - } else { - var constraits = {[constraint]: value}; - } - - if (screen && screen.orientation && screen.orientation.type){ - if (screen.orientation.type.includes("portrait")){ - if (constraits.aspectRatio){ - constraits.aspectRatio = 1/constraits.aspectRatio; + if (session.mobile){ + if (screen && screen.orientation && screen.orientation.type){ + if (screen.orientation.type.includes("portrait")){ + if (constraints.aspectRatio){ + constraints.aspectRatio = 1/constraints.aspectRatio; + } + } + } else if (window.matchMedia("(orientation: portrait)").matches){ // legacy + if (constraints.aspectRatio){ + constraints.aspectRatio = 1/constraints.aspectRatio; + } } } - } else if (window.matchMedia("(orientation: portrait)").matches){ // legacy - if (constraits.aspectRatio){ - constraits.aspectRatio = 1/constraits.aspectRatio; - } + } else { + var constraints = {[constraint]: value}; + } + + + + if (session.mobile){ + if (screen && screen.orientation && screen.orientation.type){ + if (screen.orientation.type.includes("portrait")){ + if (constraints.width && constraints.height){ + var tmp = constraints.width; + constraints.width = constraints.height; + constraints.height = tmp; + } else if (constraints.width){ + constraints.height = constraints.width; + delete constraints.width; + } else if (constraints.height){ + constraints.width = constraints.height; + delete constraints.height; + } + } + } else if (window.matchMedia("(orientation: portrait)").matches){ // legacy + if (constraints.width && constraints.height){ + var tmp = constraints.width; + constraints.width = constraints.height; + constraints.height = tmp; + } else if (constraints.width){ + constraints.height = constraints.width; + delete constraints.width; + } else if (constraints.height){ + constraints.width = constraints.height; + delete constraints.height; + } + } } log("20788"); - log(constraits); + log(constraints); + console.warn(constraints); + console.warn(constraint + " : " +value); await track0.applyConstraints({ - advanced: [constraits] + advanced: [constraints] }).then(() => { log("applied constraint"); if (save){ @@ -30891,7 +30999,7 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI session.currentCameraConstraints = track0.getSettings(); - if (screen && screen.orientation && screen.orientation.type){ + /* if (screen && screen.orientation && screen.orientation.type){ if (!screen.orientation.type.includes("portrait")){ if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; @@ -30901,7 +31009,7 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI if (session.currentCameraConstraints && session.currentCameraConstraints.aspectRatio){ session.currentCameraConstraints.aspectRatio = 1/session.currentCameraConstraints.aspectRatio; } - } + } */ cameraSettings['current'] = session.currentCameraConstraints; // this won't let failed settings be stored. //cameraSettings['current'][constraint] = value; // setting value is a problem, as it will allow for failed settings to be stored. @@ -33143,7 +33251,7 @@ function sendChatMessage(chatMsg = false, bc = false) { // filtered + visual data.msg = sanitizeChat(msg); // this is what the other person should see data.label = label; data.type = "sent"; - messageList.push(data); + messageList.push(data); sent=true; } else if ((session.directorList.indexOf(UUID)>=0) && "director".startsWith(uid)){ sendChat(msg, UUID); // send message to peers @@ -33233,6 +33341,22 @@ function sendChatMessage(chatMsg = false, bc = false) { // filtered + visual session.broadcastChannel.postMessage(data); } updateMessages(); + + if (isIFrame) { + parent.postMessage({ + "chat": data + }, session.iframetarget); + } + + + + var apiBlob = {}; + apiBlob.time = data.time; + apiBlob.msg = msg; + apiBlob.label = session.label; + apiBlob.type = data.type; + pokeAPI("chat", apiBlob); + return true; } @@ -33516,19 +33640,33 @@ function replaceURLs(message) { }); } -function getChatMessage(msg, label = false, director = false, overlay = false) { +function getChatMessage(msg, label = false, director = false, overlay = false, UUID=false) { msg = sanitizeChat(msg); // keep it clean. if (msg == "") { return; } + data = {}; + data.time = Date.now(); + + var apiBlob = {}; + apiBlob.time = data.time; + apiBlob.msg = msg; + apiBlob.label = label; + apiBlob.type = "recv"; + + if (UUID!==false){ + apiBlob.UUID = UUID; + if (UUID in session.rpcs){ + apiBlob.streamID = session.rpcs[UUID].streamID || false; + } + } + if (label) { label = sanitizeLabel(label); } - - data = {}; - data.time = Date.now(); + data.msg = msg; if (label) { data.label = label; @@ -33574,9 +33712,12 @@ function getChatMessage(msg, label = false, director = false, overlay = false) { if (isIFrame) { parent.postMessage({ - "gotChat": data + "gotChat": data, // deprecated + "chat": data }, session.iframetarget); } + + pokeAPI("chat", apiBlob); if (session.chatbutton===false){return;} // messages can still appear as overlays ^ @@ -36666,6 +36807,10 @@ function setupGuestLabelControl(UUID){ miniTranslate(labelID,"main-director"); //labelID.innerHTML = getTranslation("main-director"); labelID.classList.remove("addALabel"); + } else if (session.directorList.indexOf(UUID)>=0){ + miniTranslate(labelID,"co-director"); + //labelID.innerHTML = getTranslation("co-director"); + labelID.classList.remove("addALabel"); } else { miniTranslate(labelID,"add-a-label"); //labelID.innerHTML = getTranslation("add-a-label"); // Replace underscores with a Space when publishing to HTML. No Double spaces. @@ -36686,6 +36831,10 @@ function setupGuestLabelControl(UUID){ miniTranslate(ee.target,"main-director"); //ee.target.innerHTML = getTranslation("main-director"); ee.target.classList.remove("addALabel"); + } else if (session.directorList.indexOf(UUID)>=0){ + miniTranslate(ee.target,"co-director"); + //ee.target.innerHTML = getTranslation("co-director"); + ee.target.classList.remove("addALabel"); } else { miniTranslate(ee.target,"add-a-label"); //ee.target.innerHTML = getTranslation("add-a-label"); @@ -36714,6 +36863,9 @@ function updateLabelDirectors(UUID){ //elements.innerHTML = getTranslation("main-director"); miniTranslate(elements,"main-director"); elements.classList.remove("addALabel"); + } else if (session.directorList.indexOf(UUID)>=0){ + miniTranslate(elements,"co-director"); + elements.classList.remove("addALabel"); } else { //elements.innerHTML = getTranslation("add-a-label"); miniTranslate(elements,"add-a-label"); @@ -36726,6 +36878,9 @@ function updateLabelDirectors2(UUID){ //elements.innerHTML = getTranslation("main-director"); miniTranslate(elements,"main-director"); elements.classList.remove("addALabel"); + } else if (session.directorList.indexOf(UUID)>=0){ + miniTranslate(elements,"co-director"); + elements.classList.remove("addALabel"); } else { //elements.innerHTML = getTranslation("add-a-label"); miniTranslate(elements,"add-a-label"); @@ -39210,6 +39365,7 @@ async function whepIn(whepInput=false, whepInputToken=false, UUID=false){ // PLA session.rpcs[UUID].channelOffset = false; session.rpcs[UUID].channelWidth = false; session.rpcs[UUID].settings = false; + session.rpcs[UUID].defaultSpeaker = false; session.rpcs[UUID].lockedVideoBitrate = false; // doesn't do anything session.rpcs[UUID].lockedAudioBitrate = false; session.rpcs[UUID].manualBandwidth = false; // doesn't do anything, except maybe help keep track of pause/play states diff --git a/main.css b/main.css index e7b37d3..8e183d3 100644 --- a/main.css +++ b/main.css @@ -649,13 +649,14 @@ button.hint { cursor:pointer; } .overlayCloseBtn{ - padding: 0; - margin: 10px; - width: 16px; - height: 16px; - position: relative; - bottom: 10px; - background-color: #DDDD; + padding: 0; + width: 16px; + height: 16px; + position: relative; + bottom: 7px; + padding: 18px 18px 20px 18px; + font-size: 22px; + margin-left: 20px; } #overlayMsgs{ diff --git a/main.js b/main.js index 2c44814..60e2dbe 100644 --- a/main.js +++ b/main.js @@ -892,8 +892,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s document.documentElement.style.setProperty('--full-screen-button', 'none'); getById("fullscreenPage").classList.remove("hidden"); } + } else if (urlParams.has('nofullscreenbutton') || urlParams.has('nofsb')){ // just an alternative; might be compoundable + session.nofullwindowbutton = true; } + if (urlParams.has('pip2') || urlParams.has('pipall')){ // just an alternative; might be compoundable if (typeof documentPictureInPicture !== "undefined"){ getById("PictureInPicturePage").classList.remove("hidden"); @@ -1124,7 +1127,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s } if (urlParams.has('layout')) { - session.accept_layouts = true; + + if (!urlParams.get('layout')){ + session.accept_layouts = true; + } try { session.layout = JSON.parse(decodeURIComponent(urlParams.get('layout'))) || JSON.parse(urlParams.get('layout')) || {}; } catch(e){ @@ -3909,6 +3915,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s setInterval(function(){activeSpeaker(false);},100); } } + if (urlParams.has('activespeakerdelay') || urlParams.has('speakerviewdelay') || urlParams.has('sasdelay')){ + session.activeSpeakerTimeout = urlParams.get('activespeakerdelay') || urlParams.get('speakerviewdelay') || urlParams.get('sasdelay') || 0; + session.activeSpeakerTimeout = parseInt(session.activeSpeakerTimeout); + } if (urlParams.has('noisegatesettings')){ session.noisegateSettings = urlParams.get('noisegatesettings'); diff --git a/mixer.html b/mixer.html index 1f0dc76..4e0a38f 100644 --- a/mixer.html +++ b/mixer.html @@ -337,6 +337,16 @@ width: 15px; height: 15px; } + + @keyframes highlight { + 0% { background-color: white; } + 10% { background-color: #d7fd5d8c; } + 100% { background-color: white; } + } + + .updated { + animation: highlight 1s; + } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 13px rgb(0 0 0 / 90%); @@ -345,7 +355,7 @@ ::-webkit-scrollbar-thumb { border-radius: 4px; - -webkit-box-shadow: inset 0 0 16px rgb(150 150 150 / 100%); + -webkit-box-shadow: inset 0 0 16px rgb(0 0 0 / 100%); border: solid 3px transparent; } @@ -584,6 +594,23 @@ cursor:pointer!important; } + + #imageCarousel { + display: flex; + overflow-x: auto; + scroll-behavior: smooth; + max-width: 400px; + } + #imageCarousel img { + max-width: 100px; + margin: 10px; + cursor: pointer; + transition: transform 0.25s ease; + } + #imageCarousel img:hover { + transform: scale(1.1); + } + .canvasContainer:hover>button{ display:inline-block; padding: 3.2px; @@ -925,7 +952,11 @@ Generate a random room name
-
+ + + Generate a random password + +