@relaymessenger/livekit 0.1.0-staging.10 → 0.1.0-staging.12
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/README.md +64 -4
- package/dist/engine-werift-video.d.ts +70 -0
- package/dist/engine-werift-video.d.ts.map +1 -0
- package/dist/engine-werift-video.js +594 -0
- package/dist/engine-werift-video.js.map +1 -0
- package/dist/engine-werift.d.ts +29 -0
- package/dist/engine-werift.d.ts.map +1 -1
- package/dist/engine-werift.js +120 -25
- package/dist/engine-werift.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/transport.d.ts +42 -5
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +265 -33
- package/dist/transport.js.map +1 -1
- package/dist/video-frame.d.ts +56 -0
- package/dist/video-frame.d.ts.map +1 -0
- package/dist/video-frame.js +245 -0
- package/dist/video-frame.js.map +1 -0
- package/dist/video-rtp.d.ts +51 -0
- package/dist/video-rtp.d.ts.map +1 -0
- package/dist/video-rtp.js +294 -0
- package/dist/video-rtp.js.map +1 -0
- package/dist/video.d.ts +144 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +228 -0
- package/dist/video.js.map +1 -0
- package/package.json +6 -3
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video for the werift engine: `node-webcodecs` 1.3.0 encodes and decodes
|
|
3
|
+
* (its static build: LGPL FFmpeg with openh264 and libvpx), `rtp-packet`
|
|
4
|
+
* packetizes, `video-rtp.ts` depacketizes, werift carries RTP and RTCP.
|
|
5
|
+
*
|
|
6
|
+
* Choices measured on 2026-09-22 (/tmp/video-spike-webcodecs, the spike that
|
|
7
|
+
* picked this engine), each kept here:
|
|
8
|
+
* - `NODE_WEBCODECS_FORCE=static` selects the bundled FFmpeg
|
|
9
|
+
* (node-webcodecs dist/native.js `load()`; the default order tries a
|
|
10
|
+
* dynamic build linked against system FFmpeg first).
|
|
11
|
+
* - `hardwareAcceleration: "prefer-software"` on encoder and decoder: on a
|
|
12
|
+
* Mac, VideoToolbox otherwise takes the stream.
|
|
13
|
+
* - H.264 is sent as constrained baseline `avc1.42e01f`, Annex-B; the codec
|
|
14
|
+
* string FFmpeg reports for H.264 is "MPEG4/ISO/AVC", so the codec is never
|
|
15
|
+
* matched by FFmpeg's name, only by the negotiated MIME type.
|
|
16
|
+
* - A keyframe every 1 s, and on every PLI or FIR from the SFU.
|
|
17
|
+
* - The send codec is the first codec of the SFU's answer (werift
|
|
18
|
+
* rtpSender.js:408 `this.codec = params.codecs[0]`).
|
|
19
|
+
* - The receive codec is learned from the payload type of the first RTP
|
|
20
|
+
* packet, looked up in the pulled m-line's codecs: the SFU's pull offer
|
|
21
|
+
* lists every codec (spike receiver.mjs).
|
|
22
|
+
* - werift sends no PLI on loss by itself: the receiver sends one when the
|
|
23
|
+
* stream starts, when a frame is dropped and on a decode error, then every
|
|
24
|
+
* 1 s until a keyframe decodes (spike receiver.mjs `pliTimer`).
|
|
25
|
+
*/
|
|
26
|
+
import { MediaStreamTrack, RtpPacket, } from "werift";
|
|
27
|
+
import { JitterBuffer } from "rtp-packet";
|
|
28
|
+
import { VideoCodec, } from "./video.js";
|
|
29
|
+
import { VideoBufferType, VideoFrame, VideoRotation, videoFrameLength } from "./video-frame.js";
|
|
30
|
+
import { VIDEO_CLOCK_RATE, VideoFrameAssembler, createVideoPacketizer, } from "./video-rtp.js";
|
|
31
|
+
export const KEYFRAME_INTERVAL_MS = 1_000;
|
|
32
|
+
export const KEYFRAME_REQUEST_INTERVAL_MS = 1_000;
|
|
33
|
+
export const DEFAULT_VIDEO_BITRATE = 800_000;
|
|
34
|
+
export const DEFAULT_VIDEO_FRAMERATE = 30;
|
|
35
|
+
/** Frames waiting in the encoder before new captures are dropped instead of queued. */
|
|
36
|
+
const MAX_ENCODE_QUEUE = 3;
|
|
37
|
+
/** Reorder window ahead of the frame assembler (rtp-packet `JitterBuffer` default). */
|
|
38
|
+
const JITTER_LATENCY_MS = 50;
|
|
39
|
+
const STATS_WINDOW_MS = 5_000;
|
|
40
|
+
const CVO_URI = "urn:3gpp:video-orientation";
|
|
41
|
+
let webCodecs;
|
|
42
|
+
/** Loads node-webcodecs once, on first video use, so audio-only calls never load FFmpeg. */
|
|
43
|
+
export const loadWebCodecs = () => {
|
|
44
|
+
webCodecs ??= (async () => {
|
|
45
|
+
process.env.NODE_WEBCODECS_FORCE ??= "static";
|
|
46
|
+
try {
|
|
47
|
+
const module = await import("node-webcodecs");
|
|
48
|
+
if (!module.isNativeAvailable())
|
|
49
|
+
throw new Error("native binding did not load");
|
|
50
|
+
return module;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
webCodecs = undefined;
|
|
54
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
55
|
+
throw new Error(`Relay video needs the optional dependency node-webcodecs (prebuilt for darwin-arm64, linux-x64 and linux-arm64): ${reason}`);
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
return webCodecs;
|
|
59
|
+
};
|
|
60
|
+
class FrameClock {
|
|
61
|
+
count = 0;
|
|
62
|
+
firstAt;
|
|
63
|
+
lastAt;
|
|
64
|
+
#recent = [];
|
|
65
|
+
mark(now = Date.now()) {
|
|
66
|
+
this.count += 1;
|
|
67
|
+
this.firstAt ??= now;
|
|
68
|
+
this.lastAt = now;
|
|
69
|
+
this.#recent.push(now);
|
|
70
|
+
this.recent(now);
|
|
71
|
+
}
|
|
72
|
+
recent(now = Date.now()) {
|
|
73
|
+
const floor = now - STATS_WINDOW_MS;
|
|
74
|
+
let drop = 0;
|
|
75
|
+
while (drop < this.#recent.length && this.#recent[drop] < floor)
|
|
76
|
+
drop += 1;
|
|
77
|
+
if (drop)
|
|
78
|
+
this.#recent.splice(0, drop);
|
|
79
|
+
return this.#recent.length;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const codecOf = (mimeType) => {
|
|
83
|
+
const lower = mimeType?.toLowerCase();
|
|
84
|
+
if (lower === "video/h264")
|
|
85
|
+
return "h264";
|
|
86
|
+
if (lower === "video/vp8")
|
|
87
|
+
return "vp8";
|
|
88
|
+
return undefined;
|
|
89
|
+
};
|
|
90
|
+
/** WebCodecs pixel format for a LiveKit buffer type the encoder takes directly. */
|
|
91
|
+
const encoderFormat = (type) => {
|
|
92
|
+
if (type === VideoBufferType.I420)
|
|
93
|
+
return "I420";
|
|
94
|
+
if (type === VideoBufferType.RGBA)
|
|
95
|
+
return "RGBA";
|
|
96
|
+
if (type === VideoBufferType.BGRA)
|
|
97
|
+
return "BGRA";
|
|
98
|
+
return undefined;
|
|
99
|
+
};
|
|
100
|
+
const monotonicUs = () => Math.round(performance.now() * 1_000);
|
|
101
|
+
/**
|
|
102
|
+
* Raw frames in, H.264 or VP8 RTP out on one werift track. One sender lives
|
|
103
|
+
* for the whole call; a restart binds it to the new peer's transceiver.
|
|
104
|
+
*/
|
|
105
|
+
export class WeriftVideoSender {
|
|
106
|
+
track;
|
|
107
|
+
#track;
|
|
108
|
+
#wc;
|
|
109
|
+
#bitrate;
|
|
110
|
+
#framerate;
|
|
111
|
+
#preferred;
|
|
112
|
+
#ssrc = (Math.random() * 0xffffffff) >>> 0;
|
|
113
|
+
#transceiver;
|
|
114
|
+
#unsubscribe = [];
|
|
115
|
+
#encoder;
|
|
116
|
+
#encoderKey = "";
|
|
117
|
+
#packetizer;
|
|
118
|
+
#packetizerCodec;
|
|
119
|
+
#enabled = true;
|
|
120
|
+
#closed = false;
|
|
121
|
+
#keyframeWanted = true;
|
|
122
|
+
#lastKeyframeAt = Number.NEGATIVE_INFINITY;
|
|
123
|
+
#lastTimestampUs = 0;
|
|
124
|
+
#codec;
|
|
125
|
+
#width;
|
|
126
|
+
#height;
|
|
127
|
+
#captured = 0;
|
|
128
|
+
#dropped = 0;
|
|
129
|
+
#keyframes = 0;
|
|
130
|
+
#rtpPackets = 0;
|
|
131
|
+
#bytes = 0;
|
|
132
|
+
#keyframeRequests = 0;
|
|
133
|
+
#encodeErrors = 0;
|
|
134
|
+
#encoded = new FrameClock();
|
|
135
|
+
constructor(wc, options = {}) {
|
|
136
|
+
this.#wc = wc;
|
|
137
|
+
this.#bitrate = Number(options.videoEncoding?.maxBitrate ?? DEFAULT_VIDEO_BITRATE);
|
|
138
|
+
this.#framerate = options.videoEncoding?.maxFramerate ?? DEFAULT_VIDEO_FRAMERATE;
|
|
139
|
+
this.#preferred = options.videoCodec === VideoCodec.VP8 ? "vp8" : "h264";
|
|
140
|
+
this.#track = new MediaStreamTrack({ kind: "video", id: "camera", streamId: "relay-call" });
|
|
141
|
+
this.track = this.#track;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Offer the codecs this sender can encode, the preferred one first (werift
|
|
145
|
+
* fills an empty `transceiver.codecs` from the peer's config at
|
|
146
|
+
* `createOffer`, peerConnection.js:520-523, so setting it here wins).
|
|
147
|
+
*/
|
|
148
|
+
bind(transceiver, peer) {
|
|
149
|
+
for (const unsubscribe of this.#unsubscribe)
|
|
150
|
+
unsubscribe();
|
|
151
|
+
this.#unsubscribe = [];
|
|
152
|
+
const bound = transceiver;
|
|
153
|
+
const rank = (mimeType) => (codecOf(mimeType) === this.#preferred ? 0 : 1);
|
|
154
|
+
bound.codecs = (peer.config.codecs.video ?? [])
|
|
155
|
+
.filter((codec) => codecOf(codec.mimeType) !== undefined)
|
|
156
|
+
.sort((a, b) => rank(a.mimeType) - rank(b.mimeType));
|
|
157
|
+
this.#transceiver = bound;
|
|
158
|
+
this.#keyframeWanted = true;
|
|
159
|
+
this.#packetizer = undefined;
|
|
160
|
+
this.#packetizerCodec = undefined;
|
|
161
|
+
const pli = bound.sender.onPictureLossIndication.subscribe(() => this.#requestKeyframe());
|
|
162
|
+
const rtcp = bound.sender.onRtcp.subscribe((packet) => {
|
|
163
|
+
// Payload-specific feedback (206) with FMT 4 is a Full Intra Request (RFC 5104 section 4.3.1).
|
|
164
|
+
const feedback = packet.feedback;
|
|
165
|
+
if (packet.type === 206 && feedback?.count === 4)
|
|
166
|
+
this.#requestKeyframe();
|
|
167
|
+
});
|
|
168
|
+
this.#unsubscribe.push(pli.unSubscribe, rtcp.unSubscribe);
|
|
169
|
+
}
|
|
170
|
+
setEnabled(enabled) {
|
|
171
|
+
if (enabled && !this.#enabled)
|
|
172
|
+
this.#keyframeWanted = true;
|
|
173
|
+
this.#enabled = enabled;
|
|
174
|
+
}
|
|
175
|
+
capture(frame, timestampUs, rotation) {
|
|
176
|
+
this.#captured += 1;
|
|
177
|
+
if (this.#closed || !this.#enabled) {
|
|
178
|
+
this.#dropped += 1;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (rotation !== VideoRotation.VIDEO_ROTATION_0) {
|
|
182
|
+
throw new Error("Relay video sends upright frames only; rotate the frame before captureFrame.");
|
|
183
|
+
}
|
|
184
|
+
// The first codec of the answer; undefined until the SFU has answered.
|
|
185
|
+
const codec = codecOf(this.#transceiver?.sender.codec?.mimeType);
|
|
186
|
+
if (!codec) {
|
|
187
|
+
this.#dropped += 1;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this.#codec = codec;
|
|
191
|
+
let input = frame;
|
|
192
|
+
let format = encoderFormat(frame.type);
|
|
193
|
+
if (!format) {
|
|
194
|
+
input = frame.convert(VideoBufferType.I420);
|
|
195
|
+
format = "I420";
|
|
196
|
+
}
|
|
197
|
+
const expected = videoFrameLength(input.type, input.width, input.height);
|
|
198
|
+
if (input.data.length < expected) {
|
|
199
|
+
throw new Error(`VideoFrame data holds ${input.data.length} bytes; ${input.width}x${input.height} needs ${expected}.`);
|
|
200
|
+
}
|
|
201
|
+
const encoder = this.#ensureEncoder(codec, input.width, input.height);
|
|
202
|
+
if (encoder.encodeQueueSize >= MAX_ENCODE_QUEUE) {
|
|
203
|
+
this.#dropped += 1;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
let us = timestampUs === BigInt(0) ? monotonicUs() : Number(timestampUs);
|
|
207
|
+
if (us <= this.#lastTimestampUs)
|
|
208
|
+
us = this.#lastTimestampUs + 1;
|
|
209
|
+
this.#lastTimestampUs = us;
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
const keyFrame = this.#keyframeWanted || now - this.#lastKeyframeAt >= KEYFRAME_INTERVAL_MS;
|
|
212
|
+
if (keyFrame) {
|
|
213
|
+
this.#keyframeWanted = false;
|
|
214
|
+
this.#lastKeyframeAt = now;
|
|
215
|
+
}
|
|
216
|
+
const wcFrame = new this.#wc.VideoFrame(input.data.subarray(0, expected), {
|
|
217
|
+
format,
|
|
218
|
+
codedWidth: input.width,
|
|
219
|
+
codedHeight: input.height,
|
|
220
|
+
timestamp: us,
|
|
221
|
+
});
|
|
222
|
+
try {
|
|
223
|
+
encoder.encode(wcFrame, { keyFrame });
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
wcFrame.close();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
stats() {
|
|
230
|
+
return {
|
|
231
|
+
codec: this.#codec,
|
|
232
|
+
framesCaptured: this.#captured,
|
|
233
|
+
framesEncoded: this.#encoded.count,
|
|
234
|
+
framesDropped: this.#dropped,
|
|
235
|
+
keyframes: this.#keyframes,
|
|
236
|
+
rtpPackets: this.#rtpPackets,
|
|
237
|
+
bytes: this.#bytes,
|
|
238
|
+
keyframeRequests: this.#keyframeRequests,
|
|
239
|
+
encodeErrors: this.#encodeErrors,
|
|
240
|
+
firstFrameAt: this.#encoded.firstAt,
|
|
241
|
+
lastFrameAt: this.#encoded.lastAt,
|
|
242
|
+
recentFrames: this.#encoded.recent(),
|
|
243
|
+
width: this.#width,
|
|
244
|
+
height: this.#height,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
close() {
|
|
248
|
+
if (this.#closed)
|
|
249
|
+
return;
|
|
250
|
+
this.#closed = true;
|
|
251
|
+
for (const unsubscribe of this.#unsubscribe)
|
|
252
|
+
unsubscribe();
|
|
253
|
+
this.#unsubscribe = [];
|
|
254
|
+
this.#closeEncoder();
|
|
255
|
+
this.#track.stop();
|
|
256
|
+
}
|
|
257
|
+
#requestKeyframe() {
|
|
258
|
+
this.#keyframeRequests += 1;
|
|
259
|
+
this.#keyframeWanted = true;
|
|
260
|
+
}
|
|
261
|
+
#ensureEncoder(codec, width, height) {
|
|
262
|
+
const key = `${codec}:${width}x${height}`;
|
|
263
|
+
if (this.#encoder && this.#encoderKey === key && this.#encoder.state === "configured")
|
|
264
|
+
return this.#encoder;
|
|
265
|
+
this.#closeEncoder();
|
|
266
|
+
const encoder = new this.#wc.VideoEncoder({
|
|
267
|
+
output: (chunk) => this.#output(codec, chunk),
|
|
268
|
+
error: () => {
|
|
269
|
+
this.#encodeErrors += 1;
|
|
270
|
+
this.#keyframeWanted = true;
|
|
271
|
+
if (this.#encoder === encoder)
|
|
272
|
+
this.#encoder = undefined;
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
encoder.configure({
|
|
276
|
+
codec: codec === "h264" ? "avc1.42e01f" : "vp8",
|
|
277
|
+
width,
|
|
278
|
+
height,
|
|
279
|
+
bitrate: this.#bitrate,
|
|
280
|
+
framerate: this.#framerate,
|
|
281
|
+
latencyMode: "realtime",
|
|
282
|
+
hardwareAcceleration: "prefer-software",
|
|
283
|
+
...(codec === "h264" ? { avc: { format: "annexb" } } : {}),
|
|
284
|
+
});
|
|
285
|
+
this.#encoder = encoder;
|
|
286
|
+
this.#encoderKey = key;
|
|
287
|
+
this.#width = width;
|
|
288
|
+
this.#height = height;
|
|
289
|
+
this.#keyframeWanted = true;
|
|
290
|
+
return encoder;
|
|
291
|
+
}
|
|
292
|
+
#closeEncoder() {
|
|
293
|
+
const encoder = this.#encoder;
|
|
294
|
+
this.#encoder = undefined;
|
|
295
|
+
this.#encoderKey = "";
|
|
296
|
+
if (!encoder || encoder.state === "closed")
|
|
297
|
+
return;
|
|
298
|
+
try {
|
|
299
|
+
encoder.close();
|
|
300
|
+
}
|
|
301
|
+
catch { /* already closed */ }
|
|
302
|
+
}
|
|
303
|
+
#output(codec, chunk) {
|
|
304
|
+
if (this.#closed)
|
|
305
|
+
return;
|
|
306
|
+
const data = new Uint8Array(chunk.byteLength);
|
|
307
|
+
chunk.copyTo(data);
|
|
308
|
+
if (this.#packetizerCodec !== codec || !this.#packetizer) {
|
|
309
|
+
// werift's sender rewrites SSRC, payload type, sequence and timestamp
|
|
310
|
+
// base (rtpSender.js:544-549), so these are local placeholders.
|
|
311
|
+
this.#packetizer = createVideoPacketizer(codec, { ssrc: this.#ssrc, payloadType: 96 });
|
|
312
|
+
this.#packetizerCodec = codec;
|
|
313
|
+
}
|
|
314
|
+
const keyframe = chunk.type === "key";
|
|
315
|
+
const packets = this.#packetizer.packetize(data, chunk.timestamp, keyframe);
|
|
316
|
+
for (const packet of packets) {
|
|
317
|
+
this.#track.writeRtp(RtpPacket.deSerialize(packet));
|
|
318
|
+
this.#rtpPackets += 1;
|
|
319
|
+
this.#bytes += packet.length;
|
|
320
|
+
}
|
|
321
|
+
if (keyframe)
|
|
322
|
+
this.#keyframes += 1;
|
|
323
|
+
this.#encoded.mark();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* One pulled video m-line: RTP in, decoded I420 frames out. RTP is counted
|
|
328
|
+
* always; it is reordered, assembled and decoded only while active.
|
|
329
|
+
*/
|
|
330
|
+
export class WeriftVideoReceiver {
|
|
331
|
+
onframe = null;
|
|
332
|
+
#track;
|
|
333
|
+
#transceiver;
|
|
334
|
+
#unsubscribe;
|
|
335
|
+
#wc;
|
|
336
|
+
#active = false;
|
|
337
|
+
#stopped = false;
|
|
338
|
+
#payloadType;
|
|
339
|
+
#codec;
|
|
340
|
+
#codecLabel;
|
|
341
|
+
#codecString = "";
|
|
342
|
+
#ssrc;
|
|
343
|
+
#jitter;
|
|
344
|
+
#assembler;
|
|
345
|
+
#decoder;
|
|
346
|
+
#waitingForKeyframe = true;
|
|
347
|
+
#lastKeyframeRequestAt = Number.NEGATIVE_INFINITY;
|
|
348
|
+
#keyframeTimer;
|
|
349
|
+
#rotation = VideoRotation.VIDEO_ROTATION_0;
|
|
350
|
+
#firstRtpTimestamp;
|
|
351
|
+
#lastRtpTimestamp = 0;
|
|
352
|
+
#rtpTimestampWraps = 0;
|
|
353
|
+
#outputChain = Promise.resolve();
|
|
354
|
+
#rtpPackets = 0;
|
|
355
|
+
#skippedDeltas = 0;
|
|
356
|
+
#decodeErrors = 0;
|
|
357
|
+
#keyframeRequests = 0;
|
|
358
|
+
#width;
|
|
359
|
+
#height;
|
|
360
|
+
#decoded = new FrameClock();
|
|
361
|
+
constructor(track, transceiver) {
|
|
362
|
+
this.#track = track;
|
|
363
|
+
this.#transceiver = transceiver;
|
|
364
|
+
const { unSubscribe } = track.onReceiveRtp.subscribe((rtp, extensions) => {
|
|
365
|
+
this.#rtpPackets += 1;
|
|
366
|
+
if (!this.#active || this.#stopped)
|
|
367
|
+
return;
|
|
368
|
+
this.#receive(rtp, extensions);
|
|
369
|
+
});
|
|
370
|
+
this.#unsubscribe = unSubscribe;
|
|
371
|
+
}
|
|
372
|
+
setActive(active) {
|
|
373
|
+
if (this.#stopped || active === this.#active)
|
|
374
|
+
return;
|
|
375
|
+
this.#active = active;
|
|
376
|
+
if (!active) {
|
|
377
|
+
this.#resetPipeline();
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
void loadWebCodecs().then((wc) => {
|
|
381
|
+
this.#wc = wc;
|
|
382
|
+
if (this.#active)
|
|
383
|
+
this.#requestKeyframe();
|
|
384
|
+
}, () => {
|
|
385
|
+
this.#decodeErrors += 1;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
stats() {
|
|
389
|
+
return {
|
|
390
|
+
codec: this.#codecLabel,
|
|
391
|
+
rtpPackets: this.#rtpPackets,
|
|
392
|
+
framesAssembled: this.#assembler?.frames ?? 0,
|
|
393
|
+
framesDropped: (this.#assembler?.dropped ?? 0) + this.#skippedDeltas,
|
|
394
|
+
framesDecoded: this.#decoded.count,
|
|
395
|
+
decodeErrors: this.#decodeErrors,
|
|
396
|
+
keyframeRequests: this.#keyframeRequests,
|
|
397
|
+
firstFrameAt: this.#decoded.firstAt,
|
|
398
|
+
lastFrameAt: this.#decoded.lastAt,
|
|
399
|
+
recentFrames: this.#decoded.recent(),
|
|
400
|
+
width: this.#width,
|
|
401
|
+
height: this.#height,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
stop() {
|
|
405
|
+
if (this.#stopped)
|
|
406
|
+
return;
|
|
407
|
+
this.#stopped = true;
|
|
408
|
+
this.onframe = null;
|
|
409
|
+
this.#unsubscribe();
|
|
410
|
+
this.#resetPipeline();
|
|
411
|
+
}
|
|
412
|
+
#receive(rtp, extensions) {
|
|
413
|
+
const header = rtp.header;
|
|
414
|
+
if (this.#payloadType === undefined) {
|
|
415
|
+
this.#payloadType = header.payloadType;
|
|
416
|
+
const codec = this.#transceiver?.codecs.find((candidate) => candidate.payloadType === header.payloadType);
|
|
417
|
+
this.#codecLabel = codec?.mimeType ?? `pt ${header.payloadType}`;
|
|
418
|
+
this.#codec = codecOf(codec?.mimeType);
|
|
419
|
+
const profile = /profile-level-id=([0-9a-f]{6})/i.exec(codec?.parameters ?? "")?.[1];
|
|
420
|
+
this.#codecString = this.#codec === "vp8" ? "vp8" : `avc1.${(profile ?? "42e01f").toLowerCase()}`;
|
|
421
|
+
}
|
|
422
|
+
if (header.payloadType !== this.#payloadType || !this.#codec || !rtp.payload?.length)
|
|
423
|
+
return;
|
|
424
|
+
this.#ssrc = header.ssrc;
|
|
425
|
+
const orientation = extensions?.[CVO_URI];
|
|
426
|
+
if (orientation)
|
|
427
|
+
this.#rotation = (((orientation.r1 ?? 0) << 1) | (orientation.r0 ?? 0));
|
|
428
|
+
if (!this.#jitter) {
|
|
429
|
+
const codec = this.#codec;
|
|
430
|
+
this.#assembler = new VideoFrameAssembler(codec, (frame) => this.#frame(frame), () => {
|
|
431
|
+
this.#waitingForKeyframe = true;
|
|
432
|
+
this.#requestKeyframe();
|
|
433
|
+
});
|
|
434
|
+
this.#jitter = new JitterBuffer({
|
|
435
|
+
latency: JITTER_LATENCY_MS,
|
|
436
|
+
output: (packet) => this.#assembler?.push(packet),
|
|
437
|
+
});
|
|
438
|
+
this.#requestKeyframe();
|
|
439
|
+
}
|
|
440
|
+
this.#jitter.push({
|
|
441
|
+
sequenceNumber: header.sequenceNumber,
|
|
442
|
+
timestamp: header.timestamp,
|
|
443
|
+
marker: header.marker,
|
|
444
|
+
payload: rtp.payload,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
#frame(frame) {
|
|
448
|
+
const wc = this.#wc;
|
|
449
|
+
if (!wc || !this.#active)
|
|
450
|
+
return;
|
|
451
|
+
if (this.#waitingForKeyframe && !frame.keyframe) {
|
|
452
|
+
this.#skippedDeltas += 1;
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (!this.#decoder || this.#decoder.state === "closed") {
|
|
456
|
+
if (!frame.keyframe) {
|
|
457
|
+
this.#skippedDeltas += 1;
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
this.#decoder = this.#createDecoder(wc);
|
|
461
|
+
}
|
|
462
|
+
if (frame.keyframe) {
|
|
463
|
+
this.#waitingForKeyframe = false;
|
|
464
|
+
this.#stopKeyframeTimer();
|
|
465
|
+
}
|
|
466
|
+
const timestampUs = this.#timestampUs(frame.timestamp);
|
|
467
|
+
try {
|
|
468
|
+
this.#decoder.decode(new wc.EncodedVideoChunk({
|
|
469
|
+
type: frame.keyframe ? "key" : "delta",
|
|
470
|
+
timestamp: timestampUs,
|
|
471
|
+
data: frame.data,
|
|
472
|
+
}));
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
this.#decodeFailed();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
#createDecoder(wc) {
|
|
479
|
+
const decoder = new wc.VideoDecoder({
|
|
480
|
+
output: (output) => {
|
|
481
|
+
const rotation = this.#rotation;
|
|
482
|
+
this.#outputChain = this.#outputChain.then(() => this.#emit(output, rotation));
|
|
483
|
+
},
|
|
484
|
+
error: () => {
|
|
485
|
+
if (this.#decoder === decoder)
|
|
486
|
+
this.#decodeFailed();
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
decoder.configure({ codec: this.#codecString, hardwareAcceleration: "prefer-software", optimizeForLatency: true });
|
|
490
|
+
return decoder;
|
|
491
|
+
}
|
|
492
|
+
async #emit(output, rotation) {
|
|
493
|
+
try {
|
|
494
|
+
const width = output.codedWidth;
|
|
495
|
+
const height = output.codedHeight;
|
|
496
|
+
const options = { format: "I420" };
|
|
497
|
+
const data = new Uint8Array(output.allocationSize(options));
|
|
498
|
+
await output.copyTo(data, options);
|
|
499
|
+
const tight = videoFrameLength(VideoBufferType.I420, width, height);
|
|
500
|
+
const frame = new VideoFrame(data.length === tight ? data : data.subarray(0, tight), width, height, VideoBufferType.I420);
|
|
501
|
+
this.#width = width;
|
|
502
|
+
this.#height = height;
|
|
503
|
+
this.#decoded.mark();
|
|
504
|
+
const event = { frame, timestampUs: BigInt(output.timestamp), rotation };
|
|
505
|
+
if (!this.#stopped && this.#active)
|
|
506
|
+
this.onframe?.(event);
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
this.#decodeErrors += 1;
|
|
510
|
+
}
|
|
511
|
+
finally {
|
|
512
|
+
output.close();
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
#decodeFailed() {
|
|
516
|
+
this.#decodeErrors += 1;
|
|
517
|
+
const decoder = this.#decoder;
|
|
518
|
+
this.#decoder = undefined;
|
|
519
|
+
if (decoder && decoder.state !== "closed") {
|
|
520
|
+
try {
|
|
521
|
+
decoder.close();
|
|
522
|
+
}
|
|
523
|
+
catch { /* already closed */ }
|
|
524
|
+
}
|
|
525
|
+
this.#waitingForKeyframe = true;
|
|
526
|
+
this.#requestKeyframe();
|
|
527
|
+
}
|
|
528
|
+
/** RTP timestamp (90 kHz, wrapping at 2^32) to microseconds since this stream's first frame. */
|
|
529
|
+
#timestampUs(rtpTimestamp) {
|
|
530
|
+
if (this.#firstRtpTimestamp === undefined)
|
|
531
|
+
this.#firstRtpTimestamp = rtpTimestamp;
|
|
532
|
+
if (rtpTimestamp < this.#lastRtpTimestamp && this.#lastRtpTimestamp - rtpTimestamp > 0x80000000) {
|
|
533
|
+
this.#rtpTimestampWraps += 1;
|
|
534
|
+
}
|
|
535
|
+
this.#lastRtpTimestamp = rtpTimestamp;
|
|
536
|
+
const ticks = this.#rtpTimestampWraps * 0x100000000 + rtpTimestamp - this.#firstRtpTimestamp;
|
|
537
|
+
return Math.round((ticks * 1_000_000) / VIDEO_CLOCK_RATE);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* PLI to the sender, at once unless one left in the last 1 s; while no
|
|
541
|
+
* keyframe has arrived, a timer repeats it every 1 s.
|
|
542
|
+
*/
|
|
543
|
+
#requestKeyframe() {
|
|
544
|
+
if (this.#stopped || !this.#active)
|
|
545
|
+
return;
|
|
546
|
+
if (Date.now() - this.#lastKeyframeRequestAt >= KEYFRAME_REQUEST_INTERVAL_MS)
|
|
547
|
+
this.#sendPli();
|
|
548
|
+
if (this.#keyframeTimer)
|
|
549
|
+
return;
|
|
550
|
+
this.#keyframeTimer = setInterval(() => {
|
|
551
|
+
if (!this.#waitingForKeyframe || !this.#active) {
|
|
552
|
+
this.#stopKeyframeTimer();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
this.#sendPli();
|
|
556
|
+
}, KEYFRAME_REQUEST_INTERVAL_MS);
|
|
557
|
+
this.#keyframeTimer.unref?.();
|
|
558
|
+
}
|
|
559
|
+
#sendPli() {
|
|
560
|
+
const ssrc = this.#ssrc ?? this.#track.ssrc;
|
|
561
|
+
const receiver = this.#transceiver?.receiver;
|
|
562
|
+
if (ssrc === undefined || !receiver)
|
|
563
|
+
return;
|
|
564
|
+
this.#lastKeyframeRequestAt = Date.now();
|
|
565
|
+
this.#keyframeRequests += 1;
|
|
566
|
+
void receiver.sendRtcpPLI(ssrc).catch(() => undefined);
|
|
567
|
+
}
|
|
568
|
+
#stopKeyframeTimer() {
|
|
569
|
+
if (!this.#keyframeTimer)
|
|
570
|
+
return;
|
|
571
|
+
clearInterval(this.#keyframeTimer);
|
|
572
|
+
this.#keyframeTimer = undefined;
|
|
573
|
+
}
|
|
574
|
+
#resetPipeline() {
|
|
575
|
+
this.#stopKeyframeTimer();
|
|
576
|
+
this.#jitter?.close();
|
|
577
|
+
this.#jitter = undefined;
|
|
578
|
+
this.#assembler?.reset();
|
|
579
|
+
const decoder = this.#decoder;
|
|
580
|
+
this.#decoder = undefined;
|
|
581
|
+
if (decoder && decoder.state !== "closed") {
|
|
582
|
+
try {
|
|
583
|
+
decoder.close();
|
|
584
|
+
}
|
|
585
|
+
catch { /* already closed */ }
|
|
586
|
+
}
|
|
587
|
+
this.#waitingForKeyframe = true;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
export const createWeriftVideoFactory = () => ({
|
|
591
|
+
createVideoSender: async (options) => new WeriftVideoSender(await loadWebCodecs(), options),
|
|
592
|
+
createVideoReceiver: (track, transceiver) => new WeriftVideoReceiver(track, transceiver),
|
|
593
|
+
});
|
|
594
|
+
//# sourceMappingURL=engine-werift-video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-werift-video.js","sourceRoot":"","sources":["../src/engine-werift-video.ts"],"names":[],"mappings":"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"}
|
package/dist/engine-werift.d.ts
CHANGED
|
@@ -8,6 +8,35 @@ export declare const WERIFT_PACKET_MS = 20;
|
|
|
8
8
|
export type WeriftAudioSourceData = Parameters<RelayAudioSourceLike["onData"]>[0];
|
|
9
9
|
/** Packets counted for `diagnostics()`; the recent window is the last 5 s. */
|
|
10
10
|
export declare const STATS_WINDOW_MS = 5000;
|
|
11
|
+
/**
|
|
12
|
+
* A pacer more than this far behind its clock re-anchors instead of bursting
|
|
13
|
+
* the backlog. LiveKit's native `AudioSource` (rust-sdks
|
|
14
|
+
* webrtc-sys/src/audio_track.cpp:161-188) runs a 10 ms libwebrtc
|
|
15
|
+
* `RepeatingTask`, which schedules against an absolute run time and makes up
|
|
16
|
+
* every lost tick with zero delay, unbounded (rtc_base/task_utils/
|
|
17
|
+
* repeating_task.cc:86-89, `delay -= lost_time; delay = max(delay, 0)`). The
|
|
18
|
+
* bound is ours: 10 packets, so an event-loop hiccup is made up in full and a
|
|
19
|
+
* real stall does not dump seconds of audio on the receiver at once.
|
|
20
|
+
* Sources saved under _sources/audio-pacing-20260922.
|
|
21
|
+
*/
|
|
22
|
+
export declare const WERIFT_MAX_CATCH_UP_MS = 200;
|
|
23
|
+
/**
|
|
24
|
+
* Wall-clock RTP audio pacing: packet `n` of a run is due at `start + n × 20 ms`,
|
|
25
|
+
* so the average rate is exactly one packet per 20 ms however late the timer
|
|
26
|
+
* fires. `take(now)` returns how many packets are due and counts them as sent.
|
|
27
|
+
*/
|
|
28
|
+
export declare class RtpAudioPacer {
|
|
29
|
+
#private;
|
|
30
|
+
readonly packetMs: number;
|
|
31
|
+
readonly maxCatchUpMs: number;
|
|
32
|
+
constructor(packetMs?: number, maxCatchUpMs?: number);
|
|
33
|
+
/** Packets due by `now` and not yet sent; the first call of a run sends one at once. */
|
|
34
|
+
take(now: number): number;
|
|
35
|
+
/** When the next packet is due; `-Infinity` before the first `take` of a run. */
|
|
36
|
+
nextDueAt(): number;
|
|
37
|
+
/** Forget the run; the next `take` starts a new clock. */
|
|
38
|
+
reset(): void;
|
|
39
|
+
}
|
|
11
40
|
/** Convert any PCM16 frame to interleaved 48 kHz stereo by linear interpolation. */
|
|
12
41
|
export declare const toWireFormat: (data: {
|
|
13
42
|
samples: Int16Array;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-werift.d.ts","sourceRoot":"","sources":["../src/engine-werift.ts"],"names":[],"mappings":"AAqCA,OAAO,EAGL,iBAAiB,
|
|
1
|
+
{"version":3,"file":"engine-werift.d.ts","sourceRoot":"","sources":["../src/engine-werift.ts"],"names":[],"mappings":"AAqCA,OAAO,EAGL,iBAAiB,EAQlB,MAAM,QAAQ,CAAC;AAEhB,OAAO,KAAK,EAGV,oBAAoB,EAIpB,yBAAyB,EAEzB,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB,sGAAsG;AACtG,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAMnC,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAElF,8EAA8E;AAC9E,eAAO,MAAM,eAAe,OAAQ,CAAC;AA8BrC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;GAIG;AACH,qBAAa,aAAa;;IAKtB,QAAQ,CAAC,QAAQ;IACjB,QAAQ,CAAC,YAAY;gBADZ,QAAQ,SAAmB,EAC3B,YAAY,SAAyB;IAGhD,wFAAwF;IACxF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAWzB,iFAAiF;IACjF,SAAS,IAAI,MAAM;IAInB,0DAA0D;IAC1D,KAAK,IAAI,IAAI;CAId;AAED,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,MAAM;IACjC,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,KAAG,UAwBH,CAAC;AAmSF,eAAO,MAAM,0BAA0B,GACrC,SAAQ,yBAAyE,KAChF,iBAkBC,CAAC;AAEL,eAAO,MAAM,yBAAyB,QAAO,kBAK3C,CAAC"}
|