Add support for ContinuousUpdates
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.
This commit is contained in:
parent
3df1326239
commit
76a86ff514
@ -57,7 +57,8 @@ var RFB;
|
|||||||
['Cursor', -239 ],
|
['Cursor', -239 ],
|
||||||
['ExtendedDesktopSize', -308 ],
|
['ExtendedDesktopSize', -308 ],
|
||||||
['xvp', -309 ],
|
['xvp', -309 ],
|
||||||
['Fence', -312 ]
|
['Fence', -312 ],
|
||||||
|
['ContinuousUpdates', -313 ]
|
||||||
];
|
];
|
||||||
|
|
||||||
this._encHandlers = {};
|
this._encHandlers = {};
|
||||||
@ -73,6 +74,9 @@ var RFB;
|
|||||||
|
|
||||||
this._supportsFence = false;
|
this._supportsFence = false;
|
||||||
|
|
||||||
|
this._supportsContinuousUpdates = false;
|
||||||
|
this._enabledContinuousUpdates = false;
|
||||||
|
|
||||||
// Frame buffer update state
|
// Frame buffer update state
|
||||||
this._FBU = {
|
this._FBU = {
|
||||||
rects: 0,
|
rects: 0,
|
||||||
@ -975,7 +979,7 @@ var RFB;
|
|||||||
|
|
||||||
RFB.messages.pixelFormat(this._sock, this._fb_Bpp, this._fb_depth, this._true_color);
|
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.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.fbu_rt_start = (new Date()).getTime();
|
||||||
this._timing.pixels = 0;
|
this._timing.pixels = 0;
|
||||||
@ -1051,7 +1055,13 @@ var RFB;
|
|||||||
var length = this._sock.rQshift8();
|
var length = this._sock.rQshift8();
|
||||||
|
|
||||||
if (this._sock.rQwait("ServerFence payload", length, 9)) { return false; }
|
if (this._sock.rQwait("ServerFence payload", length, 9)) { return false; }
|
||||||
var payload = this._sock.rQshiftStr(length); // FIXME: 64 bytes max
|
|
||||||
|
if (length > 64) {
|
||||||
|
Util.Warn("Bad payload length (" + length + ") in fence response");
|
||||||
|
length = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = this._sock.rQshiftStr(length);
|
||||||
|
|
||||||
this._supportsFence = true;
|
this._supportsFence = true;
|
||||||
|
|
||||||
@ -1116,7 +1126,10 @@ var RFB;
|
|||||||
case 0: // FramebufferUpdate
|
case 0: // FramebufferUpdate
|
||||||
var ret = this._framebufferUpdate();
|
var ret = this._framebufferUpdate();
|
||||||
if (ret) {
|
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;
|
return ret;
|
||||||
|
|
||||||
@ -1131,6 +1144,20 @@ var RFB;
|
|||||||
case 3: // ServerCutText
|
case 3: // ServerCutText
|
||||||
return this._handle_server_cut_text();
|
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
|
case 248: // ServerFence
|
||||||
return this._handle_server_fence_msg();
|
return this._handle_server_fence_msg();
|
||||||
|
|
||||||
@ -1245,6 +1272,13 @@ var RFB;
|
|||||||
|
|
||||||
return true; // We finished this FBU
|
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, [
|
Util.make_properties(RFB, [
|
||||||
@ -1419,6 +1453,26 @@ var RFB;
|
|||||||
sock.flush();
|
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) {
|
pixelFormat: function (sock, bpp, depth, true_color) {
|
||||||
var buff = sock._sQ;
|
var buff = sock._sQ;
|
||||||
var offset = sock._sQlen;
|
var offset = sock._sQlen;
|
||||||
@ -1490,12 +1544,12 @@ var RFB;
|
|||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
fbUpdateRequests: function (sock, cleanDirty, fb_width, fb_height) {
|
fbUpdateRequests: function (sock, onlyNonInc, cleanDirty, fb_width, fb_height) {
|
||||||
var offsetIncrement = 0;
|
var offsetIncrement = 0;
|
||||||
|
|
||||||
var cb = cleanDirty.cleanBox;
|
var cb = cleanDirty.cleanBox;
|
||||||
var w, h;
|
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;
|
w = typeof cb.w === "undefined" ? fb_width : cb.w;
|
||||||
h = typeof cb.h === "undefined" ? fb_height : cb.h;
|
h = typeof cb.h === "undefined" ? fb_height : cb.h;
|
||||||
// Request incremental for clean box
|
// Request incremental for clean box
|
||||||
@ -2102,6 +2156,7 @@ var RFB;
|
|||||||
this._display.resize(this._fb_width, this._fb_height);
|
this._display.resize(this._fb_width, this._fb_height);
|
||||||
this._onFBResize(this, this._fb_width, this._fb_height);
|
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||||
|
this._updateContinuousUpdates();
|
||||||
|
|
||||||
this._FBU.bytes = 0;
|
this._FBU.bytes = 0;
|
||||||
this._FBU.rects -= 1;
|
this._FBU.rects -= 1;
|
||||||
|
|||||||
@ -1197,6 +1197,33 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||||||
expect(client._sock).to.have.sent(expected_msg._sQ);
|
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 () {
|
it('should parse out information from a header before any actual data comes in', function () {
|
||||||
client.set_onFBUReceive(sinon.spy());
|
client.set_onFBUReceive(sinon.spy());
|
||||||
var rect_info = { x: 8, y: 11, width: 27, height: 32, encoding: 0x02, encodingName: 'RRE' };
|
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);
|
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 () {
|
it('should fail on an unknown message type', function () {
|
||||||
client._sock._websocket._receive_data(new Uint8Array([87]));
|
client._sock._websocket._receive_data(new Uint8Array([87]));
|
||||||
expect(client._rfb_state).to.equal('failed');
|
expect(client._rfb_state).to.equal('failed');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user