]>
git.proxmox.com Git - mirror_novnc.git/blob - tests/playback.js
cac9c8a6c738994a9d44e0a4fc92486d42ce8ca7
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2012 Joel Martin
4 * Licensed under MPL 2.0 (see LICENSE.txt)
7 import RFB
from '../core/rfb.js';
8 import * as Log
from '../core/util/logging.js';
9 import Base64
from '../core/base64.js';
12 if (window
.setImmediate
=== undefined) {
13 let _immediateIdCounter
= 1;
14 const _immediateFuncs
= {};
16 window
.setImmediate
= (func
) => {
17 const index
= _immediateIdCounter
++;
18 _immediateFuncs
[index
] = func
;
19 window
.postMessage("noVNC immediate trigger:" + index
, "*");
23 window
.clearImmediate
= (id
) => {
27 const _onMessage
= (event
) => {
28 if ((typeof event
.data
!== "string") ||
29 (event
.data
.indexOf("noVNC immediate trigger:") !== 0)) {
33 const index
= event
.data
.slice("noVNC immediate trigger:".length
);
35 const callback
= _immediateFuncs
[index
];
36 if (callback
=== undefined) {
40 delete _immediateFuncs
[index
];
44 window
.addEventListener("message", _onMessage
);
47 export default class RecordingPlayer
{
48 constructor(frames
, encoding
, disconnected
) {
49 this._frames
= frames
;
50 this._encoding
= encoding
;
52 this._disconnected
= disconnected
;
54 if (this._encoding
=== undefined) {
55 const frame
= this._frames
[0];
56 const start
= frame
.indexOf('{', 1) + 1;
57 if (frame
.slice(start
).startsWith('UkZC')) {
58 this._encoding
= 'base64';
60 this._encoding
= 'binary';
64 this._rfb
= undefined;
65 this._frame_length
= this._frames
.length
;
67 this._frame_index
= 0;
68 this._start_time
= undefined;
69 this._realtime
= true;
70 this._trafficManagement
= true;
72 this._running
= false;
74 this.onfinish
= () => {};
77 run(realtime
, trafficManagement
) {
78 // initialize a new RFB
79 this._rfb
= new RFB(document
.getElementById('VNC_screen'), 'wss://test');
80 this._rfb
.viewOnly
= true;
81 this._rfb
.addEventListener("disconnect",
82 this._handleDisconnect
.bind(this));
83 this._enablePlaybackMode();
85 // reset the frame index and timer
86 this._frame_index
= 0;
87 this._start_time
= (new Date()).getTime();
89 this._realtime
= realtime
;
90 this._trafficManagement
= (trafficManagement
=== undefined) ? !realtime
: trafficManagement
;
94 this._queueNextPacket();
97 // _enablePlaybackMode mocks out things not required for running playback
98 _enablePlaybackMode() {
99 this._rfb
._sock
.send
= () => {};
100 this._rfb
._sock
.close
= () => {};
101 this._rfb
._sock
.flush
= () => {};
102 this._rfb
._sock
.open = function () {
104 this._eventHandlers
.open();
109 if (!this._running
) { return; }
111 let frame
= this._frames
[this._frame_index
];
114 while (this._frame_index
< this._frame_length
&& frame
.charAt(0) === "}") {
116 frame
= this._frames
[this._frame_index
];
119 if (frame
=== 'EOF') {
120 Log
.Debug('Finished, found EOF');
125 if (this._frame_index
>= this._frame_length
) {
126 Log
.Debug('Finished, no more frames');
131 if (this._realtime
) {
132 const foffset
= frame
.slice(1, frame
.indexOf('{', 1));
133 const toffset
= (new Date()).getTime() - this._start_time
;
134 let delay
= foffset
- toffset
;
135 if (delay
< 1) delay
= 1;
137 setTimeout(this._doPacket
.bind(this), delay
);
139 setImmediate(this._doPacket
.bind(this));
144 // Avoid having excessive queue buildup in non-realtime mode
145 if (this._trafficManagement
&& this._rfb
._flushing
) {
146 const orig
= this._rfb
._display
.onflush
;
147 this._rfb
._display
.onflush
= () => {
148 this._rfb
._display
.onflush
= orig
;
149 this._rfb
._onFlush();
155 const frame
= this._frames
[this._frame_index
];
156 let start
= frame
.indexOf('{', 1) + 1;
158 if (this._encoding
=== 'base64') {
159 u8
= Base64
.decode(frame
.slice(start
));
162 u8
= new Uint8Array(frame
.length
- start
);
163 for (let i
= 0; i
< frame
.length
- start
; i
++) {
164 u8
[i
] = frame
.charCodeAt(start
+ i
);
168 this._rfb
._sock
._recv_message({'data': u8
});
171 this._queueNextPacket();
175 if (this._rfb
._display
.pending()) {
176 this._rfb
._display
.onflush
= () => {
177 if (this._rfb
._flushing
) {
178 this._rfb
._onFlush();
182 this._rfb
._display
.flush();
184 this._running
= false;
185 this._rfb
._sock
._eventHandlers
.close({code
: 1000, reason
: ""});
187 this.onfinish((new Date()).getTime() - this._start_time
);
191 _handleDisconnect(evt
) {
192 this._running
= false;
193 this._disconnected(evt
.detail
.clean
, this._frame_index
);