@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 +21 -0
- package/README.md +81 -0
- package/dist/engine-werift.d.ts +17 -0
- package/dist/engine-werift.d.ts.map +1 -0
- package/dist/engine-werift.js +199 -0
- package/dist/engine-werift.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/livekit.d.ts +57 -0
- package/dist/livekit.d.ts.map +1 -0
- package/dist/livekit.js +169 -0
- package/dist/livekit.js.map +1 -0
- package/dist/transport.d.ts +66 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +417 -0
- package/dist/transport.js.map +1 -0
- package/package.json +77 -0
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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/livekit.js
ADDED
|
@@ -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
|
+
}
|