@relaymessenger/livekit 0.1.0-staging.11 → 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/dist/video.js ADDED
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Video tracks for Relay calls, with LiveKit's public API shape.
3
+ *
4
+ * Names and semantics copied from `@livekit/rtc-node` 0.13.35
5
+ * (node_modules/@livekit/rtc-node/src):
6
+ * - video_source.ts:18-75: `new VideoSource(width, height)`,
7
+ * `captureFrame(frame, timestampUs = BigInt(0), rotation = VIDEO_ROTATION_0)`
8
+ * which throws "VideoSource is closed" after `close()`.
9
+ * - track.ts:241-268: `LocalVideoTrack.createVideoTrack(name, source)` and
10
+ * `close(closeSource = true)`.
11
+ * - video_stream.ts:12-16 and :94-98: `VideoFrameEvent { frame, timestampUs,
12
+ * rotation }` and `class VideoStream extends ReadableStream<VideoFrameEvent>`
13
+ * built from a remote track, read with `for await`.
14
+ * - participant.ts:737 `publishTrack(track, options)` and :783
15
+ * `unpublishTrack(...)`; the publish options `videoCodec` and
16
+ * `videoEncoding { maxBitrate, maxFramerate }` from
17
+ * @livekit/rtc-ffi-bindings proto/room_pb.d.ts:1792-1859, and `VideoCodec`
18
+ * (VP8 = 0, H264 = 1) from proto/video_frame_pb.d.ts:28-50.
19
+ * The optional `{ capacity, format }` of `VideoStream` is LiveKit's Python SDK
20
+ * (livekit-rtc/livekit/rtc/video_stream.py:42-60, `RingQueue` in _utils.py:78-94:
21
+ * capacity 0 keeps every frame, a positive capacity drops the oldest).
22
+ *
23
+ * Relay semantics (PROTOCOL.md sections 1-2, _artifacts/calls-facetime-20260922):
24
+ * a participant publishes at most one `video` track; publishing it the first
25
+ * time negotiates it with an add-track offer and announces `userUpdate
26
+ * { video: true }`; unpublishing stops sending and announces `video: false`
27
+ * but leaves the track negotiated, so publishing again only resumes.
28
+ */
29
+ import { ReadableStream } from "node:stream/web";
30
+ import { VideoBufferType, VideoFrame, VideoRotation } from "./video-frame.js";
31
+ export { VideoBufferType, VideoFrame, VideoRotation } from "./video-frame.js";
32
+ /** Same names and numbers as LiveKit's `VideoCodec`; Relay sends these two. */
33
+ export var VideoCodec;
34
+ (function (VideoCodec) {
35
+ VideoCodec[VideoCodec["VP8"] = 0] = "VP8";
36
+ VideoCodec[VideoCodec["H264"] = 1] = "H264";
37
+ })(VideoCodec || (VideoCodec = {}));
38
+ export class VideoSource {
39
+ width;
40
+ height;
41
+ /** @internal */
42
+ closed = false;
43
+ #sinks = new Set();
44
+ constructor(width, height) {
45
+ this.width = width;
46
+ this.height = height;
47
+ }
48
+ /**
49
+ * Hand one raw frame to the published track. RGBA, BGRA and I420 (LiveKit
50
+ * `VideoBufferType`) go to the encoder as they are; the other packed RGB
51
+ * layouts are converted to I420 first. `timestampUs` 0 means "now".
52
+ * Frames captured while the track is not published are dropped.
53
+ */
54
+ captureFrame(frame, timestampUs = BigInt(0), rotation = VideoRotation.VIDEO_ROTATION_0) {
55
+ if (this.closed)
56
+ throw new Error("VideoSource is closed");
57
+ for (const sink of this.#sinks)
58
+ sink(frame, timestampUs, rotation);
59
+ }
60
+ async close() {
61
+ this.closed = true;
62
+ this.#sinks.clear();
63
+ }
64
+ /** @internal */
65
+ _attach(sink) {
66
+ this.#sinks.add(sink);
67
+ return () => this.#sinks.delete(sink);
68
+ }
69
+ }
70
+ export class LocalVideoTrack {
71
+ kind = "video";
72
+ name;
73
+ /** @internal */
74
+ source;
75
+ constructor(name, source) {
76
+ this.name = name;
77
+ this.source = source;
78
+ }
79
+ static createVideoTrack(name, source) {
80
+ return new LocalVideoTrack(name, source);
81
+ }
82
+ async close(closeSource = true) {
83
+ if (closeSource)
84
+ await this.source.close();
85
+ }
86
+ }
87
+ /**
88
+ * The other participant's camera. Emitted once per call by the transport's
89
+ * `trackSubscribed` event; it survives SFU restarts (the transport moves it
90
+ * onto the new session's receiver), so a `VideoStream` read from it keeps going.
91
+ */
92
+ export class RemoteVideoTrack {
93
+ kind = "video";
94
+ name = "video";
95
+ #receiver;
96
+ #retired;
97
+ #consumers = new Set();
98
+ #ended = false;
99
+ /** Counters summed over every receiver this track has had. */
100
+ stats() {
101
+ const current = this.#receiver?.stats();
102
+ const retired = this.#retired;
103
+ if (!retired)
104
+ return current;
105
+ if (!current)
106
+ return { ...retired, recentFrames: 0 };
107
+ return {
108
+ ...current,
109
+ rtpPackets: retired.rtpPackets + current.rtpPackets,
110
+ framesAssembled: retired.framesAssembled + current.framesAssembled,
111
+ framesDropped: retired.framesDropped + current.framesDropped,
112
+ framesDecoded: retired.framesDecoded + current.framesDecoded,
113
+ decodeErrors: retired.decodeErrors + current.decodeErrors,
114
+ keyframeRequests: retired.keyframeRequests + current.keyframeRequests,
115
+ firstFrameAt: retired.firstFrameAt ?? current.firstFrameAt,
116
+ lastFrameAt: current.lastFrameAt ?? retired.lastFrameAt,
117
+ };
118
+ }
119
+ /** @internal The transport moves the track onto a new session's receiver. */
120
+ _attach(receiver) {
121
+ this._detach();
122
+ this.#receiver = receiver;
123
+ receiver.onframe = (event) => {
124
+ for (const consumer of this.#consumers)
125
+ consumer.push(event);
126
+ };
127
+ receiver.setActive(this.#consumers.size > 0);
128
+ }
129
+ /** @internal */
130
+ _detach() {
131
+ const receiver = this.#receiver;
132
+ if (!receiver)
133
+ return;
134
+ this.#receiver = undefined;
135
+ const stats = receiver.stats();
136
+ const retired = this.#retired;
137
+ this.#retired = retired
138
+ ? {
139
+ ...stats,
140
+ rtpPackets: retired.rtpPackets + stats.rtpPackets,
141
+ framesAssembled: retired.framesAssembled + stats.framesAssembled,
142
+ framesDropped: retired.framesDropped + stats.framesDropped,
143
+ framesDecoded: retired.framesDecoded + stats.framesDecoded,
144
+ decodeErrors: retired.decodeErrors + stats.decodeErrors,
145
+ keyframeRequests: retired.keyframeRequests + stats.keyframeRequests,
146
+ firstFrameAt: retired.firstFrameAt ?? stats.firstFrameAt,
147
+ lastFrameAt: stats.lastFrameAt ?? retired.lastFrameAt,
148
+ }
149
+ : stats;
150
+ receiver.onframe = null;
151
+ receiver.stop();
152
+ }
153
+ /** @internal The call is over: every `VideoStream` ends. */
154
+ _end() {
155
+ this._detach();
156
+ this.#ended = true;
157
+ for (const consumer of [...this.#consumers])
158
+ consumer.end();
159
+ this.#consumers.clear();
160
+ }
161
+ /** @internal */
162
+ _subscribe(consumer) {
163
+ if (this.#ended) {
164
+ consumer.end();
165
+ return () => undefined;
166
+ }
167
+ this.#consumers.add(consumer);
168
+ if (this.#consumers.size === 1)
169
+ this.#receiver?.setActive(true);
170
+ return () => {
171
+ this.#consumers.delete(consumer);
172
+ if (this.#consumers.size === 0)
173
+ this.#receiver?.setActive(false);
174
+ };
175
+ }
176
+ }
177
+ /**
178
+ * Decoded frames of a remote video track. Decoding starts when the first
179
+ * stream opens and stops when the last one is cancelled.
180
+ */
181
+ export class VideoStream extends ReadableStream {
182
+ constructor(track, options = {}) {
183
+ const capacity = options.capacity ?? 0;
184
+ const format = options.format;
185
+ const queue = [];
186
+ let waiting;
187
+ let ended = false;
188
+ let unsubscribe;
189
+ const wake = () => {
190
+ const resolve = waiting;
191
+ waiting = undefined;
192
+ resolve?.();
193
+ };
194
+ super({
195
+ start: () => {
196
+ unsubscribe = track._subscribe({
197
+ push: (event) => {
198
+ if (capacity > 0 && queue.length >= capacity)
199
+ queue.shift();
200
+ queue.push(event);
201
+ wake();
202
+ },
203
+ end: () => {
204
+ ended = true;
205
+ wake();
206
+ },
207
+ });
208
+ },
209
+ pull: async (controller) => {
210
+ while (queue.length === 0 && !ended)
211
+ await new Promise((resolve) => { waiting = resolve; });
212
+ const event = queue.shift();
213
+ if (!event) {
214
+ controller.close();
215
+ return;
216
+ }
217
+ const frame = format === undefined || format === event.frame.type ? event.frame : event.frame.convert(format);
218
+ controller.enqueue({ ...event, frame });
219
+ },
220
+ cancel: () => {
221
+ unsubscribe?.();
222
+ ended = true;
223
+ wake();
224
+ },
225
+ }, { highWaterMark: 0 });
226
+ }
227
+ }
228
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../src/video.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@relaymessenger/livekit",
3
- "version": "0.1.0-staging.11",
4
- "description": "Relay WebRTC audio transport and LiveKit Agents integration for Node.js.",
3
+ "version": "0.1.0-staging.12",
4
+ "description": "Relay WebRTC audio and video transport and LiveKit Agents integration for Node.js.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/index.js",
@@ -39,10 +39,12 @@
39
39
  "dependencies": {
40
40
  "@evan/opus": "1.0.3",
41
41
  "@relaymessenger/sdk": "0.3.6-staging.19",
42
+ "rtp-packet": "0.4.2",
42
43
  "werift": "0.24.4"
43
44
  },
44
45
  "optionalDependencies": {
45
- "@roamhq/wrtc": "^0.10.0"
46
+ "@roamhq/wrtc": "^0.10.0",
47
+ "node-webcodecs": "1.3.0"
46
48
  },
47
49
  "peerDependencies": {
48
50
  "@livekit/agents": "^1.9.0",
@@ -72,6 +74,7 @@
72
74
  "livekit",
73
75
  "webrtc",
74
76
  "voice",
77
+ "video",
75
78
  "agents"
76
79
  ]
77
80
  }