]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Add ability to set compression level
authorSamuel Mannehed <samuel@cendio.se>
Fri, 1 May 2020 14:14:15 +0000 (16:14 +0200)
committerSamuel Mannehed <samuel@cendio.se>
Fri, 1 May 2020 18:47:36 +0000 (20:47 +0200)
Fixes github issue #1382.

app/ui.js
core/rfb.js
docs/API.md
docs/EMBEDDING.md
tests/test.rfb.js
vnc.html

index 32b6e9850c95fc4887ad11360f9c9039e51f1bec..61ddffe0e7d8269c77885afd6ef430b4a58473f0 100644 (file)
--- a/app/ui.js
+++ b/app/ui.js
@@ -162,6 +162,7 @@ const UI = {
         UI.initSetting('view_clip', false);
         UI.initSetting('resize', 'off');
         UI.initSetting('quality', 6);
+        UI.initSetting('compression', 2);
         UI.initSetting('shared', true);
         UI.initSetting('view_only', false);
         UI.initSetting('show_dot', false);
@@ -350,6 +351,8 @@ const UI = {
         UI.addSettingChangeHandler('resize', UI.updateViewClip);
         UI.addSettingChangeHandler('quality');
         UI.addSettingChangeHandler('quality', UI.updateQuality);
+        UI.addSettingChangeHandler('compression');
+        UI.addSettingChangeHandler('compression', UI.updateCompression);
         UI.addSettingChangeHandler('view_clip');
         UI.addSettingChangeHandler('view_clip', UI.updateViewClip);
         UI.addSettingChangeHandler('shared');
@@ -841,6 +844,7 @@ const UI = {
         UI.updateSetting('view_clip');
         UI.updateSetting('resize');
         UI.updateSetting('quality');
+        UI.updateSetting('compression');
         UI.updateSetting('shared');
         UI.updateSetting('view_only');
         UI.updateSetting('path');
@@ -1043,6 +1047,7 @@ const UI = {
         UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
         UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
         UI.rfb.qualityLevel = parseInt(UI.getSetting('quality'));
+        UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
         UI.rfb.showDotCursor = UI.getSetting('show_dot');
 
         UI.updateViewOnly(); // requires UI.rfb
@@ -1349,6 +1354,18 @@ const UI = {
 /* ------^-------
  *   /QUALITY
  * ==============
+ *  COMPRESSION
+ * ------v------*/
+
+    updateCompression() {
+        if (!UI.rfb) return;
+
+        UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
+    },
+
+/* ------^-------
+ *  /COMPRESSION
+ * ==============
  *    KEYBOARD
  * ------v------*/
 
index 0593c195aab048a3d4affdaf821221e9d6cb99c0..4a8483fdd8fdb68b4694488d4bd5337f806a23eb 100644 (file)
@@ -278,6 +278,7 @@ export default class RFB extends EventTargetMixin {
         }
 
         this._qualityLevel = 6;
+        this._compressionLevel = 2;
     }
 
     // ===== PROPERTIES =====
@@ -360,6 +361,26 @@ export default class RFB extends EventTargetMixin {
         }
     }
 
+    get compressionLevel() {
+        return this._compressionLevel;
+    }
+    set compressionLevel(compressionLevel) {
+        if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {
+            Log.Error("compressionLevel must be an integer between 0 and 9");
+            return;
+        }
+
+        if (this._compressionLevel === compressionLevel) {
+            return;
+        }
+
+        this._compressionLevel = compressionLevel;
+
+        if (this._rfb_connection_state === 'connected') {
+            this._sendEncodings();
+        }
+    }
+
     // ===== PUBLIC METHODS =====
 
     disconnect() {
@@ -1411,7 +1432,7 @@ export default class RFB extends EventTargetMixin {
 
         // Psuedo-encoding settings
         encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
-        encs.push(encodings.pseudoEncodingCompressLevel0 + 2);
+        encs.push(encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);
 
         encs.push(encodings.pseudoEncodingDesktopSize);
         encs.push(encodings.pseudoEncodingLastRect);
index db43ec67fe3595b214667b5c05a0af342c6ea4d9..59b7cf17418c1b432726c7c8e4fb726abdc80cd8 100644 (file)
@@ -69,6 +69,14 @@ protocol stream.
     Value `0` implies low quality and `9` implies high quality.
     Default value is `6`.
 
+`compressionLevel`
+  - Is an `int` in range `[0-9]` controlling the desired compression
+    level. Value `0` means no compression. Level 1 uses a minimum of CPU
+    resources and achieves weak compression ratios, while level 9 offers
+    best compression but is slow in terms of CPU consumption on the server
+    side. Use high levels with very slow network connections.
+    Default value is `2`.
+
 `capabilities` *Read only*
   - Is an `Object` indicating which optional extensions are available
     on the server. Some methods may only be called if the corresponding
index 3f85f4b33d3bb271cedf744112c61a3310705f97..6a5dcd801147a9d9d203a18046cccf1d0fee8dea 100644 (file)
@@ -63,6 +63,8 @@ query string. Currently the following options are available:
 
 * `quality` - The session JPEG quality level. Can be `0` to `9`.
 
+* `compression` - The session compression level. Can be `0` to `9`.
+
 * `show_dot` - If a dot cursor should be shown when the remote server provides
   no local cursor, or provides a fully-transparent (invisible) cursor.
 
index 4e2739358390bdd3caba3689553acc0b028c1858..a8975c2e775356dc56e889670232b3f4b1cd7d1b 100644 (file)
@@ -2967,6 +2967,108 @@ describe('Remote Frame Buffer Protocol Client', function () {
             expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality);
         });
     });
+
+    describe('Compression level setting', function () {
+        const defaultCompression = 2;
+
+        let client;
+
+        beforeEach(function () {
+            client = make_rfb();
+            sinon.spy(RFB.messages, "clientEncodings");
+        });
+
+        afterEach(function () {
+            RFB.messages.clientEncodings.restore();
+        });
+
+        it(`should equal ${defaultCompression} by default`, function () {
+            expect(client._compressionLevel).to.equal(defaultCompression);
+        });
+
+        it('should ignore non-integers when set', function () {
+            client.compressionLevel = '1';
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = 1.5;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = null;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = undefined;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = {};
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+        });
+
+        it('should ignore integers out of range [0, 9]', function () {
+            client.compressionLevel = -1;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = 10;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+        });
+
+        it('should send clientEncodings with new compression value', function () {
+            let newCompression;
+
+            newCompression = 5;
+            client.compressionLevel = newCompression;
+            expect(client.compressionLevel).to.equal(newCompression);
+            expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+            expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
+        });
+
+        it('should not send clientEncodings if compression is the same', function () {
+            let newCompression;
+
+            newCompression = 9;
+            client.compressionLevel = newCompression;
+            expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+            expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client.compressionLevel = newCompression;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+        });
+
+        it('should not send clientEncodings if not in connected state', function () {
+            let newCompression;
+
+            client._rfb_connection_state = '';
+            newCompression = 7;
+            client.compressionLevel = newCompression;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client._rfb_connection_state = 'connnecting';
+            newCompression = 6;
+            client.compressionLevel = newCompression;
+            expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+            RFB.messages.clientEncodings.resetHistory();
+
+            client._rfb_connection_state = 'connected';
+            newCompression = 5;
+            client.compressionLevel = newCompression;
+            expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+            expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
+        });
+    });
 });
 
 describe('RFB messages', function () {
index 571ca20acb2be1b75d347d9e27e0a481e1283336..a1bbb21998eac5cb0dbcde49297960fce3c48661 100644 (file)
--- a/vnc.html
+++ b/vnc.html
                                 <label for="noVNC_setting_quality">Quality:</label>
                                 <input id="noVNC_setting_quality" type="range" min="0" max="9" value="6">
                             </li>
+                            <li>
+                                <label for="noVNC_setting_compression">Compression level:</label>
+                                <input id="noVNC_setting_compression" type="range" min="0" max="9" value="2">
+                            </li>
                             <li><hr></li>
                             <li>
                                 <label for="noVNC_setting_repeaterID">Repeater ID:</label>