Skip to content

Commit

Permalink
Add ability to set compression level
Browse files Browse the repository at this point in the history
Fixes github issue novnc#1382.
  • Loading branch information
samhed committed May 1, 2020
1 parent a672168 commit 479d8ce
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 1 deletion.
17 changes: 17 additions & 0 deletions app/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1349,6 +1354,18 @@ const UI = {
/* ------^-------
* /QUALITY
* ==============
* COMPRESSION
* ------v------*/

updateCompression() {
if (!UI.rfb) return;

UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
},

/* ------^-------
* /COMPRESSION
* ==============
* KEYBOARD
* ------v------*/

Expand Down
23 changes: 22 additions & 1 deletion core/rfb.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export default class RFB extends EventTargetMixin {
}

this._qualityLevel = 6;
this._compressionLevel = 2;
}

// ===== PROPERTIES =====
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/EMBEDDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
102 changes: 102 additions & 0 deletions tests/test.rfb.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down
4 changes: 4 additions & 0 deletions vnc.html
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ <h1 class="noVNC_logo" translate="no"><span>no</span><br>VNC</h1>
<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>
Expand Down

0 comments on commit 479d8ce

Please sign in to comment.