summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2019-01-08 11:05:05 +0100
committerPierre Ossman <ossman@cendio.se>2019-01-08 12:24:39 +0100
commit527a1fd0ae98c57ef860e4d44d42da26aad28e30 (patch)
treea06a79a64b9e96bc7af11e645d72c8ba3cee74ed
parent18439b0680811f175e39ce381d0faa138f868d3c (diff)
downloadnovnc-527a1fd0ae98c57ef860e4d44d42da26aad28e30.tar.gz
Pre-convert recordings for playback
Convert the recordings ahead of time instead of during the playback. That way we aren't messing up the profiling with time spent converting data, rather than processing it.
-rw-r--r--tests/playback-ui.js54
-rw-r--r--tests/playback.js38
2 files changed, 51 insertions, 41 deletions
diff --git a/tests/playback-ui.js b/tests/playback-ui.js
index 012eebc..9492c0e 100644
--- a/tests/playback-ui.js
+++ b/tests/playback-ui.js
@@ -2,9 +2,9 @@
import * as WebUtil from '../app/webutil.js';
import RecordingPlayer from './playback.js';
+import Base64 from '../core/base64.js';
let frames = null;
-let encoding = null;
function message(str) {
const cell = document.getElementById('messages');
@@ -19,7 +19,7 @@ function loadFile() {
return Promise.reject("Must specify data=FOO in query string.");
}
- message("Loading " + fname);
+ message("Loading " + fname + "...");
return new Promise((resolve, reject) => {
const script = document.createElement("script");
@@ -41,21 +41,62 @@ function enableUI() {
document.getElementById('mode1').checked = true;
}
- message("VNC_frame_data.length: " + VNC_frame_data.length);
+ message("Loaded " + VNC_frame_data.length + " frames");
const startButton = document.getElementById('startButton');
startButton.disabled = false;
startButton.addEventListener('click', start);
+ message("Converting...");
+
frames = VNC_frame_data;
+
+ let encoding;
// Only present in older recordings
if (window.VNC_frame_encoding) {
encoding = VNC_frame_encoding;
+ } else {
+ let frame = frames[0];
+ let start = frame.indexOf('{', 1) + 1;
+ if (frame.slice(start).startsWith('UkZC')) {
+ encoding = 'base64';
+ } else {
+ encoding = 'binary';
+ }
+ }
+
+ for (let i = 0;i < frames.length;i++) {
+ let frame = frames[i];
+
+ if (frame === "EOF") {
+ frames.splice(i);
+ break;
+ }
+
+ let dataIdx = frame.indexOf('{', 1) + 1;
+
+ let time = parseInt(frame.slice(1, dataIdx - 1));
+
+ let u8;
+ if (encoding === 'base64') {
+ u8 = Base64.decode(frame.slice(dataIdx));
+ } else {
+ u8 = new Uint8Array(frame.length - dataIdx);
+ for (let j = 0; j < frame.length - dataIdx; j++) {
+ u8[j] = frame.charCodeAt(dataIdx + j);
+ }
+ }
+
+ frames[i] = { fromClient: frame[0] === '}',
+ timestamp: time,
+ data: u8 };
}
+
+ message("Ready");
}
class IterationPlayer {
- constructor(iterations, frames, encoding) {
+ constructor(iterations, frames) {
this._iterations = iterations;
this._iteration = undefined;
@@ -64,7 +105,6 @@ class IterationPlayer {
this._start_time = undefined;
this._frames = frames;
- this._encoding = encoding;
this._state = 'running';
@@ -84,7 +124,7 @@ class IterationPlayer {
}
_nextIteration() {
- const player = new RecordingPlayer(this._frames, this._encoding, this._disconnected.bind(this));
+ const player = new RecordingPlayer(this._frames, this._disconnected.bind(this));
player.onfinish = this._iterationFinish.bind(this);
if (this._state !== 'running') { return; }
@@ -147,7 +187,7 @@ function start() {
mode = 'realtime';
}
- const player = new IterationPlayer(iterations, frames, encoding);
+ const player = new IterationPlayer(iterations, frames);
player.oniterationfinish = (evt) => {
message(`Iteration ${evt.number} took ${evt.duration}ms`);
};
diff --git a/tests/playback.js b/tests/playback.js
index acaef74..5bd8103 100644
--- a/tests/playback.js
+++ b/tests/playback.js
@@ -6,7 +6,6 @@
import RFB from '../core/rfb.js';
import * as Log from '../core/util/logging.js';
-import Base64 from '../core/base64.js';
// Immediate polyfill
if (window.setImmediate === undefined) {
@@ -44,22 +43,11 @@ if (window.setImmediate === undefined) {
}
export default class RecordingPlayer {
- constructor(frames, encoding, disconnected) {
+ constructor(frames, disconnected) {
this._frames = frames;
- this._encoding = encoding;
this._disconnected = disconnected;
- if (this._encoding === undefined) {
- const frame = this._frames[0];
- const start = frame.indexOf('{', 1) + 1;
- if (frame.slice(start).startsWith('UkZC')) {
- this._encoding = 'base64';
- } else {
- this._encoding = 'binary';
- }
- }
-
this._rfb = undefined;
this._frame_length = this._frames.length;
@@ -112,17 +100,11 @@ export default class RecordingPlayer {
let frame = this._frames[this._frame_index];
// skip send frames
- while (this._frame_index < this._frame_length && frame.charAt(0) === "}") {
+ while (this._frame_index < this._frame_length && frame.fromClient) {
this._frame_index++;
frame = this._frames[this._frame_index];
}
- if (frame === 'EOF') {
- Log.Debug('Finished, found EOF');
- this._finish();
- return;
- }
-
if (this._frame_index >= this._frame_length) {
Log.Debug('Finished, no more frames');
this._finish();
@@ -130,9 +112,8 @@ export default class RecordingPlayer {
}
if (this._realtime) {
- const foffset = frame.slice(1, frame.indexOf('{', 1));
const toffset = (new Date()).getTime() - this._start_time;
- let delay = foffset - toffset;
+ let delay = frame.timestamp - toffset;
if (delay < 1) delay = 1;
setTimeout(this._doPacket.bind(this), delay);
@@ -154,19 +135,8 @@ export default class RecordingPlayer {
}
const frame = this._frames[this._frame_index];
- let start = frame.indexOf('{', 1) + 1;
- let u8;
- if (this._encoding === 'base64') {
- u8 = Base64.decode(frame.slice(start));
- start = 0;
- } else {
- u8 = new Uint8Array(frame.length - start);
- for (let i = 0; i < frame.length - start; i++) {
- u8[i] = frame.charCodeAt(start + i);
- }
- }
- this._rfb._sock._recv_message({'data': u8});
+ this._rfb._sock._recv_message({'data': frame.data});
this._frame_index++;
this._queueNextPacket();