summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Mannehed <samuel@cendio.se>2020-05-01 16:14:15 +0200
committerSamuel Mannehed <samuel@cendio.se>2020-05-01 16:14:15 +0200
commit67ed5e1643a35d858434fc04d6f96e7aa338a68e (patch)
tree7921e41fa5fa46455769db040275ce9e76fb4c87
parente7fa686f329c3fb9e391387e0fdf28de1241f4a0 (diff)
downloadnovnc-compressionlevel.tar.gz
Add ability to set compression levelcompressionlevel
Fixes github issue #1382.
-rw-r--r--app/ui.js17
-rw-r--r--core/rfb.js23
-rw-r--r--docs/API.md8
-rw-r--r--docs/EMBEDDING.md2
-rw-r--r--tests/test.rfb.js102
-rw-r--r--vnc.html4
6 files changed, 155 insertions, 1 deletions
diff --git a/app/ui.js b/app/ui.js
index 32b6e98..61ddffe 100644
--- 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------*/
diff --git a/core/rfb.js b/core/rfb.js
index 0593c19..4a8483f 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -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);
diff --git a/docs/API.md b/docs/API.md
index db43ec6..e6b0e66 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -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. This only
+ applies to connections using the Tight encoding. 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
diff --git a/docs/EMBEDDING.md b/docs/EMBEDDING.md
index 3f85f4b..6a5dcd8 100644
--- a/docs/EMBEDDING.md
+++ b/docs/EMBEDDING.md
@@ -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.
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index 4e27393..a8975c2 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -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 () {
diff --git a/vnc.html b/vnc.html
index 571ca20..a1bbb21 100644
--- a/vnc.html
+++ b/vnc.html
@@ -211,6 +211,10 @@
<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>