fix for screen share + zoom

This commit is contained in:
steveseguin 2023-09-25 02:59:10 -04:00
parent 883bd18410
commit 7694dec33a
8 changed files with 599 additions and 496 deletions

View File

@ -58,7 +58,7 @@
<meta property="twitter:image" content="./media/vdoNinja_logo_full.png" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#0f131d" />
<link rel="stylesheet" href="./main.css?ver=363" />
<link rel="stylesheet" href="./main.css?ver=365" />
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.js"></script>
<style id="lightbox-animations" type="text/css"></style>
@ -92,7 +92,7 @@
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=49"></script>
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=693"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=695"></script>
<input id="zoomSlider" type="range" style="display: none;" />
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:2%;-webkit-app-region: drag;min-height:20px;"></span>
<div id="header">
@ -1000,7 +1000,7 @@
<span style="color:#daad09;">Welcome to VDO Ninja! We've rebranded! Nothing else is changing and we're staying 100% free.</span>
</h4>
<br />
🌻 Site last updated on July 25th. Development <a target="_blank" title="Open a page with recent VDO.Ninja development and feature updates" href='https://updates.vdo.ninja/'>updates are here.</a>
🍂 Site last updated on September 8th. You can also still access the previous version, which <a href="https://vdo.ninja/v23/">is hosted here</a>. Development <a target="_blank" title="Open a page with recent VDO.Ninja development and feature updates" href="https://updates.vdo.ninja/">updates are here.</a>
<br />
<br />
<h3>
@ -2630,11 +2630,11 @@
// session.hidehome = true; // If used, 'hide home' will make the landing page inaccessible, along with hiding a few go-home elements.
// session.record = false; // uncomment to block users from being able to record via vdo.ninja's built in recording function
</script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=904"></script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=915"></script>
<!--
// If you wish to change branding, blank offers a good clean start.
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
-->
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=725"></script>
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=734"></script>
</body>
</html>

158
lib.js
View File

@ -3309,6 +3309,14 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
return;
} // if Audio only, then we don't want to set or update any aspect ratio.
if (session.keepIncomingVideosInLandscape){
if (aspectRatio < 1){ // session.keepIncomingVideosInLandscape
v.rotated = session.keepIncomingVideosInLandscape;
} else {
v.rotated = 0;
}
}
if (v.resetAR){
log("ASPECT RATIO UNMUTED");
delete(v.resetAR);
@ -3328,6 +3336,8 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
pokeIframeAPI("aspect-ratio", v.dataset.aspectRatio, v.dataset.UUID, v.dataset.sid);
setTimeout(function(){updateMixer();},1);
}
});
if (typeof session.volume == "number"){
@ -3911,8 +3921,43 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
if (session.pipWindow){
var hi = 0;
var w = session.pipWindow.innerWidth;
var h = session.pipWindow.innerHeight;
var w = session.pipWindow.clientHeight;
var h = session.pipWindow.clientWidth;
} else if (document.body.dataset.rotated){
var hi = header.offsetHeight;
var w = document.body.clientHeight;
if (session.widget){
w *= 0.75;
try {
let widget = document.getElementById("widget");
if (!widget){
widget = document.createElement("iframe");
widget.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;midi;";
widget.id = "widget";
widget.src = parseURL4Iframe(session.widget);
log(widget.src);
document.body.appendChild(widget);
playarea.style.left = "0";
playarea.style.width = "75%";
}
widget.style.height = "calc(100% - " +hi + "px)";
widget.style.top = hi;
} catch(e){
errorlog(e);
}
}
var h = document.body.clientWidth - hi;
if (session.dedicatedControlBarSpace || document.body.clientWidth<=700 ){ // # This needs to be reviewed.
if (session.dedicatedControlBarSpace!==false){
if (document.getElementById("subControlButtons") && !session.overlayControls){
if (!document.getElementById("subControlButtons").yOffset || (document.getElementById("subControlButtons").yOffset>-10)){
h = document.body.clientWidth - hi - document.getElementById("subControlButtons").offsetHeight;
}
}
}
}
} else {
var hi = header.offsetHeight;
var w = window.innerWidth;
@ -4094,9 +4139,9 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
}
if (soloVideo!==false){
session.screenShareElement.style.display="none";
//session.screenShareElement.style.display="none";
} else if (session.activeSpeaker && (!session.activelySpeaking)){
session.screenShareElement.style.display="none";
//session.screenShareElement.style.display="none";
} else {
mediaPool.push(session.screenShareElement);
}
@ -5211,6 +5256,14 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
return;
}
if (vid.needsLoading){
try {
vid.load();
} catch(e){
errorlog(e);
}
}
if (session.slots){
if (("slot" in vid) && parseInt(vid.slot)){
i = parseInt(vid.slot) - 1;
@ -5782,7 +5835,10 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
label.style.fontSize = parseInt(fontsize)+"px";
}
label.innerText = session.rpcs[vid.dataset.UUID].label;
if (label.innerText){
//label.innerHTML = label.innerHTML.replace(/\\n/g,"<br />");
label.innerHTML = label.innerHTML.split("\\n").map(word => `<span>${word}</span>`).join(" ");
}
} else if ((session.showlabels===true) && (vid.id === "videosource") && (session.label)){ // local source
// creates a label holder that's the same size of the vid element.
@ -5823,6 +5879,11 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
}
label.innerText = sanitizeLabel(session.label);//.replace(/[\W]+/g,"_").replace(/_+/g, ' ');
if (label.innerText){
label.innerHTML = label.innerHTML.split("\\n").map(word => `<span>${word}</span>`).join(" ");
}
holder.appendChild(label);
} else if (holder.label){
holder.label.remove();
@ -6782,6 +6843,13 @@ session.remoteZoom = function(zoom){
warnlog("No zoom supported on this device");
return;
}
if (("min" in capabilities.zoom) && ("max" in capabilities.zoom)){
if (capabilities.zoom.max === capabilities.zoom.min){
warnlog("zoom only has one fixed setting");
}
return;
}
if (session.zoom==false){
session.zoom = capabilities.zoom.min;
}
@ -7761,7 +7829,7 @@ function updateUserList(){
var insert = document.createElement("div");
if (session.rpcs[UUID].label){
insert.innerText = session.rpcs[UUID].label + "";
insert.innerText = session.rpcs[UUID].label.split("\\n")[0] + "";
} else if (session.directorList.indexOf(UUID)>=0){
miniTranslate(insert,"director");
//insert.innerHTML = getTranslation("director");
@ -10588,7 +10656,7 @@ function printMyStats(menu, screenshare=false) { // see: setupStatsMenu
}
}
if ((iOS) || (iPad)){
if (iOS || iPad){
menu.innerHTML += "<br /><div style='height:100px'></div>";
}
try {
@ -11627,7 +11695,7 @@ function toggleSpeakerMute(apply = false) { // TODO: I need to have this be MUTE
pokeAPI("speakerMuted", session.speakerMuted);
}
if ((iOS) || (iPad)) {
if (iOS || iPad) {
resetupAudioOut();
}
}
@ -14256,16 +14324,19 @@ function updateForceRotate(skipLastBit=false){
}
}
function updateForceRotatedCSS(){
var rotateThis = session.forceRotate;
function updateForceRotatedCSS(rotateThis=session.forceRotate){
if (rotateThis==270){
document.body.setAttribute( "style", "transform: rotate(270deg);position: absolute;top: 100vh;left: 0;height: 100vw;width: 100vh;transform-origin: 0 0;");
document.body.dataset.rotated = "1";
} else if (rotateThis==90){
document.body.setAttribute( "style", "transform: rotate(90deg);position: absolute;top: 0;left: 100vw;height: 100vw;width: 100vh;transform-origin: 0 0;");
document.body.dataset.rotated = "1";
} else if (rotateThis==180){
document.body.setAttribute( "style", "transform: rotate(180deg);position: absolute;top: 100vh;left: 100vw;height: 100vh;width: 100vw;transform-origin: 0 0;");
document.body.dataset.rotated = ""
} else {
document.body.setAttribute( "style", "");
document.body.dataset.rotated = ""
}
}
@ -15115,7 +15186,7 @@ session.publishIFrame = function(iframeURL){
} // publishIframe
session.publishWhepSrc = function(){
/* session.publishWhepSrc = function(){
if (!session.whepSrc){errorlog("no WHEP Src");return;}
@ -15226,7 +15297,7 @@ session.publishWhepSrc = function(){
session.seedStream();
return container;
} // publishWhepSrc
} // publishWhepSrc */
function outboundAudioPipeline(){ // this function isn't letting me change the audio source
@ -18588,7 +18659,7 @@ function requestOutputAudioStream() {
if (!(session.cleanOutput)) {
if (window.isSecureContext) {
warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
} else if ((iOS) || (iPad)) {
} else if (iOS || iPad) {
warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
} else {
warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
@ -18652,7 +18723,7 @@ async function requestAudioStream() {
if (!(session.cleanOutput)) {
if (window.isSecureContext) {
warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
} else if ((iOS) || (iPad)) {
} else if (iOS || iPad) {
warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
} else {
warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
@ -19867,7 +19938,7 @@ function gotDevices2(deviceInfos) {
audioOutputSelect.onchange = function() {
log("audioOutputSelect.onchange = function() {");
if ((iOS) || (iPad)) {
if (iOS || iPad) {
return;
}
@ -20085,7 +20156,7 @@ function playtone(screen = false, tonename="testtone") {
},500);
timeoutTone = true;
if ((iOS) || (iPad)) {
if (iOS || iPad) {
// try{
// session.audioContext.resume();
// } catch(e){errorlog(e);}
@ -20462,7 +20533,7 @@ function reconnectDevices(event) { /// TODO: Perhaps change this to only if the
warnlog("A media device has changed");
if ((iOS) || (iPad)) { // consider adding this back, but if no problem, whatever.
if (iOS || iPad) { // consider adding this back, but if no problem, whatever.
return;
}
@ -22272,7 +22343,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
if (session.facingMode){
constraints.video.facingMode = { exact: session.facingMode }; // user or environment
} else if ((iOS) || (iPad)) {
} else if (iOS || iPad) {
constraints.video.deviceId = {
exact: videoSelect.value
}; // iPhone 6s compatible ? Needs to be exact for iPhone 6s
@ -25436,6 +25507,7 @@ function dragElement(elmnt) {
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
@ -25447,6 +25519,8 @@ function dragElement(elmnt) {
dragged = true;
millis = Date.now();
if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
var touch = e.touches[0] || e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
@ -25456,7 +25530,11 @@ function dragElement(elmnt) {
pos1 = e.clientX;
pos2 = e.clientY;
}
if (!zoomable){
return;
}
var zoom = parseFloat((pos4 - pos2) * 2 / elmnt.offsetHeight);
if (zoom > 1) {
@ -25465,9 +25543,8 @@ function dragElement(elmnt) {
zoom = -1.0;
}
input.value = zoom * (input.max - input.min) + input.min;
//if (input.value != pos0) {
updateCameraConstraints("zoom", input.value, false, false);
//}
}
function closeDragElement(e) {
@ -25543,14 +25620,17 @@ function dragElement(elmnt) {
log("focusable");
focusable = true;
}
if ('zoom' in capabilities) {
log("zoomable;");
zoomable = true;
input.min = capabilities.zoom.min;
input.max = capabilities.zoom.max;
input.step = capabilities.zoom.step;
input.value = settings.zoom;
if (capabilities.zoom.min !== capabilities.zoom.max){
log("zoomable;");
zoomable = true;
input.min = capabilities.zoom.min;
input.max = capabilities.zoom.max;
input.step = capabilities.zoom.step;
input.value = settings.zoom;
}
}
}
@ -29101,6 +29181,11 @@ var updateCameraConstraintsNext = false;
async function updateCameraConstraints(constraint, value = null, ctrl=false, UUID=false, save=true) {
if ((constraint === "zoom") && (value === 0)){
log("can't zoom to zero");
return;
}
log("updateCameraConstraintsBusy..?");
if (updateCameraConstraintsBusy){
@ -29146,6 +29231,7 @@ async function updateCameraConstraints(constraint, value = null, ctrl=false, UUI
log("updateCameraConstraintsNext:");
log(updateCameraConstraintsNext);
try {
if (track0.getSettings){
var cameraSettings = {};
@ -29541,7 +29627,7 @@ function setupWebcamSelection(miconly=false) {
outputSelect.onchange = function() {
if ((iOS) || (iPad)) {
if (iOS || iPad) {
return;
}
if (Firefox && !session.mobile){
@ -30292,7 +30378,7 @@ async function requestBasicPermissions(constraint = {video: true, audio: true},
if (!(session.cleanOutput)) {
if (window.isSecureContext) {
warnUser("An error has occured when trying to access the webcam or microphone. The reason is not known.");
} else if ((iOS) || (iPad)) {
} else if (iOS || iPad) {
warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
} else {
warnUser("Error acessing camera or microphone.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
@ -33063,8 +33149,12 @@ async function recordLocalVideo(action = null, videoKbps = false, remote=false)
getById("recordLocalbutton").dataset.state = "0";
getById("recordLocalbutton").style.backgroundColor = "";
getById("recordLocalbutton").innerHTML = '<i class="toggleSize las la-exclamation" ></i>';
if (restart!==true){
warnUser("Media Recording Stopped due to an error: "+restart);
} else {
warnUser("Media Recording Stopped due to an error.");
}
restart = false;
warnUser("Media Recording Stopped due to an error.");
} else {
getById("recordLocalbutton").innerHTML = '<i class="toggleSize las la-spinner" ></i>';
getById("recordLocalbutton").dataset.state = "2";
@ -33315,7 +33405,11 @@ async function recordLocalVideo(action = null, videoKbps = false, remote=false)
video.recorder.mediaRecorder.onerror = function(event) {
errorlog(event);
video.recorder.stop(true);
if (event && event.error && event.error.name){
video.recorder.stop(event.error.name);
} else {
video.recorder.stop(true);
}
};
video.srcObject.ended = function(event) {

View File

@ -3942,6 +3942,30 @@ a#reshare {
pointer-events:none;
}
.video-label>span:nth-child(2) {
font-size: 50%;
display: block;
text-align: center;
}
.video-label>span:nth-child(3) {
font-size: 25%;
display: block;
text-align: center;
line-height: 200%;
}
.video-label>span:nth-child(4) {
font-size: 25%;
display: block;
text-align: center;
line-height: 200%;
}
.video-label>span:nth-child(5) {
font-size: 25%;
display: block;
text-align: center;
line-height: 200%;
}
.video-label.zoom {
bottom: 0;
left: 0;

38
main.js
View File

@ -778,15 +778,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
if (urlParams.has("rotatewindow") || urlParams.has("rotatepage")){
let rotateThis = parseInt(urlParams.get("rotatewindow")) || parseInt(urlParams.get("rotatepage")) || 90;
if (rotateThis==270){
document.body.setAttribute( "style", "transform: rotate(270deg);position: absolute;top: 100vh;left: 0;height: 100vw;width: 100vh;transform-origin: 0 0;");
} else if (rotateThis==90){
document.body.setAttribute( "style", "transform: rotate(90deg);position: absolute;top: 0;left: 100vw;height: 100vw;width: 100vh;transform-origin: 0 0;");
} else if (rotateThis==180){
document.body.setAttribute( "style", "transform: rotate(180deg);position: absolute;top: 100vh;left: 100vw;height: 100vh;width: 100vw;transform-origin: 0 0;");
} else {
document.body.setAttribute( "style", "");
}
updateForceRotatedCSS(rotateThis);
}
if (urlParams.has('facing') ) {
@ -823,6 +815,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
if (urlParams.has('forceviewerlandscape')){
session.keepIncomingVideosInLandscape = parseInt(urlParams.get('forceviewerlandscape')) || 270;
}
document.addEventListener('fullscreenchange', event => {
log("full screen change event");
@ -3914,8 +3910,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
if (urlParams.has('sendframes')) {
session.sendframes = urlParams.get('sendframes');
if(session.sendframes){
session.sendframes = decodeURIComponent(session.sendframes);
if (session.sendframes){
try {
session.sendframes = decodeURIComponent(session.sendframes);
} catch(e){}
} else {
session.sendframes = session.iframetarget || "*";
}
@ -4505,8 +4503,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.screenShareLabel = session.screenShareLabel.replace(/_/g, " ")
}
// this is not the same as creating a whep source
if (urlParams.has('whepshare') || urlParams.has('whepsrc')) { // URL or data:base64 image. Becomes local to this viewer only. This is like &avatar, but slightly different. Just CSS in this case
if (urlParams.has('whepshare') || urlParams.has('whepsrc')) {
try {
session.whepSrc = urlParams.get('whepshare') || urlParams.get('whepsrc') || null;
log("WHEP SRC: "+session.whepSrc);
@ -4514,22 +4511,15 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
try {
session.whepSrc = decodeURIComponent(session.whepSrc);
} catch(e){
session.whepSrc=null;
session.whepSrc = session.whepSrc;
}
}
if (!session.whepSrc && session.autostart){
} else {
session.whepSrc = await promptAlt("Enter the WHEP source as a URL");
}
if (session.whepSrc){
getById("whepURL").value = session.whepSrc;
session.whipoutSettings = {type:"whep", "url": session.whepSrc};
}
getById("container-16").classList.remove('hidden');
getById("container-16").classList.add("skip-animation");
getById("container-16").classList.remove('pointer');
if (session.autostart && session.whepSrc){
delayedStartupFuncs.push([session.publishWhepSrc, session.whepSrc]);
}
} catch(e){
errorlog(e);
}
@ -6470,7 +6460,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
script.onload = function() {
var script = document.createElement('script');
document.head.appendChild(script);
script.src = "./thirdparty/StreamSaver.js?v=13"; // dynamically load this only if its needed. Keeps loading time down.
script.src = "./thirdparty/StreamSaver.js?v=19"; // dynamically load this only if its needed. Keeps loading time down.
};
script.src = "./thirdparty/polyfill.min.js"; // dynamically load this only if its needed. Keeps loading time down.
},100);

View File

@ -276,9 +276,9 @@
document.getElementById("details").innerHTML += "<br /><b>Max Upload bandwidth:</b> "+parseInt(data.summary.upload/(1024*1024))+"-mbps<br />";
}
}
if (data.scores && data.scores.gaming && data.scores.gaming.classificationName && data.scores.rtc && data.scores.rtc.classificationName && data.scores.streaming && data.scores.streaming.classificationName){
document.getElementById("details").innerHTML += "<br /><b>Gaming:</b> "+data.scores.gaming.classificationName+", <b>RTC:</b> "+data.scores.rtc.classificationName+", <b>Streaming:</b> "+data.scores.streaming.classificationName+"<br />";
}
//if (data.scores && data.scores.gaming && data.scores.gaming.classificationName && data.scores.rtc && data.scores.rtc.classificationName && data.scores.streaming && data.scores.streaming.classificationName){
// document.getElementById("details").innerHTML += "<br /><b>Gaming:</b> "+data.scores.gaming.classificationName+", <b>RTC:</b> "+data.scores.rtc.classificationName+", <b>Streaming:</b> //"+data.scores.streaming.classificationName+"<br />";
//}
if ("resolution" in data){
try {

View File

@ -762,10 +762,7 @@ function rotatePage(){
//iframe.style.left = "calc(" + (iframe.style.left) +" + 100vw)";
}
}
}
</script>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long