summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Trebler <at@edrilling.no>2020-02-10 12:44:36 +0100
committerAndrey Trebler <at@edrilling.no>2020-02-28 13:14:19 +0100
commitefd1f8a4f2acbd40833aa2a5fec2ed4a598e6753 (patch)
treeeabf7122b3d020cb3e75b756c00b0c5d277a8901
parentceb8ef4ec1a21bc5917185d43360aa78ff735afe (diff)
downloadnovnc-efd1f8a4f2acbd40833aa2a5fec2ed4a598e6753.tar.gz
adds qualityLevel property to RFB class for updating JPEG quality level encoding on the fly
-rw-r--r--core/rfb.js24
-rw-r--r--core/util/polyfill.js9
-rw-r--r--docs/API.md5
-rw-r--r--tests/test.rfb.js102
4 files changed, 138 insertions, 2 deletions
diff --git a/core/rfb.js b/core/rfb.js
index 536ea25..72f279a 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -275,6 +275,8 @@ export default class RFB extends EventTargetMixin {
Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");
this._showDotCursor = options.showDotCursor;
}
+
+ this._qualityLevel = 6;
}
// ===== PROPERTIES =====
@@ -337,6 +339,26 @@ export default class RFB extends EventTargetMixin {
get background() { return this._screen.style.background; }
set background(cssValue) { this._screen.style.background = cssValue; }
+ get qualityLevel() {
+ return this._qualityLevel;
+ }
+ set qualityLevel(qualityLevel) {
+ if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) {
+ Log.Error("qualityLevel must be an integer between 0 and 9");
+ return;
+ }
+
+ if (this._qualityLevel === qualityLevel) {
+ return;
+ }
+
+ this._qualityLevel = qualityLevel;
+
+ if (this._rfb_connection_state === 'connected') {
+ this._sendEncodings();
+ }
+ }
+
// ===== PUBLIC METHODS =====
disconnect() {
@@ -1294,7 +1316,7 @@ export default class RFB extends EventTargetMixin {
encs.push(encodings.encodingRaw);
// Psuedo-encoding settings
- encs.push(encodings.pseudoEncodingQualityLevel0 + 6);
+ encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
encs.push(encodings.pseudoEncodingCompressLevel0 + 2);
encs.push(encodings.pseudoEncodingDesktopSize);
diff --git a/core/util/polyfill.js b/core/util/polyfill.js
index 648ceeb..0e458c8 100644
--- a/core/util/polyfill.js
+++ b/core/util/polyfill.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2020 The noVNC Authors
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
*/
@@ -52,3 +52,10 @@ if (typeof Object.assign != 'function') {
window.CustomEvent = CustomEvent;
}
})();
+
+/* Number.isInteger() (taken from MDN) */
+Number.isInteger = Number.isInteger || function isInteger(value) {
+ return typeof value === 'number' &&
+ isFinite(value) &&
+ Math.floor(value) === value;
+};
diff --git a/docs/API.md b/docs/API.md
index aa6337f..1b00179 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -64,6 +64,11 @@ protocol stream.
to the element containing the remote session screen. The default value is `rgb(40, 40, 40)`
(solid gray color).
+`qualityLevel`
+ - Is an `int` in range `[0-9]` controlling the desired JPEG quality.
+ Value `0` implies low quality and `9` implies high quality.
+ Default value is `6`.
+
`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/tests/test.rfb.js b/tests/test.rfb.js
index 41232ae..4e27393 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -2865,6 +2865,108 @@ describe('Remote Frame Buffer Protocol Client', function () {
// error events do nothing
});
});
+
+ describe('Quality level setting', function () {
+ const defaultQuality = 6;
+
+ let client;
+
+ beforeEach(function () {
+ client = make_rfb();
+ sinon.spy(RFB.messages, "clientEncodings");
+ });
+
+ afterEach(function () {
+ RFB.messages.clientEncodings.restore();
+ });
+
+ it(`should equal ${defaultQuality} by default`, function () {
+ expect(client._qualityLevel).to.equal(defaultQuality);
+ });
+
+ it('should ignore non-integers when set', function () {
+ client.qualityLevel = '1';
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = 1.5;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = null;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = undefined;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = {};
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+ });
+
+ it('should ignore integers out of range [0, 9]', function () {
+ client.qualityLevel = -1;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = 10;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+ });
+
+ it('should send clientEncodings with new quality value', function () {
+ let newQuality;
+
+ newQuality = 8;
+ client.qualityLevel = newQuality;
+ expect(client.qualityLevel).to.equal(newQuality);
+ expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+ expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality);
+ });
+
+ it('should not send clientEncodings if quality is the same', function () {
+ let newQuality;
+
+ newQuality = 2;
+ client.qualityLevel = newQuality;
+ expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+ expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality);
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client.qualityLevel = newQuality;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+ });
+
+ it('should not send clientEncodings if not in connected state', function () {
+ let newQuality;
+
+ client._rfb_connection_state = '';
+ newQuality = 2;
+ client.qualityLevel = newQuality;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client._rfb_connection_state = 'connnecting';
+ newQuality = 6;
+ client.qualityLevel = newQuality;
+ expect(RFB.messages.clientEncodings).to.not.have.been.called;
+
+ RFB.messages.clientEncodings.resetHistory();
+
+ client._rfb_connection_state = 'connected';
+ newQuality = 5;
+ client.qualityLevel = newQuality;
+ expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
+ expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality);
+ });
+ });
});
describe('RFB messages', function () {