@ylink-sdk/mobile-web 0.1.9-beta.1 → 0.1.9-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +1 -1
- package/dist/ylink-sdk-mobile.umd.js +70 -70
- package/package.json +1 -1
- package/dist/e30037b8/VERSION +0 -6
- package/dist/e30037b8/libipvp-simd.d.ts +0 -474
- package/dist/e30037b8/libipvp-simd.js +0 -3267
- package/dist/e30037b8/libipvp-simd.prod.d.ts +0 -474
- package/dist/e30037b8/libipvp-simd.prod.js +0 -184
- package/dist/e30037b8/libipvp-simd.prod.wasm +0 -0
- package/dist/e30037b8/libipvp-simd.wasm +0 -0
- package/dist/e30037b8/libipvp.d.ts +0 -474
- package/dist/e30037b8/libipvp.js +0 -3267
- package/dist/e30037b8/libipvp.prod.d.ts +0 -474
- package/dist/e30037b8/libipvp.prod.js +0 -184
- package/dist/e30037b8/libipvp.prod.wasm +0 -0
- package/dist/e30037b8/libipvp.wasm +0 -0
- package/dist/e30037b8/librtc.d.ts +0 -438
- package/dist/e30037b8/librtc.global.js +0 -5863
- package/dist/e30037b8/librtc.global.prod.js +0 -15
- package/dist/e30037b8/libsfu-simd.d.ts +0 -767
- package/dist/e30037b8/libsfu-simd.js +0 -4822
- package/dist/e30037b8/libsfu-simd.prod.d.ts +0 -767
- package/dist/e30037b8/libsfu-simd.prod.js +0 -209
- package/dist/e30037b8/libsfu-simd.prod.wasm +0 -0
- package/dist/e30037b8/libsfu-simd.wasm +0 -0
- package/dist/e30037b8/libsfu.d.ts +0 -767
- package/dist/e30037b8/libsfu.js +0 -4822
- package/dist/e30037b8/libsfu.prod.d.ts +0 -767
- package/dist/e30037b8/libsfu.prod.js +0 -209
- package/dist/e30037b8/libsfu.prod.wasm +0 -0
- package/dist/e30037b8/libsfu.wasm +0 -0
- package/dist/e30037b8/libsvc-simd-m1.d.ts +0 -767
- package/dist/e30037b8/libsvc-simd-m1.js +0 -4921
- package/dist/e30037b8/libsvc-simd-m1.prod.d.ts +0 -767
- package/dist/e30037b8/libsvc-simd-m1.prod.js +0 -209
- package/dist/e30037b8/libsvc-simd-m1.prod.wasm +0 -0
- package/dist/e30037b8/libsvc-simd-m1.wasm +0 -0
- package/dist/e30037b8/libsvc-simd.d.ts +0 -767
- package/dist/e30037b8/libsvc-simd.js +0 -4857
- package/dist/e30037b8/libsvc-simd.prod.d.ts +0 -767
- package/dist/e30037b8/libsvc-simd.prod.js +0 -209
- package/dist/e30037b8/libsvc-simd.prod.wasm +0 -0
- package/dist/e30037b8/libsvc-simd.wasm +0 -0
- package/dist/e30037b8/libsvc.d.ts +0 -767
- package/dist/e30037b8/libsvc.js +0 -4857
- package/dist/e30037b8/libsvc.prod.d.ts +0 -767
- package/dist/e30037b8/libsvc.prod.js +0 -209
- package/dist/e30037b8/libsvc.prod.wasm +0 -0
- package/dist/e30037b8/libsvc.wasm +0 -0
- package/dist/e30037b8/native-audio-worker.global.js +0 -1583
- package/dist/e30037b8/native-audio-worker.global.prod.js +0 -15
- package/dist/e30037b8/native-video-worker.global.js +0 -1960
- package/dist/e30037b8/native-video-worker.global.prod.js +0 -15
- package/dist/e30037b8/worklet-audio-worker.global.js +0 -900
- package/dist/e30037b8/worklet-audio-worker.global.prod.js +0 -15
|
@@ -1,900 +0,0 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/*! *****************************************************************************
|
|
5
|
-
Copyright (c) Microsoft Corporation.
|
|
6
|
-
|
|
7
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
8
|
-
purpose with or without fee is hereby granted.
|
|
9
|
-
|
|
10
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
11
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
12
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
13
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
14
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
15
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
16
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
17
|
-
***************************************************************************** */
|
|
18
|
-
|
|
19
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
20
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
21
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
22
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
23
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
24
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
25
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function pipeline(middleware) {
|
|
30
|
-
return (context, next) => {
|
|
31
|
-
// last called middleware
|
|
32
|
-
let index = -1;
|
|
33
|
-
const run = (i) => __awaiter(this, void 0, void 0, function* () {
|
|
34
|
-
if (i <= index) {
|
|
35
|
-
console.warn('next() called multiple times');
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
index = i;
|
|
39
|
-
let callback = middleware[i];
|
|
40
|
-
if (i === middleware.length)
|
|
41
|
-
callback = next;
|
|
42
|
-
if (!callback)
|
|
43
|
-
return;
|
|
44
|
-
if (callback.length > 1) {
|
|
45
|
-
return callback(context, dispatch);
|
|
46
|
-
}
|
|
47
|
-
yield callback(context, dispatch);
|
|
48
|
-
return dispatch();
|
|
49
|
-
});
|
|
50
|
-
const dispatch = () => run(index + 1);
|
|
51
|
-
return dispatch();
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
class MojoReceiver {
|
|
56
|
-
constructor(channel, pipe) {
|
|
57
|
-
this.middleware = [];
|
|
58
|
-
this.pipe = pipe || Math.random().toString(36).slice(3);
|
|
59
|
-
this.channel = channel;
|
|
60
|
-
}
|
|
61
|
-
get valid() {
|
|
62
|
-
return this.channel.has(this.pipe);
|
|
63
|
-
}
|
|
64
|
-
implement(key, invoke) {
|
|
65
|
-
const m = (ctx, next) => __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
const { method, params, status, required, attached = {} } = ctx.data;
|
|
67
|
-
if (key !== method) {
|
|
68
|
-
return next();
|
|
69
|
-
}
|
|
70
|
-
let handled = false;
|
|
71
|
-
const transfer = [];
|
|
72
|
-
const reAttached = {};
|
|
73
|
-
const done = (payload) => {
|
|
74
|
-
if (handled) {
|
|
75
|
-
console.warn(`receiver[${this}] - ${method} reply multiple times`);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
handled = true;
|
|
79
|
-
this.channel.send(Object.assign(Object.assign(Object.assign({}, ctx.data), {
|
|
80
|
-
// override params as it may contains un-cloned object
|
|
81
|
-
params: undefined,
|
|
82
|
-
// override attached as it may contains un-cloned object
|
|
83
|
-
attached: reAttached }), payload), transfer);
|
|
84
|
-
};
|
|
85
|
-
const reply = {
|
|
86
|
-
transfer: (...args) => {
|
|
87
|
-
if (required) {
|
|
88
|
-
transfer.push(...args);
|
|
89
|
-
}
|
|
90
|
-
return reply;
|
|
91
|
-
},
|
|
92
|
-
resolve: (value) => {
|
|
93
|
-
if (!required) {
|
|
94
|
-
handled = true;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
done({ resolve: value, status: status + 1 });
|
|
98
|
-
},
|
|
99
|
-
reject: (reason) => {
|
|
100
|
-
if (!required) {
|
|
101
|
-
handled = true;
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
done({ status: status - 1, reject: reason });
|
|
105
|
-
},
|
|
106
|
-
// attached
|
|
107
|
-
set: (key, val) => {
|
|
108
|
-
if (required) {
|
|
109
|
-
reAttached[key] = val;
|
|
110
|
-
}
|
|
111
|
-
return reply;
|
|
112
|
-
},
|
|
113
|
-
get: (key) => attached[key],
|
|
114
|
-
};
|
|
115
|
-
try {
|
|
116
|
-
const timestamp = Date.now();
|
|
117
|
-
yield invoke(reply, params, ctx.ports);
|
|
118
|
-
if (true) {
|
|
119
|
-
const delta = Date.now() - timestamp;
|
|
120
|
-
if (delta > 100) {
|
|
121
|
-
console.log(`receiver[${this}] - ${method}() took ${delta}ms`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
console.warn(error);
|
|
127
|
-
if (!handled) {
|
|
128
|
-
reply.reject(`${error}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
ctx.data.touched = true;
|
|
132
|
-
if (!handled) {
|
|
133
|
-
yield next();
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
this.middleware.unshift(m);
|
|
137
|
-
const unload = () => {
|
|
138
|
-
const index = this.middleware.findIndex((v) => v === m);
|
|
139
|
-
if (~index) {
|
|
140
|
-
this.middleware.splice(index, 1);
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
return unload;
|
|
144
|
-
}
|
|
145
|
-
reject(msg = '') {
|
|
146
|
-
this.channel.reject(this, msg);
|
|
147
|
-
}
|
|
148
|
-
as() {
|
|
149
|
-
return this;
|
|
150
|
-
}
|
|
151
|
-
callback() {
|
|
152
|
-
return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
const { pipe, status } = ctx.data;
|
|
154
|
-
if (pipe !== this.pipe) {
|
|
155
|
-
return next();
|
|
156
|
-
}
|
|
157
|
-
if (status) {
|
|
158
|
-
return next();
|
|
159
|
-
}
|
|
160
|
-
return pipeline(this.middleware)(ctx, next);
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
toString() {
|
|
164
|
-
return `${this.pipe}`;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
class MojoRemote {
|
|
169
|
-
constructor(channel, pipe) {
|
|
170
|
-
this.sequence = 0;
|
|
171
|
-
this.pendings = new Map();
|
|
172
|
-
this.pipe = pipe || Math.random().toString(36).slice(3);
|
|
173
|
-
this.channel = channel;
|
|
174
|
-
this.accepted = defer();
|
|
175
|
-
}
|
|
176
|
-
get ready() {
|
|
177
|
-
return this.accepted.promise;
|
|
178
|
-
}
|
|
179
|
-
get valid() {
|
|
180
|
-
return this.channel.has(this.pipe);
|
|
181
|
-
}
|
|
182
|
-
make(key) {
|
|
183
|
-
const transfer = [];
|
|
184
|
-
const attached = {};
|
|
185
|
-
const ready = (params) => __awaiter(this, void 0, void 0, function* () {
|
|
186
|
-
try {
|
|
187
|
-
yield this.ready;
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
console.warn(`remote[${this}] - ${key}(${params}) failed with '${error}'`);
|
|
191
|
-
throw error;
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
const send = (params, required) => {
|
|
195
|
-
this.channel.send({
|
|
196
|
-
pipe: this.pipe,
|
|
197
|
-
sequence: ++this.sequence,
|
|
198
|
-
timestamp: Date.now(),
|
|
199
|
-
method: key,
|
|
200
|
-
status: 0,
|
|
201
|
-
params,
|
|
202
|
-
required,
|
|
203
|
-
attached,
|
|
204
|
-
}, transfer);
|
|
205
|
-
};
|
|
206
|
-
const invoke = {
|
|
207
|
-
transfer: (...args) => {
|
|
208
|
-
transfer.push(...args);
|
|
209
|
-
return invoke;
|
|
210
|
-
},
|
|
211
|
-
post: (...params) => __awaiter(this, void 0, void 0, function* () {
|
|
212
|
-
yield ready(params);
|
|
213
|
-
send(params);
|
|
214
|
-
}),
|
|
215
|
-
invoke: (...params) => __awaiter(this, void 0, void 0, function* () {
|
|
216
|
-
yield ready(params);
|
|
217
|
-
send(params, true);
|
|
218
|
-
const d = defer();
|
|
219
|
-
this.pendings.set(this.sequence, d);
|
|
220
|
-
return d.promise;
|
|
221
|
-
}),
|
|
222
|
-
// attached
|
|
223
|
-
set: (key, val) => {
|
|
224
|
-
attached[key] = val;
|
|
225
|
-
return invoke;
|
|
226
|
-
},
|
|
227
|
-
get: (key) => attached[key],
|
|
228
|
-
};
|
|
229
|
-
return invoke;
|
|
230
|
-
}
|
|
231
|
-
break(msg = '') {
|
|
232
|
-
this.channel.break(this, msg);
|
|
233
|
-
this.pendings.forEach((p) => p.reject('broken'));
|
|
234
|
-
this.pendings.clear();
|
|
235
|
-
this.accepted.reject('broken');
|
|
236
|
-
// eslint-disable-next-line prefer-promise-reject-errors
|
|
237
|
-
this.accepted.promise = Promise.reject('broken');
|
|
238
|
-
// handle uncaught promise
|
|
239
|
-
this.accepted.promise.catch(NOOP);
|
|
240
|
-
}
|
|
241
|
-
callback() {
|
|
242
|
-
return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
|
|
243
|
-
const { pipe, sequence, timestamp, method, status, reject, resolve } = ctx.data;
|
|
244
|
-
if (pipe !== this.pipe) {
|
|
245
|
-
return next();
|
|
246
|
-
}
|
|
247
|
-
if (!status) {
|
|
248
|
-
return next();
|
|
249
|
-
}
|
|
250
|
-
const d = this.pendings.get(sequence);
|
|
251
|
-
if (!d) {
|
|
252
|
-
console.log(`remote[${this}] - receive unknown ${method} reply`);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (status < 0) {
|
|
256
|
-
d.reject(reject);
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
d.resolve(resolve);
|
|
260
|
-
}
|
|
261
|
-
this.pendings.delete(sequence);
|
|
262
|
-
{
|
|
263
|
-
const delta = Date.now() - timestamp;
|
|
264
|
-
if (delta > 100) {
|
|
265
|
-
console.log(`remote[${this}] - ${method}() took ${delta}ms`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
toString() {
|
|
271
|
-
return `${this.pipe}`;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
function defer() {
|
|
275
|
-
const until = {};
|
|
276
|
-
until.promise = new Promise((resolve, reject) => {
|
|
277
|
-
until.resolve = resolve;
|
|
278
|
-
until.reject = reject;
|
|
279
|
-
});
|
|
280
|
-
// handle uncaught promise
|
|
281
|
-
until.promise.catch(NOOP);
|
|
282
|
-
if ( typeof setTimeout !== 'undefined') {
|
|
283
|
-
setTimeout(() => until.reject('timeout'), 10000);
|
|
284
|
-
}
|
|
285
|
-
return until;
|
|
286
|
-
}
|
|
287
|
-
const NOOP = () => {
|
|
288
|
-
// nothing
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
class MojoChannel {
|
|
292
|
-
// fix me
|
|
293
|
-
// incompatible onmessage ev type
|
|
294
|
-
constructor(transport) {
|
|
295
|
-
this.remotes = new Map();
|
|
296
|
-
this.receivers = new Map();
|
|
297
|
-
this.pendingReceivers = new Set();
|
|
298
|
-
const previous = transport.onmessage;
|
|
299
|
-
this.transport = transport;
|
|
300
|
-
this.transport.onmessage = (ev) => {
|
|
301
|
-
const { data, ports = [] } = ev;
|
|
302
|
-
if (isString(data)) {
|
|
303
|
-
if (/^mojo/.test(data)) {
|
|
304
|
-
const [, pipe] = data.split(':');
|
|
305
|
-
const receiver = this.receivers.get(`${pipe}`);
|
|
306
|
-
if (receiver) {
|
|
307
|
-
this.send(`accept:${receiver}`);
|
|
308
|
-
this.oninvitation && this.oninvitation(pipe, receiver);
|
|
309
|
-
receiver.onready && receiver.onready();
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
this.pendingReceivers.add(pipe);
|
|
313
|
-
this.oninvitation && this.oninvitation(pipe);
|
|
314
|
-
if (this.pendingReceivers.has(pipe)) {
|
|
315
|
-
previous && previous.call(this.transport, ev);
|
|
316
|
-
}
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (/^accept/.test(data)) {
|
|
320
|
-
const [, pipe] = data.split(':');
|
|
321
|
-
const remote = this.remotes.get(pipe);
|
|
322
|
-
if (!remote) {
|
|
323
|
-
console.log(`unknown accept:\n${data}`);
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
remote.accepted.resolve();
|
|
327
|
-
remote.onaccept && remote.onaccept();
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
if (/^reject/.test(data)) {
|
|
331
|
-
const [, pipe, msg = 'rejected'] = data.split(':');
|
|
332
|
-
const remote = this.remotes.get(pipe);
|
|
333
|
-
if (!remote) {
|
|
334
|
-
console.log(`unknown reject:\n${data}`);
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
this.remotes.delete(pipe);
|
|
338
|
-
remote.accepted.reject(msg);
|
|
339
|
-
remote.onreject && remote.onreject(msg);
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
if (/^break/.test(data)) {
|
|
343
|
-
const [, pipe, msg = 'breaked'] = data.split(':');
|
|
344
|
-
if (this.pendingReceivers.has(pipe)) {
|
|
345
|
-
this.pendingReceivers.delete(pipe);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
const receiver = this.receivers.get(pipe);
|
|
349
|
-
if (!receiver) {
|
|
350
|
-
console.log(`unknown break:\n${data}`);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
this.receivers.delete(pipe);
|
|
354
|
-
receiver.onbreak && receiver.onbreak(msg);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
if (previous) {
|
|
358
|
-
previous.call(this.transport, ev);
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
console.log(`unknown invitation:\n${data}`);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
const ctx = { data, ports };
|
|
365
|
-
pipeline([
|
|
366
|
-
...Array.from(this.remotes.values()).map((p) => p.callback()),
|
|
367
|
-
...Array.from(this.receivers.values()).map((p) => p.callback()),
|
|
368
|
-
])(ctx, () => {
|
|
369
|
-
if (previous) {
|
|
370
|
-
previous.call(this.transport, ev);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
if (data.touched) {
|
|
374
|
-
|
|
375
|
-
console.log(`unhandled method: ${data.pipe}::${data.method}\n` +
|
|
376
|
-
`forget to call resolve() or reject() in method implement?`);
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
console.log('unknown message', data);
|
|
380
|
-
});
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
fork() {
|
|
384
|
-
return new MojoChannel(this.transport);
|
|
385
|
-
}
|
|
386
|
-
has(pipe) {
|
|
387
|
-
return this.remotes.has(pipe) || this.receivers.has(pipe);
|
|
388
|
-
}
|
|
389
|
-
close() {
|
|
390
|
-
this.remotes.forEach((v) => v.break());
|
|
391
|
-
this.remotes.clear();
|
|
392
|
-
this.receivers.forEach((v) => v.reject());
|
|
393
|
-
this.receivers.clear();
|
|
394
|
-
this.transport.onmessage = null;
|
|
395
|
-
this.transport = null;
|
|
396
|
-
}
|
|
397
|
-
send(msg, transfer) {
|
|
398
|
-
this.transport.postMessage(msg, transfer);
|
|
399
|
-
}
|
|
400
|
-
reject(receiver, msg = '') {
|
|
401
|
-
this.send(`reject:${receiver}:${msg}`);
|
|
402
|
-
this.receivers.delete(`${receiver}`);
|
|
403
|
-
}
|
|
404
|
-
break(remote, msg = '') {
|
|
405
|
-
if (!this.remotes.has(`${remote}`))
|
|
406
|
-
return;
|
|
407
|
-
this.send(`break:${remote}:${msg}`);
|
|
408
|
-
this.remotes.delete(`${remote}`);
|
|
409
|
-
}
|
|
410
|
-
remote(pipe) {
|
|
411
|
-
const remote = new MojoRemote(this, pipe && `${pipe}`);
|
|
412
|
-
this.remotes.set(`${remote}`, remote);
|
|
413
|
-
this.send(`mojo:${remote}`);
|
|
414
|
-
return remote;
|
|
415
|
-
}
|
|
416
|
-
receiver(pipe) {
|
|
417
|
-
if (pipe && this.receivers.has(`${pipe}`)) {
|
|
418
|
-
console.log(`duplicate pipe: ${pipe}`);
|
|
419
|
-
}
|
|
420
|
-
const receiver = new MojoReceiver(this, pipe && `${pipe}`);
|
|
421
|
-
this.receivers.set(`${receiver}`, receiver);
|
|
422
|
-
if (this.pendingReceivers.has(`${receiver}`)) {
|
|
423
|
-
this.send(`accept:${receiver}`);
|
|
424
|
-
this.pendingReceivers.delete(`${receiver}`);
|
|
425
|
-
receiver.onready && receiver.onready();
|
|
426
|
-
}
|
|
427
|
-
return receiver;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
const isString = (val) => typeof val === 'string';
|
|
431
|
-
|
|
432
|
-
class AudioFrameBuffer {
|
|
433
|
-
constructor(builder) {
|
|
434
|
-
const { length, numberOfChannels: channels = 1, sampleRate } = builder;
|
|
435
|
-
let { data } = builder;
|
|
436
|
-
this.length = length;
|
|
437
|
-
this.numberOfChannels = channels;
|
|
438
|
-
this.sampleRate = sampleRate;
|
|
439
|
-
this.duration = length / sampleRate;
|
|
440
|
-
if (!data || !data.length || !data[0].length) {
|
|
441
|
-
// AudioBuffer do not store data as a planar sequence
|
|
442
|
-
data = [...Array(channels)].map(() => new Float32Array(length));
|
|
443
|
-
}
|
|
444
|
-
if (data.length < channels) {
|
|
445
|
-
console.warn(`invalid buffer channels ${channels} vs ${data.length}`);
|
|
446
|
-
}
|
|
447
|
-
if (data[0].length < length) {
|
|
448
|
-
console.warn(`invalid buffer length ${length} vs ${data[0].length}`);
|
|
449
|
-
}
|
|
450
|
-
this.data = data;
|
|
451
|
-
}
|
|
452
|
-
// CopyFrom
|
|
453
|
-
static From(buffer) {
|
|
454
|
-
const { sampleRate, numberOfChannels, length } = buffer;
|
|
455
|
-
const data = [...Array(numberOfChannels).keys()].map((ch) => buffer.getChannelData(ch).slice());
|
|
456
|
-
return new AudioFrameBuffer({ length, numberOfChannels, sampleRate, data });
|
|
457
|
-
}
|
|
458
|
-
static Copy(dst, src) {
|
|
459
|
-
const { numberOfChannels: channels } = dst;
|
|
460
|
-
const { numberOfChannels: available } = src;
|
|
461
|
-
for (let ch = 0; ch < channels; ch++) {
|
|
462
|
-
dst.copyToChannel(src.getChannelData(Math.min(ch, available - 1)), ch);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
static Clip(buffer, begin, end) {
|
|
466
|
-
const { sampleRate, numberOfChannels } = buffer;
|
|
467
|
-
const data = AudioFrameBuffer.Data(buffer, begin, end);
|
|
468
|
-
const { length } = data[0];
|
|
469
|
-
return new AudioFrameBuffer({ length, numberOfChannels, sampleRate, data });
|
|
470
|
-
}
|
|
471
|
-
static Data(buffer, begin, end) {
|
|
472
|
-
return [...Array(buffer.numberOfChannels)].map((_, ch) => buffer.getChannelData(ch).subarray(begin, end));
|
|
473
|
-
}
|
|
474
|
-
static Builder(buffer) {
|
|
475
|
-
const { length, numberOfChannels, sampleRate } = buffer;
|
|
476
|
-
const data = AudioFrameBuffer.Data(buffer);
|
|
477
|
-
return {
|
|
478
|
-
length,
|
|
479
|
-
numberOfChannels,
|
|
480
|
-
sampleRate,
|
|
481
|
-
data,
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
copyFromChannel(destination, channel = 0, bufferOffset = 0) {
|
|
485
|
-
if (channel >= this.numberOfChannels) {
|
|
486
|
-
console.warn('invalid channel');
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
const data = this.getChannelData(channel);
|
|
490
|
-
if (bufferOffset >= data.length) {
|
|
491
|
-
console.warn('invalid offset');
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
const source = data.subarray(bufferOffset);
|
|
495
|
-
destination.set(source.subarray(0, Math.min(source.length, destination.length)));
|
|
496
|
-
}
|
|
497
|
-
copyToChannel(source, channel = 0, bufferOffset = 0) {
|
|
498
|
-
if (channel >= this.numberOfChannels) {
|
|
499
|
-
console.warn('invalid channel');
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
const data = this.getChannelData(channel);
|
|
503
|
-
if (bufferOffset >= this.length) {
|
|
504
|
-
console.warn('invalid offset');
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const length = Math.min(this.length - bufferOffset, source.length);
|
|
508
|
-
const clipped = source.subarray(0, length);
|
|
509
|
-
data.set(clipped, bufferOffset);
|
|
510
|
-
}
|
|
511
|
-
getChannelData(channel) {
|
|
512
|
-
return this.data[channel];
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// export const enum SpeechType {
|
|
517
|
-
var VADActivity;
|
|
518
|
-
(function (VADActivity) {
|
|
519
|
-
VADActivity[VADActivity["kVadActive"] = 0] = "kVadActive";
|
|
520
|
-
VADActivity[VADActivity["kVadPassive"] = 1] = "kVadPassive";
|
|
521
|
-
VADActivity[VADActivity["kVadUnknown"] = 2] = "kVadUnknown";
|
|
522
|
-
})(VADActivity || (VADActivity = {}));
|
|
523
|
-
// export const enum SpeechType {
|
|
524
|
-
var SpeechType;
|
|
525
|
-
(function (SpeechType) {
|
|
526
|
-
SpeechType[SpeechType["kNormalSpeech"] = 0] = "kNormalSpeech";
|
|
527
|
-
SpeechType[SpeechType["kPLC"] = 1] = "kPLC";
|
|
528
|
-
SpeechType[SpeechType["kCNG"] = 2] = "kCNG";
|
|
529
|
-
SpeechType[SpeechType["kPLCCNG"] = 3] = "kPLCCNG";
|
|
530
|
-
SpeechType[SpeechType["kCodecPLC"] = 4] = "kCodecPLC";
|
|
531
|
-
SpeechType[SpeechType["kUndefined"] = 5] = "kUndefined";
|
|
532
|
-
})(SpeechType || (SpeechType = {}));
|
|
533
|
-
class AudioFrame {
|
|
534
|
-
constructor(builder) {
|
|
535
|
-
this.buffer = builder.buffer;
|
|
536
|
-
this.timestamp = builder.timestamp;
|
|
537
|
-
this.elapsedTimeMs = builder.elapsedTimeMs;
|
|
538
|
-
this.ntpTimeMs = builder.ntpTimeMs;
|
|
539
|
-
this.vad = builder.vad || VADActivity.kVadUnknown;
|
|
540
|
-
this.speech = builder.speech || SpeechType.kUndefined;
|
|
541
|
-
}
|
|
542
|
-
get sampleRate() {
|
|
543
|
-
return this.buffer.sampleRate;
|
|
544
|
-
}
|
|
545
|
-
get samples() {
|
|
546
|
-
return this.buffer.length;
|
|
547
|
-
}
|
|
548
|
-
get channels() {
|
|
549
|
-
return this.buffer.numberOfChannels;
|
|
550
|
-
}
|
|
551
|
-
get duration() {
|
|
552
|
-
return this.buffer.duration;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
function CopyAudioFrame(output, outputOffset = 0, input, inputOffset = 0, length = input.length) {
|
|
557
|
-
const { numberOfChannels: channels } = output;
|
|
558
|
-
const { numberOfChannels: available } = input;
|
|
559
|
-
for (let channel = 0; channel < channels; channel++) {
|
|
560
|
-
const source = input
|
|
561
|
-
.getChannelData(Math.min(channel, available - 1))
|
|
562
|
-
.subarray(inputOffset, inputOffset + length);
|
|
563
|
-
output.copyToChannel(source, channel, outputOffset);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
function makeAudioReshaper(wanted, callback, factory) {
|
|
568
|
-
let pending;
|
|
569
|
-
let offset = 0;
|
|
570
|
-
return (input) => {
|
|
571
|
-
const { samples, channels, sampleRate } = input;
|
|
572
|
-
let current = 0;
|
|
573
|
-
while (current < samples) {
|
|
574
|
-
const needed = wanted - offset;
|
|
575
|
-
const available = samples - current;
|
|
576
|
-
const total = Math.min(available, needed);
|
|
577
|
-
if (!needed) {
|
|
578
|
-
callback(pending);
|
|
579
|
-
pending = null;
|
|
580
|
-
}
|
|
581
|
-
if (!pending) {
|
|
582
|
-
pending = factory
|
|
583
|
-
? factory(wanted)
|
|
584
|
-
: new AudioFrame({
|
|
585
|
-
buffer: new AudioFrameBuffer({
|
|
586
|
-
length: wanted,
|
|
587
|
-
numberOfChannels: channels,
|
|
588
|
-
sampleRate,
|
|
589
|
-
}),
|
|
590
|
-
});
|
|
591
|
-
offset = 0;
|
|
592
|
-
}
|
|
593
|
-
CopyAudioFrame(pending.buffer, offset, input.buffer, current, total);
|
|
594
|
-
current += total;
|
|
595
|
-
offset += total;
|
|
596
|
-
}
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
class AudioFrameQueue {
|
|
601
|
-
constructor() {
|
|
602
|
-
this.queue = [];
|
|
603
|
-
// total audio samples
|
|
604
|
-
this.total = 0;
|
|
605
|
-
// audio samples offset
|
|
606
|
-
this.offset = 0;
|
|
607
|
-
}
|
|
608
|
-
get length() {
|
|
609
|
-
return this.total;
|
|
610
|
-
}
|
|
611
|
-
clear() {
|
|
612
|
-
this.queue.length = 0;
|
|
613
|
-
this.total = 0;
|
|
614
|
-
this.offset = 0;
|
|
615
|
-
}
|
|
616
|
-
shift() {
|
|
617
|
-
if (!this.total)
|
|
618
|
-
return;
|
|
619
|
-
const frame = this.queue[0];
|
|
620
|
-
const available = frame.samples - this.offset;
|
|
621
|
-
if (this.offset) {
|
|
622
|
-
console.log('maybe unexpected samples');
|
|
623
|
-
}
|
|
624
|
-
return this.pull(available);
|
|
625
|
-
}
|
|
626
|
-
push(frame) {
|
|
627
|
-
const input = (frame) => {
|
|
628
|
-
this.queue.push(frame);
|
|
629
|
-
this.total += frame.samples;
|
|
630
|
-
};
|
|
631
|
-
if (!this.onpush) {
|
|
632
|
-
input(frame);
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
const { samples, callback, factory, reshape = false } = this.onpush;
|
|
636
|
-
let { reshaper } = this.onpush;
|
|
637
|
-
if (reshape) {
|
|
638
|
-
if (!reshaper) {
|
|
639
|
-
reshaper = makeAudioReshaper(samples, input, factory);
|
|
640
|
-
this.onpush.reshaper = reshaper;
|
|
641
|
-
}
|
|
642
|
-
// reshape & input
|
|
643
|
-
reshaper(frame);
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
input(frame);
|
|
647
|
-
}
|
|
648
|
-
while (this.total - this.offset >= samples) {
|
|
649
|
-
callback(reshape ? this.shift() : this.pull(samples, factory && factory(samples)));
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
pull(wanted, output) {
|
|
653
|
-
if (wanted <= 0) {
|
|
654
|
-
wanted < 0 && console.warn(`invalid samples: ${wanted}`);
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
if (this.onpull) {
|
|
658
|
-
const { samples, callback, eager } = this.onpull;
|
|
659
|
-
while (this.total < Math.max(samples, wanted) * (eager ? 2 : 1)) {
|
|
660
|
-
const frame = callback(this.total, wanted);
|
|
661
|
-
if (!frame) {
|
|
662
|
-
break;
|
|
663
|
-
}
|
|
664
|
-
this.queue.push(frame);
|
|
665
|
-
this.total += frame.samples;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
if (this.total < wanted) {
|
|
669
|
-
console.warn('audio frame drained');
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
let current = 0;
|
|
673
|
-
let { offset } = this;
|
|
674
|
-
while (current < wanted) {
|
|
675
|
-
const frame = this.queue.shift();
|
|
676
|
-
const available = frame.samples - offset;
|
|
677
|
-
const needed = wanted - current;
|
|
678
|
-
const length = Math.min(available, needed);
|
|
679
|
-
if (!available) {
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
// clip buffer w/o copy
|
|
683
|
-
if (!output && !current && available >= needed) {
|
|
684
|
-
const buffer = AudioFrameBuffer.Clip(frame.buffer, offset, offset + needed);
|
|
685
|
-
output = new AudioFrame({ buffer });
|
|
686
|
-
if (available > needed) {
|
|
687
|
-
offset += length;
|
|
688
|
-
this.queue.unshift(frame);
|
|
689
|
-
}
|
|
690
|
-
else {
|
|
691
|
-
offset = 0;
|
|
692
|
-
}
|
|
693
|
-
break;
|
|
694
|
-
}
|
|
695
|
-
// copy needed or available
|
|
696
|
-
if (!output) {
|
|
697
|
-
const buffer = new AudioFrameBuffer({
|
|
698
|
-
length: wanted,
|
|
699
|
-
numberOfChannels: frame.channels,
|
|
700
|
-
sampleRate: frame.sampleRate,
|
|
701
|
-
});
|
|
702
|
-
output = new AudioFrame({ buffer });
|
|
703
|
-
}
|
|
704
|
-
if (output.samples < wanted) {
|
|
705
|
-
console.warn('invalid frame buffer length');
|
|
706
|
-
}
|
|
707
|
-
CopyAudioFrame(output.buffer, current, frame.buffer, offset, length);
|
|
708
|
-
current += length;
|
|
709
|
-
if (available > needed) {
|
|
710
|
-
offset += length;
|
|
711
|
-
this.queue.unshift(frame);
|
|
712
|
-
break;
|
|
713
|
-
}
|
|
714
|
-
offset = 0;
|
|
715
|
-
if (this.onpull) {
|
|
716
|
-
// optional chaining
|
|
717
|
-
// this.onpull.drain?.(frame);
|
|
718
|
-
const { drain } = this.onpull;
|
|
719
|
-
drain && drain(frame);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
this.total -= wanted;
|
|
723
|
-
this.offset = offset;
|
|
724
|
-
return output;
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
class WorkletAudioTransport extends AudioWorkletProcessor {
|
|
729
|
-
constructor({ processorOptions = {} }) {
|
|
730
|
-
super();
|
|
731
|
-
this.bufferPool = [];
|
|
732
|
-
this.bufferSize = processorOptions.bufferSize || (sampleRate / 100) * 3; // 30ms
|
|
733
|
-
this.channel = new MojoChannel(this.port);
|
|
734
|
-
this.receiver = this.channel.receiver('worklet-audio-transport-host');
|
|
735
|
-
this.receiver.implement('setup', (reply, [sinkref = false], [port1, port2]) => {
|
|
736
|
-
if (!port1) {
|
|
737
|
-
console.warn('setup() without host message port');
|
|
738
|
-
reply.resolve();
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
dispose();
|
|
742
|
-
// processor api
|
|
743
|
-
if (!port2) {
|
|
744
|
-
this.host = new MojoChannel(port1);
|
|
745
|
-
this.processor = this.host.remote('worklet-audio-processor-host');
|
|
746
|
-
reply.resolve();
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
this.sinkref = sinkref;
|
|
750
|
-
// source|sink api
|
|
751
|
-
this.sourceHost = new MojoChannel(port1);
|
|
752
|
-
this.source = this.sourceHost.remote('worklet-audio-source-host');
|
|
753
|
-
this.sinkHost = new MojoChannel(port2);
|
|
754
|
-
this.sink = this.sinkHost.remote('worklet-audio-sink-host');
|
|
755
|
-
reply.resolve();
|
|
756
|
-
});
|
|
757
|
-
const disable = (remote) => {
|
|
758
|
-
if (!remote)
|
|
759
|
-
return;
|
|
760
|
-
remote.break();
|
|
761
|
-
};
|
|
762
|
-
const close = (host) => {
|
|
763
|
-
if (!host)
|
|
764
|
-
return;
|
|
765
|
-
host.transport.close();
|
|
766
|
-
host.close();
|
|
767
|
-
};
|
|
768
|
-
const dispose = () => {
|
|
769
|
-
this.host = close(this.host);
|
|
770
|
-
this.processor = disable(this.processor);
|
|
771
|
-
this.sourceHost = close(this.sourceHost);
|
|
772
|
-
this.source = disable(this.source);
|
|
773
|
-
this.sinkHost = close(this.sinkHost);
|
|
774
|
-
this.sink = disable(this.sink);
|
|
775
|
-
};
|
|
776
|
-
this.processor = this.channel.remote('worklet-audio-processor-host');
|
|
777
|
-
this.inputBuffer = new AudioFrameQueue();
|
|
778
|
-
this.outputBuffer = new AudioFrameQueue();
|
|
779
|
-
const onpull = (builder) => {
|
|
780
|
-
if (!builder)
|
|
781
|
-
return;
|
|
782
|
-
const buffer = new AudioFrameBuffer(builder);
|
|
783
|
-
const frame = new AudioFrame({ buffer });
|
|
784
|
-
const { outputBuffer, bufferSize, processor } = this;
|
|
785
|
-
outputBuffer.push(frame);
|
|
786
|
-
const delay = outputBuffer.total;
|
|
787
|
-
if (delay > bufferSize * 2) {
|
|
788
|
-
console.log(`output delay: ${Math.ceil((delay / sampleRate) * 1000)}ms`);
|
|
789
|
-
processor && processor.make('processdelay').post(delay);
|
|
790
|
-
}
|
|
791
|
-
if (this.sinkref && this.source) {
|
|
792
|
-
this.source.make('onref').post(builder);
|
|
793
|
-
}
|
|
794
|
-
};
|
|
795
|
-
this.inputBuffer.onpush = {
|
|
796
|
-
samples: this.bufferSize,
|
|
797
|
-
reshape: true,
|
|
798
|
-
factory: (length) => {
|
|
799
|
-
const frame = this.bufferPool.shift();
|
|
800
|
-
if (!frame || frame.buffer.length !== length) {
|
|
801
|
-
const buffer = new AudioFrameBuffer({
|
|
802
|
-
length,
|
|
803
|
-
numberOfChannels: this.channels,
|
|
804
|
-
sampleRate,
|
|
805
|
-
});
|
|
806
|
-
return new AudioFrame({ buffer });
|
|
807
|
-
}
|
|
808
|
-
if (this.bufferPool.length > 4) {
|
|
809
|
-
console.log(`reduce audio buffer pool: ${this.bufferPool.length}`);
|
|
810
|
-
}
|
|
811
|
-
while (this.bufferPool.length > 4) {
|
|
812
|
-
this.bufferPool.pop();
|
|
813
|
-
}
|
|
814
|
-
return frame;
|
|
815
|
-
},
|
|
816
|
-
callback: (frame) => {
|
|
817
|
-
const builder = AudioFrameBuffer.Builder(frame.buffer);
|
|
818
|
-
const { processor, source } = this;
|
|
819
|
-
// processor api
|
|
820
|
-
if (processor) {
|
|
821
|
-
processor
|
|
822
|
-
.make('process')
|
|
823
|
-
.transfer(...builder.data.map((d) => d.buffer))
|
|
824
|
-
.invoke(builder)
|
|
825
|
-
.then(onpull)
|
|
826
|
-
.catch(() => {
|
|
827
|
-
// ignore
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
// source|sink api
|
|
831
|
-
if (source) {
|
|
832
|
-
source
|
|
833
|
-
.make('onpush')
|
|
834
|
-
.transfer(...builder.data.map((d) => d.buffer))
|
|
835
|
-
.post(builder);
|
|
836
|
-
}
|
|
837
|
-
},
|
|
838
|
-
};
|
|
839
|
-
let pulling = false;
|
|
840
|
-
this.outputBuffer.onpull = {
|
|
841
|
-
samples: this.bufferSize,
|
|
842
|
-
callback: () => {
|
|
843
|
-
if (pulling)
|
|
844
|
-
return;
|
|
845
|
-
const { sink, bufferSize, channels } = this;
|
|
846
|
-
// source|sink api
|
|
847
|
-
if (sink) {
|
|
848
|
-
sink
|
|
849
|
-
.make('onpull')
|
|
850
|
-
.invoke(bufferSize, channels, sampleRate)
|
|
851
|
-
.then(onpull)
|
|
852
|
-
.finally(() => (pulling = false));
|
|
853
|
-
pulling = true;
|
|
854
|
-
}
|
|
855
|
-
},
|
|
856
|
-
drain: (frame) => {
|
|
857
|
-
this.bufferPool.push(frame);
|
|
858
|
-
},
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
process(inputs, outputs) {
|
|
862
|
-
const input = inputs[0];
|
|
863
|
-
const output = outputs[0];
|
|
864
|
-
if (!output.length)
|
|
865
|
-
return true;
|
|
866
|
-
const numberOfChannels = output.length;
|
|
867
|
-
const samples = output[0].length;
|
|
868
|
-
this.channels = numberOfChannels;
|
|
869
|
-
// input is reused which means buffer can not be queued.
|
|
870
|
-
this.inputBuffer.push(new AudioFrame({
|
|
871
|
-
buffer: new AudioFrameBuffer({
|
|
872
|
-
length: samples,
|
|
873
|
-
numberOfChannels,
|
|
874
|
-
sampleRate,
|
|
875
|
-
data: input,
|
|
876
|
-
}),
|
|
877
|
-
}));
|
|
878
|
-
const frame = new AudioFrame({
|
|
879
|
-
buffer: new AudioFrameBuffer({
|
|
880
|
-
length: samples,
|
|
881
|
-
numberOfChannels,
|
|
882
|
-
sampleRate,
|
|
883
|
-
data: output,
|
|
884
|
-
}),
|
|
885
|
-
});
|
|
886
|
-
if (!this.outputBuffer.pull(samples, frame)) {
|
|
887
|
-
// copy last sample if drained, prevent audio glitches
|
|
888
|
-
if (this.lastsample) {
|
|
889
|
-
output.forEach((data, ch) => data.fill(this.lastsample[ch]));
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
else {
|
|
893
|
-
this.lastsample = output.map((val) => val[val.length - 1]);
|
|
894
|
-
}
|
|
895
|
-
return true;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
registerProcessor('worklet-audio-transport', WorkletAudioTransport);
|
|
899
|
-
|
|
900
|
-
}());
|