@memberjunction/ai-bridge-livekit 5.41.0 → 5.42.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/README.md +14 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/livekit-bridge.d.ts +2 -0
- package/dist/livekit-bridge.d.ts.map +1 -1
- package/dist/livekit-bridge.js +16 -1
- package/dist/livekit-bridge.js.map +1 -1
- package/dist/livekit-native-sdk.d.ts +302 -0
- package/dist/livekit-native-sdk.d.ts.map +1 -0
- package/dist/livekit-native-sdk.js +320 -0
- package/dist/livekit-native-sdk.js.map +1 -0
- package/dist/livekit-sdk.d.ts +5 -0
- package/dist/livekit-sdk.d.ts.map +1 -1
- package/dist/register-native.d.ts +19 -0
- package/dist/register-native.d.ts.map +1 -0
- package/dist/register-native.js +32 -0
- package/dist/register-native.js.map +1 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -80,11 +80,20 @@ export interface ILiveKitRoomSdk {
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
**Native binding:** this package ships **`LiveKitNativeMeetingSdk`** (`livekit-native-sdk.ts`) — the
|
|
84
|
+
two-way adapter over the LiveKit room client, activated with `bridge.SetSdkFactory(BindLiveKitNative())`
|
|
85
|
+
(auto-bound by the engine as the registered default for `DriverClass = 'LiveKitBridge'`). It's the MJ-side
|
|
86
|
+
adapter, unit-tested against a fake module; none of the SDK types leak into this package.
|
|
87
|
+
|
|
88
|
+
**The real room client now ships too:** [`@memberjunction/ai-bridge-livekit-native`](../LiveKitNative)
|
|
89
|
+
wraps `@livekit/rtc-node` behind this adapter's `NativeRoomModule` contract. The LiveKit coordinator points
|
|
90
|
+
`NativeModuleSpecifier` at it by default (overridable via the `LIVEKIT_NATIVE_MODULE` env), so a deployment
|
|
91
|
+
just needs to `npm install @livekit/rtc-node` on the agent host. Until a module is configured, `connect`
|
|
92
|
+
throws an explicit "load the native LiveKit module" error.
|
|
93
|
+
|
|
94
|
+
LiveKit is the recommended **internal proving ground** (pair with the `mj-livekit-room` Explorer tab or the
|
|
95
|
+
LiveKit Agents Playground) — see
|
|
96
|
+
[`plans/realtime/native-bridge-buildout-plan.md`](../../../../plans/realtime/native-bridge-buildout-plan.md) §6.
|
|
88
97
|
|
|
89
98
|
## Echo / self-audio
|
|
90
99
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
export * from './livekit-sdk.js';
|
|
2
|
+
export * from './livekit-native-sdk.js';
|
|
2
3
|
export * from './livekit-meeting-controls.js';
|
|
3
4
|
export * from './livekit-bridge.js';
|
|
5
|
+
export * from './register-native.js';
|
|
4
6
|
import { LoadLiveKitBridge } from './livekit-bridge.js';
|
|
7
|
+
import { RegisterLiveKitNativeSdk } from './register-native.js';
|
|
5
8
|
// Static reference so bundlers cannot tree-shake the @RegisterClass(BaseRealtimeBridge, 'LiveKitBridge')
|
|
6
9
|
// registration. Calling the no-op here keeps the driver resolvable by the engine's ClassFactory.
|
|
7
10
|
LoadLiveKitBridge();
|
|
11
|
+
// Register LiveKit's native two-way SDK binding so the engine auto-binds it at StartBridgeSession.
|
|
12
|
+
RegisterLiveKitNativeSdk();
|
|
8
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,yGAAyG;AACzG,iGAAiG;AACjG,iBAAiB,EAAE,CAAC;AACpB,mGAAmG;AACnG,wBAAwB,EAAE,CAAC"}
|
package/dist/livekit-bridge.d.ts
CHANGED
|
@@ -91,6 +91,8 @@ export declare class LiveKitBridge extends BaseRealtimeBridge {
|
|
|
91
91
|
* @param track The outbound track the frame targets.
|
|
92
92
|
* @param frame The media frame to send.
|
|
93
93
|
*/
|
|
94
|
+
/** Flushes the agent's queued outbound voice on barge-in (the user interrupted the agent). */
|
|
95
|
+
FlushOutboundMedia(): void;
|
|
94
96
|
SendMedia(track: BridgeMediaTrackKind, frame: BridgeMediaFrame): void;
|
|
95
97
|
/**
|
|
96
98
|
* Registers the inbound-media handler. The driver forwards each raw per-participant audio frame
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"livekit-bridge.d.ts","sourceRoot":"","sources":["../src/livekit-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EAErB,qBAAqB,EACrB,iCAAiC,EACpC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEH,qBAAqB,EAKxB,MAAM,eAAe,CAAC;AAGvB;;;GAGG;AACH,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"livekit-bridge.d.ts","sourceRoot":"","sources":["../src/livekit-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EAErB,qBAAqB,EACrB,iCAAiC,EACpC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEH,qBAAqB,EAKxB,MAAM,eAAe,CAAC;AAGvB;;;GAGG;AACH,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AA0C3D;;;;;;;;;GASG;AACH,qBACa,aAAc,SAAQ,kBAAkB;IACjD,8EAA8E;IAC9E,OAAO,CAAC,GAAG,CAAgC;IAE3C,sFAAsF;IACtF,OAAO,CAAC,WAAW,CAAuB;IAE1C,sGAAsG;IACtG,OAAO,CAAC,YAAY,CAAC,CAAoC;IAEzD,4EAA4E;IAC5E,OAAO,CAAC,kBAAkB,CAAC,CAAkD;IAE7E,+FAA+F;IAC/F,OAAO,CAAC,eAAe,CAAkD;IAEzE;;;;OAIG;IACH,OAAO,CAAC,UAAU,CAKhB;IAEF;;;;;;OAMG;IACI,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAM1D;;;;;;;;;OASG;IACU,OAAO,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA2B9E;;;;OAIG;IACU,UAAU,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvE;;;;;;;OAOG;IACH,8FAA8F;IAC9E,kBAAkB,IAAI,IAAI;IAInC,SAAS,CAAC,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IA4B5E;;;;;OAKG;IACI,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI;IAMhE;;;;;;;OAOG;IACmB,eAAe,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IASzE;;;;;;OAMG;IACa,mBAAmB,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,qBAAqB,EAAE,KAAK,IAAI,GAAG,IAAI;IAKnG;;;;OAIG;IACa,6BAA6B,IAAI,iCAAiC,GAAG,IAAI;IAMzF;;;;;;OAMG;IACU,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzD,4FAA4F;IAC5F,IAAW,WAAW,IAAI,MAAM,GAAG,IAAI,CAEtC;IAID;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAKlB,gHAAgH;YAClG,aAAa;IAU3B,4GAA4G;IAC5G,OAAO,CAAC,sBAAsB;IAK9B,wGAAwG;IACxG,OAAO,CAAC,gBAAgB;IASxB,mFAAmF;IACnF,OAAO,CAAC,QAAQ;IAUhB,+FAA+F;IAC/F,OAAO,CAAC,YAAY;CAcvB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
package/dist/livekit-bridge.js
CHANGED
|
@@ -56,13 +56,24 @@ function mapParticipantRole(role, isLocal) {
|
|
|
56
56
|
return 'Participant';
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* The bot-identity convention the LiveKit room coordinator mints (`agent-<agentSessionId>`). A bridge only
|
|
61
|
+
* knows its OWN bot via `IsLocal`; OTHER agents in a multi-agent room are REMOTE participants, so they must
|
|
62
|
+
* be recognized by this identity prefix. Without it every other agent reads as a human — breaking
|
|
63
|
+
* turn-taking's agent-exclusion (an agent treats another agent's speech as being addressed) AND the
|
|
64
|
+
* "are any humans still present?" occupancy check the engine uses to auto-leave an empty room.
|
|
65
|
+
*/
|
|
66
|
+
function isAgentParticipantIdentity(identity) {
|
|
67
|
+
return typeof identity === 'string' && identity.toLowerCase().startsWith('agent-');
|
|
68
|
+
}
|
|
59
69
|
/** Maps a LiveKit participant onto the bridge's {@link BridgeParticipantInfo}. */
|
|
60
70
|
function toBridgeParticipant(p) {
|
|
61
71
|
return {
|
|
62
72
|
ExternalId: p.Identity,
|
|
63
73
|
DisplayName: p.DisplayName,
|
|
64
74
|
Role: mapParticipantRole(p.Role, p.IsLocal),
|
|
65
|
-
|
|
75
|
+
// The local bot OR any remote agent bot (by identity convention) counts as an agent, not a human.
|
|
76
|
+
IsAgent: p.IsLocal === true || isAgentParticipantIdentity(p.Identity),
|
|
66
77
|
};
|
|
67
78
|
}
|
|
68
79
|
/**
|
|
@@ -165,6 +176,10 @@ let LiveKitBridge = class LiveKitBridge extends BaseRealtimeBridge {
|
|
|
165
176
|
* @param track The outbound track the frame targets.
|
|
166
177
|
* @param frame The media frame to send.
|
|
167
178
|
*/
|
|
179
|
+
/** Flushes the agent's queued outbound voice on barge-in (the user interrupted the agent). */
|
|
180
|
+
FlushOutboundMedia() {
|
|
181
|
+
this.sdk?.flushOutboundAudio();
|
|
182
|
+
}
|
|
168
183
|
SendMedia(track, frame) {
|
|
169
184
|
if (!this.sdk) {
|
|
170
185
|
return; // not connected — drop
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"livekit-bridge.js","sourceRoot":"","sources":["../src/livekit-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;;;;;;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EACH,kBAAkB,GASrB,MAAM,gCAAgC,CAAC;AASxC,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,eAAe,CAAC;AAE3D;;;GAGG;AACH,SAAS,kBAAkB,CAAC,IAA4B,EAAE,OAA4B;IAClF,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,QAAQ,IAAI,EAAE,CAAC;QACX,KAAK,MAAM;YACP,OAAO,MAAM,CAAC;QAClB,KAAK,QAAQ;YACT,OAAO,QAAQ,CAAC;QACpB;YACI,OAAO,aAAa,CAAC;IAC7B,CAAC;AACL,CAAC;AAED,kFAAkF;AAClF,SAAS,mBAAmB,CAAC,CAAqB;IAC9C,OAAO;QACH,UAAU,EAAE,CAAC,CAAC,QAAQ;QACtB,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC;QAC3C,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,IAAI;
|
|
1
|
+
{"version":3,"file":"livekit-bridge.js","sourceRoot":"","sources":["../src/livekit-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `LiveKitNativeMeetingSdk` — a **real, two-way** {@link ILiveKitRoomSdk} binding over the
|
|
3
|
+
* **native LiveKit server/agents SDK** (the Node room-participant build: `livekit-server-sdk` for token
|
|
4
|
+
* minting + admin, plus a room client such as `@livekit/rtc-node` that publishes/subscribes media). It
|
|
5
|
+
* gives the agent both **hearing** (each remote participant's subscribed audio track → a diarized
|
|
6
|
+
* {@link LiveKitAudioFrame}) and a **voice** ({@link publishAudioFrame} forwards the agent's synthesized
|
|
7
|
+
* PCM onto the bot's published audio track), plus full video/screen publish and the data-channel "chat".
|
|
8
|
+
*
|
|
9
|
+
* ## Why a native binding
|
|
10
|
+
* Publishing audio *into* a LiveKit room requires a real WebRTC participant — there is no receive-only
|
|
11
|
+
* shortcut as there is for some 3rd-party platforms. The native LiveKit room client exposes a
|
|
12
|
+
* publish-track **send** path alongside per-participant subscribed-track **receive** callbacks, so a
|
|
13
|
+
* single binding carries **bidirectional** media. This is the binding a two-way "agent talks in the
|
|
14
|
+
* room" deployment uses.
|
|
15
|
+
*
|
|
16
|
+
* ## The native module seam (no SDK types leak)
|
|
17
|
+
* The real LiveKit Node SDK is loaded **lazily** behind an injectable {@link NativeModuleLoader}, so this
|
|
18
|
+
* package builds and unit-tests with **no SDK installed and no network**. The adapter depends ONLY on the
|
|
19
|
+
* small structural {@link NativeRoomModule} / {@link NativeRoomClient} surface declared below — none of
|
|
20
|
+
* LiveKit's real types leak into the package. Tests inject a fake module; production points
|
|
21
|
+
* {@link LiveKitNativeSdkConfig.NativeModuleSpecifier} at the real room-client wrapper.
|
|
22
|
+
*
|
|
23
|
+
* ## Auth (deployment responsibility)
|
|
24
|
+
* The bot joins with a signed LiveKit **access token** (room name + grants) minted upstream by MJ's
|
|
25
|
+
* token/credential layer from the API **key/secret**. The ws URL + key/secret resolve **upstream** (MJ
|
|
26
|
+
* credential system / provider `Configuration`) and are **never inlined** at a call site. When a
|
|
27
|
+
* pre-signed token is supplied via {@link LiveKitConnectArgs.AccessToken} the adapter forwards it; when a
|
|
28
|
+
* deployment lets the native module mint the token, the resolved key/secret + ws URL are handed to
|
|
29
|
+
* {@link NativeRoomModule.createRoomClient}.
|
|
30
|
+
*
|
|
31
|
+
* Every spot where the native module's exact surface is assumed carries a `// VERIFY against the native
|
|
32
|
+
* LiveKit Node SDK wrapper` note so a live test can confirm it.
|
|
33
|
+
*
|
|
34
|
+
* @module @memberjunction/ai-bridge-livekit
|
|
35
|
+
* @author MemberJunction.com
|
|
36
|
+
*/
|
|
37
|
+
import { ILiveKitRoomSdk, LiveKitAudioFrame, LiveKitConnectArgs, LiveKitConnectResult, LiveKitParticipant, LiveKitParticipantRole } from './livekit-sdk.js';
|
|
38
|
+
/** One subscribed per-participant audio frame the native room client surfaces (inbound hearing + diarization). */
|
|
39
|
+
export interface NativeRoomAudioFrame {
|
|
40
|
+
/** Raw PCM bytes for this frame (`Uint8Array` view or standalone `ArrayBuffer`). */
|
|
41
|
+
data: Uint8Array | ArrayBuffer;
|
|
42
|
+
/** The LiveKit participant identity that produced the audio (the diarization speaker label). */
|
|
43
|
+
participantIdentity: string;
|
|
44
|
+
/** The participant's display name at capture time, when the client provides it. */
|
|
45
|
+
name?: string;
|
|
46
|
+
/** Optional epoch-ms capture timestamp. */
|
|
47
|
+
timestampMs?: number;
|
|
48
|
+
}
|
|
49
|
+
/** One participant as the native room client reports it. Mapped onto {@link LiveKitParticipant}. */
|
|
50
|
+
export interface NativeRoomParticipant {
|
|
51
|
+
/** The native participant identity (stable, application-assigned). */
|
|
52
|
+
identity: string;
|
|
53
|
+
/** The participant's display name (LiveKit's `name` attribute). */
|
|
54
|
+
name?: string;
|
|
55
|
+
/** The participant's role as the client/metadata reports it (`host` / `cohost` / `participant`). */
|
|
56
|
+
role?: string;
|
|
57
|
+
/** Whether this participant is the bot itself (LiveKit's local participant). */
|
|
58
|
+
isLocal?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** The arguments the native room client's `connect()` accepts. Mirrors {@link LiveKitConnectArgs}. */
|
|
61
|
+
export interface NativeConnectArgs {
|
|
62
|
+
/** The LiveKit room server ws URL (e.g. `wss://livekit.myorg.com`). Resolved upstream. */
|
|
63
|
+
url: string;
|
|
64
|
+
/** The signed LiveKit access token authorizing the bot to join (resolved upstream; never inline). */
|
|
65
|
+
token: string;
|
|
66
|
+
/** The bot's display name in the participant list. */
|
|
67
|
+
name: string;
|
|
68
|
+
}
|
|
69
|
+
/** What the native room client's `connect()` resolves to. */
|
|
70
|
+
export interface NativeConnectResult {
|
|
71
|
+
/** The bot's own participant identity in the joined room. */
|
|
72
|
+
localIdentity: string;
|
|
73
|
+
/** The LiveKit room name the bot joined. */
|
|
74
|
+
roomName: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The live native room client the module hands back. The surface mirrors {@link ILiveKitRoomSdk} but in
|
|
78
|
+
* the native SDK's own (lower-cased) vocabulary; this adapter maps between the two. VERIFY against the
|
|
79
|
+
* native LiveKit Node SDK wrapper.
|
|
80
|
+
*/
|
|
81
|
+
export interface NativeRoomClient {
|
|
82
|
+
/** Connects to the room (async — the native connect handshake is network-bound). */
|
|
83
|
+
connect(args: NativeConnectArgs): Promise<NativeConnectResult>;
|
|
84
|
+
/** Disconnects from the room and releases native resources. */
|
|
85
|
+
disconnect(): Promise<void>;
|
|
86
|
+
/** Publishes one raw PCM frame on the bot's audio track (the agent's voice). */
|
|
87
|
+
publishAudio(pcm: ArrayBuffer): void;
|
|
88
|
+
/** Drops all pending/queued outbound audio — flushes the agent's voice on barge-in. */
|
|
89
|
+
flushOutbound(): void;
|
|
90
|
+
/** Publishes one raw frame on the bot's camera/video track. */
|
|
91
|
+
publishVideo(frame: ArrayBuffer): void;
|
|
92
|
+
/** Publishes one raw frame on the bot's screen-share track. */
|
|
93
|
+
publishScreen(frame: ArrayBuffer): void;
|
|
94
|
+
/** Registers the inbound per-participant subscribed-audio callback. "Latest handler wins." */
|
|
95
|
+
onAudioFrame(cb: (frame: NativeRoomAudioFrame) => void): void;
|
|
96
|
+
/** Registers the participant-connected callback. */
|
|
97
|
+
onParticipantConnected(cb: (participant: NativeRoomParticipant) => void): void;
|
|
98
|
+
/** Registers the participant-disconnected callback (identity of the participant that left). */
|
|
99
|
+
onParticipantDisconnected(cb: (participantIdentity: string) => void): void;
|
|
100
|
+
/** Returns the current participant roster (including the bot). */
|
|
101
|
+
getParticipants(): Promise<NativeRoomParticipant[]>;
|
|
102
|
+
/** Publishes a reliable message on the room data channel (the room-native "chat"). */
|
|
103
|
+
publishData(text: string): Promise<void>;
|
|
104
|
+
/** Registers the room-disconnected callback (SFU closed / the bot was removed). */
|
|
105
|
+
onDisconnected(cb: () => void): void;
|
|
106
|
+
}
|
|
107
|
+
/** The native room module surface — a factory that constructs a {@link NativeRoomClient}. */
|
|
108
|
+
export interface NativeRoomModule {
|
|
109
|
+
/**
|
|
110
|
+
* Constructs a native room client from resolved options (credentials already resolved upstream).
|
|
111
|
+
* VERIFY against the native LiveKit Node SDK wrapper (`createRoomClient` vs a `Room` constructor).
|
|
112
|
+
*/
|
|
113
|
+
createRoomClient(options: NativeRoomClientOptions): NativeRoomClient;
|
|
114
|
+
}
|
|
115
|
+
/** Options passed to {@link NativeRoomModule.createRoomClient}. Credentials are resolved upstream. */
|
|
116
|
+
export interface NativeRoomClientOptions {
|
|
117
|
+
/** The LiveKit room server ws URL (resolved upstream). */
|
|
118
|
+
Url?: string;
|
|
119
|
+
/** The LiveKit API key (resolved upstream; used to mint the join token when not pre-signed). */
|
|
120
|
+
ApiKey?: string;
|
|
121
|
+
/** The LiveKit API secret (resolved upstream). Used only to sign the join token. */
|
|
122
|
+
ApiSecret?: string;
|
|
123
|
+
/**
|
|
124
|
+
* PCM rate (Hz) the agent's model CONSUMES — the rate inbound room audio is resampled to. Default 24000
|
|
125
|
+
* (OpenAI); Gemini Live = 16000. A wrapper that ignores this stays on its constructed default.
|
|
126
|
+
*/
|
|
127
|
+
InboundSampleRate?: number;
|
|
128
|
+
/** PCM rate (Hz) the agent's model EMITS — the bot's published voice-track rate. Default 24000. */
|
|
129
|
+
OutboundSampleRate?: number;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolved configuration for {@link LiveKitNativeMeetingSdk}. Credentials resolve **upstream** (MJ
|
|
133
|
+
* credential system / provider `Configuration`) — this object carries already-resolved values; **never
|
|
134
|
+
* inline secrets** at a call site.
|
|
135
|
+
*/
|
|
136
|
+
export interface LiveKitNativeSdkConfig {
|
|
137
|
+
/** The LiveKit room server ws URL (resolved upstream). */
|
|
138
|
+
Url?: string;
|
|
139
|
+
/** The LiveKit API key (resolved upstream). Used to mint the join token when not pre-signed. */
|
|
140
|
+
ApiKey?: string;
|
|
141
|
+
/** The LiveKit API secret (resolved upstream). Used only to sign the join token. */
|
|
142
|
+
ApiSecret?: string;
|
|
143
|
+
/** A pre-signed LiveKit access token, when the deployment mints it out-of-band instead of via key/secret. */
|
|
144
|
+
AccessToken?: string;
|
|
145
|
+
/** The bot's display name (defaults applied by the bridge when absent). */
|
|
146
|
+
BotDisplayName?: string;
|
|
147
|
+
/**
|
|
148
|
+
* The module specifier of the native LiveKit room-client wrapper to load (e.g. an internal wrapper
|
|
149
|
+
* package name or an absolute path to a sidecar entry). Required in production; tests inject a loader.
|
|
150
|
+
*/
|
|
151
|
+
NativeModuleSpecifier?: string;
|
|
152
|
+
/**
|
|
153
|
+
* PCM rate (Hz) the agent's realtime model **consumes** — the rate inbound room audio is resampled to
|
|
154
|
+
* before reaching the model. Threaded from the model via the engine (`IRealtimeSession.InputSampleRate`).
|
|
155
|
+
* Default 24000 (OpenAI); Gemini Live = 16000. Mismatch = the agent never hears the user on the bridge.
|
|
156
|
+
*/
|
|
157
|
+
InboundSampleRate?: number;
|
|
158
|
+
/** PCM rate (Hz) the agent's model **emits** — the bot's published voice track rate. Default 24000. */
|
|
159
|
+
OutboundSampleRate?: number;
|
|
160
|
+
}
|
|
161
|
+
/** Normalizes the native client's free-form role string onto the seam's {@link LiveKitParticipantRole}. */
|
|
162
|
+
export declare function mapNativeRole(role?: string): LiveKitParticipantRole;
|
|
163
|
+
/**
|
|
164
|
+
* **Pure mapping** of one native participant onto the seam's {@link LiveKitParticipant}. Isolated from the
|
|
165
|
+
* native client and from I/O so it is unit-tested directly.
|
|
166
|
+
*/
|
|
167
|
+
export declare function mapNativeParticipant(p: NativeRoomParticipant): LiveKitParticipant;
|
|
168
|
+
/**
|
|
169
|
+
* Coerces a `Uint8Array` view or `ArrayBuffer` into a standalone `ArrayBuffer`, **copying** the exact
|
|
170
|
+
* window of a view (so the result never aliases a larger backing buffer). The LiveKit package has no
|
|
171
|
+
* pre-existing PCM-coercion helper to reuse, so this is defined here; it is the single such export.
|
|
172
|
+
*/
|
|
173
|
+
export declare function toArrayBuffer(data: Uint8Array | ArrayBuffer): ArrayBuffer;
|
|
174
|
+
/**
|
|
175
|
+
* **Pure mapping** of one native inbound audio frame onto the seam's diarized {@link LiveKitAudioFrame}.
|
|
176
|
+
* Copies the PCM (see {@link toArrayBuffer}) and resolves the speaker label. Isolated for direct testing.
|
|
177
|
+
*/
|
|
178
|
+
export declare function mapNativeAudioFrame(frame: NativeRoomAudioFrame): LiveKitAudioFrame;
|
|
179
|
+
/**
|
|
180
|
+
* The injectable loader for the native LiveKit room module — overridable so unit tests supply a fake
|
|
181
|
+
* module with no SDK and no network. Production leaves it as {@link defaultNativeLoader}, which lazily
|
|
182
|
+
* imports the configured {@link LiveKitNativeSdkConfig.NativeModuleSpecifier}.
|
|
183
|
+
*/
|
|
184
|
+
export type NativeModuleLoader = (specifier: string) => Promise<NativeRoomModule>;
|
|
185
|
+
/**
|
|
186
|
+
* Lazily loads the native LiveKit room module at the given specifier (category: runtime plugin discovery
|
|
187
|
+
* from config — the wrapper path is deployment-supplied and not known at build time, hence the
|
|
188
|
+
* `@vite-ignore` on the dynamic import). Throws a precise, actionable error when it can't be loaded so a
|
|
189
|
+
* misconfigured deployment fails loudly, not silently.
|
|
190
|
+
*
|
|
191
|
+
* VERIFY against the native LiveKit Node SDK wrapper: the module's default/namespace interop + that it
|
|
192
|
+
* exposes `createRoomClient`.
|
|
193
|
+
*/
|
|
194
|
+
export declare const defaultNativeLoader: NativeModuleLoader;
|
|
195
|
+
/**
|
|
196
|
+
* A **real, two-way** {@link ILiveKitRoomSdk} over the native LiveKit Node room SDK (publish + subscribe).
|
|
197
|
+
*
|
|
198
|
+
* Gives the agent both **hearing** (per-participant subscribed audio → diarized {@link LiveKitAudioFrame}s)
|
|
199
|
+
* and a **voice** ({@link publishAudioFrame} → the native publish path), plus working video/screen publish,
|
|
200
|
+
* the data-channel chat, and roster events. Construct via {@link BindLiveKitNative} (the factory the
|
|
201
|
+
* bridge's `SetSdkFactory` wants), not directly, so config resolution + the lazy loader wire consistently.
|
|
202
|
+
*/
|
|
203
|
+
export declare class LiveKitNativeMeetingSdk implements ILiveKitRoomSdk {
|
|
204
|
+
/** Resolved config (credentials + the native module specifier). */
|
|
205
|
+
private readonly config;
|
|
206
|
+
/** The native-module loader (overridable for tests). */
|
|
207
|
+
private readonly loadModule;
|
|
208
|
+
/** The live native room client once {@link connect} succeeds. */
|
|
209
|
+
private client;
|
|
210
|
+
/** The inbound per-participant audio handler registered by the bridge. */
|
|
211
|
+
private audioHandler?;
|
|
212
|
+
/** The participant-join handler. */
|
|
213
|
+
private joinHandler?;
|
|
214
|
+
/** The participant-leave handler. */
|
|
215
|
+
private leaveHandler?;
|
|
216
|
+
/** The room-disconnected handler. */
|
|
217
|
+
private disconnectedHandler?;
|
|
218
|
+
/**
|
|
219
|
+
* @param config Resolved credentials + the native module specifier.
|
|
220
|
+
* @param loadModule The native-module loader (defaults to the lazy specifier loader).
|
|
221
|
+
*/
|
|
222
|
+
constructor(config: LiveKitNativeSdkConfig, loadModule?: NativeModuleLoader);
|
|
223
|
+
/**
|
|
224
|
+
* Loads the native module, constructs a room client, wires its callbacks, and connects to the room
|
|
225
|
+
* with the resolved access token. Brings BOTH hearing and the agent's voice online.
|
|
226
|
+
*
|
|
227
|
+
* @param args The bridge's connect args (room ws URL, signed access token, bot name).
|
|
228
|
+
* @returns The bot/room identifiers.
|
|
229
|
+
* @throws When the native module specifier is missing or the module can't be loaded.
|
|
230
|
+
*/
|
|
231
|
+
connect(args: LiveKitConnectArgs): Promise<LiveKitConnectResult>;
|
|
232
|
+
/** Disconnects from the room and releases the native client. Tolerant of teardown errors. */
|
|
233
|
+
disconnect(): Promise<void>;
|
|
234
|
+
/**
|
|
235
|
+
* Publishes one raw PCM frame on the bot's audio track — **the agent's real voice into the room**, via
|
|
236
|
+
* the native publish path. No-ops (without throwing) before {@link connect} so an early model frame
|
|
237
|
+
* never crashes the session.
|
|
238
|
+
*
|
|
239
|
+
* @param pcm The PCM audio bytes to publish into the room.
|
|
240
|
+
*/
|
|
241
|
+
publishAudioFrame(pcm: ArrayBuffer): void;
|
|
242
|
+
/** Flushes the agent's queued outbound audio (barge-in). No-ops before connect. */
|
|
243
|
+
flushOutboundAudio(): void;
|
|
244
|
+
/**
|
|
245
|
+
* Publishes one raw video frame on the bot's camera track via the native publish path. No-ops before
|
|
246
|
+
* {@link connect}.
|
|
247
|
+
*
|
|
248
|
+
* @param frame The video frame bytes to publish.
|
|
249
|
+
*/
|
|
250
|
+
publishVideoFrame(frame: ArrayBuffer): void;
|
|
251
|
+
/**
|
|
252
|
+
* Publishes one raw screen-share frame on the bot's screen track via the native publish path. No-ops
|
|
253
|
+
* before {@link connect}.
|
|
254
|
+
*
|
|
255
|
+
* @param frame The screen frame bytes to publish.
|
|
256
|
+
*/
|
|
257
|
+
publishScreenFrame(frame: ArrayBuffer): void;
|
|
258
|
+
/** Registers the inbound per-participant audio handler (the diarized hearing path). */
|
|
259
|
+
onAudioTrack(cb: (frame: LiveKitAudioFrame) => void): void;
|
|
260
|
+
/** Registers the participant-join handler. */
|
|
261
|
+
onParticipantJoin(cb: (participant: LiveKitParticipant) => void): void;
|
|
262
|
+
/** Registers the participant-leave handler. */
|
|
263
|
+
onParticipantLeave(cb: (participantIdentity: string) => void): void;
|
|
264
|
+
/** Returns the current roster from the native client, mapped to {@link LiveKitParticipant}. */
|
|
265
|
+
getParticipants(): Promise<LiveKitParticipant[]>;
|
|
266
|
+
/** Registers the room-disconnected handler. */
|
|
267
|
+
onDisconnected(cb: () => void): void;
|
|
268
|
+
/**
|
|
269
|
+
* Sends a reliable text message on the room data channel via the native client — the room-native
|
|
270
|
+
* "chat". No-ops (without throwing) before {@link connect}.
|
|
271
|
+
*
|
|
272
|
+
* @param text The data/chat message text.
|
|
273
|
+
*/
|
|
274
|
+
sendDataMessage(text: string): Promise<void>;
|
|
275
|
+
/** Wires the native client's callbacks to this adapter's handlers, mapping native shapes to the seam. */
|
|
276
|
+
private wireClient;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Builds the {@link import('./livekit-sdk.js').LiveKitRoomSdkFactory}-shaped factory that constructs a
|
|
280
|
+
* {@link LiveKitNativeMeetingSdk} from the bridge's per-session `Configuration`. Pass the result to
|
|
281
|
+
* `LiveKitBridge.SetSdkFactory(...)` so a deployment activates **two-way native LiveKit media** without
|
|
282
|
+
* code changes to the driver.
|
|
283
|
+
*
|
|
284
|
+
* Reads the ws URL / API key/secret / pre-signed token + bot name + the native module specifier out of
|
|
285
|
+
* the config map the engine passes at connect (credentials resolved upstream — **never inline secrets**).
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* // Where bridge drivers are configured (creds already resolved from the MJ credential system):
|
|
289
|
+
* bridge.SetSdkFactory(BindLiveKitNative());
|
|
290
|
+
*
|
|
291
|
+
* @param loadModule Optional native-module loader override (tests inject a fake; production omits it).
|
|
292
|
+
* @returns A factory `(config) => LiveKitNativeMeetingSdk`.
|
|
293
|
+
*/
|
|
294
|
+
export declare function BindLiveKitNative(loadModule?: NativeModuleLoader): (config?: Record<string, unknown>) => LiveKitNativeMeetingSdk;
|
|
295
|
+
/**
|
|
296
|
+
* Extracts a {@link LiveKitNativeSdkConfig} from the engine's loosely-typed `Configuration` map without
|
|
297
|
+
* ever widening to `any`. Each field is read + type-checked individually so a malformed config yields a
|
|
298
|
+
* clean, partially-resolved object (and {@link LiveKitNativeMeetingSdk.connect} then throws a precise
|
|
299
|
+
* error if the required specifier is absent) rather than a half-typed blob.
|
|
300
|
+
*/
|
|
301
|
+
export declare function readNativeConfig(config?: Record<string, unknown>): LiveKitNativeSdkConfig;
|
|
302
|
+
//# sourceMappingURL=livekit-native-sdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"livekit-native-sdk.d.ts","sourceRoot":"","sources":["../src/livekit-native-sdk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `LiveKitNativeMeetingSdk` — a **real, two-way** {@link ILiveKitRoomSdk} binding over the
|
|
3
|
+
* **native LiveKit server/agents SDK** (the Node room-participant build: `livekit-server-sdk` for token
|
|
4
|
+
* minting + admin, plus a room client such as `@livekit/rtc-node` that publishes/subscribes media). It
|
|
5
|
+
* gives the agent both **hearing** (each remote participant's subscribed audio track → a diarized
|
|
6
|
+
* {@link LiveKitAudioFrame}) and a **voice** ({@link publishAudioFrame} forwards the agent's synthesized
|
|
7
|
+
* PCM onto the bot's published audio track), plus full video/screen publish and the data-channel "chat".
|
|
8
|
+
*
|
|
9
|
+
* ## Why a native binding
|
|
10
|
+
* Publishing audio *into* a LiveKit room requires a real WebRTC participant — there is no receive-only
|
|
11
|
+
* shortcut as there is for some 3rd-party platforms. The native LiveKit room client exposes a
|
|
12
|
+
* publish-track **send** path alongside per-participant subscribed-track **receive** callbacks, so a
|
|
13
|
+
* single binding carries **bidirectional** media. This is the binding a two-way "agent talks in the
|
|
14
|
+
* room" deployment uses.
|
|
15
|
+
*
|
|
16
|
+
* ## The native module seam (no SDK types leak)
|
|
17
|
+
* The real LiveKit Node SDK is loaded **lazily** behind an injectable {@link NativeModuleLoader}, so this
|
|
18
|
+
* package builds and unit-tests with **no SDK installed and no network**. The adapter depends ONLY on the
|
|
19
|
+
* small structural {@link NativeRoomModule} / {@link NativeRoomClient} surface declared below — none of
|
|
20
|
+
* LiveKit's real types leak into the package. Tests inject a fake module; production points
|
|
21
|
+
* {@link LiveKitNativeSdkConfig.NativeModuleSpecifier} at the real room-client wrapper.
|
|
22
|
+
*
|
|
23
|
+
* ## Auth (deployment responsibility)
|
|
24
|
+
* The bot joins with a signed LiveKit **access token** (room name + grants) minted upstream by MJ's
|
|
25
|
+
* token/credential layer from the API **key/secret**. The ws URL + key/secret resolve **upstream** (MJ
|
|
26
|
+
* credential system / provider `Configuration`) and are **never inlined** at a call site. When a
|
|
27
|
+
* pre-signed token is supplied via {@link LiveKitConnectArgs.AccessToken} the adapter forwards it; when a
|
|
28
|
+
* deployment lets the native module mint the token, the resolved key/secret + ws URL are handed to
|
|
29
|
+
* {@link NativeRoomModule.createRoomClient}.
|
|
30
|
+
*
|
|
31
|
+
* Every spot where the native module's exact surface is assumed carries a `// VERIFY against the native
|
|
32
|
+
* LiveKit Node SDK wrapper` note so a live test can confirm it.
|
|
33
|
+
*
|
|
34
|
+
* @module @memberjunction/ai-bridge-livekit
|
|
35
|
+
* @author MemberJunction.com
|
|
36
|
+
*/
|
|
37
|
+
import { LogError } from '@memberjunction/core';
|
|
38
|
+
/** Normalizes the native client's free-form role string onto the seam's {@link LiveKitParticipantRole}. */
|
|
39
|
+
export function mapNativeRole(role) {
|
|
40
|
+
switch ((role ?? '').trim().toLowerCase()) {
|
|
41
|
+
case 'host':
|
|
42
|
+
return 'Host';
|
|
43
|
+
case 'cohost':
|
|
44
|
+
case 'co-host':
|
|
45
|
+
return 'CoHost';
|
|
46
|
+
default:
|
|
47
|
+
return 'Participant';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* **Pure mapping** of one native participant onto the seam's {@link LiveKitParticipant}. Isolated from the
|
|
52
|
+
* native client and from I/O so it is unit-tested directly.
|
|
53
|
+
*/
|
|
54
|
+
export function mapNativeParticipant(p) {
|
|
55
|
+
return {
|
|
56
|
+
Identity: String(p.identity),
|
|
57
|
+
DisplayName: p.name,
|
|
58
|
+
Role: mapNativeRole(p.role),
|
|
59
|
+
IsLocal: p.isLocal,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Coerces a `Uint8Array` view or `ArrayBuffer` into a standalone `ArrayBuffer`, **copying** the exact
|
|
64
|
+
* window of a view (so the result never aliases a larger backing buffer). The LiveKit package has no
|
|
65
|
+
* pre-existing PCM-coercion helper to reuse, so this is defined here; it is the single such export.
|
|
66
|
+
*/
|
|
67
|
+
export function toArrayBuffer(data) {
|
|
68
|
+
if (data instanceof ArrayBuffer) {
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
const copy = new Uint8Array(data.byteLength);
|
|
72
|
+
copy.set(data);
|
|
73
|
+
return copy.buffer;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* **Pure mapping** of one native inbound audio frame onto the seam's diarized {@link LiveKitAudioFrame}.
|
|
77
|
+
* Copies the PCM (see {@link toArrayBuffer}) and resolves the speaker label. Isolated for direct testing.
|
|
78
|
+
*/
|
|
79
|
+
export function mapNativeAudioFrame(frame) {
|
|
80
|
+
return {
|
|
81
|
+
Pcm: toArrayBuffer(frame.data),
|
|
82
|
+
ParticipantIdentity: String(frame.participantIdentity),
|
|
83
|
+
DisplayName: frame.name,
|
|
84
|
+
TimestampMs: typeof frame.timestampMs === 'number' ? frame.timestampMs : Date.now(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Structural guard: a value is a {@link NativeRoomModule} when it exposes a `createRoomClient` function. */
|
|
88
|
+
function isNativeModule(value) {
|
|
89
|
+
return (value != null &&
|
|
90
|
+
typeof value === 'object' &&
|
|
91
|
+
typeof value.createRoomClient === 'function');
|
|
92
|
+
}
|
|
93
|
+
/** Unwraps a `{ default }` interop wrapper (CJS-with-default), returning the inner value or the input. */
|
|
94
|
+
function unwrapDefault(mod) {
|
|
95
|
+
if (mod && typeof mod === 'object' && 'default' in mod) {
|
|
96
|
+
const inner = mod.default;
|
|
97
|
+
if (isNativeModule(inner)) {
|
|
98
|
+
return inner;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return mod;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Lazily loads the native LiveKit room module at the given specifier (category: runtime plugin discovery
|
|
105
|
+
* from config — the wrapper path is deployment-supplied and not known at build time, hence the
|
|
106
|
+
* `@vite-ignore` on the dynamic import). Throws a precise, actionable error when it can't be loaded so a
|
|
107
|
+
* misconfigured deployment fails loudly, not silently.
|
|
108
|
+
*
|
|
109
|
+
* VERIFY against the native LiveKit Node SDK wrapper: the module's default/namespace interop + that it
|
|
110
|
+
* exposes `createRoomClient`.
|
|
111
|
+
*/
|
|
112
|
+
export const defaultNativeLoader = async (specifier) => {
|
|
113
|
+
try {
|
|
114
|
+
const mod = await import(/* @vite-ignore */ specifier);
|
|
115
|
+
const resolved = unwrapDefault(mod);
|
|
116
|
+
if (!isNativeModule(resolved)) {
|
|
117
|
+
throw new Error('resolved module has no createRoomClient() factory');
|
|
118
|
+
}
|
|
119
|
+
return resolved;
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
123
|
+
throw new Error(`LiveKitNativeMeetingSdk could not load the native LiveKit room module at '${specifier}'. Build/install ` +
|
|
124
|
+
'the native LiveKit Node room-client wrapper (livekit-server-sdk + a room client like @livekit/rtc-node) ' +
|
|
125
|
+
`and set LiveKitNativeSdkConfig.NativeModuleSpecifier to it. Underlying error: ${message}`);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* A **real, two-way** {@link ILiveKitRoomSdk} over the native LiveKit Node room SDK (publish + subscribe).
|
|
130
|
+
*
|
|
131
|
+
* Gives the agent both **hearing** (per-participant subscribed audio → diarized {@link LiveKitAudioFrame}s)
|
|
132
|
+
* and a **voice** ({@link publishAudioFrame} → the native publish path), plus working video/screen publish,
|
|
133
|
+
* the data-channel chat, and roster events. Construct via {@link BindLiveKitNative} (the factory the
|
|
134
|
+
* bridge's `SetSdkFactory` wants), not directly, so config resolution + the lazy loader wire consistently.
|
|
135
|
+
*/
|
|
136
|
+
export class LiveKitNativeMeetingSdk {
|
|
137
|
+
/**
|
|
138
|
+
* @param config Resolved credentials + the native module specifier.
|
|
139
|
+
* @param loadModule The native-module loader (defaults to the lazy specifier loader).
|
|
140
|
+
*/
|
|
141
|
+
constructor(config, loadModule = defaultNativeLoader) {
|
|
142
|
+
/** The live native room client once {@link connect} succeeds. */
|
|
143
|
+
this.client = null;
|
|
144
|
+
this.config = config;
|
|
145
|
+
this.loadModule = loadModule;
|
|
146
|
+
}
|
|
147
|
+
// ── ILiveKitRoomSdk — lifecycle ──────────────────────────────────────────────────
|
|
148
|
+
/**
|
|
149
|
+
* Loads the native module, constructs a room client, wires its callbacks, and connects to the room
|
|
150
|
+
* with the resolved access token. Brings BOTH hearing and the agent's voice online.
|
|
151
|
+
*
|
|
152
|
+
* @param args The bridge's connect args (room ws URL, signed access token, bot name).
|
|
153
|
+
* @returns The bot/room identifiers.
|
|
154
|
+
* @throws When the native module specifier is missing or the module can't be loaded.
|
|
155
|
+
*/
|
|
156
|
+
async connect(args) {
|
|
157
|
+
const specifier = this.config.NativeModuleSpecifier;
|
|
158
|
+
if (!specifier) {
|
|
159
|
+
throw new Error('LiveKitNativeMeetingSdk.connect: no NativeModuleSpecifier configured. Set it to the native LiveKit ' +
|
|
160
|
+
'Node room-client wrapper in the session Configuration. See the README.');
|
|
161
|
+
}
|
|
162
|
+
const mod = await this.loadModule(specifier);
|
|
163
|
+
const client = mod.createRoomClient({
|
|
164
|
+
Url: args.RoomUrl || this.config.Url,
|
|
165
|
+
ApiKey: this.config.ApiKey,
|
|
166
|
+
ApiSecret: this.config.ApiSecret,
|
|
167
|
+
// The model's audio format (threaded from IRealtimeSession via the engine) — so inbound room
|
|
168
|
+
// audio is resampled to what the model consumes (OpenAI 24 kHz; Gemini Live 16 kHz).
|
|
169
|
+
InboundSampleRate: this.config.InboundSampleRate,
|
|
170
|
+
OutboundSampleRate: this.config.OutboundSampleRate,
|
|
171
|
+
});
|
|
172
|
+
this.wireClient(client);
|
|
173
|
+
const result = await client.connect({
|
|
174
|
+
url: args.RoomUrl || this.config.Url || '',
|
|
175
|
+
token: args.AccessToken || this.config.AccessToken || '',
|
|
176
|
+
name: args.BotDisplayName || this.config.BotDisplayName || 'AI Agent',
|
|
177
|
+
});
|
|
178
|
+
this.client = client;
|
|
179
|
+
return {
|
|
180
|
+
BotIdentity: String(result.localIdentity),
|
|
181
|
+
RoomName: result.roomName,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/** Disconnects from the room and releases the native client. Tolerant of teardown errors. */
|
|
185
|
+
async disconnect() {
|
|
186
|
+
const client = this.client;
|
|
187
|
+
this.client = null;
|
|
188
|
+
if (client) {
|
|
189
|
+
try {
|
|
190
|
+
await client.disconnect();
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
LogError(`[LiveKitNativeMeetingSdk] disconnect() failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ── ILiveKitRoomSdk — two-way media (real) ───────────────────────────────────────
|
|
198
|
+
/**
|
|
199
|
+
* Publishes one raw PCM frame on the bot's audio track — **the agent's real voice into the room**, via
|
|
200
|
+
* the native publish path. No-ops (without throwing) before {@link connect} so an early model frame
|
|
201
|
+
* never crashes the session.
|
|
202
|
+
*
|
|
203
|
+
* @param pcm The PCM audio bytes to publish into the room.
|
|
204
|
+
*/
|
|
205
|
+
publishAudioFrame(pcm) {
|
|
206
|
+
this.client?.publishAudio(pcm);
|
|
207
|
+
}
|
|
208
|
+
/** Flushes the agent's queued outbound audio (barge-in). No-ops before connect. */
|
|
209
|
+
flushOutboundAudio() {
|
|
210
|
+
this.client?.flushOutbound();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Publishes one raw video frame on the bot's camera track via the native publish path. No-ops before
|
|
214
|
+
* {@link connect}.
|
|
215
|
+
*
|
|
216
|
+
* @param frame The video frame bytes to publish.
|
|
217
|
+
*/
|
|
218
|
+
publishVideoFrame(frame) {
|
|
219
|
+
this.client?.publishVideo(frame);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Publishes one raw screen-share frame on the bot's screen track via the native publish path. No-ops
|
|
223
|
+
* before {@link connect}.
|
|
224
|
+
*
|
|
225
|
+
* @param frame The screen frame bytes to publish.
|
|
226
|
+
*/
|
|
227
|
+
publishScreenFrame(frame) {
|
|
228
|
+
this.client?.publishScreen(frame);
|
|
229
|
+
}
|
|
230
|
+
/** Registers the inbound per-participant audio handler (the diarized hearing path). */
|
|
231
|
+
onAudioTrack(cb) {
|
|
232
|
+
this.audioHandler = cb;
|
|
233
|
+
}
|
|
234
|
+
// ── ILiveKitRoomSdk — roster + signals ───────────────────────────────────────────
|
|
235
|
+
/** Registers the participant-join handler. */
|
|
236
|
+
onParticipantJoin(cb) {
|
|
237
|
+
this.joinHandler = cb;
|
|
238
|
+
}
|
|
239
|
+
/** Registers the participant-leave handler. */
|
|
240
|
+
onParticipantLeave(cb) {
|
|
241
|
+
this.leaveHandler = cb;
|
|
242
|
+
}
|
|
243
|
+
/** Returns the current roster from the native client, mapped to {@link LiveKitParticipant}. */
|
|
244
|
+
async getParticipants() {
|
|
245
|
+
if (!this.client) {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
const natives = await this.client.getParticipants();
|
|
249
|
+
return natives.map(mapNativeParticipant);
|
|
250
|
+
}
|
|
251
|
+
/** Registers the room-disconnected handler. */
|
|
252
|
+
onDisconnected(cb) {
|
|
253
|
+
this.disconnectedHandler = cb;
|
|
254
|
+
}
|
|
255
|
+
// ── ILiveKitRoomSdk — data channel (real) ────────────────────────────────────────
|
|
256
|
+
/**
|
|
257
|
+
* Sends a reliable text message on the room data channel via the native client — the room-native
|
|
258
|
+
* "chat". No-ops (without throwing) before {@link connect}.
|
|
259
|
+
*
|
|
260
|
+
* @param text The data/chat message text.
|
|
261
|
+
*/
|
|
262
|
+
async sendDataMessage(text) {
|
|
263
|
+
await this.client?.publishData(text);
|
|
264
|
+
}
|
|
265
|
+
// ── internals ────────────────────────────────────────────────────────────────────
|
|
266
|
+
/** Wires the native client's callbacks to this adapter's handlers, mapping native shapes to the seam. */
|
|
267
|
+
wireClient(client) {
|
|
268
|
+
client.onAudioFrame((frame) => this.audioHandler?.(mapNativeAudioFrame(frame)));
|
|
269
|
+
client.onParticipantConnected((p) => this.joinHandler?.(mapNativeParticipant(p)));
|
|
270
|
+
client.onParticipantDisconnected((id) => this.leaveHandler?.(String(id)));
|
|
271
|
+
client.onDisconnected(() => this.disconnectedHandler?.());
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Builds the {@link import('./livekit-sdk.js').LiveKitRoomSdkFactory}-shaped factory that constructs a
|
|
276
|
+
* {@link LiveKitNativeMeetingSdk} from the bridge's per-session `Configuration`. Pass the result to
|
|
277
|
+
* `LiveKitBridge.SetSdkFactory(...)` so a deployment activates **two-way native LiveKit media** without
|
|
278
|
+
* code changes to the driver.
|
|
279
|
+
*
|
|
280
|
+
* Reads the ws URL / API key/secret / pre-signed token + bot name + the native module specifier out of
|
|
281
|
+
* the config map the engine passes at connect (credentials resolved upstream — **never inline secrets**).
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* // Where bridge drivers are configured (creds already resolved from the MJ credential system):
|
|
285
|
+
* bridge.SetSdkFactory(BindLiveKitNative());
|
|
286
|
+
*
|
|
287
|
+
* @param loadModule Optional native-module loader override (tests inject a fake; production omits it).
|
|
288
|
+
* @returns A factory `(config) => LiveKitNativeMeetingSdk`.
|
|
289
|
+
*/
|
|
290
|
+
export function BindLiveKitNative(loadModule = defaultNativeLoader) {
|
|
291
|
+
return (config) => new LiveKitNativeMeetingSdk(readNativeConfig(config), loadModule);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Extracts a {@link LiveKitNativeSdkConfig} from the engine's loosely-typed `Configuration` map without
|
|
295
|
+
* ever widening to `any`. Each field is read + type-checked individually so a malformed config yields a
|
|
296
|
+
* clean, partially-resolved object (and {@link LiveKitNativeMeetingSdk.connect} then throws a precise
|
|
297
|
+
* error if the required specifier is absent) rather than a half-typed blob.
|
|
298
|
+
*/
|
|
299
|
+
export function readNativeConfig(config) {
|
|
300
|
+
const cfg = config ?? {};
|
|
301
|
+
return {
|
|
302
|
+
Url: readString(cfg.Url),
|
|
303
|
+
ApiKey: readString(cfg.ApiKey),
|
|
304
|
+
ApiSecret: readString(cfg.ApiSecret),
|
|
305
|
+
AccessToken: readString(cfg.AccessToken),
|
|
306
|
+
BotDisplayName: readString(cfg.BotDisplayName),
|
|
307
|
+
NativeModuleSpecifier: readString(cfg.NativeModuleSpecifier),
|
|
308
|
+
InboundSampleRate: readNumber(cfg.InboundSampleRate),
|
|
309
|
+
OutboundSampleRate: readNumber(cfg.OutboundSampleRate),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/** Reads a value as a non-empty string, or `undefined`. */
|
|
313
|
+
function readString(value) {
|
|
314
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
315
|
+
}
|
|
316
|
+
/** Reads a positive finite number from a free-form config value, or `undefined`. */
|
|
317
|
+
function readNumber(value) {
|
|
318
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=livekit-native-sdk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"livekit-native-sdk.js","sourceRoot":"","sources":["../src/livekit-native-sdk.ts"],"names":[],"mappings":"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"}
|
package/dist/livekit-sdk.d.ts
CHANGED
|
@@ -113,6 +113,11 @@ export interface ILiveKitRoomSdk {
|
|
|
113
113
|
* @param pcm The PCM audio bytes to publish.
|
|
114
114
|
*/
|
|
115
115
|
publishAudioFrame(pcm: ArrayBuffer): void;
|
|
116
|
+
/**
|
|
117
|
+
* Flushes all pending/queued outbound audio (the agent's voice). Called on barge-in so the agent
|
|
118
|
+
* stops talking immediately instead of draining already-buffered audio after the model is cut off.
|
|
119
|
+
*/
|
|
120
|
+
flushOutboundAudio(): void;
|
|
116
121
|
/**
|
|
117
122
|
* Subscribes inbound per-participant audio frames (what the agent hears, carrying the speaker
|
|
118
123
|
* identity for diarization). "Latest handler wins." The SFU never echoes the bot's own published
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"livekit-sdk.d.ts","sourceRoot":"","sources":["../src/livekit-sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,0FAA0F;AAC1F,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEvE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B,oGAAoG;IACpG,QAAQ,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,IAAI,EAAE,sBAAsB,CAAC;IAC7B,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,0CAA0C;IAC1C,GAAG,EAAE,WAAW,CAAC;IACjB,6FAA6F;IAC7F,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,mGAAmG;AACnG,MAAM,WAAW,kBAAkB;IAC/B,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,uFAAuF;AACvF,MAAM,WAAW,oBAAoB;IACjC,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjE,4DAA4D;IAC5D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;;OAIG;IACH,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IAE1C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAE5C;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI,CAAC;IAEvE;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAEpE;;;;OAIG;IACH,eAAe,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACxC;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"livekit-sdk.d.ts","sourceRoot":"","sources":["../src/livekit-sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,0FAA0F;AAC1F,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEvE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B,oGAAoG;IACpG,QAAQ,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,IAAI,EAAE,sBAAsB,CAAC;IAC7B,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,0CAA0C;IAC1C,GAAG,EAAE,WAAW,CAAC;IACjB,6FAA6F;IAC7F,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,mGAAmG;AACnG,MAAM,WAAW,kBAAkB;IAC/B,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,uFAAuF;AACvF,MAAM,WAAW,oBAAoB;IACjC,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjE,4DAA4D;IAC5D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;;OAIG;IACH,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IAE1C;;;OAGG;IACH,kBAAkB,IAAI,IAAI,CAAC;IAE3B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAE5C;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI,CAAC;IAEvE;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAEpE;;;;OAIG;IACH,eAAe,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACxC;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,eAAe,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Registers the LiveKit **native two-way** SDK binding into the {@link BridgeNativeSdkRegistry}
|
|
3
|
+
* so `AIBridgeEngine.StartBridgeSession` auto-binds it onto a resolved `LiveKitBridge` before connect — no
|
|
4
|
+
* per-deployment wiring needed. The typed downcast + `SetSdkFactory` stay confined here (where the concrete
|
|
5
|
+
* `LiveKitBridge` type is known), keeping the engine seam free of provider types.
|
|
6
|
+
*
|
|
7
|
+
* A host can still override per-session via `StartBridgeSessionParams.BindSdk` — e.g. to inject a fake in a
|
|
8
|
+
* test instead of the native two-way default.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/ai-bridge-livekit
|
|
11
|
+
* @author MemberJunction.com
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Registers LiveKit's native two-way binding. Idempotent (latest-wins in the registry), and invoked from the
|
|
15
|
+
* package `index.ts` so merely importing `@memberjunction/ai-bridge-livekit` wires the default binding. Also
|
|
16
|
+
* exported as a tree-shake-safe no-op-returning function callers can reference to force-retain the module.
|
|
17
|
+
*/
|
|
18
|
+
export declare function RegisterLiveKitNativeSdk(): void;
|
|
19
|
+
//# sourceMappingURL=register-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-native.d.ts","sourceRoot":"","sources":["../src/register-native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAO/C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Registers the LiveKit **native two-way** SDK binding into the {@link BridgeNativeSdkRegistry}
|
|
3
|
+
* so `AIBridgeEngine.StartBridgeSession` auto-binds it onto a resolved `LiveKitBridge` before connect — no
|
|
4
|
+
* per-deployment wiring needed. The typed downcast + `SetSdkFactory` stay confined here (where the concrete
|
|
5
|
+
* `LiveKitBridge` type is known), keeping the engine seam free of provider types.
|
|
6
|
+
*
|
|
7
|
+
* A host can still override per-session via `StartBridgeSessionParams.BindSdk` — e.g. to inject a fake in a
|
|
8
|
+
* test instead of the native two-way default.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/ai-bridge-livekit
|
|
11
|
+
* @author MemberJunction.com
|
|
12
|
+
*/
|
|
13
|
+
import { BridgeNativeSdkRegistry } from '@memberjunction/ai-bridge-base';
|
|
14
|
+
import { BindLiveKitNative } from './livekit-native-sdk.js';
|
|
15
|
+
/** The `MJ: AI Bridge Providers.DriverClass` value the LiveKit provider row carries. */
|
|
16
|
+
const LIVEKIT_DRIVER_CLASS = 'LiveKitBridge';
|
|
17
|
+
/**
|
|
18
|
+
* Registers LiveKit's native two-way binding. Idempotent (latest-wins in the registry), and invoked from the
|
|
19
|
+
* package `index.ts` so merely importing `@memberjunction/ai-bridge-livekit` wires the default binding. Also
|
|
20
|
+
* exported as a tree-shake-safe no-op-returning function callers can reference to force-retain the module.
|
|
21
|
+
*/
|
|
22
|
+
export function RegisterLiveKitNativeSdk() {
|
|
23
|
+
BridgeNativeSdkRegistry.Instance.Register(LIVEKIT_DRIVER_CLASS, (driver) => {
|
|
24
|
+
// Safe downcast: the registry is keyed by DriverClass, so the engine only ever applies this to the
|
|
25
|
+
// LiveKitBridge it resolved for 'LiveKitBridge'. BindLiveKitNative() defaults to the lazy native
|
|
26
|
+
// loader, which reads NativeModuleSpecifier from the per-session Configuration.
|
|
27
|
+
driver.SetSdkFactory(BindLiveKitNative());
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Register on import (mirrors the LoadLiveKitBridge() tree-shake pattern in index.ts).
|
|
31
|
+
RegisterLiveKitNativeSdk();
|
|
32
|
+
//# sourceMappingURL=register-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-native.js","sourceRoot":"","sources":["../src/register-native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gCAAgC,CAAC;AAE7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,wFAAwF;AACxF,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACpC,uBAAuB,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC,MAA0B,EAAE,EAAE;QAC3F,mGAAmG;QACnG,iGAAiG;QACjG,gFAAgF;QAC/E,MAAwB,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACP,CAAC;AAED,uFAAuF;AACvF,wBAAwB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ai-bridge-livekit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.42.0",
|
|
5
5
|
"description": "MemberJunction: LiveKit Realtime Bridge driver — the MJ-native multi-party room. Unlike the other bridges (which connect OUT to a 3rd-party meeting platform), LiveKit is a SELF-HOSTED WebRTC SFU that MJ runs itself. Connects the realtime agent engine to a LiveKit room as a bot participant (audio/video/screen in+out, per-participant diarization, data-channel chat) via an injectable LiveKit room SDK seam, and contributes a Meeting Controls facilitator channel.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"author": "MemberJunction.com",
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@memberjunction/core": "5.
|
|
21
|
-
"@memberjunction/global": "5.
|
|
22
|
-
"@memberjunction/core-entities": "5.
|
|
23
|
-
"@memberjunction/ai-bridge-base": "5.
|
|
20
|
+
"@memberjunction/core": "5.42.0",
|
|
21
|
+
"@memberjunction/global": "5.42.0",
|
|
22
|
+
"@memberjunction/core-entities": "5.42.0",
|
|
23
|
+
"@memberjunction/ai-bridge-base": "5.42.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "24.10.11",
|