Skip to content

Commit 67ed5e1

Browse files
committed
Add ability to set compression level
Fixes github issue #1382.
1 parent e7fa686 commit 67ed5e1

File tree

6 files changed

+155
-1
lines changed

6 files changed

+155
-1
lines changed

app/ui.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ const UI = {
162162
UI.initSetting('view_clip', false);
163163
UI.initSetting('resize', 'off');
164164
UI.initSetting('quality', 6);
165+
UI.initSetting('compression', 2);
165166
UI.initSetting('shared', true);
166167
UI.initSetting('view_only', false);
167168
UI.initSetting('show_dot', false);
@@ -350,6 +351,8 @@ const UI = {
350351
UI.addSettingChangeHandler('resize', UI.updateViewClip);
351352
UI.addSettingChangeHandler('quality');
352353
UI.addSettingChangeHandler('quality', UI.updateQuality);
354+
UI.addSettingChangeHandler('compression');
355+
UI.addSettingChangeHandler('compression', UI.updateCompression);
353356
UI.addSettingChangeHandler('view_clip');
354357
UI.addSettingChangeHandler('view_clip', UI.updateViewClip);
355358
UI.addSettingChangeHandler('shared');
@@ -841,6 +844,7 @@ const UI = {
841844
UI.updateSetting('view_clip');
842845
UI.updateSetting('resize');
843846
UI.updateSetting('quality');
847+
UI.updateSetting('compression');
844848
UI.updateSetting('shared');
845849
UI.updateSetting('view_only');
846850
UI.updateSetting('path');
@@ -1043,6 +1047,7 @@ const UI = {
10431047
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
10441048
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
10451049
UI.rfb.qualityLevel = parseInt(UI.getSetting('quality'));
1050+
UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
10461051
UI.rfb.showDotCursor = UI.getSetting('show_dot');
10471052

10481053
UI.updateViewOnly(); // requires UI.rfb
@@ -1349,6 +1354,18 @@ const UI = {
13491354
/* ------^-------
13501355
* /QUALITY
13511356
* ==============
1357+
* COMPRESSION
1358+
* ------v------*/
1359+
1360+
updateCompression() {
1361+
if (!UI.rfb) return;
1362+
1363+
UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
1364+
},
1365+
1366+
/* ------^-------
1367+
* /COMPRESSION
1368+
* ==============
13521369
* KEYBOARD
13531370
* ------v------*/
13541371

core/rfb.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ export default class RFB extends EventTargetMixin {
278278
}
279279

280280
this._qualityLevel = 6;
281+
this._compressionLevel = 2;
281282
}
282283

283284
// ===== PROPERTIES =====
@@ -360,6 +361,26 @@ export default class RFB extends EventTargetMixin {
360361
}
361362
}
362363

364+
get compressionLevel() {
365+
return this._compressionLevel;
366+
}
367+
set compressionLevel(compressionLevel) {
368+
if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {
369+
Log.Error("compressionLevel must be an integer between 0 and 9");
370+
return;
371+
}
372+
373+
if (this._compressionLevel === compressionLevel) {
374+
return;
375+
}
376+
377+
this._compressionLevel = compressionLevel;
378+
379+
if (this._rfb_connection_state === 'connected') {
380+
this._sendEncodings();
381+
}
382+
}
383+
363384
// ===== PUBLIC METHODS =====
364385

365386
disconnect() {
@@ -1411,7 +1432,7 @@ export default class RFB extends EventTargetMixin {
14111432

14121433
// Psuedo-encoding settings
14131434
encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
1414-
encs.push(encodings.pseudoEncodingCompressLevel0 + 2);
1435+
encs.push(encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);
14151436

14161437
encs.push(encodings.pseudoEncodingDesktopSize);
14171438
encs.push(encodings.pseudoEncodingLastRect);

docs/API.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ protocol stream.
6969
Value `0` implies low quality and `9` implies high quality.
7070
Default value is `6`.
7171

72+
`compressionLevel`
73+
- Is an `int` in range `[0-9]` controlling the desired compression
74+
level. Value `0` means no compression. Level 1 uses a minimum of CPU
75+
resources and achieves weak compression ratios, while level 9 offers
76+
best compression but is slow in terms of CPU consumption on the server
77+
side. Use high levels with very slow network connections. This only
78+
applies to connections using the Tight encoding. Default value is `2`.
79+
7280
`capabilities` *Read only*
7381
- Is an `Object` indicating which optional extensions are available
7482
on the server. Some methods may only be called if the corresponding

docs/EMBEDDING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ query string. Currently the following options are available:
6363

6464
* `quality` - The session JPEG quality level. Can be `0` to `9`.
6565

66+
* `compression` - The session compression level. Can be `0` to `9`.
67+
6668
* `show_dot` - If a dot cursor should be shown when the remote server provides
6769
no local cursor, or provides a fully-transparent (invisible) cursor.
6870

tests/test.rfb.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2967,6 +2967,108 @@ describe('Remote Frame Buffer Protocol Client', function () {
29672967
expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality);
29682968
});
29692969
});
2970+
2971+
describe('Compression level setting', function () {
2972+
const defaultCompression = 2;
2973+
2974+
let client;
2975+
2976+
beforeEach(function () {
2977+
client = make_rfb();
2978+
sinon.spy(RFB.messages, "clientEncodings");
2979+
});
2980+
2981+
afterEach(function () {
2982+
RFB.messages.clientEncodings.restore();
2983+
});
2984+
2985+
it(`should equal ${defaultCompression} by default`, function () {
2986+
expect(client._compressionLevel).to.equal(defaultCompression);
2987+
});
2988+
2989+
it('should ignore non-integers when set', function () {
2990+
client.compressionLevel = '1';
2991+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
2992+
2993+
RFB.messages.clientEncodings.resetHistory();
2994+
2995+
client.compressionLevel = 1.5;
2996+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
2997+
2998+
RFB.messages.clientEncodings.resetHistory();
2999+
3000+
client.compressionLevel = null;
3001+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3002+
3003+
RFB.messages.clientEncodings.resetHistory();
3004+
3005+
client.compressionLevel = undefined;
3006+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3007+
3008+
RFB.messages.clientEncodings.resetHistory();
3009+
3010+
client.compressionLevel = {};
3011+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3012+
});
3013+
3014+
it('should ignore integers out of range [0, 9]', function () {
3015+
client.compressionLevel = -1;
3016+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3017+
3018+
RFB.messages.clientEncodings.resetHistory();
3019+
3020+
client.compressionLevel = 10;
3021+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3022+
});
3023+
3024+
it('should send clientEncodings with new compression value', function () {
3025+
let newCompression;
3026+
3027+
newCompression = 5;
3028+
client.compressionLevel = newCompression;
3029+
expect(client.compressionLevel).to.equal(newCompression);
3030+
expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
3031+
expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
3032+
});
3033+
3034+
it('should not send clientEncodings if compression is the same', function () {
3035+
let newCompression;
3036+
3037+
newCompression = 9;
3038+
client.compressionLevel = newCompression;
3039+
expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
3040+
expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
3041+
3042+
RFB.messages.clientEncodings.resetHistory();
3043+
3044+
client.compressionLevel = newCompression;
3045+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3046+
});
3047+
3048+
it('should not send clientEncodings if not in connected state', function () {
3049+
let newCompression;
3050+
3051+
client._rfb_connection_state = '';
3052+
newCompression = 7;
3053+
client.compressionLevel = newCompression;
3054+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3055+
3056+
RFB.messages.clientEncodings.resetHistory();
3057+
3058+
client._rfb_connection_state = 'connnecting';
3059+
newCompression = 6;
3060+
client.compressionLevel = newCompression;
3061+
expect(RFB.messages.clientEncodings).to.not.have.been.called;
3062+
3063+
RFB.messages.clientEncodings.resetHistory();
3064+
3065+
client._rfb_connection_state = 'connected';
3066+
newCompression = 5;
3067+
client.compressionLevel = newCompression;
3068+
expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
3069+
expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression);
3070+
});
3071+
});
29703072
});
29713073

29723074
describe('RFB messages', function () {

vnc.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ <h1 class="noVNC_logo" translate="no"><span>no</span><br>VNC</h1>
211211
<label for="noVNC_setting_quality">Quality:</label>
212212
<input id="noVNC_setting_quality" type="range" min="0" max="9" value="6">
213213
</li>
214+
<li>
215+
<label for="noVNC_setting_compression">Compression level:</label>
216+
<input id="noVNC_setting_compression" type="range" min="0" max="9" value="2">
217+
</li>
214218
<li><hr></li>
215219
<li>
216220
<label for="noVNC_setting_repeaterID">Repeater ID:</label>

0 commit comments

Comments
 (0)