@relaymessenger/livekit 0.1.0-staging.11 → 0.1.0-staging.13
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 +54 -1
- 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.map +1 -1
- package/dist/engine-werift.js +36 -9
- 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 +32 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +152 -6
- 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 +7 -4
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
`@relaymessenger/livekit` connects Relay Calls to TypeScript LiveKit Agents.
|
|
4
4
|
Relay stays responsible for the Call resource and signaling; the package owns
|
|
5
5
|
the Node WebRTC peer and translates audio between Relay and LiveKit `AudioFrame`
|
|
6
|
-
objects. Application code does not handle Cloudflare, SDP, ICE, or SFU
|
|
6
|
+
objects, and sends and receives video with LiveKit's video API. Application code does not handle Cloudflare, SDP, ICE, or SFU
|
|
7
7
|
credentials.
|
|
8
8
|
|
|
9
9
|
Install it next to the Relay SDK and the LiveKit Agents runtime:
|
|
@@ -87,6 +87,59 @@ await transport.writeAudio({
|
|
|
87
87
|
await transport.waitForPlayout();
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
+
## Video
|
|
91
|
+
|
|
92
|
+
Relay calls carry video whenever a camera is on. The video API copies
|
|
93
|
+
LiveKit's `@livekit/rtc-node` names: `VideoSource`, `LocalVideoTrack`,
|
|
94
|
+
`VideoFrame`, `VideoBufferType`, `VideoStream`. Video needs the default
|
|
95
|
+
`"werift"` engine and the optional dependency `node-webcodecs` (prebuilt for
|
|
96
|
+
macOS arm64 and Linux x64/arm64).
|
|
97
|
+
|
|
98
|
+
Send a video feed:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import {
|
|
102
|
+
LocalVideoTrack,
|
|
103
|
+
VideoBufferType,
|
|
104
|
+
VideoFrame,
|
|
105
|
+
VideoSource,
|
|
106
|
+
} from "@relaymessenger/livekit/transport";
|
|
107
|
+
|
|
108
|
+
await transport.connect();
|
|
109
|
+
|
|
110
|
+
const source = new VideoSource(640, 480);
|
|
111
|
+
const track = LocalVideoTrack.createVideoTrack("camera", source);
|
|
112
|
+
await transport.publishTrack(track, {
|
|
113
|
+
videoEncoding: { maxBitrate: 800_000, maxFramerate: 15 },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// RGBA, BGRA or I420 bytes, tightly packed.
|
|
117
|
+
source.captureFrame(new VideoFrame(rgba, 640, 480, VideoBufferType.RGBA));
|
|
118
|
+
|
|
119
|
+
// Camera off, then on again; the track stays negotiated.
|
|
120
|
+
await transport.unpublishTrack(track);
|
|
121
|
+
await transport.publishTrack(track);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Receive the other participant's video:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { VideoBufferType, VideoStream } from "@relaymessenger/livekit/transport";
|
|
128
|
+
|
|
129
|
+
transport.on("trackSubscribed", async (track) => {
|
|
130
|
+
const stream = new VideoStream(track, { format: VideoBufferType.RGBA, capacity: 2 });
|
|
131
|
+
for await (const { frame, timestampUs } of stream) {
|
|
132
|
+
// frame.data is width x height x 4 bytes of RGBA.
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
transport.on("remoteVideo", (on) => {
|
|
136
|
+
// The other participant's camera started or stopped sending.
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Frames are decoded only while a `VideoStream` is open. `transport.videoStats()`
|
|
141
|
+
reports frames, packets, keyframes and decode errors in both directions.
|
|
142
|
+
|
|
90
143
|
## ICE servers, TURN, and diagnostics
|
|
91
144
|
|
|
92
145
|
By default the peer uses Cloudflare's STUN server
|
|
@@ -0,0 +1,70 @@
|
|
|
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, type RTCRtpTransceiver } from "werift";
|
|
27
|
+
import type { RelayMediaStreamTrackLike } from "./transport.js";
|
|
28
|
+
import { type RelayVideoFactory, type RelayVideoReceiverLike, type RelayVideoReceiverStats, type RelayVideoSenderLike, type RelayVideoSenderStats, type TrackPublishOptions } from "./video.js";
|
|
29
|
+
import { VideoFrame, VideoRotation } from "./video-frame.js";
|
|
30
|
+
type WebCodecs = typeof import("node-webcodecs");
|
|
31
|
+
export declare const KEYFRAME_INTERVAL_MS = 1000;
|
|
32
|
+
export declare const KEYFRAME_REQUEST_INTERVAL_MS = 1000;
|
|
33
|
+
export declare const DEFAULT_VIDEO_BITRATE = 800000;
|
|
34
|
+
export declare const DEFAULT_VIDEO_FRAMERATE = 30;
|
|
35
|
+
/** Loads node-webcodecs once, on first video use, so audio-only calls never load FFmpeg. */
|
|
36
|
+
export declare const loadWebCodecs: () => Promise<WebCodecs>;
|
|
37
|
+
/**
|
|
38
|
+
* Raw frames in, H.264 or VP8 RTP out on one werift track. One sender lives
|
|
39
|
+
* for the whole call; a restart binds it to the new peer's transceiver.
|
|
40
|
+
*/
|
|
41
|
+
export declare class WeriftVideoSender implements RelayVideoSenderLike {
|
|
42
|
+
#private;
|
|
43
|
+
readonly track: RelayMediaStreamTrackLike;
|
|
44
|
+
constructor(wc: WebCodecs, options?: TrackPublishOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Offer the codecs this sender can encode, the preferred one first (werift
|
|
47
|
+
* fills an empty `transceiver.codecs` from the peer's config at
|
|
48
|
+
* `createOffer`, peerConnection.js:520-523, so setting it here wins).
|
|
49
|
+
*/
|
|
50
|
+
bind(transceiver: unknown, peer: unknown): void;
|
|
51
|
+
setEnabled(enabled: boolean): void;
|
|
52
|
+
capture(frame: VideoFrame, timestampUs: bigint, rotation: VideoRotation): void;
|
|
53
|
+
stats(): RelayVideoSenderStats;
|
|
54
|
+
close(): void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* One pulled video m-line: RTP in, decoded I420 frames out. RTP is counted
|
|
58
|
+
* always; it is reordered, assembled and decoded only while active.
|
|
59
|
+
*/
|
|
60
|
+
export declare class WeriftVideoReceiver implements RelayVideoReceiverLike {
|
|
61
|
+
#private;
|
|
62
|
+
onframe: RelayVideoReceiverLike["onframe"];
|
|
63
|
+
constructor(track: MediaStreamTrack, transceiver: RTCRtpTransceiver | undefined);
|
|
64
|
+
setActive(active: boolean): void;
|
|
65
|
+
stats(): RelayVideoReceiverStats;
|
|
66
|
+
stop(): void;
|
|
67
|
+
}
|
|
68
|
+
export declare const createWeriftVideoFactory: () => RelayVideoFactory;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=engine-werift-video.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-werift-video.d.ts","sourceRoot":"","sources":["../src/engine-werift-video.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EACL,gBAAgB,EAEhB,KAAK,iBAAiB,EAGvB,MAAM,QAAQ,CAAC;AAEhB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAmB,UAAU,EAAE,aAAa,EAAoB,MAAM,kBAAkB,CAAC;AAWhG,KAAK,SAAS,GAAG,cAAc,gBAAgB,CAAC,CAAC;AAMjD,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAC1C,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AAClD,eAAO,MAAM,qBAAqB,SAAU,CAAC;AAC7C,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAU1C,4FAA4F;AAC5F,eAAO,MAAM,aAAa,QAAO,OAAO,CAAC,SAAS,CAgBjD,CAAC;AA0CF;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,oBAAoB;;IAC5D,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;gBA8B9B,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,mBAAwB;IAS5D;;;;OAIG;IACH,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAqB/C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKlC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAqD9E,KAAK,IAAI,qBAAqB;IAmB9B,KAAK,IAAI,IAAI;CAwEd;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,sBAAsB;;IAChE,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAQ;gBA+BtC,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,GAAG,SAAS;IAW/E,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAehC,KAAK,IAAI,uBAAuB;IAiBhC,IAAI,IAAI,IAAI;CA8Kb;AAED,eAAO,MAAM,wBAAwB,QAAO,iBAI1C,CAAC"}
|