@relaymessenger/livekit 0.1.0-staging.16 → 0.1.0-staging.17
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 +14 -188
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/livekit.d.ts +5 -7
- package/dist/livekit.d.ts.map +1 -1
- package/dist/livekit.js +15 -20
- package/dist/livekit.js.map +1 -1
- package/package.json +3 -8
- package/dist/engine-werift-video.d.ts +0 -70
- package/dist/engine-werift-video.d.ts.map +0 -1
- package/dist/engine-werift-video.js +0 -594
- package/dist/engine-werift-video.js.map +0 -1
- package/dist/engine-werift.d.ts +0 -48
- package/dist/engine-werift.d.ts.map +0 -1
- package/dist/engine-werift.js +0 -457
- package/dist/engine-werift.js.map +0 -1
- package/dist/transport.d.ts +0 -327
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -1354
- package/dist/transport.js.map +0 -1
- package/dist/video-frame.d.ts +0 -56
- package/dist/video-frame.d.ts.map +0 -1
- package/dist/video-frame.js +0 -245
- package/dist/video-frame.js.map +0 -1
- package/dist/video-rtp.d.ts +0 -51
- package/dist/video-rtp.d.ts.map +0 -1
- package/dist/video-rtp.js +0 -294
- package/dist/video-rtp.js.map +0 -1
- package/dist/video.d.ts +0 -144
- package/dist/video.d.ts.map +0 -1
- package/dist/video.js +0 -228
- package/dist/video.js.map +0 -1
package/dist/engine-werift.js
DELETED
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Relay's default call participant engine: werift (pure-TypeScript WebRTC:
|
|
3
|
-
* ICE, DTLS, SRTP, RTP) plus `@evan/opus` (prebuilt libopus, WASM fallback).
|
|
4
|
-
*
|
|
5
|
-
* API sources read for this file, in node_modules/werift/lib/webrtc/src:
|
|
6
|
-
* - peerConnection.d.ts: `new RTCPeerConnection({ codecs: { audio: [...] } })`,
|
|
7
|
-
* `addTransceiver(track, { direction })`, the W3C-style `ontrack`,
|
|
8
|
-
* `onconnectionstatechange`, `localDescription`, `close()`, and the
|
|
9
|
-
* `"icegatheringstatechange"` / `"connectionstatechange"` events emitted
|
|
10
|
-
* through `EventTarget.addEventListener` (peerConnection.js:317, :330).
|
|
11
|
-
* `RTCConfiguration.iceServers: RTCIceServer[]` ({ urls, username?,
|
|
12
|
-
* credential? }) and `iceTransportPolicy: "all" | "relay"` (peerConnection.d.ts
|
|
13
|
-
* :264-273); utils.js:110-179 parses `stun|stuns|turn|turns:` URLs with
|
|
14
|
-
* `?transport=`, and `secureTransportManager.js:121` maps `"relay"` to
|
|
15
|
-
* `forceTurn`. The W3C setters `onicecandidate`, `onicegatheringstatechange`
|
|
16
|
-
* and `oniceconnectionstatechange` (peerConnection.d.ts:67-82, fired at
|
|
17
|
-
* peerConnection.js:314-341) feed the transport's ICE diagnostics.
|
|
18
|
-
* - media/track.d.ts: `MediaStreamTrack({ kind })`, `writeRtp(RtpPacket)`,
|
|
19
|
-
* `onReceiveRtp: Event<[RtpPacket, Extensions?]>` with `subscribe()`.
|
|
20
|
-
* - media/rtpSender.js:544-549: the sender rewrites ssrc and payloadType and
|
|
21
|
-
* offsets sequenceNumber/timestamp, so the local track starts both at 0.
|
|
22
|
-
* - ../../rtp/src/codec/opus.d.ts: `OpusRtpPayload.deSerialize(buffer)`.
|
|
23
|
-
* - node_modules/@evan/opus/lib.d.ts: `Encoder.encode(pcm16)` returns one Opus
|
|
24
|
-
* packet; `Decoder.decode(packet)` returns interleaved PCM16 bytes;
|
|
25
|
-
* `new Decoder({ channels?: 1 | 2, sample_rate?: 8000 | 12000 | 16000 |
|
|
26
|
-
* 24000 | 48000 })` decodes any Opus stream to that count and rate (libopus
|
|
27
|
-
* `opus_decoder_create(Fs, channels)`), which is how the sink honours
|
|
28
|
-
* `RelayInboundAudioFormat`.
|
|
29
|
-
* Participant shapes copied from the headless phone that joined Relay's room
|
|
30
|
-
* through Cloudflare's SFU on 2026-09-21 (_runtime/bin/headless-phone-webrtc.mjs
|
|
31
|
-
* lines 93-160): `bundlePolicy: "max-bundle", iceServers: []` (Cloudflare
|
|
32
|
-
* supplies its ICE candidates in the answer), the local track is id
|
|
33
|
-
* "microphone" in stream "relay-call" (Relay-iOS RelayWebRTCAudioTransport),
|
|
34
|
-
* the first RTP packet carries the marker bit, empty payloads are skipped and a
|
|
35
|
-
* decode failure never tears the sink down.
|
|
36
|
-
*/
|
|
37
|
-
import { Decoder, Encoder } from "@evan/opus";
|
|
38
|
-
import { MediaStreamTrack, OpusRtpPayload, RTCPeerConnection, RTCRtpCodecParameters, RTCRtpHeaderExtensionParameters, RtpHeader, RtpPacket, useFIR, useNACK, usePLI, } from "werift";
|
|
39
|
-
import { createWeriftVideoFactory } from "./engine-werift-video.js";
|
|
40
|
-
/** Opus on the wire is always 48 kHz; Relay sends stereo so callers may pass either channel count. */
|
|
41
|
-
export const WERIFT_SAMPLE_RATE = 48_000;
|
|
42
|
-
export const WERIFT_CHANNEL_COUNT = 2;
|
|
43
|
-
/** One RTP packet carries 20 ms: 960 frames at 48 kHz, timestamp advances by 960. */
|
|
44
|
-
export const WERIFT_PACKET_MS = 20;
|
|
45
|
-
const PACKET_FRAMES = (WERIFT_SAMPLE_RATE * WERIFT_PACKET_MS) / 1000;
|
|
46
|
-
const PACKET_SAMPLES = PACKET_FRAMES * WERIFT_CHANNEL_COUNT;
|
|
47
|
-
/** Dynamic payload type; werift's sender replaces it with the negotiated one. */
|
|
48
|
-
const LOCAL_PAYLOAD_TYPE = 111;
|
|
49
|
-
/** Packets counted for `diagnostics()`; the recent window is the last 5 s. */
|
|
50
|
-
export const STATS_WINDOW_MS = 5_000;
|
|
51
|
-
/** Monotone packet counter with first/last epoch timestamps and a 5 s window. */
|
|
52
|
-
class PacketClock {
|
|
53
|
-
count = 0;
|
|
54
|
-
firstAt;
|
|
55
|
-
lastAt;
|
|
56
|
-
#recent = [];
|
|
57
|
-
mark(now = Date.now()) {
|
|
58
|
-
this.count += 1;
|
|
59
|
-
this.firstAt ??= now;
|
|
60
|
-
this.lastAt = now;
|
|
61
|
-
this.#recent.push(now);
|
|
62
|
-
this.#prune(now);
|
|
63
|
-
}
|
|
64
|
-
recent(now = Date.now()) {
|
|
65
|
-
this.#prune(now);
|
|
66
|
-
return this.#recent.length;
|
|
67
|
-
}
|
|
68
|
-
#prune(now) {
|
|
69
|
-
const floor = now - STATS_WINDOW_MS;
|
|
70
|
-
let drop = 0;
|
|
71
|
-
while (drop < this.#recent.length && this.#recent[drop] < floor)
|
|
72
|
-
drop += 1;
|
|
73
|
-
if (drop)
|
|
74
|
-
this.#recent.splice(0, drop);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* A pacer more than this far behind its clock re-anchors instead of bursting
|
|
79
|
-
* the backlog. LiveKit's native `AudioSource` (rust-sdks
|
|
80
|
-
* webrtc-sys/src/audio_track.cpp:161-188) runs a 10 ms libwebrtc
|
|
81
|
-
* `RepeatingTask`, which schedules against an absolute run time and makes up
|
|
82
|
-
* every lost tick with zero delay, unbounded (rtc_base/task_utils/
|
|
83
|
-
* repeating_task.cc:86-89, `delay -= lost_time; delay = max(delay, 0)`). The
|
|
84
|
-
* bound is ours: 10 packets, so an event-loop hiccup is made up in full and a
|
|
85
|
-
* real stall does not dump seconds of audio on the receiver at once.
|
|
86
|
-
* Sources saved under _sources/audio-pacing-20260922.
|
|
87
|
-
*/
|
|
88
|
-
export const WERIFT_MAX_CATCH_UP_MS = 200;
|
|
89
|
-
/**
|
|
90
|
-
* Wall-clock RTP audio pacing: packet `n` of a run is due at `start + n × 20 ms`,
|
|
91
|
-
* so the average rate is exactly one packet per 20 ms however late the timer
|
|
92
|
-
* fires. `take(now)` returns how many packets are due and counts them as sent.
|
|
93
|
-
*/
|
|
94
|
-
export class RtpAudioPacer {
|
|
95
|
-
packetMs;
|
|
96
|
-
maxCatchUpMs;
|
|
97
|
-
#startedAt;
|
|
98
|
-
#sent = 0;
|
|
99
|
-
constructor(packetMs = WERIFT_PACKET_MS, maxCatchUpMs = WERIFT_MAX_CATCH_UP_MS) {
|
|
100
|
-
this.packetMs = packetMs;
|
|
101
|
-
this.maxCatchUpMs = maxCatchUpMs;
|
|
102
|
-
}
|
|
103
|
-
/** Packets due by `now` and not yet sent; the first call of a run sends one at once. */
|
|
104
|
-
take(now) {
|
|
105
|
-
if (this.#startedAt === undefined || now - this.nextDueAt() > this.maxCatchUpMs) {
|
|
106
|
-
this.#startedAt = now;
|
|
107
|
-
this.#sent = 0;
|
|
108
|
-
}
|
|
109
|
-
const due = Math.floor((now - this.#startedAt) / this.packetMs) + 1 - this.#sent;
|
|
110
|
-
if (due <= 0)
|
|
111
|
-
return 0;
|
|
112
|
-
this.#sent += due;
|
|
113
|
-
return due;
|
|
114
|
-
}
|
|
115
|
-
/** When the next packet is due; `-Infinity` before the first `take` of a run. */
|
|
116
|
-
nextDueAt() {
|
|
117
|
-
return this.#startedAt === undefined ? -Infinity : this.#startedAt + this.#sent * this.packetMs;
|
|
118
|
-
}
|
|
119
|
-
/** Forget the run; the next `take` starts a new clock. */
|
|
120
|
-
reset() {
|
|
121
|
-
this.#startedAt = undefined;
|
|
122
|
-
this.#sent = 0;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/** Convert any PCM16 frame to interleaved 48 kHz stereo by linear interpolation. */
|
|
126
|
-
export const toWireFormat = (data) => {
|
|
127
|
-
const { samples, sampleRate, channelCount } = data;
|
|
128
|
-
const inputFrames = Math.floor(samples.length / channelCount);
|
|
129
|
-
if (sampleRate === WERIFT_SAMPLE_RATE && channelCount === WERIFT_CHANNEL_COUNT) {
|
|
130
|
-
return samples;
|
|
131
|
-
}
|
|
132
|
-
const outputFrames = Math.round((inputFrames * WERIFT_SAMPLE_RATE) / sampleRate);
|
|
133
|
-
const out = new Int16Array(outputFrames * WERIFT_CHANNEL_COUNT);
|
|
134
|
-
const ratio = sampleRate / WERIFT_SAMPLE_RATE;
|
|
135
|
-
const leftIndex = 0;
|
|
136
|
-
const rightIndex = channelCount > 1 ? 1 : 0;
|
|
137
|
-
for (let frame = 0; frame < outputFrames; frame += 1) {
|
|
138
|
-
const position = frame * ratio;
|
|
139
|
-
const base = Math.min(Math.floor(position), inputFrames - 1);
|
|
140
|
-
const next = Math.min(base + 1, inputFrames - 1);
|
|
141
|
-
const fraction = position - Math.floor(position);
|
|
142
|
-
const left = samples[base * channelCount + leftIndex] * (1 - fraction)
|
|
143
|
-
+ samples[next * channelCount + leftIndex] * fraction;
|
|
144
|
-
const right = samples[base * channelCount + rightIndex] * (1 - fraction)
|
|
145
|
-
+ samples[next * channelCount + rightIndex] * fraction;
|
|
146
|
-
out[frame * 2] = Math.round(left);
|
|
147
|
-
out[frame * 2 + 1] = Math.round(right);
|
|
148
|
-
}
|
|
149
|
-
return out;
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
* PCM16 in, paced 20 ms Opus RTP out. Frames are accumulated into whole
|
|
153
|
-
* packets; an `RtpAudioPacer` on the monotonic clock decides how many are
|
|
154
|
-
* due, so the wire sees exactly 50 packets/s regardless of how the adapter
|
|
155
|
-
* chunks its writes or how late the timer fires. A timer that fired once per
|
|
156
|
-
* packet (the old `setInterval`) lost every late tick while the RTP timestamp
|
|
157
|
-
* still advanced 960 per packet: @relay's calls on 2026-09-22 sent 48.66-48.98
|
|
158
|
-
* packets/s and the phone's jitter buffer ran dry. Adapters may push
|
|
159
|
-
* far ahead of real time: `queuedMs()` is what has not left yet and
|
|
160
|
-
* `waitForDrain()` resolves once the queued application audio has been
|
|
161
|
-
* written (LiveKit's `AudioSource.queuedDuration` / `waitForPlayout` shape).
|
|
162
|
-
*
|
|
163
|
-
* From `start()` (the transport calls it when the peer first connects) until
|
|
164
|
-
* the track stops, the pump never pauses: a tick with no application audio
|
|
165
|
-
* queued writes an Opus silence frame instead, as a live microphone track
|
|
166
|
-
* does. Cloudflare's SFU refuses to pull a published track that has carried
|
|
167
|
-
* no RTP: `tracks/new` for the remote track returned `empty_track_error` "No
|
|
168
|
-
* track data from remote peer" after about 8.2 s on staging 2026-09-22, and
|
|
169
|
-
* the same pull returned in about 470 ms with silence flowing. Silence and
|
|
170
|
-
* application packets share one sequence and timestamp line, so queued audio
|
|
171
|
-
* replaces silence on the next tick with no gap and no jump.
|
|
172
|
-
*/
|
|
173
|
-
class WeriftAudioSource {
|
|
174
|
-
#encoder = new Encoder({
|
|
175
|
-
channels: WERIFT_CHANNEL_COUNT,
|
|
176
|
-
sample_rate: WERIFT_SAMPLE_RATE,
|
|
177
|
-
application: "voip",
|
|
178
|
-
});
|
|
179
|
-
/** 20 ms of digital silence, encoded once by the same encoder and reused. */
|
|
180
|
-
#silence = Buffer.from(this.#encoder.encode(new Int16Array(PACKET_SAMPLES)));
|
|
181
|
-
#track = new MediaStreamTrack({ kind: "audio", id: "microphone", streamId: "relay-call" });
|
|
182
|
-
#packets = [];
|
|
183
|
-
/** Every RTP packet written, silence included. */
|
|
184
|
-
#rtp = new PacketClock();
|
|
185
|
-
#opusPackets = 0;
|
|
186
|
-
#applicationRtpPackets = 0;
|
|
187
|
-
#silencePackets = 0;
|
|
188
|
-
#pending = new Int16Array(0);
|
|
189
|
-
#sequenceNumber = 1;
|
|
190
|
-
#timestamp = 0;
|
|
191
|
-
#first = true;
|
|
192
|
-
#pump;
|
|
193
|
-
#pacer = new RtpAudioPacer();
|
|
194
|
-
#started = false;
|
|
195
|
-
#stopped = false;
|
|
196
|
-
#drainWaiters = new Set();
|
|
197
|
-
stats() {
|
|
198
|
-
return {
|
|
199
|
-
opusPackets: this.#opusPackets,
|
|
200
|
-
rtpPackets: this.#applicationRtpPackets,
|
|
201
|
-
silencePackets: this.#silencePackets,
|
|
202
|
-
firstRtpAt: this.#rtp.firstAt,
|
|
203
|
-
lastRtpAt: this.#rtp.lastAt,
|
|
204
|
-
recentRtpPackets: this.#rtp.recent(),
|
|
205
|
-
queued: this.#packets.length,
|
|
206
|
-
pacerAlive: this.#pump !== undefined,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
createTrack() {
|
|
210
|
-
const track = this.#track;
|
|
211
|
-
const stop = track.stop;
|
|
212
|
-
track.stop = () => {
|
|
213
|
-
this.#stopped = true;
|
|
214
|
-
this.clear();
|
|
215
|
-
this.#stopPump();
|
|
216
|
-
stop();
|
|
217
|
-
};
|
|
218
|
-
return track;
|
|
219
|
-
}
|
|
220
|
-
start() {
|
|
221
|
-
if (this.#started || this.#stopped)
|
|
222
|
-
return;
|
|
223
|
-
this.#started = true;
|
|
224
|
-
this.#startPump();
|
|
225
|
-
}
|
|
226
|
-
queuedMs() {
|
|
227
|
-
return this.#packets.length * WERIFT_PACKET_MS
|
|
228
|
-
+ (this.#pending.length / WERIFT_CHANNEL_COUNT / WERIFT_SAMPLE_RATE) * 1_000;
|
|
229
|
-
}
|
|
230
|
-
waitForDrain() {
|
|
231
|
-
this.#flushPending();
|
|
232
|
-
if (this.#drained())
|
|
233
|
-
return Promise.resolve();
|
|
234
|
-
return new Promise((resolve) => this.#drainWaiters.add(resolve));
|
|
235
|
-
}
|
|
236
|
-
clear() {
|
|
237
|
-
this.#packets.length = 0;
|
|
238
|
-
this.#pending = new Int16Array(0);
|
|
239
|
-
if (!this.#started)
|
|
240
|
-
this.#stopPump();
|
|
241
|
-
this.#notifyDrained();
|
|
242
|
-
}
|
|
243
|
-
onData(data) {
|
|
244
|
-
if (this.#stopped)
|
|
245
|
-
return;
|
|
246
|
-
const wire = toWireFormat(data);
|
|
247
|
-
const merged = new Int16Array(this.#pending.length + wire.length);
|
|
248
|
-
merged.set(this.#pending);
|
|
249
|
-
merged.set(wire, this.#pending.length);
|
|
250
|
-
let offset = 0;
|
|
251
|
-
while (merged.length - offset >= PACKET_SAMPLES) {
|
|
252
|
-
const frame = merged.subarray(offset, offset + PACKET_SAMPLES);
|
|
253
|
-
this.#packets.push(Buffer.from(this.#encoder.encode(frame)));
|
|
254
|
-
this.#opusPackets += 1;
|
|
255
|
-
offset += PACKET_SAMPLES;
|
|
256
|
-
}
|
|
257
|
-
this.#pending = merged.slice(offset);
|
|
258
|
-
this.#startPump();
|
|
259
|
-
}
|
|
260
|
-
/** Pad a sub-packet remainder with silence so the tail of a segment reaches the wire. */
|
|
261
|
-
#flushPending() {
|
|
262
|
-
if (this.#stopped || this.#pending.length === 0)
|
|
263
|
-
return;
|
|
264
|
-
const padded = new Int16Array(PACKET_SAMPLES);
|
|
265
|
-
padded.set(this.#pending);
|
|
266
|
-
this.#pending = new Int16Array(0);
|
|
267
|
-
this.#packets.push(Buffer.from(this.#encoder.encode(padded)));
|
|
268
|
-
this.#opusPackets += 1;
|
|
269
|
-
this.#startPump();
|
|
270
|
-
}
|
|
271
|
-
/** Application audio only: the silence the started pump keeps writing never counts. */
|
|
272
|
-
#drained() {
|
|
273
|
-
return this.#packets.length === 0
|
|
274
|
-
&& this.#pending.length === 0
|
|
275
|
-
&& (this.#started || this.#pump === undefined);
|
|
276
|
-
}
|
|
277
|
-
#notifyDrained() {
|
|
278
|
-
if (!this.#drained())
|
|
279
|
-
return;
|
|
280
|
-
for (const resolve of [...this.#drainWaiters]) {
|
|
281
|
-
this.#drainWaiters.delete(resolve);
|
|
282
|
-
resolve();
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* The first packet of a run leaves at once; after that each wake sends
|
|
287
|
-
* every packet the pacer says is due and sleeps until the next one is due,
|
|
288
|
-
* the absolute schedule of libwebrtc's `RepeatingTask`. Before `start()` the
|
|
289
|
-
* pump stops once the queue is empty; after it, the pump runs until the
|
|
290
|
-
* track stops.
|
|
291
|
-
*/
|
|
292
|
-
#startPump() {
|
|
293
|
-
if (this.#pump || this.#stopped)
|
|
294
|
-
return;
|
|
295
|
-
if (!this.#started && this.#packets.length === 0)
|
|
296
|
-
return;
|
|
297
|
-
this.#tick();
|
|
298
|
-
}
|
|
299
|
-
#tick() {
|
|
300
|
-
if (this.#stopped)
|
|
301
|
-
return;
|
|
302
|
-
const due = this.#pacer.take(performance.now());
|
|
303
|
-
for (let sent = 0; sent < due; sent += 1) {
|
|
304
|
-
if (!this.#sendNext())
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
if (this.#packets.length === 0) {
|
|
308
|
-
if (!this.#started) {
|
|
309
|
-
this.#stopPump();
|
|
310
|
-
this.#notifyDrained();
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
this.#notifyDrained();
|
|
314
|
-
}
|
|
315
|
-
const delay = Math.max(0, Math.ceil(this.#pacer.nextDueAt() - performance.now()));
|
|
316
|
-
this.#pump = setTimeout(() => this.#tick(), delay);
|
|
317
|
-
this.#pump.unref?.();
|
|
318
|
-
}
|
|
319
|
-
#stopPump() {
|
|
320
|
-
this.#pacer.reset();
|
|
321
|
-
if (!this.#pump)
|
|
322
|
-
return;
|
|
323
|
-
clearTimeout(this.#pump);
|
|
324
|
-
this.#pump = undefined;
|
|
325
|
-
}
|
|
326
|
-
/** Writes one packet, queued audio first, else silence once started; false when nothing was written. */
|
|
327
|
-
#sendNext() {
|
|
328
|
-
if (this.#stopped)
|
|
329
|
-
return false;
|
|
330
|
-
const application = this.#packets.shift();
|
|
331
|
-
if (!application && !this.#started)
|
|
332
|
-
return false;
|
|
333
|
-
const header = new RtpHeader({
|
|
334
|
-
payloadType: LOCAL_PAYLOAD_TYPE,
|
|
335
|
-
sequenceNumber: this.#sequenceNumber,
|
|
336
|
-
timestamp: this.#timestamp,
|
|
337
|
-
ssrc: 0,
|
|
338
|
-
marker: this.#first,
|
|
339
|
-
});
|
|
340
|
-
this.#first = false;
|
|
341
|
-
this.#sequenceNumber = (this.#sequenceNumber + 1) & 0xffff;
|
|
342
|
-
this.#timestamp = (this.#timestamp + PACKET_FRAMES) >>> 0;
|
|
343
|
-
this.#track.writeRtp(new RtpPacket(header, application ?? this.#silence));
|
|
344
|
-
if (application)
|
|
345
|
-
this.#applicationRtpPackets += 1;
|
|
346
|
-
else
|
|
347
|
-
this.#silencePackets += 1;
|
|
348
|
-
this.#rtp.mark();
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
/** Opus RTP in, PCM16 in the requested format (default 48 kHz stereo) out, one `ondata` per packet. */
|
|
353
|
-
class WeriftAudioSink {
|
|
354
|
-
ondata = null;
|
|
355
|
-
#decoder;
|
|
356
|
-
#rtp = new PacketClock();
|
|
357
|
-
#decodeFailures = 0;
|
|
358
|
-
#unsubscribe;
|
|
359
|
-
stats() {
|
|
360
|
-
return {
|
|
361
|
-
rtpPackets: this.#rtp.count,
|
|
362
|
-
decodeFailures: this.#decodeFailures,
|
|
363
|
-
firstRtpAt: this.#rtp.firstAt,
|
|
364
|
-
lastRtpAt: this.#rtp.lastAt,
|
|
365
|
-
recentRtpPackets: this.#rtp.recent(),
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
constructor(track, format = { sampleRate: WERIFT_SAMPLE_RATE, channelCount: WERIFT_CHANNEL_COUNT }) {
|
|
369
|
-
const { sampleRate, channelCount } = format;
|
|
370
|
-
this.#decoder = new Decoder({ channels: channelCount, sample_rate: sampleRate });
|
|
371
|
-
const { unSubscribe } = track.onReceiveRtp.subscribe((rtp) => {
|
|
372
|
-
this.#rtp.mark();
|
|
373
|
-
const handler = this.ondata;
|
|
374
|
-
if (!handler || !rtp.payload?.length)
|
|
375
|
-
return;
|
|
376
|
-
const packet = OpusRtpPayload.deSerialize(rtp.payload);
|
|
377
|
-
let bytes;
|
|
378
|
-
try {
|
|
379
|
-
bytes = this.#decoder.decode(packet.payload);
|
|
380
|
-
}
|
|
381
|
-
catch {
|
|
382
|
-
this.#decodeFailures += 1;
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
const samples = new Int16Array(bytes.byteLength >> 1);
|
|
386
|
-
new Uint8Array(samples.buffer).set(bytes.subarray(0, samples.byteLength));
|
|
387
|
-
handler({
|
|
388
|
-
samples,
|
|
389
|
-
sampleRate,
|
|
390
|
-
bitsPerSample: 16,
|
|
391
|
-
channelCount,
|
|
392
|
-
numberOfFrames: samples.length / channelCount,
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
this.#unsubscribe = unSubscribe;
|
|
396
|
-
}
|
|
397
|
-
stop() {
|
|
398
|
-
this.ondata = null;
|
|
399
|
-
this.#unsubscribe();
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Video codecs. werift matches a remote codec by MIME type alone
|
|
404
|
-
* (`findCodecByMimeType` in `TransceiverManager.setRemoteRTP`) and throws
|
|
405
|
-
* "negotiate codecs failed." for a media section with no local codec of its
|
|
406
|
-
* kind, so every codec a phone may publish is listed. H.264 and VP8 are the
|
|
407
|
-
* ones this engine encodes and decodes (engine-werift-video.ts): H.264 as
|
|
408
|
-
* constrained baseline `42e01f`, the only H.264 profile Cloudflare's SFU
|
|
409
|
-
* accepts, with packetization-mode 1; both ask for NACK, PLI and FIR, without
|
|
410
|
-
* which the SFU sends no keyframe request. VP9 and AV1 are receive-only: a
|
|
411
|
-
* pull offer carrying them is answered, the track is not decoded.
|
|
412
|
-
*/
|
|
413
|
-
const videoCodecs = () => {
|
|
414
|
-
const feedback = () => [useNACK(), usePLI(), useFIR()];
|
|
415
|
-
return [
|
|
416
|
-
new RTCRtpCodecParameters({
|
|
417
|
-
mimeType: "video/H264",
|
|
418
|
-
clockRate: 90_000,
|
|
419
|
-
rtcpFeedback: feedback(),
|
|
420
|
-
parameters: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",
|
|
421
|
-
}),
|
|
422
|
-
new RTCRtpCodecParameters({ mimeType: "video/VP8", clockRate: 90_000, rtcpFeedback: feedback() }),
|
|
423
|
-
new RTCRtpCodecParameters({ mimeType: "video/VP9", clockRate: 90_000, direction: "recvonly" }),
|
|
424
|
-
new RTCRtpCodecParameters({ mimeType: "video/AV1", clockRate: 90_000, direction: "recvonly" }),
|
|
425
|
-
];
|
|
426
|
-
};
|
|
427
|
-
/**
|
|
428
|
-
* The 3GPP coordination-of-video-orientation extension: with it negotiated a
|
|
429
|
-
* phone sends its camera frames unrotated and says how to turn them, and the
|
|
430
|
-
* receiver reports that as `VideoFrameEvent.rotation`, as LiveKit does.
|
|
431
|
-
*/
|
|
432
|
-
const VIDEO_ORIENTATION_URI = "urn:3gpp:video-orientation";
|
|
433
|
-
export const createWeriftPeerConnection = (config = { iceServers: [], iceTransportPolicy: "all" }) => new RTCPeerConnection({
|
|
434
|
-
bundlePolicy: "max-bundle",
|
|
435
|
-
iceServers: config.iceServers,
|
|
436
|
-
iceTransportPolicy: config.iceTransportPolicy,
|
|
437
|
-
codecs: {
|
|
438
|
-
audio: [
|
|
439
|
-
new RTCRtpCodecParameters({
|
|
440
|
-
mimeType: "audio/opus",
|
|
441
|
-
clockRate: WERIFT_SAMPLE_RATE,
|
|
442
|
-
channels: WERIFT_CHANNEL_COUNT,
|
|
443
|
-
}),
|
|
444
|
-
],
|
|
445
|
-
video: videoCodecs(),
|
|
446
|
-
},
|
|
447
|
-
headerExtensions: {
|
|
448
|
-
video: [new RTCRtpHeaderExtensionParameters({ id: 1, uri: VIDEO_ORIENTATION_URI })],
|
|
449
|
-
},
|
|
450
|
-
});
|
|
451
|
-
export const createWeriftWebRTCFactory = () => ({
|
|
452
|
-
createPeerConnection: (config) => createWeriftPeerConnection(config),
|
|
453
|
-
createAudioSource: () => new WeriftAudioSource(),
|
|
454
|
-
createAudioSink: (track, format) => new WeriftAudioSink(track, format),
|
|
455
|
-
...createWeriftVideoFactory(),
|
|
456
|
-
});
|
|
457
|
-
//# sourceMappingURL=engine-werift.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine-werift.js","sourceRoot":"","sources":["../src/engine-werift.ts"],"names":[],"mappings":"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"}
|