diff --git a/meshdesktopmultiplex.js b/meshdesktopmultiplex.js index 554b8716..b9b2add7 100644 --- a/meshdesktopmultiplex.js +++ b/meshdesktopmultiplex.js @@ -82,6 +82,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { obj.lastDisplayInfoData = null; // Pointer to the last display information command from the agent (Number of displays). obj.lastDisplayLocationData = null; // Pointer to the last display location and size command from the agent. obj.desktopPaused = true; // Current desktop pause state, it's true if all viewers are paused. + obj.imageType = 1; // Current image type, 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP obj.imageCompression = 50; // Current image compression, this is the highest value of all viewers. obj.imageScaling = 1024; // Current image scaling, this is the highest value of all viewers. obj.imageFrameRate = 50; // Current framerate setting, this is the lowest values of all viewers. @@ -107,6 +108,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { if (obj.viewers.indexOf(peer) >= 0) return true; obj.viewers.push(peer); peer.desktopPaused = true; + peer.imageType = 1; peer.imageCompression = 30; peer.imageScaling = 1024; peer.imageFrameRate = 100; @@ -202,6 +204,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { // Aggressive clean up of the viewer delete peer.desktopPaused; + delete peer.imageType; delete peer.imageCompression; delete peer.imageScaling; delete peer.imageFrameRate; @@ -483,31 +486,34 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) { break; case 5: // Compression if (data.length < 10) return; - //viewer.imageType = data[4]; // Always 1=JPEG + viewer.imageType = data[4]; // Image type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP viewer.imageCompression = data[5]; viewer.imageScaling = data.readUInt16BE(6); viewer.imageFrameRate = data.readUInt16BE(8); - //console.log('Viewer-Compression', viewer.imageCompression, viewer.imageScaling, viewer.imageFrameRate); + //console.log('Viewer-Compression', viewer.imageType, viewer.imageCompression, viewer.imageScaling, viewer.imageFrameRate); // See if this changes anything + var viewersimageType = null; var viewersimageCompression = null; var viewersimageScaling = null; var viewersimageFrameRate = null; for (var i in obj.viewers) { + if (viewersimageType == null) { viewersimageType = obj.viewers[i].imageType; } else if (obj.viewers[i].imageType != viewersimageType) { viewersimageType = 1; }; // Default to JPEG if viewers has different image formats if ((viewersimageCompression == null) || (obj.viewers[i].imageCompression > viewersimageCompression)) { viewersimageCompression = obj.viewers[i].imageCompression; }; if ((viewersimageScaling == null) || (obj.viewers[i].imageScaling > viewersimageScaling)) { viewersimageScaling = obj.viewers[i].imageScaling; }; if ((viewersimageFrameRate == null) || (obj.viewers[i].imageFrameRate < viewersimageFrameRate)) { viewersimageFrameRate = obj.viewers[i].imageFrameRate; }; } if ((obj.imageCompression != viewersimageCompression) || (obj.imageScaling != viewersimageScaling) || (obj.imageFrameRate != viewersimageFrameRate)) { // Update and send to agent new compression settings + obj.imageType = viewersimageType; obj.imageCompression = viewersimageCompression; obj.imageScaling = viewersimageScaling; obj.imageFrameRate = viewersimageFrameRate - //console.log('Send-Agent-Compression', obj.imageCompression, obj.imageScaling, obj.imageFrameRate); + //console.log('Send-Agent-Compression', obj.imageType, obj.imageCompression, obj.imageScaling, obj.imageFrameRate); var cmd = Buffer.alloc(10); cmd.writeUInt16BE(5, 0); // Command 5, compression cmd.writeUInt16BE(10, 2); // Command size, 10 bytes long - cmd[4] = 1; // Image type, 1 = JPEG + cmd[4] = obj.imageType; // Image type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP cmd[5] = obj.imageCompression; // Image compression level cmd.writeUInt16BE(obj.imageScaling, 6); // Scaling level cmd.writeUInt16BE(obj.imageFrameRate, 8); // Frame rate timer diff --git a/public/scripts/agent-desktop-0.0.2.js b/public/scripts/agent-desktop-0.0.2.js index f288e957..008a46cc 100644 --- a/public/scripts/agent-desktop-0.0.2.js +++ b/public/scripts/agent-desktop-0.0.2.js @@ -41,6 +41,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { obj.sessionid = 0; obj.username; obj.oldie = false; + obj.ImageType = 1; // 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP obj.CompressionLevel = 50; obj.ScalingLevel = 1024; obj.FrameRateTimer = 100; @@ -174,11 +175,11 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x01)); } - obj.SendCompressionLevel = function (type, level, scaling, frametimer) { + obj.SendCompressionLevel = function (type, level, scaling, frametimer) { // Type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP + obj.ImageType = type; if (level) { obj.CompressionLevel = level; } if (scaling) { obj.ScalingLevel = scaling; } if (frametimer) { obj.FrameRateTimer = frametimer; } - //console.log('SendCompressionLevel', obj.CompressionLevel, obj.ScalingLevel, obj.FrameRateTimer); obj.send(String.fromCharCode(0x00, 0x05, 0x00, 0x0A, type, obj.CompressionLevel) + obj.shortToStr(obj.ScalingLevel) + obj.shortToStr(obj.FrameRateTimer)); } @@ -196,7 +197,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { obj.ScreenHeight = obj.height = height; obj.KillDraw = obj.tilesReceived; while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); } - obj.SendCompressionLevel(1); + obj.SendCompressionLevel(obj.ImageType); obj.SendUnPause(); obj.SendRemoteInputLock(2); // Query input lock state // No need to event the display size change now, it will be evented on first draw. @@ -739,7 +740,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { if (obj.xxKeyInputGrab == true) return; document.onkeyup = obj.xxKeyUp; document.onkeydown = obj.xxKeyDown; - document.onkeypress = obj.xxKeyPress; + document.onkeypress = obj.xxKeyPress;c obj.xxKeyInputGrab = true; } diff --git a/public/scripts/common-0.0.1.js b/public/scripts/common-0.0.1.js index b9fc0b12..8f934f51 100644 --- a/public/scripts/common-0.0.1.js +++ b/public/scripts/common-0.0.1.js @@ -127,4 +127,26 @@ function parseUriArgs() { if (!isSafeString(r[name])) { delete r[name]; } else { var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } } } return r; +} + +// check_webp_feature: +// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'. +// 'callback(feature, isSupported)' will be passed back the detection result (in an asynchronous way!) +// From: https://stackoverflow.com/questions/5573096/detecting-webp-support +function check_webp_feature(feature, callback) { + var kTestImages = { + lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA"//, + //lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==", + //alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==", + //animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA" + }; + var img = new Image(); + img.onload = function () { + var result = (img.width > 0) && (img.height > 0); + callback(feature, result); + }; + img.onerror = function () { + callback(feature, false); + }; + img.src = "data:image/webp;base64," + kTestImages[feature]; } \ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index daa77d10..c1ca62f5 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -1251,6 +1251,10 @@ var p12TermConsoleMsgTimer = null; var p13FilesConsoleMsgTimer = null; + // Check if WebP is supported + var webpSupport = false; + check_webp_feature('lossy', function (f, x) { webpSupport = x; }); + function startup() { if ((features & 32) == 0) { // Guard against other site's top frames (web bugs). @@ -4020,6 +4024,7 @@ p11clearConsoleMsg(); } } + desktop.m.ImageType = webpSupport ? 4 : 1; // Send 4 if WebP is supported, otherwise send 1 for JPEG. desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best. desktop.m.ScalingLevel = desktopsettings.scaling; desktop.m.FrameRateTimer = desktopsettings.framerate; @@ -4106,7 +4111,7 @@ applyDesktopSettings(); if (desktop) { if (desktop.contype == 1) { - if (desktop.State != 0) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); } + if (desktop.State != 0) { desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); } } if (desktop.contype == 2) { if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); } diff --git a/views/default.handlebars b/views/default.handlebars index d62d5c31..4d5d9ad2 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1393,6 +1393,9 @@ mql.addEventListener('change', function() { console.log('Dark Change'); }); */ + // Check if WebP is supported + var webpSupport = false; + check_webp_feature('lossy', function (f, x) { webpSupport = x; }); function startup() { if ((features & 32) == 0) { @@ -4083,7 +4086,7 @@ c.removeAttribute('onmousemove'); Q('xkvmid_' + shortid).appendChild(c); QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]); - if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); } + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); } desktop.shortid = shortid; desktop.onStateChanged = onMultiDesktopStateChange; desktop.m.onRemoteInputLockChanged = null; @@ -4506,7 +4509,7 @@ multidesktopsettings.framerate = d7framelimiter.value; localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings)); // Make changes to all current connections - for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); } + for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); } } function connectMultiDesktop(node, contype) { @@ -4537,6 +4540,7 @@ desk.attemptWebRTC = attemptWebRTC; desk.onStateChanged = onMultiDesktopStateChange; //desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); } + desk.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG. desk.m.CompressionLevel = multidesktopsettings.quality; desk.m.ScalingLevel = multidesktopsettings.scaling; if (multidesktopsettings.framerate) { desk.m.FrameRateTimer = multidesktopsettings.framerate; } @@ -7745,7 +7749,7 @@ c.removeAttribute('onclick'); Q('DeskParent').appendChild(c); desktop = xdesk; - if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); } + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); } desktop.onStateChanged = onDesktopStateChange; desktop.onMetadataChange = function(metadata) { updateMetadata(desktop, 'deskmetadata'); } if ((features2 & 0x2000) != 0) desktop.m.stopInput = true; @@ -7913,6 +7917,7 @@ webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m); webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation); webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust; + webRtcDesktop.softdesktop.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG. if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best. if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; } webRtcDesktop.softdesktop.Start(); @@ -7981,6 +7986,7 @@ } } desktop.onMetadataChange = function(metadata) { updateMetadata(desktop, 'deskmetadata'); } + desktop.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG. desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best. desktop.m.ScalingLevel = desktopsettings.scaling; if (desktopsettings.framerate) { desktop.m.FrameRateTimer = desktopsettings.framerate; } @@ -8184,7 +8190,7 @@ desktop.m.SwapMouse = desktopsettings.swapmouse; desktop.m.remoteKeyMap = desktopsettings.remotekeymap; if (desktop.State != 0) { - desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); + desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); } } if (desktop.contype == 2) {