Added remote desktop WebP support.

Ylian Saint-Hilaire committed Aug 10, 2021 at 21:50 UTC dea1df33b65824cc851b1eec42e06e38b4cde824
5 files changed +53 -13
meshdesktopmultiplex.js
+10 -4
@@ -82,6 +82,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
82 obj.lastDisplayInfoData = null; // Pointer to the last display information command from the agent (Number of displays).
83 obj.lastDisplayLocationData = null; // Pointer to the last display location and size command from the agent.
84 obj.desktopPaused = true; // Current desktop pause state, it's true if all viewers are paused.
85 + obj.imageType = 1; // Current image type, 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP
86 obj.imageCompression = 50; // Current image compression, this is the highest value of all viewers.
87 obj.imageScaling = 1024; // Current image scaling, this is the highest value of all viewers.
88 obj.imageFrameRate = 50; // Current framerate setting, this is the lowest values of all viewers.
@@ -107,6 +108,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
108 if (obj.viewers.indexOf(peer) >= 0) return true;
109 obj.viewers.push(peer);
110 peer.desktopPaused = true;
111 + peer.imageType = 1;
112 peer.imageCompression = 30;
113 peer.imageScaling = 1024;
114 peer.imageFrameRate = 100;
@@ -202,6 +204,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
204
205 // Aggressive clean up of the viewer
206 delete peer.desktopPaused;
207 + delete peer.imageType;
208 delete peer.imageCompression;
209 delete peer.imageScaling;
210 delete peer.imageFrameRate;
@@ -483,31 +486,34 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
486 break;
487 case 5: // Compression
488 if (data.length < 10) return;
486 - //viewer.imageType = data[4]; // Always 1=JPEG
489 + viewer.imageType = data[4]; // Image type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP
490 viewer.imageCompression = data[5];
491 viewer.imageScaling = data.readUInt16BE(6);
492 viewer.imageFrameRate = data.readUInt16BE(8);
490 - //console.log('Viewer-Compression', viewer.imageCompression, viewer.imageScaling, viewer.imageFrameRate);
493 + //console.log('Viewer-Compression', viewer.imageType, viewer.imageCompression, viewer.imageScaling, viewer.imageFrameRate);
494
495 // See if this changes anything
496 + var viewersimageType = null;
497 var viewersimageCompression = null;
498 var viewersimageScaling = null;
499 var viewersimageFrameRate = null;
500 for (var i in obj.viewers) {
501 + 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
502 if ((viewersimageCompression == null) || (obj.viewers[i].imageCompression > viewersimageCompression)) { viewersimageCompression = obj.viewers[i].imageCompression; };
503 if ((viewersimageScaling == null) || (obj.viewers[i].imageScaling > viewersimageScaling)) { viewersimageScaling = obj.viewers[i].imageScaling; };
504 if ((viewersimageFrameRate == null) || (obj.viewers[i].imageFrameRate < viewersimageFrameRate)) { viewersimageFrameRate = obj.viewers[i].imageFrameRate; };
505 }
506 if ((obj.imageCompression != viewersimageCompression) || (obj.imageScaling != viewersimageScaling) || (obj.imageFrameRate != viewersimageFrameRate)) {
507 // Update and send to agent new compression settings
508 + obj.imageType = viewersimageType;
509 obj.imageCompression = viewersimageCompression;
510 obj.imageScaling = viewersimageScaling;
511 obj.imageFrameRate = viewersimageFrameRate
506 - //console.log('Send-Agent-Compression', obj.imageCompression, obj.imageScaling, obj.imageFrameRate);
512 + //console.log('Send-Agent-Compression', obj.imageType, obj.imageCompression, obj.imageScaling, obj.imageFrameRate);
513 var cmd = Buffer.alloc(10);
514 cmd.writeUInt16BE(5, 0); // Command 5, compression
515 cmd.writeUInt16BE(10, 2); // Command size, 10 bytes long
510 - cmd[4] = 1; // Image type, 1 = JPEG
516 + cmd[4] = obj.imageType; // Image type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP
517 cmd[5] = obj.imageCompression; // Image compression level
518 cmd.writeUInt16BE(obj.imageScaling, 6); // Scaling level
519 cmd.writeUInt16BE(obj.imageFrameRate, 8); // Frame rate timer
public/scripts/agent-desktop-0.0.2.js
+5 -4
@@ -41,6 +41,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
41 obj.sessionid = 0;
42 obj.username;
43 obj.oldie = false;
44 + obj.ImageType = 1; // 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP
45 obj.CompressionLevel = 50;
46 obj.ScalingLevel = 1024;
47 obj.FrameRateTimer = 100;
@@ -174,11 +175,11 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
175 obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x01));
176 }
177
177 - obj.SendCompressionLevel = function (type, level, scaling, frametimer) {
178 + obj.SendCompressionLevel = function (type, level, scaling, frametimer) { // Type: 1 = JPEG, 2 = PNG, 3 = TIFF, 4 = WebP
179 + obj.ImageType = type;
180 if (level) { obj.CompressionLevel = level; }
181 if (scaling) { obj.ScalingLevel = scaling; }
182 if (frametimer) { obj.FrameRateTimer = frametimer; }
181 - //console.log('SendCompressionLevel', obj.CompressionLevel, obj.ScalingLevel, obj.FrameRateTimer);
183 obj.send(String.fromCharCode(0x00, 0x05, 0x00, 0x0A, type, obj.CompressionLevel) + obj.shortToStr(obj.ScalingLevel) + obj.shortToStr(obj.FrameRateTimer));
184 }
185
@@ -196,7 +197,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
197 obj.ScreenHeight = obj.height = height;
198 obj.KillDraw = obj.tilesReceived;
199 while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); }
199 - obj.SendCompressionLevel(1);
200 + obj.SendCompressionLevel(obj.ImageType);
201 obj.SendUnPause();
202 obj.SendRemoteInputLock(2); // Query input lock state
203 // 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) {
740 if (obj.xxKeyInputGrab == true) return;
741 document.onkeyup = obj.xxKeyUp;
742 document.onkeydown = obj.xxKeyDown;
742 - document.onkeypress = obj.xxKeyPress;
743 + document.onkeypress = obj.xxKeyPress;c
744 obj.xxKeyInputGrab = true;
745 }
746
public/scripts/common-0.0.1.js
+22
@@ -127,4 +127,26 @@ function parseUriArgs() {
127 if (!isSafeString(r[name])) { delete r[name]; } else { var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } }
128 }
129 return r;
130 +}
131 +
132 +// check_webp_feature:
133 +// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
134 +// 'callback(feature, isSupported)' will be passed back the detection result (in an asynchronous way!)
135 +// From: https://stackoverflow.com/questions/5573096/detecting-webp-support
136 +function check_webp_feature(feature, callback) {
137 + var kTestImages = {
138 + lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA"//,
139 + //lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
140 + //alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
141 + //animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
142 + };
143 + var img = new Image();
144 + img.onload = function () {
145 + var result = (img.width > 0) && (img.height > 0);
146 + callback(feature, result);
147 + };
148 + img.onerror = function () {
149 + callback(feature, false);
150 + };
151 + img.src = "data:image/webp;base64," + kTestImages[feature];
152 }
\ No newline at end of file
views/default-mobile.handlebars
+6 -1
@@ -1251,6 +1251,10 @@
1251 var p12TermConsoleMsgTimer = null;
1252 var p13FilesConsoleMsgTimer = null;
1253
1254 + // Check if WebP is supported
1255 + var webpSupport = false;
1256 + check_webp_feature('lossy', function (f, x) { webpSupport = x; });
1257 +
1258 function startup() {
1259 if ((features & 32) == 0) {
1260 // Guard against other site's top frames (web bugs).
@@ -4020,6 +4024,7 @@
4024 p11clearConsoleMsg();
4025 }
4026 }
4027 + desktop.m.ImageType = webpSupport ? 4 : 1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
4028 desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
4029 desktop.m.ScalingLevel = desktopsettings.scaling;
4030 desktop.m.FrameRateTimer = desktopsettings.framerate;
@@ -4106,7 +4111,7 @@
4111 applyDesktopSettings();
4112 if (desktop) {
4113 if (desktop.contype == 1) {
4109 - if (desktop.State != 0) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
4114 + if (desktop.State != 0) { desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
4115 }
4116 if (desktop.contype == 2) {
4117 if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
views/default.handlebars
+10 -4
@@ -1393,6 +1393,9 @@
1393 mql.addEventListener('change', function() { console.log('Dark Change'); });
1394 */
1395
1396 + // Check if WebP is supported
1397 + var webpSupport = false;
1398 + check_webp_feature('lossy', function (f, x) { webpSupport = x; });
1399
1400 function startup() {
1401 if ((features & 32) == 0) {
@@ -4083,7 +4086,7 @@
4086 c.removeAttribute('onmousemove');
4087 Q('xkvmid_' + shortid).appendChild(c);
4088 QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
4086 - if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4089 + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4090 desktop.shortid = shortid;
4091 desktop.onStateChanged = onMultiDesktopStateChange;
4092 desktop.m.onRemoteInputLockChanged = null;
@@ -4506,7 +4509,7 @@
4509 multidesktopsettings.framerate = d7framelimiter.value;
4510 localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
4511 // Make changes to all current connections
4509 - for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4512 + for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4513 }
4514
4515 function connectMultiDesktop(node, contype) {
@@ -4537,6 +4540,7 @@
4540 desk.attemptWebRTC = attemptWebRTC;
4541 desk.onStateChanged = onMultiDesktopStateChange;
4542 //desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
4543 + desk.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
4544 desk.m.CompressionLevel = multidesktopsettings.quality;
4545 desk.m.ScalingLevel = multidesktopsettings.scaling;
4546 if (multidesktopsettings.framerate) { desk.m.FrameRateTimer = multidesktopsettings.framerate; }
@@ -7745,7 +7749,7 @@
7749 c.removeAttribute('onclick');
7750 Q('DeskParent').appendChild(c);
7751 desktop = xdesk;
7748 - if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
7752 + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
7753 desktop.onStateChanged = onDesktopStateChange;
7754 desktop.onMetadataChange = function(metadata) { updateMetadata(desktop, 'deskmetadata'); }
7755 if ((features2 & 0x2000) != 0) desktop.m.stopInput = true;
@@ -7913,6 +7917,7 @@
7917 webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
7918 webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
7919 webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
7920 + webRtcDesktop.softdesktop.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
7921 if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
7922 if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
7923 webRtcDesktop.softdesktop.Start();
@@ -7981,6 +7986,7 @@
7986 }
7987 }
7988 desktop.onMetadataChange = function(metadata) { updateMetadata(desktop, 'deskmetadata'); }
7989 + desktop.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
7990 desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
7991 desktop.m.ScalingLevel = desktopsettings.scaling;
7992 if (desktopsettings.framerate) { desktop.m.FrameRateTimer = desktopsettings.framerate; }
@@ -8184,7 +8190,7 @@
8190 desktop.m.SwapMouse = desktopsettings.swapmouse;
8191 desktop.m.remoteKeyMap = desktopsettings.remotekeymap;
8192 if (desktop.State != 0) {
8187 - desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
8193 + desktop.m.SendCompressionLevel(webpSupport?4:1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
8194 }
8195 }
8196 if (desktop.contype == 2) {