@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.
Files changed (55) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/ylink-sdk-mobile.umd.js +70 -70
  3. package/package.json +1 -1
  4. package/dist/e30037b8/VERSION +0 -6
  5. package/dist/e30037b8/libipvp-simd.d.ts +0 -474
  6. package/dist/e30037b8/libipvp-simd.js +0 -3267
  7. package/dist/e30037b8/libipvp-simd.prod.d.ts +0 -474
  8. package/dist/e30037b8/libipvp-simd.prod.js +0 -184
  9. package/dist/e30037b8/libipvp-simd.prod.wasm +0 -0
  10. package/dist/e30037b8/libipvp-simd.wasm +0 -0
  11. package/dist/e30037b8/libipvp.d.ts +0 -474
  12. package/dist/e30037b8/libipvp.js +0 -3267
  13. package/dist/e30037b8/libipvp.prod.d.ts +0 -474
  14. package/dist/e30037b8/libipvp.prod.js +0 -184
  15. package/dist/e30037b8/libipvp.prod.wasm +0 -0
  16. package/dist/e30037b8/libipvp.wasm +0 -0
  17. package/dist/e30037b8/librtc.d.ts +0 -438
  18. package/dist/e30037b8/librtc.global.js +0 -5863
  19. package/dist/e30037b8/librtc.global.prod.js +0 -15
  20. package/dist/e30037b8/libsfu-simd.d.ts +0 -767
  21. package/dist/e30037b8/libsfu-simd.js +0 -4822
  22. package/dist/e30037b8/libsfu-simd.prod.d.ts +0 -767
  23. package/dist/e30037b8/libsfu-simd.prod.js +0 -209
  24. package/dist/e30037b8/libsfu-simd.prod.wasm +0 -0
  25. package/dist/e30037b8/libsfu-simd.wasm +0 -0
  26. package/dist/e30037b8/libsfu.d.ts +0 -767
  27. package/dist/e30037b8/libsfu.js +0 -4822
  28. package/dist/e30037b8/libsfu.prod.d.ts +0 -767
  29. package/dist/e30037b8/libsfu.prod.js +0 -209
  30. package/dist/e30037b8/libsfu.prod.wasm +0 -0
  31. package/dist/e30037b8/libsfu.wasm +0 -0
  32. package/dist/e30037b8/libsvc-simd-m1.d.ts +0 -767
  33. package/dist/e30037b8/libsvc-simd-m1.js +0 -4921
  34. package/dist/e30037b8/libsvc-simd-m1.prod.d.ts +0 -767
  35. package/dist/e30037b8/libsvc-simd-m1.prod.js +0 -209
  36. package/dist/e30037b8/libsvc-simd-m1.prod.wasm +0 -0
  37. package/dist/e30037b8/libsvc-simd-m1.wasm +0 -0
  38. package/dist/e30037b8/libsvc-simd.d.ts +0 -767
  39. package/dist/e30037b8/libsvc-simd.js +0 -4857
  40. package/dist/e30037b8/libsvc-simd.prod.d.ts +0 -767
  41. package/dist/e30037b8/libsvc-simd.prod.js +0 -209
  42. package/dist/e30037b8/libsvc-simd.prod.wasm +0 -0
  43. package/dist/e30037b8/libsvc-simd.wasm +0 -0
  44. package/dist/e30037b8/libsvc.d.ts +0 -767
  45. package/dist/e30037b8/libsvc.js +0 -4857
  46. package/dist/e30037b8/libsvc.prod.d.ts +0 -767
  47. package/dist/e30037b8/libsvc.prod.js +0 -209
  48. package/dist/e30037b8/libsvc.prod.wasm +0 -0
  49. package/dist/e30037b8/libsvc.wasm +0 -0
  50. package/dist/e30037b8/native-audio-worker.global.js +0 -1583
  51. package/dist/e30037b8/native-audio-worker.global.prod.js +0 -15
  52. package/dist/e30037b8/native-video-worker.global.js +0 -1960
  53. package/dist/e30037b8/native-video-worker.global.prod.js +0 -15
  54. package/dist/e30037b8/worklet-audio-worker.global.js +0 -900
  55. 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
- }());