178 lines
4.4 KiB
JavaScript
178 lines
4.4 KiB
JavaScript
const WsClientOptions = {
|
|
// required on open
|
|
url: null,
|
|
stream: null,
|
|
|
|
decode_async: false,
|
|
decode_queue_size: 0,
|
|
decode_thread_count: 0,
|
|
decode_thread_type: 0,
|
|
|
|
// need pthreads support
|
|
// COOP, COEP headers are correctly set
|
|
// https://emscripten.org/docs/porting/pthreads.html
|
|
// decode_async: false, // not works well as clone frame not supported
|
|
// decode_queue_size: 10,
|
|
// decode_thread_count: 4,
|
|
// // 1: FF_THREAD_FRAME, 2: FF_THREAD_SLICE
|
|
// decode_thread_type: 1,
|
|
|
|
player: null,
|
|
|
|
onopen: null,
|
|
onmessage: null,
|
|
onclose: null,
|
|
onerror: null,
|
|
|
|
ondata: null,
|
|
|
|
dbg: false,
|
|
log: console.log,
|
|
wasm_log_v: 0,
|
|
};
|
|
|
|
class WsClient {
|
|
#options;
|
|
#ws = null;
|
|
#decoder = null;
|
|
#t_onmsg = Date.now();
|
|
|
|
constructor(options) {
|
|
this.#options = { ...WsClientOptions, ...options };
|
|
this.#logd('ws options:')
|
|
this.#logd(this.#options);
|
|
|
|
Module.Log.set_v(this.#options.wasm_log_v);
|
|
}
|
|
|
|
static createOpenGLPlayer() {
|
|
return new Module.OpenGLPlayer();
|
|
}
|
|
|
|
#log(...args) {
|
|
this.#options.log(...args);
|
|
}
|
|
|
|
#logd(...args) {
|
|
this.#options.dbg && this.#options.log(...args);
|
|
}
|
|
|
|
isOpen() {
|
|
return this.#ws != null;
|
|
}
|
|
|
|
open(options) {
|
|
if (this.#ws != null) {
|
|
this.#log('ws open error: already opened');
|
|
return;
|
|
}
|
|
this.#options = { ...this.#options, ...options };
|
|
this.#logd('ws open options:')
|
|
this.#logd(this.#options);
|
|
if (this.#options.url == null) {
|
|
this.#log('ws open error: url is null');
|
|
return;
|
|
}
|
|
if (this.#options.stream == null) {
|
|
this.#log('ws open error: stream is null');
|
|
return;
|
|
}
|
|
|
|
this.#decoder = new Module.Decoder();
|
|
this.#decoder.open(
|
|
JSON.stringify(this.#options.stream),
|
|
this.#options.decode_queue_size,
|
|
this.#options.decode_thread_count,
|
|
this.#options.decode_thread_type,
|
|
this.#ondecode.bind(this));
|
|
|
|
const ws = new WebSocket(this.#options.url);
|
|
ws.binaryType = 'arraybuffer';
|
|
ws.onopen = (e) => this.#onopen(e);
|
|
ws.onmessage = (e) => this.#onmessage(e);
|
|
ws.onclose = (e) => this.#onclose(e);
|
|
ws.onerror = (e) => this.#onerror(e);
|
|
this.#ws = ws;
|
|
}
|
|
|
|
close() {
|
|
if (this.#ws != null) {
|
|
this.#logd('ws close');
|
|
this.#ws.close();
|
|
this.#ws = null;
|
|
this.#decoder.delete();
|
|
this.#decoder = null;
|
|
this.#options.dbg && Module.DoLeakCheck && Module.DoLeakCheck();
|
|
}
|
|
}
|
|
|
|
#onopen(e) {
|
|
this.#logd(`ws open: ${this.#options.url}`);
|
|
this.#options.onopen && this.#options.onopen(e);
|
|
}
|
|
|
|
#onmessage(e) {
|
|
if (this.#options.dbg) {
|
|
const t = Date.now();
|
|
this.#logd(`ws message: ${this.#options.url}` +
|
|
`, interval: ${t - this.#t_onmsg} ms`);
|
|
this.#t_onmsg = t;
|
|
}
|
|
this.#options.dbg && console.time("ws onmessage");
|
|
|
|
console.log('onmessage=',e);
|
|
|
|
let data = new Uint8Array(e.data);
|
|
if (this.#decoder) {
|
|
const buf = Module._malloc(data.length);
|
|
try {
|
|
Module.HEAPU8.set(data, buf);
|
|
if (this.#options.decode_async) {
|
|
this.#decoder.decodeAsync(buf, data.length);
|
|
} else {
|
|
// process the frame in #ondecode callback
|
|
const frame = this.#decoder.decode(buf, data.length);
|
|
// release the return frame reference
|
|
if (frame != null) frame.delete();
|
|
}
|
|
} finally {
|
|
Module._free(buf);
|
|
}
|
|
} else {
|
|
this.#options.ondata && this.#options.ondata(data);
|
|
}
|
|
|
|
this.#options.dbg && console.timeEnd("ws onmessage");
|
|
}
|
|
|
|
#ondecode(frame) {
|
|
this.#options.dbg && console.time("ws ondecode");
|
|
if (frame != null) {
|
|
this.#logd(`ws frame size=${frame.width}x${frame.height}, pts=${frame.pts}`);
|
|
const player = this.#options.player;
|
|
if (player) {
|
|
if (player instanceof WebGLPlayer) {
|
|
frame.bytes = frame.getBytes();
|
|
// frame.bytes = new Uint8Array(Module.HEAPU8.buffer, frame.data, frame.size);
|
|
}
|
|
player.render(frame);
|
|
}
|
|
this.#options.ondata && this.#options.ondata(frame);
|
|
frame.delete();
|
|
} else {
|
|
this.#logd("ws frame is null: decode error or need new packets");
|
|
}
|
|
this.#options.dbg && console.timeEnd("ws ondecode");
|
|
}
|
|
|
|
#onclose(e) {
|
|
this.#logd(`ws close: ${this.#options.url}`);
|
|
this.#options.onclose && this.#options.onclose(e);
|
|
}
|
|
|
|
#onerror(e) {
|
|
this.#logd(`ws error: ${this.#options.url}, ${e}`);
|
|
this.#options.onerror && this.#options.onerror(e);
|
|
}
|
|
}
|