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.
This commit is contained in:
parent
18439b0680
commit
527a1fd0ae
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
import * as WebUtil from '../app/webutil.js';
|
import * as WebUtil from '../app/webutil.js';
|
||||||
import RecordingPlayer from './playback.js';
|
import RecordingPlayer from './playback.js';
|
||||||
|
import Base64 from '../core/base64.js';
|
||||||
|
|
||||||
let frames = null;
|
let frames = null;
|
||||||
let encoding = null;
|
|
||||||
|
|
||||||
function message(str) {
|
function message(str) {
|
||||||
const cell = document.getElementById('messages');
|
const cell = document.getElementById('messages');
|
||||||
|
@ -19,7 +19,7 @@ function loadFile() {
|
||||||
return Promise.reject("Must specify data=FOO in query string.");
|
return Promise.reject("Must specify data=FOO in query string.");
|
||||||
}
|
}
|
||||||
|
|
||||||
message("Loading " + fname);
|
message("Loading " + fname + "...");
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const script = document.createElement("script");
|
const script = document.createElement("script");
|
||||||
|
@ -41,21 +41,62 @@ function enableUI() {
|
||||||
document.getElementById('mode1').checked = true;
|
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');
|
const startButton = document.getElementById('startButton');
|
||||||
startButton.disabled = false;
|
startButton.disabled = false;
|
||||||
startButton.addEventListener('click', start);
|
startButton.addEventListener('click', start);
|
||||||
|
|
||||||
|
message("Converting...");
|
||||||
|
|
||||||
frames = VNC_frame_data;
|
frames = VNC_frame_data;
|
||||||
|
|
||||||
|
let encoding;
|
||||||
// Only present in older recordings
|
// Only present in older recordings
|
||||||
if (window.VNC_frame_encoding) {
|
if (window.VNC_frame_encoding) {
|
||||||
encoding = 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 {
|
class IterationPlayer {
|
||||||
constructor(iterations, frames, encoding) {
|
constructor(iterations, frames) {
|
||||||
this._iterations = iterations;
|
this._iterations = iterations;
|
||||||
|
|
||||||
this._iteration = undefined;
|
this._iteration = undefined;
|
||||||
|
@ -64,7 +105,6 @@ class IterationPlayer {
|
||||||
this._start_time = undefined;
|
this._start_time = undefined;
|
||||||
|
|
||||||
this._frames = frames;
|
this._frames = frames;
|
||||||
this._encoding = encoding;
|
|
||||||
|
|
||||||
this._state = 'running';
|
this._state = 'running';
|
||||||
|
|
||||||
|
@ -84,7 +124,7 @@ class IterationPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_nextIteration() {
|
_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);
|
player.onfinish = this._iterationFinish.bind(this);
|
||||||
|
|
||||||
if (this._state !== 'running') { return; }
|
if (this._state !== 'running') { return; }
|
||||||
|
@ -147,7 +187,7 @@ function start() {
|
||||||
mode = 'realtime';
|
mode = 'realtime';
|
||||||
}
|
}
|
||||||
|
|
||||||
const player = new IterationPlayer(iterations, frames, encoding);
|
const player = new IterationPlayer(iterations, frames);
|
||||||
player.oniterationfinish = (evt) => {
|
player.oniterationfinish = (evt) => {
|
||||||
message(`Iteration ${evt.number} took ${evt.duration}ms`);
|
message(`Iteration ${evt.number} took ${evt.duration}ms`);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
import RFB from '../core/rfb.js';
|
import RFB from '../core/rfb.js';
|
||||||
import * as Log from '../core/util/logging.js';
|
import * as Log from '../core/util/logging.js';
|
||||||
import Base64 from '../core/base64.js';
|
|
||||||
|
|
||||||
// Immediate polyfill
|
// Immediate polyfill
|
||||||
if (window.setImmediate === undefined) {
|
if (window.setImmediate === undefined) {
|
||||||
|
@ -44,22 +43,11 @@ if (window.setImmediate === undefined) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RecordingPlayer {
|
export default class RecordingPlayer {
|
||||||
constructor(frames, encoding, disconnected) {
|
constructor(frames, disconnected) {
|
||||||
this._frames = frames;
|
this._frames = frames;
|
||||||
this._encoding = encoding;
|
|
||||||
|
|
||||||
this._disconnected = disconnected;
|
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._rfb = undefined;
|
||||||
this._frame_length = this._frames.length;
|
this._frame_length = this._frames.length;
|
||||||
|
|
||||||
|
@ -112,17 +100,11 @@ export default class RecordingPlayer {
|
||||||
let frame = this._frames[this._frame_index];
|
let frame = this._frames[this._frame_index];
|
||||||
|
|
||||||
// skip send frames
|
// 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++;
|
this._frame_index++;
|
||||||
frame = this._frames[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) {
|
if (this._frame_index >= this._frame_length) {
|
||||||
Log.Debug('Finished, no more frames');
|
Log.Debug('Finished, no more frames');
|
||||||
this._finish();
|
this._finish();
|
||||||
|
@ -130,9 +112,8 @@ export default class RecordingPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._realtime) {
|
if (this._realtime) {
|
||||||
const foffset = frame.slice(1, frame.indexOf('{', 1));
|
|
||||||
const toffset = (new Date()).getTime() - this._start_time;
|
const toffset = (new Date()).getTime() - this._start_time;
|
||||||
let delay = foffset - toffset;
|
let delay = frame.timestamp - toffset;
|
||||||
if (delay < 1) delay = 1;
|
if (delay < 1) delay = 1;
|
||||||
|
|
||||||
setTimeout(this._doPacket.bind(this), delay);
|
setTimeout(this._doPacket.bind(this), delay);
|
||||||
|
@ -154,19 +135,8 @@ export default class RecordingPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
const frame = this._frames[this._frame_index];
|
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._frame_index++;
|
||||||
|
|
||||||
this._queueNextPacket();
|
this._queueNextPacket();
|
||||||
|
|
Loading…
Reference in New Issue