summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsamhed <samuel@cendio.se>2016-06-02 16:41:38 +0200
committersamhed <samuel@cendio.se>2016-08-26 09:15:18 +0200
commit117c94d1e9d9c1f0929291b7f7bcd31d8b30ac92 (patch)
tree1b3d5a52de3e6cee7a911a133d475f38ba5fcf50
parent3df13262394515efe5877ce33fd0dbdf35e1b743 (diff)
downloadnovnc-continuousupdates.tar.gz
Add support for ContinuousUpdatescontinuousupdates
Instead of requesting frame buffer updates we can, if the server supports it, continuously recieve frame buffer updates at a rate determined by the server. The server can use fencing messages and measure response times to determine how often it will continue to send updates.
-rw-r--r--include/rfb.js59
-rw-r--r--tests/test.rfb.js70
2 files changed, 124 insertions, 5 deletions
diff --git a/include/rfb.js b/include/rfb.js
index 71672ff..fead91e 100644
--- a/include/rfb.js
+++ b/include/rfb.js
@@ -57,7 +57,8 @@ var RFB;
['Cursor', -239 ],
['ExtendedDesktopSize', -308 ],
['xvp', -309 ],
- ['Fence', -312 ]
+ ['Fence', -312 ],
+ ['ContinuousUpdates', -313 ]
];
this._encHandlers = {};
@@ -73,6 +74,9 @@ var RFB;
this._supportsFence = false;
+ this._supportsContinuousUpdates = false;
+ this._enabledContinuousUpdates = false;
+
// Frame buffer update state
this._FBU = {
rects: 0,
@@ -975,7 +979,7 @@ var RFB;
RFB.messages.pixelFormat(this._sock, this._fb_Bpp, this._fb_depth, this._true_color);
RFB.messages.clientEncodings(this._sock, this._encodings, this._local_cursor, this._true_color);
- RFB.messages.fbUpdateRequests(this._sock, this._display.getCleanDirtyReset(), this._fb_width, this._fb_height);
+ RFB.messages.fbUpdateRequests(this._sock, false, this._display.getCleanDirtyReset(), this._fb_width, this._fb_height);
this._timing.fbu_rt_start = (new Date()).getTime();
this._timing.pixels = 0;
@@ -1116,7 +1120,10 @@ var RFB;
case 0: // FramebufferUpdate
var ret = this._framebufferUpdate();
if (ret) {
- RFB.messages.fbUpdateRequests(this._sock, this._display.getCleanDirtyReset(), this._fb_width, this._fb_height);
+ RFB.messages.fbUpdateRequests(this._sock,
+ this._enabledContinuousUpdates,
+ this._display.getCleanDirtyReset(),
+ this._fb_width, this._fb_height);
}
return ret;
@@ -1131,6 +1138,20 @@ var RFB;
case 3: // ServerCutText
return this._handle_server_cut_text();
+ case 150: // EndOfContinuousUpdates
+ var first = !(this._supportsContinuousUpdates);
+ this._supportsContinuousUpdates = true;
+ this._enabledContinuousUpdates = false;
+ if (first) {
+ this._enabledContinuousUpdates = true;
+ this._updateContinuousUpdates();
+ Util.Info("Enabling continuous updates.");
+ } else {
+ // FIXME: We need to send a framebufferupdaterequest here
+ // if we add support for turning off continuous updates
+ }
+ return true;
+
case 248: // ServerFence
return this._handle_server_fence_msg();
@@ -1245,6 +1266,13 @@ var RFB;
return true; // We finished this FBU
},
+
+ _updateContinuousUpdates: function() {
+ if (!this._enabledContinuousUpdates) { return; }
+
+ RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0,
+ this._fb_width, this._fb_height);
+ }
};
Util.make_properties(RFB, [
@@ -1419,6 +1447,26 @@ var RFB;
sock.flush();
},
+ enableContinuousUpdates: function (sock, enable, x, y, width, height) {
+ var buff = sock._sQ;
+ var offset = sock._sQlen;
+
+ buff[offset] = 150; // msg-type
+ buff[offset + 1] = enable; // enable-flag
+
+ buff[offset + 2] = x >> 8; // x
+ buff[offset + 3] = x;
+ buff[offset + 4] = y >> 8; // y
+ buff[offset + 5] = y;
+ buff[offset + 6] = width >> 8; // width
+ buff[offset + 7] = width;
+ buff[offset + 8] = height >> 8; // height
+ buff[offset + 9] = height;
+
+ sock._sQlen += 10;
+ sock.flush();
+ },
+
pixelFormat: function (sock, bpp, depth, true_color) {
var buff = sock._sQ;
var offset = sock._sQlen;
@@ -1490,12 +1538,12 @@ var RFB;
sock.flush();
},
- fbUpdateRequests: function (sock, cleanDirty, fb_width, fb_height) {
+ fbUpdateRequests: function (sock, onlyNonInc, cleanDirty, fb_width, fb_height) {
var offsetIncrement = 0;
var cb = cleanDirty.cleanBox;
var w, h;
- if (cb.w > 0 && cb.h > 0) {
+ if (!onlyNonInc && (cb.w > 0 && cb.h > 0)) {
w = typeof cb.w === "undefined" ? fb_width : cb.w;
h = typeof cb.h === "undefined" ? fb_height : cb.h;
// Request incremental for clean box
@@ -2102,6 +2150,7 @@ var RFB;
this._display.resize(this._fb_width, this._fb_height);
this._onFBResize(this, this._fb_width, this._fb_height);
this._timing.fbu_rt_start = (new Date()).getTime();
+ this._updateContinuousUpdates();
this._FBU.bytes = 0;
this._FBU.rects -= 1;
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index be6aa1b..65ce5f8 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -1197,6 +1197,33 @@ describe('Remote Frame Buffer Protocol Client', function() {
expect(client._sock).to.have.sent(expected_msg._sQ);
});
+ it('should only request non-incremental rects in continuous updates mode', function () {
+ var expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: function() {}};
+ var expected_cdr = { cleanBox: { x: 0, y: 0, w: 120, h: 20 },
+ dirtyBoxes: [ { x: 120, y: 0, w: 120, h: 20 } ] };
+
+ RFB.messages.fbUpdateRequest(expected_msg, false, 120, 0, 120, 20);
+
+ client._enabledContinuousUpdates = true;
+ client._framebufferUpdate = function () { return true; };
+ client._display.getCleanDirtyReset = function () { return expected_cdr; };
+ client._sock._websocket._receive_data(new Uint8Array([0]));
+
+ expect(client._sock).to.have.sent(expected_msg._sQ);
+ });
+
+ it('should not send a request in continuous updates mode when clean', function () {
+ var expected_cdr = { cleanBox: { x: 0, y: 0, w: 240, h: 20 },
+ dirtyBoxes: [] };
+
+ client._enabledContinuousUpdates = true;
+ client._framebufferUpdate = function () { return true; };
+ client._display.getCleanDirtyReset = function () { return expected_cdr; };
+ client._sock._websocket._receive_data(new Uint8Array([0]));
+
+ expect(client._sock._websocket._get_sent_data()).to.have.length(0);
+ });
+
it('should parse out information from a header before any actual data comes in', function () {
client.set_onFBUReceive(sinon.spy());
var rect_info = { x: 8, y: 11, width: 27, height: 32, encoding: 0x02, encodingName: 'RRE' };
@@ -1730,6 +1757,49 @@ describe('Remote Frame Buffer Protocol Client', function() {
expect(client._sock).to.have.sent(expected_msg._sQ);
});
+ it('should enable continuous updates on first EndOfContinousUpdates', function () {
+ var expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: function() {}};
+
+ RFB.messages.enableContinuousUpdates(expected_msg, true, 0, 0, 640, 20);
+
+ expect(client._enabledContinuousUpdates).to.be.false;
+
+ client._sock._websocket._receive_data(new Uint8Array([150]));
+
+ expect(client._enabledContinuousUpdates).to.be.true;
+ expect(client._sock).to.have.sent(expected_msg._sQ);
+ });
+
+ it('should disable continuous updates on subsequent EndOfContinousUpdates', function () {
+ client._enabledContinuousUpdates = true;
+ client._supportsContinuousUpdates = true;
+
+ client._sock._websocket._receive_data(new Uint8Array([150]));
+
+ expect(client._enabledContinuousUpdates).to.be.false;
+ });
+
+ it('should update continuous updates on resize', function () {
+ var expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: function() {}};
+ RFB.messages.enableContinuousUpdates(expected_msg, true, 0, 0, 90, 700);
+
+ client._FBU.width = 450;
+ client._FBU.height = 160;
+
+ client._encHandlers.handle_FB_resize();
+
+ expect(client._sock._websocket._get_sent_data()).to.have.length(0);
+
+ client._enabledContinuousUpdates = true;
+
+ client._FBU.width = 90;
+ client._FBU.height = 700;
+
+ client._encHandlers.handle_FB_resize();
+
+ expect(client._sock).to.have.sent(expected_msg._sQ);
+ });
+
it('should fail on an unknown message type', function () {
client._sock._websocket._receive_data(new Uint8Array([87]));
expect(client._rfb_state).to.equal('failed');