Commit 0b8246a6 authored by NzSN's avatar NzSN

update

parent a6c2d297
......@@ -17,7 +17,7 @@ module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
basePath: '.',
// frameworks to use
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
......@@ -26,19 +26,25 @@ module.exports = function(config) {
// list of files / patterns to load in the browser
files: [
{ pattern: 'src/res.js', included: true },
{ pattern: 'src/**/*.js', included: false, served: true },
{ pattern: 'tests/**/*.js', included: true },
{ pattern: 'resources/**/*.js', included: false, served: true }
],
// list of files / patterns to exclude
exclude: [
],
exclude: [],
proxies: {},
proxies: {
'/src': '/base/src/',
'/resources': '/base/resources/',
'/workers': '/base/tests/workers/',
},
// preprocess matching files before serving them to the browser
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
preprocessors: {
'src/res.js': [ 'browserify'],
'src/*.js': [ 'browserify'],
'tests/*.spec.js': [ 'browserify' ],
},
......
......@@ -17,9 +17,7 @@ export class WW extends Observable {
});
this.#ident = name;
this.#ww = new Worker(
new URL(path, import.meta.url)
);
this.#ww = new Worker(path);
}
async start(initWorks) {
......
......@@ -90,15 +90,11 @@ export class H264EncWWGroup extends WWGroup {
// in order.
// Create Muxer
this.#muxWorker = new WW("MUX",
new URL('./workers/muxWW.js', import.meta.url)
);
this.#muxWorker = new WW("MUX", './workers/muxWW.js');
// Create Encoder
for (let i = 0; i < this.#numOfEncWorker; ++i) {
let worker = new WW("ENC_" + i,
new URL('./workers/encWW.js', import.meta.url)
);
let worker = new WW("ENC_" + i, './workers/encWW.js');
this.#encWorkers.push(worker);
}
}
......
import { WW } from '../src/WW.js';
// For Webpack 5
let url = new URL('../resources/worker.js', import.meta.url);
let url = '../resources/worker.js';
describe("WW Spec", () => {
it("Instantiation", async () => {
......@@ -46,10 +46,10 @@ describe("WW Spec", () => {
// Conntect two worker to do plus
// of an input number.
it("Worker Connect", async () => {
let srcUrl = new URL('../resources/workerSRC.js', import.meta.url);
let dstUrl = new URL('../resources/workerDST.js', import.meta.url);
let src = new WW('SRC', srcUrl);
let dst = new WW('DST', dstUrl);
let src = new WW('SRC', '../resources/workerSRC.js');
let dst = new WW('DST', '../resources/workerDST.js');
src.connect(dst, async ()=>{}, (data)=>{
return typeof(data) == 'number';
......
......@@ -128,10 +128,9 @@ describe("Channel Spec", () => {
});
it("Transfer 64 MB to WebWorker", async () => {
let url = new URL('./workers/channelWW.js', import.meta.url),
ret = true;
let ret = true;
let channel = new Channel(Math.pow(2,16));
let worker = new Worker(url, { type: 'module' });
let worker = new Worker('./workers/channelWW.js', { type: 'module' });
let sended = 0;
let dataToWrite = new Uint8Array(
......
const testsContext = require.context('.', true, /.spec.js$/);
testsContext.keys().forEach(testsContext);
import { Channel } from '../src/channel.js';
async function sleep(ms) {
await new Promise(r => setTimeout(() => r(), ms));
......@@ -31,3 +30,269 @@ async function main(mem) {
onmessage = async e => {
await main(e.data);
}
class CpySchedule {
first = { pos: 0, size: 0 }
second = { pos: 0, size: 0 }
}
/* An abstraction that help to
* easily to transfer datas to target worker
* in real time manner */
class Channel {
/* Size of memory area that help to
* maintain Channel. Types of meta info
* are shown below:
*
* 1.Write Position
* 2.Read Position
*
* Figure:
* --------------------------------------------------------------------------------------------
* | ReadPointer (4 bytes) | WritePointer (4 Bytes) | Private (4 Bytes) | Data Area (N bytes) |
* --------------------------------------------------------------------------------------------
* where N >= 2
*
* */
#rFieldPosLen = 4;
#wFieldPosLen = 4;
#priFieldLen = 4;
#numOfMetaField = 3
#fieldSize = 0;
#metaSize = 0;
#size = 0;
#totalSize = 0;
#shMem = undefined;
#view = undefined;
#buffer = undefined;
#writePointerCache = 0;
#readPointerCache = 0;
#endPos = 0;
// size's unit is byte
// bufferType parameter is mainly for testability.
constructor(size, bufferType = SharedArrayBuffer, shMem = null) {
//assert(size >= 2, `Channel require its data area has at least 2 Bytes.`)
this.#size = size;
// Init shared memory
this.#metaSize = this.#rFieldPosLen + this.#wFieldPosLen + this.#priFieldLen;
this.#shMem = shMem == null ? new bufferType(size + this.#metaSize) : shMem;
this.#view = new DataView(this.#shMem);
this.#buffer = new Uint8Array(this.#shMem);
if (shMem == null) {
this.#writePointerCache = this.#metaSize;
this.#readPointerCache = this.#metaSize;
// Init readPointer and writePointer to
// the first bytes of data area.
this.#view.setUint32(0, this.#writePointerCache);
this.#view.setUint32(4, this.#readPointerCache);
} else {
this.#writePointerCache = this.#getWritePointer();
this.#readPointerCache = this.#getReadPointer();
}
this.#size = size;
this.#totalSize = this.#metaSize + this.#size;
this.#endPos = this.#metaSize + this.#size;
}
#getReadPointer() {
return this.#view.getUint32(0);
}
#getWritePointer() {
return this.#view.getUint32(4);
}
metaSize() {
return this.#metaSize;
}
readPriv() {
return this.#view.getUint32(8);
}
writePriv(privData) {
try {
this.#view.setUint32(8, privData);
} catch (error) {
if (error instanceof RangeError)
return false;
}
return true;
}
setPriv(flag) {
let old = this.readPriv();
this.writePriv(flag | old);
}
unsetPriv(flag) {
let old = this.readPriv();
flag = flag ^ 0x11111111;
this.writePriv(flag & old);
}
/* Semantic: Is able to write 'size' of datas
* into #shMem. */
#isAbleToWrite(size) {
return this.#remain() >= size;
}
getShMem() {
return this.#shMem;
}
#remain() {
let readPos = this.#getReadPointer();
if (this.#writePointerCache == readPos) {
return this.#size - 1;
} else if (this.#writePointerCache > readPos) {
return this.#size - (this.#writePointerCache - readPos) - 1;
} else {
return readPos - this.#writePointerCache - 1;
}
}
/* Channel use an array buffer as
* a circular buffer, so some datas
* may unable to be done in one copy.
* Two times of copy is required to handle
* such kind of situation.
*
* Caution: Before making a copy schedule you must
* make sure there has enough spaces.*/
#cpySchedule(size) {
let firstCpySize = 0, secondCpySize = 0, spaceToTail = 0;
let schedule = new CpySchedule();
let readPos = this.#getReadPointer();
if (this.#writePointerCache >= readPos) {
spaceToTail = this.#endPos - this.#writePointerCache;
firstCpySize = Math.min(size, spaceToTail);
secondCpySize = firstCpySize < size ? size - firstCpySize : 0;
secondCpySize = Math.min(secondCpySize, readPos - this.#metaSize);
schedule.first.pos = this.#writePointerCache;
schedule.first.size = firstCpySize;
schedule.second.pos = secondCpySize > 0 ? this.#metaSize : 0;
schedule.second.size = secondCpySize;
} else {
schedule.first.pos = this.#writePointerCache;
schedule.first.size = Math.min(readPos - this.#writePointerCache - 1, size);
}
return schedule;
}
dataView() {
return this.#buffer;
}
isEmpty() {
return this.#getWritePointer() == this.#getReadPointer();
}
// This method is for testing purposes.
readData(size) {
let writePos = this.#getWritePointer();
let readTo = 0, readBuffer = null;
if (this.#readPointerCache == writePos) {
return new Uint8Array(0);
} else if (this.#readPointerCache < writePos) {
readTo = this.#readPointerCache + Math.min(size, writePos - this.#readPointerCache);
readBuffer = this.#buffer.slice(this.#readPointerCache, readTo);
this.#readPointerUpdate(readTo);
} else {
// To make sure
let firstRSize = Math.min(size, this.#buffer.byteLength-this.#readPointerCache);
let secondRSize = firstRSize < size ? size - firstRSize : 0;
secondRSize = Math.min(secondRSize, writePos-this.#metaSize);
readBuffer = new Uint8Array(firstRSize+secondRSize);
// First read
readBuffer.set(this.#buffer.slice(
this.#readPointerCache, this.#readPointerCache+firstRSize), 0);
// Second Read
if (secondRSize > 0) {
readBuffer.set(
this.#buffer.slice(this.#metaSize, this.#metaSize+secondRSize),
firstRSize);
this.#readPointerUpdate(this.#metaSize+secondRSize);
} else {
let newPos = this.#readPointerCache+firstRSize;
newPos = newPos == this.#buffer.byteLength ? this.#metaSize : newPos;
this.#readPointerUpdate(newPos);
}
}
return readBuffer;
}
push(data /* Uint8Array */) {
let writePos = this.#writePointerCache;
if (!this.#isAbleToWrite(data.byteLength)) {
return false;
}
/* Write to shared Memory */
// Get a copy schedule, more details please read
// comment of #cpySchedule.
let schedule = this.#cpySchedule(data.byteLength);
// Perfrom write schedule
let srcPos = 0, plan;
for (let key in schedule) {
plan = schedule[key];
if (plan.size == 0)
continue;
this.#buffer.set(
data.slice(srcPos, srcPos+plan.size), plan.pos)
srcPos += plan.size;
writePos = plan.pos+plan.size;
}
// Caution: 'Write Pointer' must be updated after
// all datas are writed but not before or
// at intermediate of some writes otherwise
// oppsite side may read invalid datas.
this.#writePointerUpdate(writePos);
return true;
}
#writePointerUpdate(pos) {
this.#writePointerCache = pos;
this.#view.setUint32(4, pos);
}
#readPointerUpdate(pos) {
this.#readPointerCache = pos;
this.#view.setUint32(0, pos);
}
}
import {COMMANDS} from '../src/WWOpts.js';
onmessage = e => {
console.log(COMMANDS.INIT_DONE);
console.log(e);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment