@relaymessenger/livekit 0.1.0-staging.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Companion Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # `@relaymessenger/livekit`
2
+
3
+ `@relaymessenger/livekit` connects Relay Calls to TypeScript LiveKit Agents.
4
+ Relay stays responsible for the Call resource and signaling; the package owns
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
7
+ credentials.
8
+
9
+ Install it next to the Relay SDK and the LiveKit Agents runtime:
10
+
11
+ ```sh
12
+ npm install @relaymessenger/sdk @relaymessenger/livekit \
13
+ @livekit/agents @livekit/rtc-node
14
+ ```
15
+
16
+ ## Answer a Relay Call
17
+
18
+ Agents receive `call.created` through the normal Relay Webhook or acknowledged
19
+ Agent WebSocket. Joining that Call's authenticated room answers it; there is no
20
+ agent call URL or separate accept endpoint.
21
+
22
+ ```ts
23
+ import { AgentSession } from "@livekit/agents";
24
+ import Relay from "@relaymessenger/sdk";
25
+ import { RelayLiveKitCall } from "@relaymessenger/livekit";
26
+
27
+ const relay = new Relay({ apiKey: process.env.RELAY_AGENT_TOKEN! });
28
+
29
+ async function answerCall(callId: string, session: AgentSession) {
30
+ const call = await RelayLiveKitCall.connect({ relay, callId });
31
+ call.attach(session);
32
+
33
+ call.transport.on("ended", () => {
34
+ void call.close();
35
+ });
36
+
37
+ return call;
38
+ }
39
+ ```
40
+
41
+ `RelayLiveKitCall.connect()` does not resolve until the WebRTC media peer has
42
+ reached `connected`. `RelayAudioInput` converts the remote participant's PCM16
43
+ audio to LiveKit frames. `RelayAudioOutput` publishes LiveKit TTS frames to
44
+ Relay, pacing larger frames into 10 ms WebRTC source slices. `clearBuffer()`
45
+ drops queued outbound audio that has not yet reached WebRTC.
46
+
47
+ Use `setMuted(true)` to publish participant mute state, `end()` to end the Relay
48
+ Call, and `close()` for local cleanup. If the signaling connection is replaced,
49
+ `call.transport.reconnect()` keeps the existing media peer and replays the same
50
+ audio publication so Relay can return its cached answer.
51
+
52
+ ## Provider-neutral transport
53
+
54
+ The WebRTC/PCM layer is a separate public entry point for future adapters that
55
+ do not use LiveKit Agents:
56
+
57
+ ```ts
58
+ import { RelayCallTransport } from "@relaymessenger/livekit/transport";
59
+
60
+ const room = relay.calls.room(callId);
61
+ const transport = new RelayCallTransport({ room });
62
+
63
+ transport.on("audio", ({ samples, sampleRate, channelCount }) => {
64
+ // Interleaved signed PCM16 from the remote Relay participant.
65
+ });
66
+
67
+ await transport.connect();
68
+ await transport.writeAudio({
69
+ samples,
70
+ sampleRate: 48_000,
71
+ channelCount: 1,
72
+ });
73
+ ```
74
+
75
+ `RelayCallTransport` consumes the SDK's `CallRoom`; it does not duplicate the
76
+ room protocol. The default engine is `werift` (pure TypeScript WebRTC) with
77
+ `@evan/opus` (prebuilt Opus, WASM fallback), so no native WebRTC binding is
78
+ loaded. Pass `engine: "wrtc"` to use the optional `@roamhq/wrtc` binding
79
+ instead. The transport boundary remains provider-neutral for additional adapters. `@livekit/agents`
80
+ and `@livekit/rtc-node` are peer dependencies so the host agent process owns
81
+ those runtimes.
@@ -0,0 +1,17 @@
1
+ import { RTCPeerConnection } from "werift";
2
+ import type { RelayAudioSourceLike, RelayWebRTCFactory } from "./transport.js";
3
+ /** Opus on the wire is always 48 kHz; Relay sends stereo so callers may pass either channel count. */
4
+ export declare const WERIFT_SAMPLE_RATE = 48000;
5
+ export declare const WERIFT_CHANNEL_COUNT = 2;
6
+ /** One RTP packet carries 20 ms: 960 frames at 48 kHz, timestamp advances by 960. */
7
+ export declare const WERIFT_PACKET_MS = 20;
8
+ export type WeriftAudioSourceData = Parameters<RelayAudioSourceLike["onData"]>[0];
9
+ /** Convert any PCM16 frame to interleaved 48 kHz stereo by linear interpolation. */
10
+ export declare const toWireFormat: (data: {
11
+ samples: Int16Array;
12
+ sampleRate: number;
13
+ channelCount: number;
14
+ }) => Int16Array;
15
+ export declare const createWeriftPeerConnection: () => RTCPeerConnection;
16
+ export declare const createWeriftWebRTCFactory: () => RelayWebRTCFactory;
17
+ //# sourceMappingURL=engine-werift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-werift.d.ts","sourceRoot":"","sources":["../src/engine-werift.ts"],"names":[],"mappings":"AA0BA,OAAO,EAGL,iBAAiB,EAIlB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAEV,oBAAoB,EAGpB,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,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;AAyHF,eAAO,MAAM,0BAA0B,QAAO,iBAa1C,CAAC;AAEL,eAAO,MAAM,yBAAyB,QAAO,kBAI3C,CAAC"}
@@ -0,0 +1,199 @@
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
+ * - media/track.d.ts: `MediaStreamTrack({ kind })`, `writeRtp(RtpPacket)`,
12
+ * `onReceiveRtp: Event<[RtpPacket, Extensions?]>` with `subscribe()`.
13
+ * - media/rtpSender.js:544-549: the sender rewrites ssrc and payloadType and
14
+ * offsets sequenceNumber/timestamp, so the local track starts both at 0.
15
+ * - ../../rtp/src/codec/opus.d.ts: `OpusRtpPayload.deSerialize(buffer)`.
16
+ * - node_modules/@evan/opus/lib.d.ts: `Encoder.encode(pcm16)` returns one Opus
17
+ * packet; `Decoder.decode(packet)` returns interleaved PCM16 bytes.
18
+ * Participant shapes copied from the headless phone that joined Relay's room
19
+ * through Cloudflare's SFU on 2026-09-21 (_runtime/bin/headless-phone-webrtc.mjs
20
+ * lines 93-160): `bundlePolicy: "max-bundle", iceServers: []` (Cloudflare
21
+ * supplies its ICE candidates in the answer), the local track is id
22
+ * "microphone" in stream "relay-call" (Relay-iOS RelayWebRTCAudioTransport),
23
+ * the first RTP packet carries the marker bit, empty payloads are skipped and a
24
+ * decode failure never tears the sink down.
25
+ */
26
+ import { Decoder, Encoder } from "@evan/opus";
27
+ import { MediaStreamTrack, OpusRtpPayload, RTCPeerConnection, RTCRtpCodecParameters, RtpHeader, RtpPacket, } from "werift";
28
+ /** Opus on the wire is always 48 kHz; Relay sends stereo so callers may pass either channel count. */
29
+ export const WERIFT_SAMPLE_RATE = 48_000;
30
+ export const WERIFT_CHANNEL_COUNT = 2;
31
+ /** One RTP packet carries 20 ms: 960 frames at 48 kHz, timestamp advances by 960. */
32
+ export const WERIFT_PACKET_MS = 20;
33
+ const PACKET_FRAMES = (WERIFT_SAMPLE_RATE * WERIFT_PACKET_MS) / 1000;
34
+ const PACKET_SAMPLES = PACKET_FRAMES * WERIFT_CHANNEL_COUNT;
35
+ /** Dynamic payload type; werift's sender replaces it with the negotiated one. */
36
+ const LOCAL_PAYLOAD_TYPE = 111;
37
+ /** Convert any PCM16 frame to interleaved 48 kHz stereo by linear interpolation. */
38
+ export const toWireFormat = (data) => {
39
+ const { samples, sampleRate, channelCount } = data;
40
+ const inputFrames = Math.floor(samples.length / channelCount);
41
+ if (sampleRate === WERIFT_SAMPLE_RATE && channelCount === WERIFT_CHANNEL_COUNT) {
42
+ return samples;
43
+ }
44
+ const outputFrames = Math.round((inputFrames * WERIFT_SAMPLE_RATE) / sampleRate);
45
+ const out = new Int16Array(outputFrames * WERIFT_CHANNEL_COUNT);
46
+ const ratio = sampleRate / WERIFT_SAMPLE_RATE;
47
+ const leftIndex = 0;
48
+ const rightIndex = channelCount > 1 ? 1 : 0;
49
+ for (let frame = 0; frame < outputFrames; frame += 1) {
50
+ const position = frame * ratio;
51
+ const base = Math.min(Math.floor(position), inputFrames - 1);
52
+ const next = Math.min(base + 1, inputFrames - 1);
53
+ const fraction = position - Math.floor(position);
54
+ const left = samples[base * channelCount + leftIndex] * (1 - fraction)
55
+ + samples[next * channelCount + leftIndex] * fraction;
56
+ const right = samples[base * channelCount + rightIndex] * (1 - fraction)
57
+ + samples[next * channelCount + rightIndex] * fraction;
58
+ out[frame * 2] = Math.round(left);
59
+ out[frame * 2 + 1] = Math.round(right);
60
+ }
61
+ return out;
62
+ };
63
+ /**
64
+ * PCM16 in, paced 20 ms Opus RTP out. Frames are accumulated into whole
65
+ * packets; a timer drains one packet every 20 ms so the wire sees a steady
66
+ * cadence regardless of how the adapter chunks its writes.
67
+ */
68
+ class WeriftAudioSource {
69
+ #encoder = new Encoder({
70
+ channels: WERIFT_CHANNEL_COUNT,
71
+ sample_rate: WERIFT_SAMPLE_RATE,
72
+ application: "voip",
73
+ });
74
+ #track = new MediaStreamTrack({ kind: "audio", id: "microphone", streamId: "relay-call" });
75
+ #packets = [];
76
+ #pending = new Int16Array(0);
77
+ #sequenceNumber = 1;
78
+ #timestamp = 0;
79
+ #first = true;
80
+ #pump;
81
+ #stopped = false;
82
+ createTrack() {
83
+ const track = this.#track;
84
+ const stop = track.stop;
85
+ track.stop = () => {
86
+ this.#stopped = true;
87
+ this.#packets.length = 0;
88
+ this.#pending = new Int16Array(0);
89
+ this.#stopPump();
90
+ stop();
91
+ };
92
+ return track;
93
+ }
94
+ onData(data) {
95
+ if (this.#stopped)
96
+ return;
97
+ const wire = toWireFormat(data);
98
+ const merged = new Int16Array(this.#pending.length + wire.length);
99
+ merged.set(this.#pending);
100
+ merged.set(wire, this.#pending.length);
101
+ let offset = 0;
102
+ while (merged.length - offset >= PACKET_SAMPLES) {
103
+ const frame = merged.subarray(offset, offset + PACKET_SAMPLES);
104
+ this.#packets.push(Buffer.from(this.#encoder.encode(frame)));
105
+ offset += PACKET_SAMPLES;
106
+ }
107
+ this.#pending = merged.slice(offset);
108
+ this.#startPump();
109
+ }
110
+ #startPump() {
111
+ if (this.#pump || this.#packets.length === 0)
112
+ return;
113
+ this.#sendNext();
114
+ if (this.#packets.length === 0)
115
+ return;
116
+ this.#pump = setInterval(() => {
117
+ this.#sendNext();
118
+ if (this.#packets.length === 0)
119
+ this.#stopPump();
120
+ }, WERIFT_PACKET_MS);
121
+ this.#pump.unref?.();
122
+ }
123
+ #stopPump() {
124
+ if (!this.#pump)
125
+ return;
126
+ clearInterval(this.#pump);
127
+ this.#pump = undefined;
128
+ }
129
+ #sendNext() {
130
+ const payload = this.#packets.shift();
131
+ if (!payload || this.#stopped)
132
+ return;
133
+ const header = new RtpHeader({
134
+ payloadType: LOCAL_PAYLOAD_TYPE,
135
+ sequenceNumber: this.#sequenceNumber,
136
+ timestamp: this.#timestamp,
137
+ ssrc: 0,
138
+ marker: this.#first,
139
+ });
140
+ this.#first = false;
141
+ this.#sequenceNumber = (this.#sequenceNumber + 1) & 0xffff;
142
+ this.#timestamp = (this.#timestamp + PACKET_FRAMES) >>> 0;
143
+ this.#track.writeRtp(new RtpPacket(header, payload));
144
+ }
145
+ }
146
+ /** Opus RTP in, PCM16 (48 kHz stereo) out, one `ondata` per packet. */
147
+ class WeriftAudioSink {
148
+ ondata = null;
149
+ #decoder = new Decoder({ channels: WERIFT_CHANNEL_COUNT, sample_rate: WERIFT_SAMPLE_RATE });
150
+ #unsubscribe;
151
+ constructor(track) {
152
+ const { unSubscribe } = track.onReceiveRtp.subscribe((rtp) => {
153
+ const handler = this.ondata;
154
+ if (!handler || !rtp.payload?.length)
155
+ return;
156
+ const packet = OpusRtpPayload.deSerialize(rtp.payload);
157
+ let bytes;
158
+ try {
159
+ bytes = this.#decoder.decode(packet.payload);
160
+ }
161
+ catch {
162
+ return;
163
+ }
164
+ const samples = new Int16Array(bytes.byteLength >> 1);
165
+ new Uint8Array(samples.buffer).set(bytes.subarray(0, samples.byteLength));
166
+ handler({
167
+ samples,
168
+ sampleRate: WERIFT_SAMPLE_RATE,
169
+ bitsPerSample: 16,
170
+ channelCount: WERIFT_CHANNEL_COUNT,
171
+ numberOfFrames: samples.length / WERIFT_CHANNEL_COUNT,
172
+ });
173
+ });
174
+ this.#unsubscribe = unSubscribe;
175
+ }
176
+ stop() {
177
+ this.ondata = null;
178
+ this.#unsubscribe();
179
+ }
180
+ }
181
+ export const createWeriftPeerConnection = () => new RTCPeerConnection({
182
+ bundlePolicy: "max-bundle",
183
+ iceServers: [],
184
+ codecs: {
185
+ audio: [
186
+ new RTCRtpCodecParameters({
187
+ mimeType: "audio/opus",
188
+ clockRate: WERIFT_SAMPLE_RATE,
189
+ channels: WERIFT_CHANNEL_COUNT,
190
+ }),
191
+ ],
192
+ },
193
+ });
194
+ export const createWeriftWebRTCFactory = () => ({
195
+ createPeerConnection: () => createWeriftPeerConnection(),
196
+ createAudioSource: () => new WeriftAudioSource(),
197
+ createAudioSink: (track) => new WeriftAudioSink(track),
198
+ });
199
+ //# sourceMappingURL=engine-werift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-werift.js","sourceRoot":"","sources":["../src/engine-werift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { RelayAudioInput, RelayAudioOutput, RelayLiveKitCall, createRelayLiveKitAudio, type RelayLiveKitAudio, type RelayLiveKitAudioOptions, type RelayLiveKitConnectOptions, } from "./livekit.js";
2
+ export { RelayCallTransport, RelayCallTransportError, type RelayAudioFrame, type RelayCallEngine, type RelayCallTransportCloseEvent, type RelayCallTransportOptions, } from "./transport.js";
3
+ export { createWeriftWebRTCFactory } from "./engine-werift.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,GAChC,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,GAC/B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { RelayAudioInput, RelayAudioOutput, RelayLiveKitCall, createRelayLiveKitAudio, } from "./livekit.js";
2
+ export { RelayCallTransport, RelayCallTransportError, } from "./transport.js";
3
+ export { createWeriftWebRTCFactory } from "./engine-werift.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,GAIxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,GAKxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { AudioInput, AudioOutput, type AgentSession } from "@livekit/agents";
2
+ import { AudioFrame } from "@livekit/rtc-node";
3
+ import type Relay from "@relaymessenger/sdk";
4
+ import type { CallRoomOptions } from "@relaymessenger/sdk";
5
+ import { RelayCallTransport } from "./transport.js";
6
+ /** LiveKit Agents input backed by the remote Relay participant's WebRTC audio. */
7
+ export declare class RelayAudioInput extends AudioInput {
8
+ #private;
9
+ constructor(transport: RelayCallTransport);
10
+ setAttached(attached: boolean): void;
11
+ close(): Promise<void>;
12
+ }
13
+ /** LiveKit Agents output that publishes TTS PCM to the Relay participant. */
14
+ export declare class RelayAudioOutput extends AudioOutput {
15
+ #private;
16
+ constructor(transport: RelayCallTransport, sampleRate?: number);
17
+ captureFrame(frame: AudioFrame): Promise<void>;
18
+ flush(): void;
19
+ clearBuffer(): void;
20
+ close(): void;
21
+ }
22
+ export interface RelayLiveKitAudio {
23
+ input: RelayAudioInput;
24
+ output: RelayAudioOutput;
25
+ }
26
+ export interface RelayLiveKitAudioOptions {
27
+ outputSampleRate?: number;
28
+ }
29
+ /** Build LiveKit Agents audio IO around an already-connected Relay transport. */
30
+ export declare const createRelayLiveKitAudio: (transport: RelayCallTransport, options?: RelayLiveKitAudioOptions) => RelayLiveKitAudio;
31
+ export interface RelayLiveKitConnectOptions extends RelayLiveKitAudioOptions {
32
+ relay: Relay;
33
+ callId: string;
34
+ room?: CallRoomOptions;
35
+ connectionTimeoutMs?: number;
36
+ }
37
+ type AgentSessionAudioTarget = Pick<AgentSession, "input" | "output">;
38
+ /**
39
+ * First-party bridge between a Relay Call and a LiveKit Agents AgentSession.
40
+ * Developers work with Relay call IDs and LiveKit audio IO; media negotiation
41
+ * stays inside the transport.
42
+ */
43
+ export declare class RelayLiveKitCall {
44
+ #private;
45
+ readonly transport: RelayCallTransport;
46
+ readonly input: RelayAudioInput;
47
+ readonly output: RelayAudioOutput;
48
+ private constructor();
49
+ static connect(options: RelayLiveKitConnectOptions): Promise<RelayLiveKitCall>;
50
+ attach(session: AgentSessionAudioTarget): void;
51
+ detach(): void;
52
+ setMuted(muted: boolean): void;
53
+ end(): void;
54
+ close(): Promise<void>;
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=livekit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"livekit.d.ts","sourceRoot":"","sources":["../src/livekit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EACL,kBAAkB,EAInB,MAAM,gBAAgB,CAAC;AAExB,kFAAkF;AAClF,qBAAa,eAAgB,SAAQ,UAAU;;gBAOjC,SAAS,EAAE,kBAAkB;IAmBhC,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAOtC;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,SAAQ,WAAW;;gBAOnC,SAAS,EAAE,kBAAkB,EAAE,UAAU,SAAS;IAK/C,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,KAAK,IAAI,IAAI;IAUb,WAAW,IAAI,IAAI;IAa5B,KAAK,IAAI,IAAI;CAWd;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,GAClC,WAAW,kBAAkB,EAC7B,UAAS,wBAA6B,KACrC,iBAGD,CAAC;AAEH,MAAM,WAAW,0BAA2B,SAAQ,wBAAwB;IAC1E,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,eAAe,CAAC;IAKvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,KAAK,uBAAuB,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,QAAQ,CAAC,CAAC;AAEtE;;;;GAIG;AACH,qBAAa,gBAAgB;;IAC3B,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAIlC,OAAO;WAMM,OAAO,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAkBpF,MAAM,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI;IAQ9C,MAAM,IAAI,IAAI;IAOd,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI9B,GAAG,IAAI,IAAI;IAIL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
@@ -0,0 +1,169 @@
1
+ import { AudioInput, AudioOutput } from "@livekit/agents";
2
+ import { AudioFrame } from "@livekit/rtc-node";
3
+ import { TransformStream } from "node:stream/web";
4
+ import { RelayCallTransport, } from "./transport.js";
5
+ /** LiveKit Agents input backed by the remote Relay participant's WebRTC audio. */
6
+ export class RelayAudioInput extends AudioInput {
7
+ #transport;
8
+ #writer;
9
+ #onAudio;
10
+ #attached = false;
11
+ #closed = false;
12
+ constructor(transport) {
13
+ super();
14
+ this.#transport = transport;
15
+ const channel = new TransformStream();
16
+ this.#writer = channel.writable.getWriter();
17
+ this.multiStream.addInputStream(channel.readable);
18
+ this.#onAudio = (frame) => {
19
+ if (this.#closed || !this.#attached)
20
+ return;
21
+ const audio = new AudioFrame(frame.samples, frame.sampleRate, frame.channelCount, frame.samples.length / frame.channelCount);
22
+ void this.#writer.write(audio).catch(() => undefined);
23
+ };
24
+ this.#transport.on("audio", this.#onAudio);
25
+ }
26
+ setAttached(attached) {
27
+ this.#attached = attached;
28
+ }
29
+ async close() {
30
+ if (this.#closed)
31
+ return;
32
+ this.#closed = true;
33
+ this.#transport.off("audio", this.#onAudio);
34
+ await this.#writer.close().catch(() => undefined);
35
+ await super.close();
36
+ }
37
+ }
38
+ /** LiveKit Agents output that publishes TTS PCM to the Relay participant. */
39
+ export class RelayAudioOutput extends AudioOutput {
40
+ #transport;
41
+ #segmentDuration = 0;
42
+ #segmentStarted = false;
43
+ #segmentStartedAt = 0;
44
+ #closed = false;
45
+ constructor(transport, sampleRate = 48_000) {
46
+ super(sampleRate, undefined, { pause: false });
47
+ this.#transport = transport;
48
+ }
49
+ async captureFrame(frame) {
50
+ if (this.#closed)
51
+ throw new Error("Relay LiveKit audio output is closed.");
52
+ await super.captureFrame(frame);
53
+ if (!this.#segmentStarted) {
54
+ this.#segmentStarted = true;
55
+ this.#segmentStartedAt = Date.now();
56
+ this.onPlaybackStarted(this.#segmentStartedAt);
57
+ }
58
+ this.#segmentDuration += frame.samplesPerChannel / frame.sampleRate;
59
+ await this.#transport.writeAudio({
60
+ samples: frame.data,
61
+ sampleRate: frame.sampleRate,
62
+ channelCount: frame.channels,
63
+ });
64
+ }
65
+ flush() {
66
+ super.flush();
67
+ if (!this.#segmentStarted)
68
+ return;
69
+ this.onPlaybackFinished({
70
+ playbackPosition: this.#segmentDuration,
71
+ interrupted: false,
72
+ });
73
+ this.#resetSegment();
74
+ }
75
+ clearBuffer() {
76
+ this.#transport.clearAudio();
77
+ if (!this.#segmentStarted)
78
+ return;
79
+ this.onPlaybackFinished({
80
+ playbackPosition: Math.min(this.#segmentDuration, Math.max(0, (Date.now() - this.#segmentStartedAt) / 1_000)),
81
+ interrupted: true,
82
+ });
83
+ this.#resetSegment();
84
+ }
85
+ close() {
86
+ if (this.#closed)
87
+ return;
88
+ this.#closed = true;
89
+ this.clearBuffer();
90
+ }
91
+ #resetSegment() {
92
+ this.#segmentDuration = 0;
93
+ this.#segmentStarted = false;
94
+ this.#segmentStartedAt = 0;
95
+ }
96
+ }
97
+ /** Build LiveKit Agents audio IO around an already-connected Relay transport. */
98
+ export const createRelayLiveKitAudio = (transport, options = {}) => ({
99
+ input: new RelayAudioInput(transport),
100
+ output: new RelayAudioOutput(transport, options.outputSampleRate),
101
+ });
102
+ /**
103
+ * First-party bridge between a Relay Call and a LiveKit Agents AgentSession.
104
+ * Developers work with Relay call IDs and LiveKit audio IO; media negotiation
105
+ * stays inside the transport.
106
+ */
107
+ export class RelayLiveKitCall {
108
+ transport;
109
+ input;
110
+ output;
111
+ #session;
112
+ #closed = false;
113
+ constructor(transport, audio) {
114
+ this.transport = transport;
115
+ this.input = audio.input;
116
+ this.output = audio.output;
117
+ }
118
+ static async connect(options) {
119
+ const transportOptions = {
120
+ relay: options.relay,
121
+ callId: options.callId,
122
+ ...(options.room ? { room: options.room } : {}),
123
+ ...(options.webRTC ? { webRTC: options.webRTC } : {}),
124
+ ...(options.iceGatheringTimeoutMs === undefined
125
+ ? {}
126
+ : { iceGatheringTimeoutMs: options.iceGatheringTimeoutMs }),
127
+ ...(options.connectionTimeoutMs === undefined
128
+ ? {}
129
+ : { connectionTimeoutMs: options.connectionTimeoutMs }),
130
+ };
131
+ const transport = new RelayCallTransport(transportOptions);
132
+ await transport.connect();
133
+ return new RelayLiveKitCall(transport, createRelayLiveKitAudio(transport, options));
134
+ }
135
+ attach(session) {
136
+ if (this.#closed)
137
+ throw new Error("Relay LiveKit Call is closed.");
138
+ if (this.#session && this.#session !== session)
139
+ this.detach();
140
+ this.#session = session;
141
+ session.input.audio = this.input;
142
+ session.output.audio = this.output;
143
+ }
144
+ detach() {
145
+ if (!this.#session)
146
+ return;
147
+ if (this.#session.input.audio === this.input)
148
+ this.#session.input.audio = null;
149
+ if (this.#session.output.audio === this.output)
150
+ this.#session.output.audio = null;
151
+ this.#session = undefined;
152
+ }
153
+ setMuted(muted) {
154
+ this.transport.setMuted(muted);
155
+ }
156
+ end() {
157
+ this.transport.end();
158
+ }
159
+ async close() {
160
+ if (this.#closed)
161
+ return;
162
+ this.#closed = true;
163
+ this.detach();
164
+ this.output.close();
165
+ await this.input.close();
166
+ this.transport.close();
167
+ }
168
+ }
169
+ //# sourceMappingURL=livekit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"livekit.js","sourceRoot":"","sources":["../src/livekit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { CallRoomEndedFrame, CallRoomOptions, CallRoomStateFrame, Relay } from "@relaymessenger/sdk";
2
+ export interface RelayAudioFrame {
3
+ /** Interleaved signed PCM16 samples. */
4
+ samples: Int16Array;
5
+ sampleRate: number;
6
+ channelCount: number;
7
+ }
8
+ export type RelayCallEngine = "werift" | "wrtc";
9
+ export interface RelayCallTransportOptions {
10
+ relay: Relay;
11
+ callId: string;
12
+ room?: CallRoomOptions;
13
+ /**
14
+ * WebRTC engine. `"werift"` (default) is pure TypeScript plus prebuilt Opus
15
+ * and loads no native binding. `"wrtc"` loads `@roamhq/wrtc` on demand.
16
+ */
17
+ engine?: RelayCallEngine;
18
+ /** Maximum wait for the WebRTC peer to become connected. Defaults to 15 seconds. */
19
+ connectionTimeoutMs?: number;
20
+ }
21
+ export interface RelayCallTransportCloseEvent {
22
+ code: number;
23
+ reason: string;
24
+ wasClean: boolean;
25
+ }
26
+ type TransportEventMap = {
27
+ audio: [RelayAudioFrame];
28
+ connected: [];
29
+ roomState: [CallRoomStateFrame];
30
+ ended: [CallRoomEndedFrame];
31
+ error: [Error];
32
+ close: [RelayCallTransportCloseEvent];
33
+ };
34
+ type TransportEvent = keyof TransportEventMap;
35
+ type TransportListener<K extends TransportEvent> = (...args: TransportEventMap[K]) => void;
36
+ export declare class RelayCallTransportError extends Error {
37
+ readonly code?: string;
38
+ constructor(message: string, code?: string);
39
+ }
40
+ /**
41
+ * Provider-neutral Node WebRTC bridge for Relay Call rooms.
42
+ *
43
+ * The class owns Relay media negotiation internally. Higher-level adapters only
44
+ * exchange PCM16 frames and call lifecycle events.
45
+ */
46
+ export declare class RelayCallTransport {
47
+ #private;
48
+ constructor(options: RelayCallTransportOptions);
49
+ on<K extends TransportEvent>(event: K, listener: TransportListener<K>): this;
50
+ off<K extends TransportEvent>(event: K, listener: TransportListener<K>): this;
51
+ connect(): Promise<void>;
52
+ /** Replace only the room signaling socket and replay the identical publication. */
53
+ reconnect(): Promise<void>;
54
+ /**
55
+ * Feed interleaved PCM16 audio into Relay. Frames are split into 10 ms WebRTC
56
+ * source slices and paced in real time, so adapters may push larger chunks.
57
+ */
58
+ writeAudio(frame: RelayAudioFrame): Promise<void>;
59
+ /** Drop queued outgoing PCM. At most one already-submitted 10 ms slice remains. */
60
+ clearAudio(): void;
61
+ setMuted(muted: boolean): void;
62
+ end(): void;
63
+ close(): void;
64
+ }
65
+ export {};
66
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAElB,eAAe,EAGf,kBAAkB,EAElB,KAAK,EACN,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAkED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,eAAe,CAAC;IAGvB;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IAKzB,oFAAoF;IACpF,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,CAAC,eAAe,CAAC,CAAC;IACzB,SAAS,EAAE,EAAE,CAAC;IACd,SAAS,EAAE,CAAC,kBAAkB,CAAC,CAAC;IAChC,KAAK,EAAE,CAAC,kBAAkB,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACf,KAAK,EAAE,CAAC,4BAA4B,CAAC,CAAC;CACvC,CAAC;AAEF,KAAK,cAAc,GAAG,MAAM,iBAAiB,CAAC;AAC9C,KAAK,iBAAiB,CAAC,CAAC,SAAS,cAAc,IAAI,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AAM3F,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAK3C;AAgCD;;;;;GAKG;AACH,qBAAa,kBAAkB;;gBA0BjB,OAAO,EAAE,yBAAyB;IAuB9C,EAAE,CAAC,CAAC,SAAS,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAU5E,GAAG,CAAC,CAAC,SAAS,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;IAKvE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B9B,mFAAmF;IAC7E,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAOhC;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBjD,mFAAmF;IACnF,UAAU,IAAI,IAAI;IAIlB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI9B,GAAG,IAAI,IAAI;IAIX,KAAK,IAAI,IAAI;CA+Od"}
@@ -0,0 +1,417 @@
1
+ const DEFAULT_ICE_GATHERING_TIMEOUT_MS = 10_000;
2
+ const DEFAULT_CONNECTION_TIMEOUT_MS = 15_000;
3
+ const AUDIO_SLICE_MS = 10;
4
+ export class RelayCallTransportError extends Error {
5
+ code;
6
+ constructor(message, code) {
7
+ super(message);
8
+ this.name = "RelayCallTransportError";
9
+ if (code !== undefined)
10
+ this.code = code;
11
+ }
12
+ }
13
+ const loadWebRTCFactory = async (engine) => {
14
+ if (engine === "werift") {
15
+ const { createWeriftWebRTCFactory } = await import("./engine-werift.js");
16
+ return createWeriftWebRTCFactory();
17
+ }
18
+ const wrtc = await import("@roamhq/wrtc");
19
+ return {
20
+ createPeerConnection: () => new wrtc.RTCPeerConnection({
21
+ bundlePolicy: "max-bundle",
22
+ iceServers: [],
23
+ }),
24
+ createAudioSource: () => new wrtc.nonstandard.RTCAudioSource(),
25
+ createAudioSink: (track) => new wrtc.nonstandard.RTCAudioSink(track),
26
+ };
27
+ };
28
+ const cloneSamples = (samples) => {
29
+ const copy = new Int16Array(samples.length);
30
+ copy.set(samples);
31
+ return copy;
32
+ };
33
+ const delay = (milliseconds) => new Promise((resolve) => {
34
+ const timer = setTimeout(resolve, milliseconds);
35
+ timer.unref?.();
36
+ });
37
+ /**
38
+ * Provider-neutral Node WebRTC bridge for Relay Call rooms.
39
+ *
40
+ * The class owns Relay media negotiation internally. Higher-level adapters only
41
+ * exchange PCM16 frames and call lifecycle events.
42
+ */
43
+ export class RelayCallTransport {
44
+ #room;
45
+ #providedFactory;
46
+ #engine;
47
+ #iceGatheringTimeoutMs;
48
+ #connectionTimeoutMs;
49
+ #listeners = new Map();
50
+ #factory;
51
+ #peer;
52
+ #audioSource;
53
+ #localTrack;
54
+ #remoteSink;
55
+ #publishTransceiver;
56
+ #publishFrame;
57
+ #initialAnswerSdp;
58
+ #negotiationTail = Promise.resolve();
59
+ #outputTail = Promise.resolve();
60
+ #audioGeneration = 0;
61
+ #reportedConnected = false;
62
+ #readySettled = false;
63
+ #readyResolve;
64
+ #readyReject;
65
+ #ready;
66
+ #handlersAttached = false;
67
+ #closed = false;
68
+ constructor(options) {
69
+ if (!options.callId.trim())
70
+ throw new Error("callId is required.");
71
+ this.#room = options.roomClient ?? options.relay.calls.room(options.callId, options.room);
72
+ this.#providedFactory = options.webRTC;
73
+ this.#engine = options.engine ?? "werift";
74
+ if (this.#engine !== "werift" && this.#engine !== "wrtc") {
75
+ throw new Error('engine must be "werift" or "wrtc".');
76
+ }
77
+ this.#iceGatheringTimeoutMs = options.iceGatheringTimeoutMs ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;
78
+ this.#connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_CONNECTION_TIMEOUT_MS;
79
+ if (!Number.isFinite(this.#iceGatheringTimeoutMs) || this.#iceGatheringTimeoutMs <= 0) {
80
+ throw new Error("iceGatheringTimeoutMs must be greater than zero.");
81
+ }
82
+ if (!Number.isFinite(this.#connectionTimeoutMs) || this.#connectionTimeoutMs <= 0) {
83
+ throw new Error("connectionTimeoutMs must be greater than zero.");
84
+ }
85
+ this.#ready = new Promise((resolve, reject) => {
86
+ this.#readyResolve = resolve;
87
+ this.#readyReject = reject;
88
+ });
89
+ void this.#ready.catch(() => undefined);
90
+ }
91
+ on(event, listener) {
92
+ let listeners = this.#listeners.get(event);
93
+ if (!listeners) {
94
+ listeners = new Set();
95
+ this.#listeners.set(event, listeners);
96
+ }
97
+ listeners.add(listener);
98
+ return this;
99
+ }
100
+ off(event, listener) {
101
+ this.#listeners.get(event)?.delete(listener);
102
+ return this;
103
+ }
104
+ async connect() {
105
+ if (this.#closed)
106
+ throw new Error("Relay Call transport is closed.");
107
+ this.#attachRoomHandlers();
108
+ await this.#room.connect();
109
+ if (this.#peer) {
110
+ await this.#waitForConnection();
111
+ return;
112
+ }
113
+ this.#factory = this.#providedFactory ?? await loadWebRTCFactory(this.#engine);
114
+ this.#audioSource = this.#factory.createAudioSource();
115
+ this.#localTrack = this.#audioSource.createTrack();
116
+ if (this.#localTrack.kind !== "audio") {
117
+ throw new RelayCallTransportError("The WebRTC binding created a non-audio Relay track.");
118
+ }
119
+ const peer = this.#factory.createPeerConnection();
120
+ this.#peer = peer;
121
+ this.#publishTransceiver = peer.addTransceiver(this.#localTrack, { direction: "sendonly" });
122
+ peer.onconnectionstatechange = () => this.#connectionStateChanged();
123
+ peer.ontrack = (event) => this.#remoteTrack(event.track);
124
+ try {
125
+ await this.#publishLocalAudio();
126
+ await this.#waitForConnection();
127
+ }
128
+ catch (error) {
129
+ this.close();
130
+ throw error;
131
+ }
132
+ }
133
+ /** Replace only the room signaling socket and replay the identical publication. */
134
+ async reconnect() {
135
+ if (this.#closed)
136
+ throw new Error("Relay Call transport is closed.");
137
+ if (!this.#publishFrame)
138
+ throw new Error("Relay Call transport is not connected.");
139
+ await this.#room.reconnect();
140
+ this.#room.send(this.#publishFrame);
141
+ }
142
+ /**
143
+ * Feed interleaved PCM16 audio into Relay. Frames are split into 10 ms WebRTC
144
+ * source slices and paced in real time, so adapters may push larger chunks.
145
+ */
146
+ writeAudio(frame) {
147
+ if (this.#closed)
148
+ return Promise.reject(new Error("Relay Call transport is closed."));
149
+ if (!this.#audioSource)
150
+ return Promise.reject(new Error("Relay Call transport is not connected."));
151
+ if (!Number.isInteger(frame.sampleRate) || frame.sampleRate <= 0 || frame.sampleRate % 100 !== 0) {
152
+ return Promise.reject(new Error("Relay audio sampleRate must be a positive multiple of 100."));
153
+ }
154
+ if (!Number.isInteger(frame.channelCount) || frame.channelCount <= 0) {
155
+ return Promise.reject(new Error("Relay audio channelCount must be a positive integer."));
156
+ }
157
+ if (frame.samples.length % frame.channelCount !== 0) {
158
+ return Promise.reject(new Error("Relay audio samples must contain complete interleaved frames."));
159
+ }
160
+ const captured = {
161
+ samples: cloneSamples(frame.samples),
162
+ sampleRate: frame.sampleRate,
163
+ channelCount: frame.channelCount,
164
+ };
165
+ const generation = this.#audioGeneration;
166
+ const queued = this.#outputTail.then(() => this.#writeAudio(captured, generation));
167
+ this.#outputTail = queued.catch(() => undefined);
168
+ return queued;
169
+ }
170
+ /** Drop queued outgoing PCM. At most one already-submitted 10 ms slice remains. */
171
+ clearAudio() {
172
+ this.#audioGeneration += 1;
173
+ }
174
+ setMuted(muted) {
175
+ this.#room.userUpdate({ muted });
176
+ }
177
+ end() {
178
+ this.#room.end();
179
+ }
180
+ close() {
181
+ if (this.#closed)
182
+ return;
183
+ this.#closed = true;
184
+ this.#rejectReady(new RelayCallTransportError("Relay Call transport closed before media connected."));
185
+ this.clearAudio();
186
+ this.#shutdownMedia();
187
+ this.#room.close();
188
+ }
189
+ async #publishLocalAudio() {
190
+ const peer = this.#requirePeer();
191
+ const offer = await peer.createOffer();
192
+ await peer.setLocalDescription(offer);
193
+ await this.#waitForIceGathering(peer);
194
+ const description = this.#localDescription("offer");
195
+ const mid = this.#publishTransceiver?.mid;
196
+ if (!mid)
197
+ throw new RelayCallTransportError("Relay audio publication has no WebRTC MID.");
198
+ this.#publishFrame = {
199
+ type: "offer",
200
+ session_description: description,
201
+ tracks: [{ mid, name: "audio" }],
202
+ };
203
+ this.#room.send(this.#publishFrame);
204
+ }
205
+ #attachRoomHandlers() {
206
+ if (this.#handlersAttached)
207
+ return;
208
+ this.#handlersAttached = true;
209
+ this.#room.on("answer", (frame) => {
210
+ this.#queueNegotiation(() => this.#serverAnswer(frame));
211
+ });
212
+ this.#room.on("offer", (frame) => {
213
+ this.#queueNegotiation(() => this.#serverOffer(frame));
214
+ });
215
+ this.#room.on("roomState", (frame) => {
216
+ this.#emit("roomState", frame);
217
+ });
218
+ this.#room.on("error", (error) => {
219
+ if (error instanceof Error) {
220
+ this.#rejectReady(error);
221
+ this.#emit("error", error);
222
+ }
223
+ else
224
+ this.#serverError(error);
225
+ });
226
+ this.#room.on("ended", (frame) => {
227
+ this.#rejectReady(new RelayCallTransportError(`Relay Call ended before media connected (${frame.reason}).`));
228
+ this.clearAudio();
229
+ this.#shutdownMedia();
230
+ this.#emit("ended", frame);
231
+ });
232
+ this.#room.on("close", (event) => {
233
+ if (!this.#reportedConnected) {
234
+ this.#rejectReady(new RelayCallTransportError(`Relay Call room closed before media connected (${event.code}).`));
235
+ }
236
+ this.#emit("close", event);
237
+ });
238
+ }
239
+ #queueNegotiation(work) {
240
+ const run = this.#negotiationTail.then(work);
241
+ this.#negotiationTail = run.catch((error) => {
242
+ const parsed = error instanceof Error ? error : new Error(String(error));
243
+ this.#rejectReady(parsed);
244
+ this.#emit("error", parsed);
245
+ });
246
+ }
247
+ async #serverAnswer(frame) {
248
+ const peer = this.#requirePeer();
249
+ const sdp = frame.session_description.sdp;
250
+ // Reconnecting the signaling socket replays the exact initial offer. Relay
251
+ // returns its cached answer; applying that answer again in stable state is
252
+ // invalid WebRTC signaling, so recognize and ignore the replay.
253
+ if (peer.signalingState === "stable" && this.#initialAnswerSdp === sdp)
254
+ return;
255
+ await peer.setRemoteDescription(frame.session_description);
256
+ this.#initialAnswerSdp ??= sdp;
257
+ }
258
+ async #serverOffer(frame) {
259
+ const peer = this.#requirePeer();
260
+ await peer.setRemoteDescription(frame.session_description);
261
+ const answer = await peer.createAnswer();
262
+ await peer.setLocalDescription(answer);
263
+ await this.#waitForIceGathering(peer);
264
+ this.#room.send({ type: "answer", session_description: this.#localDescription("answer") });
265
+ }
266
+ #serverError(frame) {
267
+ const error = new RelayCallTransportError(frame.message, frame.code);
268
+ this.#rejectReady(error);
269
+ this.#emit("error", error);
270
+ }
271
+ #connectionStateChanged() {
272
+ const state = this.#peer?.connectionState;
273
+ if (state === "connected" && !this.#reportedConnected) {
274
+ this.#reportedConnected = true;
275
+ try {
276
+ this.#room.connected();
277
+ this.#resolveReady();
278
+ this.#emit("connected");
279
+ }
280
+ catch (error) {
281
+ const parsed = error instanceof Error ? error : new Error(String(error));
282
+ this.#rejectReady(parsed);
283
+ this.#emit("error", parsed);
284
+ }
285
+ }
286
+ else if (state === "failed") {
287
+ const error = new RelayCallTransportError("Relay WebRTC connection failed.");
288
+ this.#rejectReady(error);
289
+ this.#emit("error", error);
290
+ }
291
+ }
292
+ #remoteTrack(track) {
293
+ if (track.kind !== "audio" || !this.#factory)
294
+ return;
295
+ this.#remoteSink?.stop();
296
+ const sink = this.#factory.createAudioSink(track);
297
+ this.#remoteSink = sink;
298
+ sink.ondata = (data) => {
299
+ if (this.#closed || this.#remoteSink !== sink)
300
+ return;
301
+ const channelCount = data.channelCount ?? 1;
302
+ if (data.bitsPerSample !== undefined && data.bitsPerSample !== 16) {
303
+ this.#emit("error", new RelayCallTransportError(`Relay WebRTC delivered unsupported ${data.bitsPerSample}-bit audio.`));
304
+ return;
305
+ }
306
+ this.#emit("audio", {
307
+ samples: cloneSamples(data.samples),
308
+ sampleRate: data.sampleRate,
309
+ channelCount,
310
+ });
311
+ };
312
+ }
313
+ async #writeAudio(frame, generation) {
314
+ const source = this.#audioSource;
315
+ if (!source || generation !== this.#audioGeneration)
316
+ return;
317
+ const samplesPerChannel = frame.sampleRate / 100;
318
+ const sliceSamples = samplesPerChannel * frame.channelCount;
319
+ for (let offset = 0; offset < frame.samples.length; offset += sliceSamples) {
320
+ if (this.#closed || generation !== this.#audioGeneration)
321
+ return;
322
+ const remaining = Math.min(sliceSamples, frame.samples.length - offset);
323
+ const samples = new Int16Array(sliceSamples);
324
+ samples.set(frame.samples.subarray(offset, offset + remaining));
325
+ source.onData({
326
+ samples,
327
+ sampleRate: frame.sampleRate,
328
+ bitsPerSample: 16,
329
+ channelCount: frame.channelCount,
330
+ numberOfFrames: samplesPerChannel,
331
+ });
332
+ await delay(AUDIO_SLICE_MS);
333
+ }
334
+ }
335
+ async #waitForIceGathering(peer) {
336
+ if (peer.iceGatheringState === "complete")
337
+ return;
338
+ await new Promise((resolve, reject) => {
339
+ const timeout = setTimeout(() => {
340
+ cleanup();
341
+ reject(new RelayCallTransportError("Timed out gathering Relay WebRTC ICE candidates."));
342
+ }, this.#iceGatheringTimeoutMs);
343
+ timeout.unref?.();
344
+ const changed = () => {
345
+ if (peer.iceGatheringState !== "complete")
346
+ return;
347
+ cleanup();
348
+ resolve();
349
+ };
350
+ const cleanup = () => {
351
+ clearTimeout(timeout);
352
+ peer.removeEventListener("icegatheringstatechange", changed);
353
+ };
354
+ peer.addEventListener("icegatheringstatechange", changed);
355
+ changed();
356
+ });
357
+ }
358
+ async #waitForConnection() {
359
+ if (this.#reportedConnected)
360
+ return;
361
+ await new Promise((resolve, reject) => {
362
+ const timeout = setTimeout(() => {
363
+ reject(new RelayCallTransportError("Timed out connecting Relay WebRTC media."));
364
+ }, this.#connectionTimeoutMs);
365
+ timeout.unref?.();
366
+ this.#ready.then(() => {
367
+ clearTimeout(timeout);
368
+ resolve();
369
+ }, (error) => {
370
+ clearTimeout(timeout);
371
+ reject(error);
372
+ });
373
+ });
374
+ }
375
+ #resolveReady() {
376
+ if (this.#readySettled)
377
+ return;
378
+ this.#readySettled = true;
379
+ this.#readyResolve?.();
380
+ }
381
+ #rejectReady(error) {
382
+ if (this.#readySettled)
383
+ return;
384
+ this.#readySettled = true;
385
+ this.#readyReject?.(error);
386
+ }
387
+ #localDescription(type) {
388
+ const local = this.#requirePeer().localDescription;
389
+ if (!local || local.type !== type || !local.sdp) {
390
+ throw new RelayCallTransportError(`Relay WebRTC did not produce a complete ${type} SDP.`);
391
+ }
392
+ return { type, sdp: local.sdp };
393
+ }
394
+ #requirePeer() {
395
+ if (!this.#peer)
396
+ throw new Error("Relay Call transport is not connected.");
397
+ return this.#peer;
398
+ }
399
+ #shutdownMedia() {
400
+ this.#remoteSink?.stop();
401
+ this.#remoteSink = undefined;
402
+ this.#localTrack?.stop();
403
+ this.#localTrack = undefined;
404
+ this.#peer?.close();
405
+ this.#peer = undefined;
406
+ this.#audioSource = undefined;
407
+ }
408
+ #emit(event, ...args) {
409
+ for (const listener of this.#listeners.get(event) ?? []) {
410
+ try {
411
+ listener(...args);
412
+ }
413
+ catch { /* adapters own listener failures */ }
414
+ }
415
+ }
416
+ }
417
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@relaymessenger/livekit",
3
+ "version": "0.1.0-staging.0",
4
+ "description": "Relay WebRTC audio transport and LiveKit Agents integration for Node.js.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./transport": {
16
+ "types": "./dist/transport.d.ts",
17
+ "import": "./dist/transport.js",
18
+ "default": "./dist/transport.js"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "dist/",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "scripts": {
28
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
29
+ "build": "tsc -p tsconfig.build.json",
30
+ "check": "tsc -p tsconfig.json --noEmit",
31
+ "test": "vitest run",
32
+ "validate": "npm run check && npm test && npm run build",
33
+ "prepack": "npm run validate"
34
+ },
35
+ "engines": {
36
+ "node": ">=22.22.3"
37
+ },
38
+ "license": "MIT",
39
+ "dependencies": {
40
+ "@evan/opus": "1.0.3",
41
+ "@relaymessenger/sdk": "0.3.6-staging.14",
42
+ "werift": "0.24.4"
43
+ },
44
+ "optionalDependencies": {
45
+ "@roamhq/wrtc": "^0.10.0"
46
+ },
47
+ "peerDependencies": {
48
+ "@livekit/agents": "^1.9.0",
49
+ "@livekit/rtc-node": "^0.13.34"
50
+ },
51
+ "devDependencies": {
52
+ "@livekit/agents": "^1.9.0",
53
+ "@livekit/rtc-node": "^0.13.34",
54
+ "@types/node": "^26.6.2",
55
+ "typescript": "^5.9.3",
56
+ "vitest": "^4.0.0"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public",
60
+ "registry": "https://registry.npmjs.org/",
61
+ "tag": "staging",
62
+ "provenance": true
63
+ },
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "git+https://github.com/RelayMessenger/Relay-SDK.git",
67
+ "directory": "packages/livekit"
68
+ },
69
+ "homepage": "https://github.com/RelayMessenger/Relay-SDK/tree/main/packages/livekit#readme",
70
+ "keywords": [
71
+ "relay",
72
+ "livekit",
73
+ "webrtc",
74
+ "voice",
75
+ "agents"
76
+ ]
77
+ }