@blockcast/mmt-render 0.1.0-main.c71423b8a4e4 → 0.1.0-main.ce3c8aeb7f68
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/audio/audio-render-pipeline.js +192 -247
- package/dist/audio/audio-render-pipeline.js.map +1 -1
- package/dist/audio/audio-ring-buffer.js +93 -127
- package/dist/audio/audio-ring-buffer.js.map +1 -1
- package/dist/audio/index.js +288 -360
- package/dist/audio/index.js.map +2 -2
- package/dist/pacing/frame-pacer.js +18 -38
- package/dist/pacing/frame-pacer.js.map +1 -1
- package/dist/pacing/index.js +18 -38
- package/dist/pacing/index.js.map +1 -1
- package/dist/video/index.js +103 -137
- package/dist/video/index.js.map +1 -1
- package/dist/video/keyframe-gate.js +5 -17
- package/dist/video/keyframe-gate.js.map +1 -1
- package/dist/video/video-render-pipeline.js +103 -137
- package/dist/video/video-render-pipeline.js.map +1 -1
- package/dist/worklet/render-worklet.js +171 -219
- package/dist/worklet/render-worklet.js.map +2 -2
- package/package.json +3 -3
|
@@ -1,41 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
(() => {
|
|
3
|
-
var __typeError = (msg) => {
|
|
4
|
-
throw TypeError(msg);
|
|
5
|
-
};
|
|
6
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
7
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
8
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
9
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
10
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
11
|
-
var __privateWrapper = (obj, member, setter, getter) => ({
|
|
12
|
-
set _(value) {
|
|
13
|
-
__privateSet(obj, member, value, setter);
|
|
14
|
-
},
|
|
15
|
-
get _() {
|
|
16
|
-
return __privateGet(obj, member, getter);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
3
|
// src/audio/audio-ring-buffer.ts
|
|
21
|
-
var _buffer, _writeIndex, _readIndex, _stalled, _startupFrames, _resumeFrames, _resumeFollowsStartup, _hasStarted, _capacityHeadroomFrames, _timestampAnchors, _diagEnabled, _diagReads, _diagFillSum, _diagOverflowSamples, _AudioRingBuffer_instances, pruneTimestampAnchors_fn, refillFrames_fn;
|
|
22
4
|
var AudioRingBuffer = class {
|
|
5
|
+
#buffer;
|
|
6
|
+
#writeIndex = 0;
|
|
7
|
+
#readIndex = 0;
|
|
8
|
+
#stalled;
|
|
9
|
+
#startupFrames;
|
|
10
|
+
#resumeFrames;
|
|
11
|
+
#resumeFollowsStartup;
|
|
12
|
+
#hasStarted;
|
|
13
|
+
#capacityHeadroomFrames;
|
|
14
|
+
#timestampAnchors = [];
|
|
15
|
+
#diagEnabled;
|
|
16
|
+
#diagReads = 0;
|
|
17
|
+
#diagFillSum = 0;
|
|
18
|
+
#diagOverflowSamples = 0;
|
|
23
19
|
constructor(config) {
|
|
24
|
-
__privateAdd(this, _AudioRingBuffer_instances);
|
|
25
|
-
__privateAdd(this, _buffer);
|
|
26
|
-
__privateAdd(this, _writeIndex, 0);
|
|
27
|
-
__privateAdd(this, _readIndex, 0);
|
|
28
|
-
__privateAdd(this, _stalled);
|
|
29
|
-
__privateAdd(this, _startupFrames);
|
|
30
|
-
__privateAdd(this, _resumeFrames);
|
|
31
|
-
__privateAdd(this, _resumeFollowsStartup);
|
|
32
|
-
__privateAdd(this, _hasStarted);
|
|
33
|
-
__privateAdd(this, _capacityHeadroomFrames);
|
|
34
|
-
__privateAdd(this, _timestampAnchors, []);
|
|
35
|
-
__privateAdd(this, _diagEnabled);
|
|
36
|
-
__privateAdd(this, _diagReads, 0);
|
|
37
|
-
__privateAdd(this, _diagFillSum, 0);
|
|
38
|
-
__privateAdd(this, _diagOverflowSamples, 0);
|
|
39
20
|
if (!Number.isInteger(config.channels) || config.channels <= 0) {
|
|
40
21
|
throw new Error("invalid channels");
|
|
41
22
|
}
|
|
@@ -61,35 +42,35 @@
|
|
|
61
42
|
}
|
|
62
43
|
this.channels = config.channels;
|
|
63
44
|
this.rate = config.rate;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
45
|
+
this.#startupFrames = startupFrames;
|
|
46
|
+
this.#resumeFrames = resumeFrames;
|
|
47
|
+
this.#resumeFollowsStartup = config.resumeFrames === void 0;
|
|
48
|
+
this.#hasStarted = config.startUnstalled ?? false;
|
|
49
|
+
this.#capacityHeadroomFrames = capacityFrames - thresholdFrames;
|
|
50
|
+
this.#stalled = !(config.startUnstalled ?? false);
|
|
51
|
+
this.#diagEnabled = config.diag ?? false;
|
|
52
|
+
this.#buffer = Array.from(
|
|
72
53
|
{ length: config.channels },
|
|
73
54
|
() => new Float32Array(capacityFrames)
|
|
74
|
-
)
|
|
55
|
+
);
|
|
75
56
|
}
|
|
76
57
|
get stalled() {
|
|
77
|
-
return
|
|
58
|
+
return this.#stalled;
|
|
78
59
|
}
|
|
79
60
|
get startupFrames() {
|
|
80
|
-
return
|
|
61
|
+
return this.#startupFrames;
|
|
81
62
|
}
|
|
82
63
|
get capacity() {
|
|
83
|
-
return
|
|
64
|
+
return this.#buffer[0].length;
|
|
84
65
|
}
|
|
85
66
|
get length() {
|
|
86
|
-
return
|
|
67
|
+
return this.#writeIndex - this.#readIndex;
|
|
87
68
|
}
|
|
88
69
|
/** Timestamp of the next media sample after the PCM already emitted. */
|
|
89
70
|
get timestampUs() {
|
|
90
|
-
const anchor =
|
|
91
|
-
if (!anchor || anchor.sampleIndex >
|
|
92
|
-
return anchor.timestampUs + (
|
|
71
|
+
const anchor = this.#timestampAnchors[0];
|
|
72
|
+
if (!anchor || anchor.sampleIndex > this.#readIndex) return void 0;
|
|
73
|
+
return anchor.timestampUs + (this.#readIndex - anchor.sampleIndex) / this.rate * 1e6;
|
|
93
74
|
}
|
|
94
75
|
write(timestampUs, data) {
|
|
95
76
|
if (data.length !== this.channels) throw new Error("wrong channel count");
|
|
@@ -99,68 +80,68 @@
|
|
|
99
80
|
if (data.some((channel) => channel.length !== samples)) {
|
|
100
81
|
throw new Error("mismatched channel lengths");
|
|
101
82
|
}
|
|
102
|
-
const start =
|
|
83
|
+
const start = this.#writeIndex;
|
|
103
84
|
const end = start + samples;
|
|
104
|
-
|
|
105
|
-
const overflow = end -
|
|
85
|
+
this.#timestampAnchors.push({ sampleIndex: start, timestampUs });
|
|
86
|
+
const overflow = end - this.#readIndex - this.capacity;
|
|
106
87
|
if (overflow > 0) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
|
|
88
|
+
this.#stalled = false;
|
|
89
|
+
this.#hasStarted = true;
|
|
90
|
+
this.#readIndex += overflow;
|
|
91
|
+
if (this.#diagEnabled) this.#diagOverflowSamples += overflow;
|
|
92
|
+
this.#pruneTimestampAnchors();
|
|
112
93
|
}
|
|
113
|
-
const refillFrames =
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
94
|
+
const refillFrames = this.#hasStarted ? this.#resumeFrames : this.#startupFrames;
|
|
95
|
+
if (this.#stalled && end - this.#readIndex >= refillFrames) {
|
|
96
|
+
this.#stalled = false;
|
|
97
|
+
this.#hasStarted = true;
|
|
117
98
|
}
|
|
118
99
|
for (let channel = 0; channel < this.channels; channel++) {
|
|
119
100
|
const src = data[channel];
|
|
120
|
-
const dst =
|
|
101
|
+
const dst = this.#buffer[channel];
|
|
121
102
|
for (let i = 0; i < samples; i++) {
|
|
122
103
|
dst[(start + i) % dst.length] = src[i];
|
|
123
104
|
}
|
|
124
105
|
}
|
|
125
|
-
|
|
106
|
+
this.#writeIndex = end;
|
|
126
107
|
}
|
|
127
108
|
read(output) {
|
|
128
109
|
if (output.length !== this.channels) throw new Error("wrong channel count");
|
|
129
|
-
if (
|
|
110
|
+
if (this.#stalled) return 0;
|
|
130
111
|
const available = this.length;
|
|
131
112
|
if (available === 0) {
|
|
132
|
-
|
|
113
|
+
this.#stalled = true;
|
|
133
114
|
return 0;
|
|
134
115
|
}
|
|
135
116
|
const requested = output[0].length;
|
|
136
117
|
const readSamples = Math.min(available, requested);
|
|
137
118
|
for (let channel = 0; channel < this.channels; channel++) {
|
|
138
119
|
const dst = output[channel];
|
|
139
|
-
const src =
|
|
120
|
+
const src = this.#buffer[channel];
|
|
140
121
|
for (let i = 0; i < readSamples; i++) {
|
|
141
|
-
dst[i] = src[(
|
|
122
|
+
dst[i] = src[(this.#readIndex + i) % src.length];
|
|
142
123
|
}
|
|
143
124
|
for (let i = readSamples; i < requested; i++) dst[i] = 0;
|
|
144
125
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (readSamples < requested)
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
126
|
+
this.#readIndex += readSamples;
|
|
127
|
+
this.#pruneTimestampAnchors();
|
|
128
|
+
if (readSamples < requested) this.#stalled = true;
|
|
129
|
+
if (this.#diagEnabled) {
|
|
130
|
+
this.#diagReads++;
|
|
131
|
+
this.#diagFillSum += available;
|
|
151
132
|
}
|
|
152
133
|
return readSamples;
|
|
153
134
|
}
|
|
154
135
|
/** Clear queued PCM; optionally treat the next fill as post-start recovery. */
|
|
155
136
|
reset(startUnstalled = false, resumeAfterReset = false) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
137
|
+
this.#writeIndex = 0;
|
|
138
|
+
this.#readIndex = 0;
|
|
139
|
+
this.#stalled = !startUnstalled;
|
|
140
|
+
this.#hasStarted = startUnstalled || resumeAfterReset;
|
|
141
|
+
this.#timestampAnchors = [];
|
|
142
|
+
this.#diagReads = 0;
|
|
143
|
+
this.#diagFillSum = 0;
|
|
144
|
+
this.#diagOverflowSamples = 0;
|
|
164
145
|
}
|
|
165
146
|
/**
|
|
166
147
|
* Change the startup latency while preserving the configured storage
|
|
@@ -175,18 +156,18 @@
|
|
|
175
156
|
if (!Number.isSafeInteger(newStartupFrames) || newStartupFrames <= 0) {
|
|
176
157
|
throw new Error("invalid latency");
|
|
177
158
|
}
|
|
178
|
-
const newResumeFrames =
|
|
179
|
-
const newCapacity = Math.max(newStartupFrames, newResumeFrames) +
|
|
159
|
+
const newResumeFrames = this.#resumeFollowsStartup ? newStartupFrames : this.#resumeFrames;
|
|
160
|
+
const newCapacity = Math.max(newStartupFrames, newResumeFrames) + this.#capacityHeadroomFrames;
|
|
180
161
|
if (!Number.isSafeInteger(newCapacity) || newCapacity < Math.max(newStartupFrames, newResumeFrames)) {
|
|
181
162
|
throw new Error("invalid capacity frames");
|
|
182
163
|
}
|
|
183
|
-
const wasStalled =
|
|
184
|
-
|
|
185
|
-
|
|
164
|
+
const wasStalled = this.#stalled;
|
|
165
|
+
this.#startupFrames = newStartupFrames;
|
|
166
|
+
this.#resumeFrames = newResumeFrames;
|
|
186
167
|
if (newCapacity === this.capacity) {
|
|
187
|
-
if (wasStalled && this.length >=
|
|
188
|
-
|
|
189
|
-
|
|
168
|
+
if (wasStalled && this.length >= this.#refillFrames()) {
|
|
169
|
+
this.#stalled = false;
|
|
170
|
+
this.#hasStarted = true;
|
|
190
171
|
}
|
|
191
172
|
return;
|
|
192
173
|
}
|
|
@@ -195,80 +176,63 @@
|
|
|
195
176
|
() => new Float32Array(newCapacity)
|
|
196
177
|
);
|
|
197
178
|
const samplesToKeep = Math.min(this.length, newCapacity);
|
|
198
|
-
const copyStart =
|
|
179
|
+
const copyStart = this.#writeIndex - samplesToKeep;
|
|
199
180
|
for (let channel = 0; channel < this.channels; channel++) {
|
|
200
|
-
const src =
|
|
181
|
+
const src = this.#buffer[channel];
|
|
201
182
|
const dst = next[channel];
|
|
202
183
|
for (let i = 0; i < samplesToKeep; i++) {
|
|
203
184
|
const sampleIndex = copyStart + i;
|
|
204
185
|
dst[sampleIndex % dst.length] = src[sampleIndex % src.length];
|
|
205
186
|
}
|
|
206
187
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (!
|
|
188
|
+
this.#buffer = next;
|
|
189
|
+
this.#readIndex = copyStart;
|
|
190
|
+
this.#pruneTimestampAnchors();
|
|
191
|
+
this.#stalled = samplesToKeep === 0 || wasStalled && samplesToKeep < this.#refillFrames();
|
|
192
|
+
if (!this.#stalled) this.#hasStarted = true;
|
|
212
193
|
}
|
|
213
194
|
getDiagAndReset() {
|
|
214
|
-
if (!
|
|
195
|
+
if (!this.#diagEnabled || this.#diagReads === 0) return null;
|
|
215
196
|
const result = {
|
|
216
|
-
reads:
|
|
217
|
-
avgFill: Math.round(
|
|
197
|
+
reads: this.#diagReads,
|
|
198
|
+
avgFill: Math.round(this.#diagFillSum / this.#diagReads),
|
|
218
199
|
capacity: this.capacity,
|
|
219
200
|
skips: 0,
|
|
220
201
|
dups: 0,
|
|
221
|
-
overflowSamples:
|
|
202
|
+
overflowSamples: this.#diagOverflowSamples
|
|
222
203
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
204
|
+
this.#diagReads = 0;
|
|
205
|
+
this.#diagFillSum = 0;
|
|
206
|
+
this.#diagOverflowSamples = 0;
|
|
226
207
|
return result;
|
|
227
208
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
_capacityHeadroomFrames = new WeakMap();
|
|
238
|
-
_timestampAnchors = new WeakMap();
|
|
239
|
-
_diagEnabled = new WeakMap();
|
|
240
|
-
_diagReads = new WeakMap();
|
|
241
|
-
_diagFillSum = new WeakMap();
|
|
242
|
-
_diagOverflowSamples = new WeakMap();
|
|
243
|
-
_AudioRingBuffer_instances = new WeakSet();
|
|
244
|
-
pruneTimestampAnchors_fn = function() {
|
|
245
|
-
let keep = 0;
|
|
246
|
-
while (keep + 1 < __privateGet(this, _timestampAnchors).length && __privateGet(this, _timestampAnchors)[keep + 1].sampleIndex <= __privateGet(this, _readIndex)) {
|
|
247
|
-
keep++;
|
|
209
|
+
#pruneTimestampAnchors() {
|
|
210
|
+
let keep = 0;
|
|
211
|
+
while (keep + 1 < this.#timestampAnchors.length && this.#timestampAnchors[keep + 1].sampleIndex <= this.#readIndex) {
|
|
212
|
+
keep++;
|
|
213
|
+
}
|
|
214
|
+
if (keep > 0) this.#timestampAnchors.splice(0, keep);
|
|
215
|
+
}
|
|
216
|
+
#refillFrames() {
|
|
217
|
+
return this.#hasStarted ? this.#resumeFrames : this.#startupFrames;
|
|
248
218
|
}
|
|
249
|
-
if (keep > 0) __privateGet(this, _timestampAnchors).splice(0, keep);
|
|
250
|
-
};
|
|
251
|
-
refillFrames_fn = function() {
|
|
252
|
-
return __privateGet(this, _hasStarted) ? __privateGet(this, _resumeFrames) : __privateGet(this, _startupFrames);
|
|
253
219
|
};
|
|
254
220
|
|
|
255
221
|
// src/audio/render-worklet.ts
|
|
256
|
-
var _buffer2, _underflow, _diagUnderflow, _started, _stateCounter, _diagEnabled2, _diagCounter, _generation, _writtenFrames, _heldUntilStart, _resumeAfterReset, _Render_instances, flushDiag_fn;
|
|
257
222
|
var Render = class extends AudioWorkletProcessor {
|
|
223
|
+
#buffer;
|
|
224
|
+
#underflow = 0;
|
|
225
|
+
#diagUnderflow = 0;
|
|
226
|
+
#started = false;
|
|
227
|
+
#stateCounter = 0;
|
|
228
|
+
#diagEnabled = false;
|
|
229
|
+
#diagCounter = 0;
|
|
230
|
+
#generation = 0;
|
|
231
|
+
#writtenFrames = 0;
|
|
232
|
+
#heldUntilStart = false;
|
|
233
|
+
#resumeAfterReset = false;
|
|
258
234
|
constructor() {
|
|
259
235
|
super();
|
|
260
|
-
__privateAdd(this, _Render_instances);
|
|
261
|
-
__privateAdd(this, _buffer2);
|
|
262
|
-
__privateAdd(this, _underflow, 0);
|
|
263
|
-
__privateAdd(this, _diagUnderflow, 0);
|
|
264
|
-
__privateAdd(this, _started, false);
|
|
265
|
-
__privateAdd(this, _stateCounter, 0);
|
|
266
|
-
__privateAdd(this, _diagEnabled2, false);
|
|
267
|
-
__privateAdd(this, _diagCounter, 0);
|
|
268
|
-
__privateAdd(this, _generation, 0);
|
|
269
|
-
__privateAdd(this, _writtenFrames, 0);
|
|
270
|
-
__privateAdd(this, _heldUntilStart, false);
|
|
271
|
-
__privateAdd(this, _resumeAfterReset, false);
|
|
272
236
|
this.port.onmessage = (event) => {
|
|
273
237
|
const msg = event.data;
|
|
274
238
|
if (msg.type === "init") {
|
|
@@ -282,8 +246,8 @@
|
|
|
282
246
|
if (!Number.isSafeInteger(capacityFrames) || capacityFrames < startupFrames) {
|
|
283
247
|
throw new Error("invalid capacity frames");
|
|
284
248
|
}
|
|
285
|
-
|
|
286
|
-
|
|
249
|
+
this.#generation = msg.generation;
|
|
250
|
+
this.#buffer = new AudioRingBuffer({
|
|
287
251
|
channels: msg.channels,
|
|
288
252
|
rate: msg.rate,
|
|
289
253
|
latencyMs: msg.latencyMs,
|
|
@@ -295,108 +259,96 @@
|
|
|
295
259
|
startUnstalled: msg.startUnstalled,
|
|
296
260
|
warmupReads: msg.warmupReads,
|
|
297
261
|
diag: msg.diag ?? false
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
262
|
+
});
|
|
263
|
+
this.#diagEnabled = msg.diag ?? false;
|
|
264
|
+
this.#underflow = 0;
|
|
265
|
+
this.#diagUnderflow = 0;
|
|
266
|
+
this.#started = false;
|
|
267
|
+
this.#writtenFrames = 0;
|
|
268
|
+
this.#heldUntilStart = heldUntilStart;
|
|
269
|
+
this.#resumeAfterReset = heldUntilStart;
|
|
306
270
|
} else if (msg.type === "data") {
|
|
307
|
-
if (!
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (
|
|
271
|
+
if (!this.#buffer) return;
|
|
272
|
+
this.#buffer.write(msg.timestamp, msg.data);
|
|
273
|
+
this.#writtenFrames += msg.data[0]?.length ?? 0;
|
|
274
|
+
if (this.#heldUntilStart || this.#diagEnabled) {
|
|
311
275
|
this.port.postMessage({
|
|
312
276
|
type: "writeAck",
|
|
313
|
-
generation:
|
|
314
|
-
bufferedFrames:
|
|
315
|
-
writtenFrames:
|
|
277
|
+
generation: this.#generation,
|
|
278
|
+
bufferedFrames: this.#buffer.length,
|
|
279
|
+
writtenFrames: this.#writtenFrames
|
|
316
280
|
});
|
|
317
281
|
}
|
|
318
282
|
} else if (msg.type === "start") {
|
|
319
|
-
if (msg.generation ===
|
|
283
|
+
if (msg.generation === this.#generation) this.#heldUntilStart = false;
|
|
320
284
|
} else if (msg.type === "latency") {
|
|
321
|
-
if (!
|
|
322
|
-
|
|
285
|
+
if (!this.#buffer) return;
|
|
286
|
+
this.#buffer.resize(msg.latencyMs);
|
|
323
287
|
} else if (msg.type === "reset") {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
288
|
+
this.#generation = msg.generation;
|
|
289
|
+
this.#buffer?.reset(msg.startUnstalled ?? false, this.#resumeAfterReset);
|
|
290
|
+
this.#underflow = 0;
|
|
291
|
+
this.#diagUnderflow = 0;
|
|
292
|
+
this.#started = false;
|
|
293
|
+
this.#writtenFrames = 0;
|
|
294
|
+
this.#heldUntilStart = false;
|
|
331
295
|
} else if (msg.type === "requestDiag") {
|
|
332
|
-
|
|
296
|
+
this.#flushDiag();
|
|
333
297
|
}
|
|
334
298
|
};
|
|
335
299
|
}
|
|
336
300
|
process(_inputs, outputs) {
|
|
337
301
|
const output = outputs[0];
|
|
338
|
-
const samplesRead =
|
|
339
|
-
if (samplesRead > 0)
|
|
340
|
-
if (samplesRead < output[0].length &&
|
|
302
|
+
const samplesRead = this.#heldUntilStart ? 0 : this.#buffer?.read(output) ?? 0;
|
|
303
|
+
if (samplesRead > 0) this.#started = true;
|
|
304
|
+
if (samplesRead < output[0].length && this.#started) {
|
|
341
305
|
const missing = output[0].length - samplesRead;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
} else if (
|
|
345
|
-
console.warn(`audio underflow: ${Math.round(1e3 *
|
|
346
|
-
|
|
306
|
+
this.#underflow += missing;
|
|
307
|
+
this.#diagUnderflow += missing;
|
|
308
|
+
} else if (this.#underflow > 0 && this.#buffer) {
|
|
309
|
+
console.warn(`audio underflow: ${Math.round(1e3 * this.#underflow / this.#buffer.rate)}ms`);
|
|
310
|
+
this.#underflow = 0;
|
|
347
311
|
}
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
|
|
312
|
+
this.#stateCounter++;
|
|
313
|
+
if (this.#buffer && this.#stateCounter >= 5) {
|
|
314
|
+
this.#stateCounter = 0;
|
|
351
315
|
const msg = {
|
|
352
316
|
type: "state",
|
|
353
|
-
generation:
|
|
354
|
-
timestamp:
|
|
355
|
-
stalled:
|
|
356
|
-
bufferedFrames:
|
|
357
|
-
writtenFrames:
|
|
317
|
+
generation: this.#generation,
|
|
318
|
+
timestamp: this.#heldUntilStart ? void 0 : this.#buffer.timestampUs,
|
|
319
|
+
stalled: this.#heldUntilStart || this.#buffer.stalled,
|
|
320
|
+
bufferedFrames: this.#buffer.length,
|
|
321
|
+
writtenFrames: this.#writtenFrames
|
|
358
322
|
};
|
|
359
323
|
this.port.postMessage(msg);
|
|
360
324
|
}
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
if (
|
|
364
|
-
|
|
365
|
-
|
|
325
|
+
if (this.#diagEnabled && this.#buffer) {
|
|
326
|
+
this.#diagCounter++;
|
|
327
|
+
if (this.#diagCounter >= 375) {
|
|
328
|
+
this.#diagCounter = 0;
|
|
329
|
+
this.#flushDiag();
|
|
366
330
|
}
|
|
367
331
|
}
|
|
368
332
|
return true;
|
|
369
333
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
type: "ringBufDiag",
|
|
389
|
-
generation: __privateGet(this, _generation),
|
|
390
|
-
reads: d?.reads ?? 0,
|
|
391
|
-
avgFill: d?.avgFill ?? 0,
|
|
392
|
-
capacity: d?.capacity ?? __privateGet(this, _buffer2).capacity,
|
|
393
|
-
skipsPerSec: d?.skips ?? 0,
|
|
394
|
-
dupsPerSec: d?.dups ?? 0,
|
|
395
|
-
overflowSamplesPerSec: d?.overflowSamples ?? 0,
|
|
396
|
-
underflowSamplesPerSec: __privateGet(this, _diagUnderflow)
|
|
397
|
-
};
|
|
398
|
-
__privateSet(this, _diagUnderflow, 0);
|
|
399
|
-
this.port.postMessage(msg);
|
|
334
|
+
#flushDiag() {
|
|
335
|
+
if (!this.#buffer) return;
|
|
336
|
+
const d = this.#buffer.getDiagAndReset();
|
|
337
|
+
if (!d && this.#diagUnderflow === 0) return;
|
|
338
|
+
const msg = {
|
|
339
|
+
type: "ringBufDiag",
|
|
340
|
+
generation: this.#generation,
|
|
341
|
+
reads: d?.reads ?? 0,
|
|
342
|
+
avgFill: d?.avgFill ?? 0,
|
|
343
|
+
capacity: d?.capacity ?? this.#buffer.capacity,
|
|
344
|
+
skipsPerSec: d?.skips ?? 0,
|
|
345
|
+
dupsPerSec: d?.dups ?? 0,
|
|
346
|
+
overflowSamplesPerSec: d?.overflowSamples ?? 0,
|
|
347
|
+
underflowSamplesPerSec: this.#diagUnderflow
|
|
348
|
+
};
|
|
349
|
+
this.#diagUnderflow = 0;
|
|
350
|
+
this.port.postMessage(msg);
|
|
351
|
+
}
|
|
400
352
|
};
|
|
401
353
|
registerProcessor("mmt-render", Render);
|
|
402
354
|
})();
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/audio/audio-ring-buffer.ts", "../../src/audio/render-worklet.ts"],
|
|
4
4
|
"sourcesContent": ["/**\n * Timestamp-anchored FIFO shared by MMT AudioWorklet consumers.\n *\n * PCM remains in decoder emission order. Media timestamps are exact anchors\n * for playout reporting only; they never reposition samples or trigger a\n * guessed discontinuity. The FIFO starts after its full catalog-derived\n * latency is buffered and performs no sample skip/dup clock recovery.\n */\n\nexport interface AudioRingBufferConfig {\n channels: number\n rate: number\n latencyMs: number\n /** Exact PCM startup threshold. Overrides latencyMs when provided. */\n startupFrames?: number\n /** PCM refill threshold after the first underrun. Defaults to startupFrames. */\n resumeFrames?: number\n /** Exact PCM storage ceiling. Must cover the startup and resume thresholds. */\n capacityFrames?: number\n startUnstalled?: boolean\n /** Deprecated compatibility input. Clock recovery is not performed. */\n warmupReads?: number\n diag?: boolean\n}\n\nexport interface AudioRingBufferDiag {\n reads: number\n avgFill: number\n capacity: number\n skips: number\n dups: number\n overflowSamples: number\n}\n\ntype TimestampAnchor = {\n sampleIndex: number\n timestampUs: number\n}\n\nexport class AudioRingBuffer {\n readonly channels: number\n readonly rate: number\n\n #buffer: Float32Array[]\n #writeIndex = 0\n #readIndex = 0\n #stalled: boolean\n #startupFrames: number\n #resumeFrames: number\n #resumeFollowsStartup: boolean\n #hasStarted: boolean\n #capacityHeadroomFrames: number\n #timestampAnchors: TimestampAnchor[] = []\n\n #diagEnabled: boolean\n #diagReads = 0\n #diagFillSum = 0\n #diagOverflowSamples = 0\n\n constructor(config: AudioRingBufferConfig) {\n if (!Number.isInteger(config.channels) || config.channels <= 0) {\n throw new Error('invalid channels')\n }\n if (!Number.isFinite(config.rate) || config.rate <= 0) {\n throw new Error('invalid sample rate')\n }\n if (!Number.isFinite(config.latencyMs) || config.latencyMs <= 0) {\n throw new Error('invalid latency')\n }\n\n const latencyFrames = Math.ceil(config.rate * (config.latencyMs / 1000))\n const startupFrames = config.startupFrames ?? latencyFrames\n const resumeFrames = config.resumeFrames ?? startupFrames\n const thresholdFrames = Math.max(startupFrames, resumeFrames)\n const capacityFrames = config.capacityFrames ?? Math.max(latencyFrames, thresholdFrames)\n if (!Number.isSafeInteger(startupFrames) || startupFrames <= 0) {\n throw new Error('invalid startup frames')\n }\n if (!Number.isSafeInteger(resumeFrames) || resumeFrames <= 0) {\n throw new Error('invalid resume frames')\n }\n if (!Number.isSafeInteger(capacityFrames) || capacityFrames < thresholdFrames) {\n throw new Error('invalid capacity frames')\n }\n\n this.channels = config.channels\n this.rate = config.rate\n this.#startupFrames = startupFrames\n this.#resumeFrames = resumeFrames\n this.#resumeFollowsStartup = config.resumeFrames === undefined\n this.#hasStarted = config.startUnstalled ?? false\n this.#capacityHeadroomFrames = capacityFrames - thresholdFrames\n this.#stalled = !(config.startUnstalled ?? false)\n this.#diagEnabled = config.diag ?? false\n this.#buffer = Array.from(\n { length: config.channels },\n () => new Float32Array(capacityFrames),\n )\n }\n\n get stalled(): boolean { return this.#stalled }\n get startupFrames(): number { return this.#startupFrames }\n get capacity(): number { return this.#buffer[0].length }\n get length(): number { return this.#writeIndex - this.#readIndex }\n\n /** Timestamp of the next media sample after the PCM already emitted. */\n get timestampUs(): number | undefined {\n const anchor = this.#timestampAnchors[0]\n if (!anchor || anchor.sampleIndex > this.#readIndex) return undefined\n return anchor.timestampUs + ((this.#readIndex - anchor.sampleIndex) / this.rate) * 1_000_000\n }\n\n write(timestampUs: number, data: Float32Array[]): void {\n if (data.length !== this.channels) throw new Error('wrong channel count')\n if (!Number.isFinite(timestampUs)) throw new Error('invalid timestamp')\n const samples = data[0].length\n if (samples === 0) return\n if (data.some((channel) => channel.length !== samples)) {\n throw new Error('mismatched channel lengths')\n }\n\n const start = this.#writeIndex\n const end = start + samples\n this.#timestampAnchors.push({ sampleIndex: start, timestampUs })\n\n const overflow = end - this.#readIndex - this.capacity\n if (overflow > 0) {\n this.#stalled = false\n this.#hasStarted = true\n this.#readIndex += overflow\n if (this.#diagEnabled) this.#diagOverflowSamples += overflow\n this.#pruneTimestampAnchors()\n }\n\n const refillFrames = this.#hasStarted ? this.#resumeFrames : this.#startupFrames\n if (this.#stalled && end - this.#readIndex >= refillFrames) {\n this.#stalled = false\n this.#hasStarted = true\n }\n\n for (let channel = 0; channel < this.channels; channel++) {\n const src = data[channel]\n const dst = this.#buffer[channel]\n for (let i = 0; i < samples; i++) {\n dst[(start + i) % dst.length] = src[i]\n }\n }\n this.#writeIndex = end\n }\n\n read(output: Float32Array[]): number {\n if (output.length !== this.channels) throw new Error('wrong channel count')\n if (this.#stalled) return 0\n\n const available = this.length\n if (available === 0) {\n this.#stalled = true\n return 0\n }\n\n const requested = output[0].length\n const readSamples = Math.min(available, requested)\n\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = output[channel]\n const src = this.#buffer[channel]\n for (let i = 0; i < readSamples; i++) {\n dst[i] = src[(this.#readIndex + i) % src.length]\n }\n for (let i = readSamples; i < requested; i++) dst[i] = 0\n }\n\n this.#readIndex += readSamples\n this.#pruneTimestampAnchors()\n if (readSamples < requested) this.#stalled = true\n\n if (this.#diagEnabled) {\n this.#diagReads++\n this.#diagFillSum += available\n }\n return readSamples\n }\n\n /** Clear queued PCM; optionally treat the next fill as post-start recovery. */\n reset(startUnstalled = false, resumeAfterReset = false): void {\n this.#writeIndex = 0\n this.#readIndex = 0\n this.#stalled = !startUnstalled\n this.#hasStarted = startUnstalled || resumeAfterReset\n this.#timestampAnchors = []\n this.#diagReads = 0\n this.#diagFillSum = 0\n this.#diagOverflowSamples = 0\n }\n\n /**\n * Change the startup latency while preserving the configured storage\n * headroom above its buffering thresholds. Active playout keeps draining\n * retained PCM; a stalled buffer waits for its startup or resume threshold.\n */\n resize(latencyMs: number): void {\n if (!Number.isFinite(latencyMs) || latencyMs <= 0) {\n throw new Error('invalid latency')\n }\n const newStartupFrames = Math.ceil(this.rate * (latencyMs / 1000))\n if (!Number.isSafeInteger(newStartupFrames) || newStartupFrames <= 0) {\n throw new Error('invalid latency')\n }\n const newResumeFrames = this.#resumeFollowsStartup ? newStartupFrames : this.#resumeFrames\n const newCapacity =\n Math.max(newStartupFrames, newResumeFrames) + this.#capacityHeadroomFrames\n if (\n !Number.isSafeInteger(newCapacity) ||\n newCapacity < Math.max(newStartupFrames, newResumeFrames)\n ) {\n throw new Error('invalid capacity frames')\n }\n const wasStalled = this.#stalled\n this.#startupFrames = newStartupFrames\n this.#resumeFrames = newResumeFrames\n if (newCapacity === this.capacity) {\n if (wasStalled && this.length >= this.#refillFrames()) {\n this.#stalled = false\n this.#hasStarted = true\n }\n return\n }\n\n const next = Array.from(\n { length: this.channels },\n () => new Float32Array(newCapacity),\n )\n const samplesToKeep = Math.min(this.length, newCapacity)\n const copyStart = this.#writeIndex - samplesToKeep\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#buffer[channel]\n const dst = next[channel]\n for (let i = 0; i < samplesToKeep; i++) {\n const sampleIndex = copyStart + i\n dst[sampleIndex % dst.length] = src[sampleIndex % src.length]\n }\n }\n\n this.#buffer = next\n this.#readIndex = copyStart\n this.#pruneTimestampAnchors()\n this.#stalled = samplesToKeep === 0 || (wasStalled && samplesToKeep < this.#refillFrames())\n if (!this.#stalled) this.#hasStarted = true\n }\n\n getDiagAndReset(): AudioRingBufferDiag | null {\n if (!this.#diagEnabled || this.#diagReads === 0) return null\n const result: AudioRingBufferDiag = {\n reads: this.#diagReads,\n avgFill: Math.round(this.#diagFillSum / this.#diagReads),\n capacity: this.capacity,\n skips: 0,\n dups: 0,\n overflowSamples: this.#diagOverflowSamples,\n }\n this.#diagReads = 0\n this.#diagFillSum = 0\n this.#diagOverflowSamples = 0\n return result\n }\n\n #pruneTimestampAnchors(): void {\n let keep = 0\n while (\n keep + 1 < this.#timestampAnchors.length &&\n this.#timestampAnchors[keep + 1].sampleIndex <= this.#readIndex\n ) {\n keep++\n }\n if (keep > 0) this.#timestampAnchors.splice(0, keep)\n }\n\n #refillFrames(): number {\n return this.#hasStarted ? this.#resumeFrames : this.#startupFrames\n }\n}\n", "/**\n * Shared AudioWorklet render processor.\n *\n * This file is bundled into a self-contained IIFE at build time\n * (dist/worklet/render-worklet.js) because AudioWorkletGlobalScope cannot\n * resolve bare specifiers. The AudioRingBuffer dependency is inlined at\n * bundle time; do not import from @blockcast packages at runtime.\n *\n * Consumers load the prebuilt bundle via audioWorklet.addModule(url) where\n * url is obtained from `@blockcast/mmt-render/audio/worklet-url`.\n */\n\nimport { AudioRingBuffer } from './audio-ring-buffer.js'\nimport type { FromMain, ToMain } from './render-messages.js'\n\nclass Render extends AudioWorkletProcessor {\n #buffer?: AudioRingBuffer\n #underflow = 0\n #diagUnderflow = 0\n #started = false\n #stateCounter = 0\n #diagEnabled = false\n #diagCounter = 0\n #generation = 0\n #writtenFrames = 0\n #heldUntilStart = false\n #resumeAfterReset = false\n\n constructor() {\n super()\n this.port.onmessage = (event: MessageEvent<FromMain>) => {\n const msg = event.data\n if (msg.type === 'init') {\n const heldUntilStart = msg.holdUntilStart ?? false\n const latencyFrames = Math.ceil(msg.rate * (msg.latencyMs / 1000))\n const startupFrames = msg.startupFrames ?? latencyFrames\n // Keep one latency window above the release threshold so PCM accepted\n // during the writeAck -> start round trip cannot evict the prefill head.\n const capacityFrames =\n msg.capacityFrames ?? Math.max(latencyFrames, startupFrames) + latencyFrames\n if (!Number.isSafeInteger(startupFrames) || startupFrames <= 0) {\n throw new Error('invalid startup frames')\n }\n if (!Number.isSafeInteger(capacityFrames) || capacityFrames < startupFrames) {\n throw new Error('invalid capacity frames')\n }\n this.#generation = msg.generation\n this.#buffer = new AudioRingBuffer({\n channels: msg.channels,\n rate: msg.rate,\n latencyMs: msg.latencyMs,\n // The explicit start gate owns the one-time startup prefill. Once\n // released, resume from an underrun as soon as new PCM is accepted.\n startupFrames,\n resumeFrames: heldUntilStart ? 1 : undefined,\n capacityFrames,\n startUnstalled: msg.startUnstalled,\n warmupReads: msg.warmupReads,\n diag: msg.diag ?? false,\n })\n this.#diagEnabled = msg.diag ?? false\n this.#underflow = 0\n this.#diagUnderflow = 0\n this.#started = false\n this.#writtenFrames = 0\n this.#heldUntilStart = heldUntilStart\n this.#resumeAfterReset = heldUntilStart\n } else if (msg.type === 'data') {\n if (!this.#buffer) return\n this.#buffer.write(msg.timestamp, msg.data)\n this.#writtenFrames += msg.data[0]?.length ?? 0\n if (this.#heldUntilStart || this.#diagEnabled) {\n this.port.postMessage({\n type: 'writeAck',\n generation: this.#generation,\n bufferedFrames: this.#buffer.length,\n writtenFrames: this.#writtenFrames,\n })\n }\n } else if (msg.type === 'start') {\n if (msg.generation === this.#generation) this.#heldUntilStart = false\n } else if (msg.type === 'latency') {\n if (!this.#buffer) return\n this.#buffer.resize(msg.latencyMs)\n } else if (msg.type === 'reset') {\n this.#generation = msg.generation\n this.#buffer?.reset(msg.startUnstalled ?? false, this.#resumeAfterReset)\n this.#underflow = 0\n this.#diagUnderflow = 0\n this.#started = false\n this.#writtenFrames = 0\n this.#heldUntilStart = false\n } else if (msg.type === 'requestDiag') {\n this.#flushDiag()\n }\n }\n }\n\n process(_inputs: Float32Array[][], outputs: Float32Array[][]): boolean {\n const output = outputs[0]\n const samplesRead = this.#heldUntilStart ? 0 : (this.#buffer?.read(output) ?? 0)\n\n if (samplesRead > 0) this.#started = true\n if (samplesRead < output[0].length && this.#started) {\n const missing = output[0].length - samplesRead\n this.#underflow += missing\n this.#diagUnderflow += missing\n } else if (this.#underflow > 0 && this.#buffer) {\n // eslint-disable-next-line no-console\n console.warn(`audio underflow: ${Math.round((1000 * this.#underflow) / this.#buffer.rate)}ms`)\n this.#underflow = 0\n }\n\n // State update ~60/sec (every 5 processes at 128-sample quantum @ 48kHz \u2248 2.67ms each)\n this.#stateCounter++\n if (this.#buffer && this.#stateCounter >= 5) {\n this.#stateCounter = 0\n const msg: ToMain = {\n type: 'state',\n generation: this.#generation,\n timestamp: this.#heldUntilStart ? undefined : this.#buffer.timestampUs,\n stalled: this.#heldUntilStart || this.#buffer.stalled,\n bufferedFrames: this.#buffer.length,\n writtenFrames: this.#writtenFrames,\n }\n this.port.postMessage(msg)\n }\n\n // Diag telemetry every ~1s if enabled.\n if (this.#diagEnabled && this.#buffer) {\n this.#diagCounter++\n if (this.#diagCounter >= 375) {\n this.#diagCounter = 0\n this.#flushDiag()\n }\n }\n\n return true\n }\n\n #flushDiag(): void {\n if (!this.#buffer) return\n const d = this.#buffer.getDiagAndReset()\n if (!d && this.#diagUnderflow === 0) return\n const msg: ToMain = {\n type: 'ringBufDiag',\n generation: this.#generation,\n reads: d?.reads ?? 0,\n avgFill: d?.avgFill ?? 0,\n capacity: d?.capacity ?? this.#buffer.capacity,\n skipsPerSec: d?.skips ?? 0,\n dupsPerSec: d?.dups ?? 0,\n overflowSamplesPerSec: d?.overflowSamples ?? 0,\n underflowSamplesPerSec: this.#diagUnderflow,\n }\n this.#diagUnderflow = 0\n this.port.postMessage(msg)\n }\n}\n\nregisterProcessor('mmt-render', Render)\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
5
|
+
"mappings": ";;;AAuCO,MAAM,kBAAN,MAAsB;AAAA,IAI3B;AAAA,IACA,cAAc;AAAA,IACd,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAuC,CAAC;AAAA,IAExC;AAAA,IACA,aAAa;AAAA,IACb,eAAe;AAAA,IACf,uBAAuB;AAAA,IAEvB,YAAY,QAA+B;AACzC,UAAI,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,OAAO,YAAY,GAAG;AAC9D,cAAM,IAAI,MAAM,kBAAkB;AAAA,MACpC;AACA,UAAI,CAAC,OAAO,SAAS,OAAO,IAAI,KAAK,OAAO,QAAQ,GAAG;AACrD,cAAM,IAAI,MAAM,qBAAqB;AAAA,MACvC;AACA,UAAI,CAAC,OAAO,SAAS,OAAO,SAAS,KAAK,OAAO,aAAa,GAAG;AAC/D,cAAM,IAAI,MAAM,iBAAiB;AAAA,MACnC;AAEA,YAAM,gBAAgB,KAAK,KAAK,OAAO,QAAQ,OAAO,YAAY,IAAK;AACvE,YAAM,gBAAgB,OAAO,iBAAiB;AAC9C,YAAM,eAAe,OAAO,gBAAgB;AAC5C,YAAM,kBAAkB,KAAK,IAAI,eAAe,YAAY;AAC5D,YAAM,iBAAiB,OAAO,kBAAkB,KAAK,IAAI,eAAe,eAAe;AACvF,UAAI,CAAC,OAAO,cAAc,aAAa,KAAK,iBAAiB,GAAG;AAC9D,cAAM,IAAI,MAAM,wBAAwB;AAAA,MAC1C;AACA,UAAI,CAAC,OAAO,cAAc,YAAY,KAAK,gBAAgB,GAAG;AAC5D,cAAM,IAAI,MAAM,uBAAuB;AAAA,MACzC;AACA,UAAI,CAAC,OAAO,cAAc,cAAc,KAAK,iBAAiB,iBAAiB;AAC7E,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,WAAK,WAAW,OAAO;AACvB,WAAK,OAAO,OAAO;AACnB,WAAK,iBAAiB;AACtB,WAAK,gBAAgB;AACrB,WAAK,wBAAwB,OAAO,iBAAiB;AACrD,WAAK,cAAc,OAAO,kBAAkB;AAC5C,WAAK,0BAA0B,iBAAiB;AAChD,WAAK,WAAW,EAAE,OAAO,kBAAkB;AAC3C,WAAK,eAAe,OAAO,QAAQ;AACnC,WAAK,UAAU,MAAM;AAAA,QACnB,EAAE,QAAQ,OAAO,SAAS;AAAA,QAC1B,MAAM,IAAI,aAAa,cAAc;AAAA,MACvC;AAAA,IACF;AAAA,IAEA,IAAI,UAAmB;AAAE,aAAO,KAAK;AAAA,IAAS;AAAA,IAC9C,IAAI,gBAAwB;AAAE,aAAO,KAAK;AAAA,IAAe;AAAA,IACzD,IAAI,WAAmB;AAAE,aAAO,KAAK,QAAQ,CAAC,EAAE;AAAA,IAAO;AAAA,IACvD,IAAI,SAAiB;AAAE,aAAO,KAAK,cAAc,KAAK;AAAA,IAAW;AAAA;AAAA,IAGjE,IAAI,cAAkC;AACpC,YAAM,SAAS,KAAK,kBAAkB,CAAC;AACvC,UAAI,CAAC,UAAU,OAAO,cAAc,KAAK,WAAY,QAAO;AAC5D,aAAO,OAAO,eAAgB,KAAK,aAAa,OAAO,eAAe,KAAK,OAAQ;AAAA,IACrF;AAAA,IAEA,MAAM,aAAqB,MAA4B;AACrD,UAAI,KAAK,WAAW,KAAK,SAAU,OAAM,IAAI,MAAM,qBAAqB;AACxE,UAAI,CAAC,OAAO,SAAS,WAAW,EAAG,OAAM,IAAI,MAAM,mBAAmB;AACtE,YAAM,UAAU,KAAK,CAAC,EAAE;AACxB,UAAI,YAAY,EAAG;AACnB,UAAI,KAAK,KAAK,CAAC,YAAY,QAAQ,WAAW,OAAO,GAAG;AACtD,cAAM,IAAI,MAAM,4BAA4B;AAAA,MAC9C;AAEA,YAAM,QAAQ,KAAK;AACnB,YAAM,MAAM,QAAQ;AACpB,WAAK,kBAAkB,KAAK,EAAE,aAAa,OAAO,YAAY,CAAC;AAE/D,YAAM,WAAW,MAAM,KAAK,aAAa,KAAK;AAC9C,UAAI,WAAW,GAAG;AAChB,aAAK,WAAW;AAChB,aAAK,cAAc;AACnB,aAAK,cAAc;AACnB,YAAI,KAAK,aAAc,MAAK,wBAAwB;AACpD,aAAK,uBAAuB;AAAA,MAC9B;AAEA,YAAM,eAAe,KAAK,cAAc,KAAK,gBAAgB,KAAK;AAClE,UAAI,KAAK,YAAY,MAAM,KAAK,cAAc,cAAc;AAC1D,aAAK,WAAW;AAChB,aAAK,cAAc;AAAA,MACrB;AAEA,eAAS,UAAU,GAAG,UAAU,KAAK,UAAU,WAAW;AACxD,cAAM,MAAM,KAAK,OAAO;AACxB,cAAM,MAAM,KAAK,QAAQ,OAAO;AAChC,iBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,eAAK,QAAQ,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC;AAAA,QACvC;AAAA,MACF;AACA,WAAK,cAAc;AAAA,IACrB;AAAA,IAEA,KAAK,QAAgC;AACnC,UAAI,OAAO,WAAW,KAAK,SAAU,OAAM,IAAI,MAAM,qBAAqB;AAC1E,UAAI,KAAK,SAAU,QAAO;AAE1B,YAAM,YAAY,KAAK;AACvB,UAAI,cAAc,GAAG;AACnB,aAAK,WAAW;AAChB,eAAO;AAAA,MACT;AAEA,YAAM,YAAY,OAAO,CAAC,EAAE;AAC5B,YAAM,cAAc,KAAK,IAAI,WAAW,SAAS;AAEjD,eAAS,UAAU,GAAG,UAAU,KAAK,UAAU,WAAW;AACxD,cAAM,MAAM,OAAO,OAAO;AAC1B,cAAM,MAAM,KAAK,QAAQ,OAAO;AAChC,iBAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,cAAI,CAAC,IAAI,KAAK,KAAK,aAAa,KAAK,IAAI,MAAM;AAAA,QACjD;AACA,iBAAS,IAAI,aAAa,IAAI,WAAW,IAAK,KAAI,CAAC,IAAI;AAAA,MACzD;AAEA,WAAK,cAAc;AACnB,WAAK,uBAAuB;AAC5B,UAAI,cAAc,UAAW,MAAK,WAAW;AAE7C,UAAI,KAAK,cAAc;AACrB,aAAK;AACL,aAAK,gBAAgB;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AAAA;AAAA,IAGA,MAAM,iBAAiB,OAAO,mBAAmB,OAAa;AAC5D,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,WAAK,WAAW,CAAC;AACjB,WAAK,cAAc,kBAAkB;AACrC,WAAK,oBAAoB,CAAC;AAC1B,WAAK,aAAa;AAClB,WAAK,eAAe;AACpB,WAAK,uBAAuB;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,OAAO,WAAyB;AAC9B,UAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,GAAG;AACjD,cAAM,IAAI,MAAM,iBAAiB;AAAA,MACnC;AACA,YAAM,mBAAmB,KAAK,KAAK,KAAK,QAAQ,YAAY,IAAK;AACjE,UAAI,CAAC,OAAO,cAAc,gBAAgB,KAAK,oBAAoB,GAAG;AACpE,cAAM,IAAI,MAAM,iBAAiB;AAAA,MACnC;AACA,YAAM,kBAAkB,KAAK,wBAAwB,mBAAmB,KAAK;AAC7E,YAAM,cACJ,KAAK,IAAI,kBAAkB,eAAe,IAAI,KAAK;AACrD,UACE,CAAC,OAAO,cAAc,WAAW,KACjC,cAAc,KAAK,IAAI,kBAAkB,eAAe,GACxD;AACA,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AACA,YAAM,aAAa,KAAK;AACxB,WAAK,iBAAiB;AACtB,WAAK,gBAAgB;AACrB,UAAI,gBAAgB,KAAK,UAAU;AACjC,YAAI,cAAc,KAAK,UAAU,KAAK,cAAc,GAAG;AACrD,eAAK,WAAW;AAChB,eAAK,cAAc;AAAA,QACrB;AACA;AAAA,MACF;AAEA,YAAM,OAAO,MAAM;AAAA,QACjB,EAAE,QAAQ,KAAK,SAAS;AAAA,QACxB,MAAM,IAAI,aAAa,WAAW;AAAA,MACpC;AACA,YAAM,gBAAgB,KAAK,IAAI,KAAK,QAAQ,WAAW;AACvD,YAAM,YAAY,KAAK,cAAc;AACrC,eAAS,UAAU,GAAG,UAAU,KAAK,UAAU,WAAW;AACxD,cAAM,MAAM,KAAK,QAAQ,OAAO;AAChC,cAAM,MAAM,KAAK,OAAO;AACxB,iBAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,gBAAM,cAAc,YAAY;AAChC,cAAI,cAAc,IAAI,MAAM,IAAI,IAAI,cAAc,IAAI,MAAM;AAAA,QAC9D;AAAA,MACF;AAEA,WAAK,UAAU;AACf,WAAK,aAAa;AAClB,WAAK,uBAAuB;AAC5B,WAAK,WAAW,kBAAkB,KAAM,cAAc,gBAAgB,KAAK,cAAc;AACzF,UAAI,CAAC,KAAK,SAAU,MAAK,cAAc;AAAA,IACzC;AAAA,IAEA,kBAA8C;AAC5C,UAAI,CAAC,KAAK,gBAAgB,KAAK,eAAe,EAAG,QAAO;AACxD,YAAM,SAA8B;AAAA,QAClC,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK,MAAM,KAAK,eAAe,KAAK,UAAU;AAAA,QACvD,UAAU,KAAK;AAAA,QACf,OAAO;AAAA,QACP,MAAM;AAAA,QACN,iBAAiB,KAAK;AAAA,MACxB;AACA,WAAK,aAAa;AAClB,WAAK,eAAe;AACpB,WAAK,uBAAuB;AAC5B,aAAO;AAAA,IACT;AAAA,IAEA,yBAA+B;AAC7B,UAAI,OAAO;AACX,aACE,OAAO,IAAI,KAAK,kBAAkB,UAClC,KAAK,kBAAkB,OAAO,CAAC,EAAE,eAAe,KAAK,YACrD;AACA;AAAA,MACF;AACA,UAAI,OAAO,EAAG,MAAK,kBAAkB,OAAO,GAAG,IAAI;AAAA,IACrD;AAAA,IAEA,gBAAwB;AACtB,aAAO,KAAK,cAAc,KAAK,gBAAgB,KAAK;AAAA,IACtD;AAAA,EACF;;;ACzQA,MAAM,SAAN,cAAqB,sBAAsB;AAAA,IACzC;AAAA,IACA,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IAEpB,cAAc;AACZ,YAAM;AACN,WAAK,KAAK,YAAY,CAAC,UAAkC;AACvD,cAAM,MAAM,MAAM;AAClB,YAAI,IAAI,SAAS,QAAQ;AACvB,gBAAM,iBAAiB,IAAI,kBAAkB;AAC7C,gBAAM,gBAAgB,KAAK,KAAK,IAAI,QAAQ,IAAI,YAAY,IAAK;AACjE,gBAAM,gBAAgB,IAAI,iBAAiB;AAG3C,gBAAM,iBACJ,IAAI,kBAAkB,KAAK,IAAI,eAAe,aAAa,IAAI;AACjE,cAAI,CAAC,OAAO,cAAc,aAAa,KAAK,iBAAiB,GAAG;AAC9D,kBAAM,IAAI,MAAM,wBAAwB;AAAA,UAC1C;AACA,cAAI,CAAC,OAAO,cAAc,cAAc,KAAK,iBAAiB,eAAe;AAC3E,kBAAM,IAAI,MAAM,yBAAyB;AAAA,UAC3C;AACA,eAAK,cAAc,IAAI;AACvB,eAAK,UAAU,IAAI,gBAAgB;AAAA,YACjC,UAAU,IAAI;AAAA,YACd,MAAM,IAAI;AAAA,YACV,WAAW,IAAI;AAAA;AAAA;AAAA,YAGf;AAAA,YACA,cAAc,iBAAiB,IAAI;AAAA,YACnC;AAAA,YACA,gBAAgB,IAAI;AAAA,YACpB,aAAa,IAAI;AAAA,YACjB,MAAM,IAAI,QAAQ;AAAA,UACpB,CAAC;AACD,eAAK,eAAe,IAAI,QAAQ;AAChC,eAAK,aAAa;AAClB,eAAK,iBAAiB;AACtB,eAAK,WAAW;AAChB,eAAK,iBAAiB;AACtB,eAAK,kBAAkB;AACvB,eAAK,oBAAoB;AAAA,QAC3B,WAAW,IAAI,SAAS,QAAQ;AAC9B,cAAI,CAAC,KAAK,QAAS;AACnB,eAAK,QAAQ,MAAM,IAAI,WAAW,IAAI,IAAI;AAC1C,eAAK,kBAAkB,IAAI,KAAK,CAAC,GAAG,UAAU;AAC9C,cAAI,KAAK,mBAAmB,KAAK,cAAc;AAC7C,iBAAK,KAAK,YAAY;AAAA,cACpB,MAAM;AAAA,cACN,YAAY,KAAK;AAAA,cACjB,gBAAgB,KAAK,QAAQ;AAAA,cAC7B,eAAe,KAAK;AAAA,YACtB,CAAC;AAAA,UACH;AAAA,QACF,WAAW,IAAI,SAAS,SAAS;AAC/B,cAAI,IAAI,eAAe,KAAK,YAAa,MAAK,kBAAkB;AAAA,QAClE,WAAW,IAAI,SAAS,WAAW;AACjC,cAAI,CAAC,KAAK,QAAS;AACnB,eAAK,QAAQ,OAAO,IAAI,SAAS;AAAA,QACnC,WAAW,IAAI,SAAS,SAAS;AAC/B,eAAK,cAAc,IAAI;AACvB,eAAK,SAAS,MAAM,IAAI,kBAAkB,OAAO,KAAK,iBAAiB;AACvE,eAAK,aAAa;AAClB,eAAK,iBAAiB;AACtB,eAAK,WAAW;AAChB,eAAK,iBAAiB;AACtB,eAAK,kBAAkB;AAAA,QACzB,WAAW,IAAI,SAAS,eAAe;AACrC,eAAK,WAAW;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,QAAQ,SAA2B,SAAoC;AACrE,YAAM,SAAS,QAAQ,CAAC;AACxB,YAAM,cAAc,KAAK,kBAAkB,IAAK,KAAK,SAAS,KAAK,MAAM,KAAK;AAE9E,UAAI,cAAc,EAAG,MAAK,WAAW;AACrC,UAAI,cAAc,OAAO,CAAC,EAAE,UAAU,KAAK,UAAU;AACnD,cAAM,UAAU,OAAO,CAAC,EAAE,SAAS;AACnC,aAAK,cAAc;AACnB,aAAK,kBAAkB;AAAA,MACzB,WAAW,KAAK,aAAa,KAAK,KAAK,SAAS;AAE9C,gBAAQ,KAAK,oBAAoB,KAAK,MAAO,MAAO,KAAK,aAAc,KAAK,QAAQ,IAAI,CAAC,IAAI;AAC7F,aAAK,aAAa;AAAA,MACpB;AAGA,WAAK;AACL,UAAI,KAAK,WAAW,KAAK,iBAAiB,GAAG;AAC3C,aAAK,gBAAgB;AACrB,cAAM,MAAc;AAAA,UAClB,MAAM;AAAA,UACN,YAAY,KAAK;AAAA,UACjB,WAAW,KAAK,kBAAkB,SAAY,KAAK,QAAQ;AAAA,UAC3D,SAAS,KAAK,mBAAmB,KAAK,QAAQ;AAAA,UAC9C,gBAAgB,KAAK,QAAQ;AAAA,UAC7B,eAAe,KAAK;AAAA,QACtB;AACA,aAAK,KAAK,YAAY,GAAG;AAAA,MAC3B;AAGA,UAAI,KAAK,gBAAgB,KAAK,SAAS;AACrC,aAAK;AACL,YAAI,KAAK,gBAAgB,KAAK;AAC5B,eAAK,eAAe;AACpB,eAAK,WAAW;AAAA,QAClB;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,aAAmB;AACjB,UAAI,CAAC,KAAK,QAAS;AACnB,YAAM,IAAI,KAAK,QAAQ,gBAAgB;AACvC,UAAI,CAAC,KAAK,KAAK,mBAAmB,EAAG;AACrC,YAAM,MAAc;AAAA,QAClB,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,OAAO,GAAG,SAAS;AAAA,QACnB,SAAS,GAAG,WAAW;AAAA,QACvB,UAAU,GAAG,YAAY,KAAK,QAAQ;AAAA,QACtC,aAAa,GAAG,SAAS;AAAA,QACzB,YAAY,GAAG,QAAQ;AAAA,QACvB,uBAAuB,GAAG,mBAAmB;AAAA,QAC7C,wBAAwB,KAAK;AAAA,MAC/B;AACA,WAAK,iBAAiB;AACtB,WAAK,KAAK,YAAY,GAAG;AAAA,IAC3B;AAAA,EACF;AAEA,oBAAkB,cAAc,MAAM;",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|