2020-03-31 01:27:59 +02:00
|
|
|
import {CodecType} from "tc-backend/web/codec/Codec";
|
|
|
|
|
2018-04-11 17:56:09 +02:00
|
|
|
const prefix = "[CodecWorker] ";
|
2018-04-18 20:12:10 +02:00
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
export interface CodecWorker {
|
2018-04-11 17:56:09 +02:00
|
|
|
name();
|
2018-04-19 18:42:34 +02:00
|
|
|
initialise?() : string;
|
2018-04-11 17:56:09 +02:00
|
|
|
deinitialise();
|
|
|
|
decode(data: Uint8Array);
|
|
|
|
encode(data: Float32Array) : Uint8Array | string;
|
|
|
|
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
let supported_types = {};
|
|
|
|
export function register_codec(type: CodecType, allocator: (options?: any) => Promise<CodecWorker>) {
|
|
|
|
supported_types[type] = allocator;
|
|
|
|
}
|
|
|
|
|
|
|
|
let initialize_callback: () => Promise<true | string>;
|
|
|
|
export function set_initialize_callback(callback: () => Promise<true | string>) {
|
|
|
|
initialize_callback = callback;
|
|
|
|
}
|
2018-04-11 17:56:09 +02:00
|
|
|
|
2020-03-31 02:11:55 +02:00
|
|
|
export let codec_instance: CodecWorker;
|
2020-03-31 01:27:59 +02:00
|
|
|
let globally_initialized = false;
|
|
|
|
let global_initialize_result;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param command
|
|
|
|
* @param data
|
|
|
|
* @return string on error or object on success
|
|
|
|
*/
|
|
|
|
async function handle_message(command: string, data: any) : Promise<string | object> {
|
|
|
|
switch (command) {
|
|
|
|
case "global-initialize":
|
2020-03-31 16:43:21 +02:00
|
|
|
try {
|
|
|
|
const init_result = globally_initialized ? global_initialize_result : await initialize_callback();
|
|
|
|
globally_initialized = true;
|
2020-03-31 01:27:59 +02:00
|
|
|
|
2020-03-31 16:43:21 +02:00
|
|
|
if(typeof init_result === "string")
|
|
|
|
throw init_result;
|
|
|
|
} catch (e) {
|
|
|
|
if(typeof e === "string")
|
|
|
|
return e;
|
|
|
|
throw e;
|
|
|
|
}
|
2020-03-31 01:27:59 +02:00
|
|
|
|
|
|
|
return {};
|
2018-04-11 17:56:09 +02:00
|
|
|
case "initialise":
|
2020-03-31 02:11:55 +02:00
|
|
|
console.log(prefix + "Initialize for codec %s", CodecType[data.type as CodecType]);
|
2020-03-31 01:27:59 +02:00
|
|
|
if(!supported_types[data.type])
|
|
|
|
return "type unsupported";
|
|
|
|
|
|
|
|
try {
|
2020-03-31 02:11:55 +02:00
|
|
|
codec_instance = await supported_types[data.type](data.options);
|
2020-03-31 01:27:59 +02:00
|
|
|
} catch(ex) {
|
|
|
|
console.error(prefix + "Failed to allocate codec: %o", ex);
|
|
|
|
return typeof ex === "string" ? ex : "failed to allocate codec";
|
2018-04-11 17:56:09 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 02:11:55 +02:00
|
|
|
const error = codec_instance.initialise();
|
2020-03-31 01:27:59 +02:00
|
|
|
if(error) return error;
|
|
|
|
|
|
|
|
return {};
|
2018-04-11 17:56:09 +02:00
|
|
|
case "encodeSamples":
|
2020-04-18 19:37:30 +02:00
|
|
|
if(!codec_instance)
|
|
|
|
return "codec not initialized/initialize failed";
|
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
let encodeArray = new Float32Array(data.length);
|
2018-04-11 17:56:09 +02:00
|
|
|
for(let index = 0; index < encodeArray.length; index++)
|
|
|
|
encodeArray[index] = data.data[index];
|
|
|
|
|
2020-03-31 02:11:55 +02:00
|
|
|
let encodeResult = codec_instance.encode(encodeArray);
|
2020-03-31 01:27:59 +02:00
|
|
|
if(typeof encodeResult === "string")
|
|
|
|
return encodeResult;
|
|
|
|
else
|
|
|
|
return { data: encodeResult, length: encodeResult.length };
|
2018-04-11 17:56:09 +02:00
|
|
|
case "decodeSamples":
|
2020-04-18 19:37:30 +02:00
|
|
|
if(!codec_instance)
|
|
|
|
return "codec not initialized/initialize failed";
|
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
let decodeArray = new Uint8Array(data.length);
|
2018-04-11 17:56:09 +02:00
|
|
|
for(let index = 0; index < decodeArray.length; index++)
|
|
|
|
decodeArray[index] = data.data[index];
|
|
|
|
|
2020-03-31 02:11:55 +02:00
|
|
|
let decodeResult = codec_instance.decode(decodeArray);
|
2020-03-31 01:27:59 +02:00
|
|
|
if(typeof decodeResult === "string")
|
|
|
|
return decodeResult;
|
|
|
|
else
|
|
|
|
return { data: decodeResult, length: decodeResult.length };
|
2018-04-11 17:56:09 +02:00
|
|
|
case "reset":
|
2020-03-31 02:11:55 +02:00
|
|
|
codec_instance.reset();
|
2018-04-11 17:56:09 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-03-31 01:27:59 +02:00
|
|
|
return "unknown command";
|
2018-04-11 17:56:09 +02:00
|
|
|
}
|
2020-03-31 01:27:59 +02:00
|
|
|
}
|
2018-04-18 20:12:10 +02:00
|
|
|
|
2018-04-11 17:56:09 +02:00
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
const handle_message_event = (e: MessageEvent) => {
|
|
|
|
const token = e.data.token;
|
|
|
|
const received = Date.now();
|
2018-05-07 11:51:50 +02:00
|
|
|
|
2020-03-31 01:27:59 +02:00
|
|
|
const send_result = result => {
|
|
|
|
const data = {};
|
|
|
|
if(typeof result === "object") {
|
|
|
|
data["result"] = result;
|
|
|
|
data["success"] = true;
|
|
|
|
} else if(typeof result === "string") {
|
|
|
|
data["error"] = result;
|
|
|
|
data["success"] = false;
|
|
|
|
} else {
|
|
|
|
data["error"] = "invalid result";
|
|
|
|
data["success"] = false;
|
|
|
|
}
|
|
|
|
data["token"] = token;
|
|
|
|
data["timestamp_received"] = received;
|
|
|
|
data["timestamp_send"] = Date.now();
|
|
|
|
|
2020-03-31 02:11:55 +02:00
|
|
|
postMessage(data, undefined);
|
2020-03-31 01:27:59 +02:00
|
|
|
};
|
|
|
|
handle_message(e.data.command, e.data.data).then(res => {
|
|
|
|
if(token) {
|
|
|
|
send_result(res);
|
|
|
|
}
|
|
|
|
}).catch(error => {
|
|
|
|
console.warn("An error has been thrown while handing command %s: %o", e.data.command, error);
|
|
|
|
if(token) {
|
|
|
|
send_result(typeof error === "string" ? error : "unexpected exception has been thrown");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
addEventListener("message", handle_message_event);
|