@spatialwalk/avatarkit-rtc 1.0.0-beta.1
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 +417 -0
- package/dist/assets/animation-worker-CUXZycUw.js.map +1 -0
- package/dist/core/AnimationHandler.d.ts +17 -0
- package/dist/core/AnimationHandler.d.ts.map +1 -0
- package/dist/core/AvatarPlayer.d.ts +119 -0
- package/dist/core/AvatarPlayer.d.ts.map +1 -0
- package/dist/core/RTCProvider.d.ts +84 -0
- package/dist/core/RTCProvider.d.ts.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/index10.js +67 -0
- package/dist/index10.js.map +1 -0
- package/dist/index11.js +390 -0
- package/dist/index11.js.map +1 -0
- package/dist/index12.js +108 -0
- package/dist/index12.js.map +1 -0
- package/dist/index13.js +18 -0
- package/dist/index13.js.map +1 -0
- package/dist/index14.js +48 -0
- package/dist/index14.js.map +1 -0
- package/dist/index15.js +29 -0
- package/dist/index15.js.map +1 -0
- package/dist/index16.js +144 -0
- package/dist/index16.js.map +1 -0
- package/dist/index17.js +106 -0
- package/dist/index17.js.map +1 -0
- package/dist/index18.js +28 -0
- package/dist/index18.js.map +1 -0
- package/dist/index2.js +220 -0
- package/dist/index2.js.map +1 -0
- package/dist/index3.js +586 -0
- package/dist/index3.js.map +1 -0
- package/dist/index4.js +410 -0
- package/dist/index4.js.map +1 -0
- package/dist/index5.js +20 -0
- package/dist/index5.js.map +1 -0
- package/dist/index6.js +282 -0
- package/dist/index6.js.map +1 -0
- package/dist/index7.js +53 -0
- package/dist/index7.js.map +1 -0
- package/dist/index8.js +189 -0
- package/dist/index8.js.map +1 -0
- package/dist/index9.js +178 -0
- package/dist/index9.js.map +1 -0
- package/dist/proto/animation.d.ts +12 -0
- package/dist/proto/animation.d.ts.map +1 -0
- package/dist/providers/agora/AgoraProvider.d.ts +71 -0
- package/dist/providers/agora/AgoraProvider.d.ts.map +1 -0
- package/dist/providers/agora/SEIExtractor.d.ts +29 -0
- package/dist/providers/agora/SEIExtractor.d.ts.map +1 -0
- package/dist/providers/agora/index.d.ts +11 -0
- package/dist/providers/agora/index.d.ts.map +1 -0
- package/dist/providers/agora/types.d.ts +14 -0
- package/dist/providers/agora/types.d.ts.map +1 -0
- package/dist/providers/base/BaseProvider.d.ts +11 -0
- package/dist/providers/base/BaseProvider.d.ts.map +1 -0
- package/dist/providers/index.d.ts +10 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/livekit/LiveKitProvider.d.ts +64 -0
- package/dist/providers/livekit/LiveKitProvider.d.ts.map +1 -0
- package/dist/providers/livekit/VP8Extractor.d.ts +10 -0
- package/dist/providers/livekit/VP8Extractor.d.ts.map +1 -0
- package/dist/providers/livekit/animation-transform.d.ts +11 -0
- package/dist/providers/livekit/animation-transform.d.ts.map +1 -0
- package/dist/providers/livekit/animation-worker.d.ts +14 -0
- package/dist/providers/livekit/animation-worker.d.ts.map +1 -0
- package/dist/providers/livekit/index.d.ts +11 -0
- package/dist/providers/livekit/index.d.ts.map +1 -0
- package/dist/providers/livekit/types.d.ts +11 -0
- package/dist/providers/livekit/types.d.ts.map +1 -0
- package/dist/providers/livekit/utils.d.ts +11 -0
- package/dist/providers/livekit/utils.d.ts.map +1 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/package.json +61 -0
package/dist/index4.js
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { BaseProvider } from "./index10.js";
|
|
5
|
+
import { isAgoraConfig, ConnectionState } from "./index5.js";
|
|
6
|
+
import { SEIExtractor } from "./index11.js";
|
|
7
|
+
import { logger } from "./index7.js";
|
|
8
|
+
class AgoraProvider extends BaseProvider {
|
|
9
|
+
constructor(_options = {}) {
|
|
10
|
+
super();
|
|
11
|
+
/** Provider name identifier */
|
|
12
|
+
__publicField(this, "name", "agora");
|
|
13
|
+
/** @internal */
|
|
14
|
+
__publicField(this, "client", null);
|
|
15
|
+
/** @internal Dynamic SDK - type is any due to dynamic import */
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
__publicField(this, "agoraSDK", null);
|
|
18
|
+
// Animation track subscription (stored for cleanup, actual callbacks handled by SEIExtractor)
|
|
19
|
+
/** @internal */
|
|
20
|
+
__publicField(this, "_animationCallbacks", null);
|
|
21
|
+
/** @internal */
|
|
22
|
+
__publicField(this, "seiExtractor", null);
|
|
23
|
+
/** @internal */
|
|
24
|
+
__publicField(this, "remoteUsers", /* @__PURE__ */ new Map());
|
|
25
|
+
/** @internal */
|
|
26
|
+
__publicField(this, "videoContainers", /* @__PURE__ */ new Map());
|
|
27
|
+
// Audio track subscription
|
|
28
|
+
/** @internal */
|
|
29
|
+
__publicField(this, "audioCallbacks", null);
|
|
30
|
+
/** @internal */
|
|
31
|
+
__publicField(this, "localAudioTrack", null);
|
|
32
|
+
/** @internal */
|
|
33
|
+
__publicField(this, "remoteAudioTracks", /* @__PURE__ */ new Map());
|
|
34
|
+
// Debug mode
|
|
35
|
+
/** @internal */
|
|
36
|
+
__publicField(this, "debugLogging", false);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Enable or disable debug logging.
|
|
40
|
+
* @param enabled - Whether to enable debug logging
|
|
41
|
+
*/
|
|
42
|
+
setDebugLogging(enabled) {
|
|
43
|
+
this.debugLogging = enabled;
|
|
44
|
+
if (this.seiExtractor) {
|
|
45
|
+
this.seiExtractor.setDebugLogging(enabled);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Load Agora SDK dynamically.
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
async loadSDK() {
|
|
54
|
+
if (this.agoraSDK) {
|
|
55
|
+
return this.agoraSDK;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const sdk = await import("agora-rtc-sdk-ng");
|
|
59
|
+
this.agoraSDK = sdk.default ?? sdk;
|
|
60
|
+
return this.agoraSDK;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
logger.error("Agora", "Failed to load SDK:", error);
|
|
63
|
+
throw new Error(
|
|
64
|
+
"❌ Failed to load agora-rtc-sdk-ng.\nPlease ensure it is installed: pnpm add agora-rtc-sdk-ng"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async connect(config) {
|
|
69
|
+
if (!isAgoraConfig(config)) {
|
|
70
|
+
throw new Error("AgoraProvider requires appId and channel in connection config");
|
|
71
|
+
}
|
|
72
|
+
const agoraConfig = config;
|
|
73
|
+
const AgoraRTC = await this.loadSDK();
|
|
74
|
+
AgoraRTC.setParameter("ENABLE_VIDEO_SEI", true);
|
|
75
|
+
this.client = AgoraRTC.createClient({
|
|
76
|
+
mode: "rtc",
|
|
77
|
+
codec: "h264"
|
|
78
|
+
// Required for SEI support
|
|
79
|
+
});
|
|
80
|
+
this.setConnectionState("connecting");
|
|
81
|
+
this.setupEventListeners(AgoraRTC);
|
|
82
|
+
try {
|
|
83
|
+
await this.client.join(
|
|
84
|
+
agoraConfig.appId,
|
|
85
|
+
agoraConfig.channel,
|
|
86
|
+
agoraConfig.token || null,
|
|
87
|
+
agoraConfig.uid ?? null
|
|
88
|
+
);
|
|
89
|
+
this.setConnectionState("connected");
|
|
90
|
+
this.emit("connected");
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.setConnectionState("failed");
|
|
93
|
+
this.emit("error", error);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Setup Agora client event listeners
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
setupEventListeners(_AgoraRTC) {
|
|
102
|
+
this.client.on("connection-state-change", (curState, _revState) => {
|
|
103
|
+
const mapConnectionState = (state) => {
|
|
104
|
+
switch (state) {
|
|
105
|
+
case "DISCONNECTED":
|
|
106
|
+
case "DISCONNECTING":
|
|
107
|
+
return ConnectionState.Disconnected;
|
|
108
|
+
case "CONNECTING":
|
|
109
|
+
return ConnectionState.Connecting;
|
|
110
|
+
case "CONNECTED":
|
|
111
|
+
return ConnectionState.Connected;
|
|
112
|
+
case "RECONNECTING":
|
|
113
|
+
return ConnectionState.Reconnecting;
|
|
114
|
+
default:
|
|
115
|
+
return ConnectionState.Failed;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
this.setConnectionState(mapConnectionState(curState));
|
|
119
|
+
if (curState === "CONNECTED") {
|
|
120
|
+
this.emit("connected");
|
|
121
|
+
} else if (curState === "DISCONNECTED") {
|
|
122
|
+
this.cleanup();
|
|
123
|
+
this.emit("disconnected");
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
this.client.on("user-published", async (user, mediaType) => {
|
|
127
|
+
if (this.debugLogging) {
|
|
128
|
+
logger.info("Agora", `User published: ${user.uid}, mediaType=${mediaType}`);
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await this.client.subscribe(user, mediaType);
|
|
132
|
+
if (mediaType === "video") {
|
|
133
|
+
if (user.videoTrack) {
|
|
134
|
+
this.handleVideoTrack(user, user.videoTrack);
|
|
135
|
+
} else {
|
|
136
|
+
logger.warn("Agora", `Video track is null after subscribe for user ${user.uid}`);
|
|
137
|
+
}
|
|
138
|
+
} else if (mediaType === "audio") {
|
|
139
|
+
if (user.audioTrack) {
|
|
140
|
+
this.handleAudioTrack(user, user.audioTrack);
|
|
141
|
+
} else {
|
|
142
|
+
logger.warn("Agora", `Audio track is null after subscribe for user ${user.uid}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error("Agora", `Failed to subscribe to ${mediaType} from ${user.uid}:`, error);
|
|
147
|
+
this.emit("error", error);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
this.client.on("user-unpublished", (user, mediaType) => {
|
|
151
|
+
var _a, _b;
|
|
152
|
+
if (this.debugLogging) {
|
|
153
|
+
logger.info("Agora", `User unpublished: ${user.uid}, mediaType=${mediaType}`);
|
|
154
|
+
}
|
|
155
|
+
if (mediaType === "video") {
|
|
156
|
+
this.removeVideoContainer(user.uid);
|
|
157
|
+
this.remoteUsers.delete(user.uid);
|
|
158
|
+
} else if (mediaType === "audio") {
|
|
159
|
+
const track = this.remoteAudioTracks.get(user.uid);
|
|
160
|
+
if (track) {
|
|
161
|
+
track.stop();
|
|
162
|
+
this.remoteAudioTracks.delete(user.uid);
|
|
163
|
+
}
|
|
164
|
+
if (this.audioCallbacks) {
|
|
165
|
+
(_b = (_a = this.audioCallbacks).onAudioLost) == null ? void 0 : _b.call(_a, user);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
this.client.on("user-joined", (user) => {
|
|
170
|
+
logger.info("Agora", `User joined: ${user.uid}`);
|
|
171
|
+
});
|
|
172
|
+
this.client.on("user-left", (user, reason) => {
|
|
173
|
+
logger.info("Agora", `User left: ${user.uid}, reason: ${reason}`);
|
|
174
|
+
this.remoteUsers.delete(user.uid);
|
|
175
|
+
const audioTrack = this.remoteAudioTracks.get(user.uid);
|
|
176
|
+
if (audioTrack) {
|
|
177
|
+
audioTrack.stop();
|
|
178
|
+
this.remoteAudioTracks.delete(user.uid);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
this.client.on("exception", (error) => {
|
|
182
|
+
logger.error("Agora", "Exception:", error);
|
|
183
|
+
this.emit("error", new Error(error.msg || String(error)));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Handle video track from remote user.
|
|
188
|
+
* Sets up SEI event listeners and plays to hidden container.
|
|
189
|
+
* @internal
|
|
190
|
+
*/
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
192
|
+
handleVideoTrack(user, track) {
|
|
193
|
+
if (this.debugLogging) {
|
|
194
|
+
logger.info("Agora", `Handling video track from ${user.uid}`);
|
|
195
|
+
}
|
|
196
|
+
const seiHandler = (seiData) => {
|
|
197
|
+
if (this.seiExtractor) {
|
|
198
|
+
this.seiExtractor.handleSEIData(seiData);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
track.on("sei-received", seiHandler);
|
|
202
|
+
track.on("video-sei-received", seiHandler);
|
|
203
|
+
const container = document.createElement("div");
|
|
204
|
+
container.style.display = "none";
|
|
205
|
+
container.style.position = "absolute";
|
|
206
|
+
container.style.left = "-9999px";
|
|
207
|
+
container.id = `agora-video-${user.uid}`;
|
|
208
|
+
document.body.appendChild(container);
|
|
209
|
+
this.videoContainers.set(user.uid, container);
|
|
210
|
+
track.play(container);
|
|
211
|
+
if (this.debugLogging) {
|
|
212
|
+
logger.info("Agora", `Video track playing, SEI listeners attached for user ${user.uid}`);
|
|
213
|
+
}
|
|
214
|
+
const existingUser = this.remoteUsers.get(user.uid);
|
|
215
|
+
if (existingUser) {
|
|
216
|
+
existingUser.videoTrack = track;
|
|
217
|
+
} else {
|
|
218
|
+
this.remoteUsers.set(user.uid, { videoTrack: track });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Handle audio track from remote user.
|
|
223
|
+
* @internal
|
|
224
|
+
*/
|
|
225
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
226
|
+
handleAudioTrack(user, track) {
|
|
227
|
+
var _a, _b;
|
|
228
|
+
if (this.debugLogging) {
|
|
229
|
+
logger.info("Agora", `Handling audio track from ${user.uid}`);
|
|
230
|
+
}
|
|
231
|
+
track.play();
|
|
232
|
+
this.remoteAudioTracks.set(user.uid, track);
|
|
233
|
+
if (this.debugLogging) {
|
|
234
|
+
logger.info("Agora", `Audio track playing for user ${user.uid}`);
|
|
235
|
+
}
|
|
236
|
+
if (this.audioCallbacks) {
|
|
237
|
+
(_b = (_a = this.audioCallbacks).onAudioReceived) == null ? void 0 : _b.call(_a, user);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Remove video container for a user.
|
|
242
|
+
* @internal
|
|
243
|
+
*/
|
|
244
|
+
removeVideoContainer(uid) {
|
|
245
|
+
const container = this.videoContainers.get(uid);
|
|
246
|
+
if (container) {
|
|
247
|
+
container.remove();
|
|
248
|
+
this.videoContainers.delete(uid);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async disconnect() {
|
|
252
|
+
this.cleanup();
|
|
253
|
+
if (this.client) {
|
|
254
|
+
await this.client.leave();
|
|
255
|
+
this.client = null;
|
|
256
|
+
}
|
|
257
|
+
this.setConnectionState("disconnected");
|
|
258
|
+
this.emit("disconnected");
|
|
259
|
+
}
|
|
260
|
+
getConnectionState() {
|
|
261
|
+
if (!this.client) {
|
|
262
|
+
return "disconnected";
|
|
263
|
+
}
|
|
264
|
+
return this.connectionState;
|
|
265
|
+
}
|
|
266
|
+
async subscribeAnimationTrack(callbacks) {
|
|
267
|
+
this._animationCallbacks = callbacks;
|
|
268
|
+
this.seiExtractor = new SEIExtractor();
|
|
269
|
+
this.seiExtractor.setDebugLogging(this.debugLogging);
|
|
270
|
+
this.seiExtractor.initialize(callbacks);
|
|
271
|
+
if (this.client) {
|
|
272
|
+
const remoteUsers = this.client.remoteUsers;
|
|
273
|
+
for (const user of remoteUsers) {
|
|
274
|
+
if (user.videoTrack) {
|
|
275
|
+
const seiHandler = (seiData) => {
|
|
276
|
+
if (this.seiExtractor) {
|
|
277
|
+
this.seiExtractor.handleSEIData(seiData);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
user.videoTrack.on("sei-received", seiHandler);
|
|
281
|
+
user.videoTrack.on("video-sei-received", seiHandler);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async unsubscribeAnimationTrack() {
|
|
287
|
+
this._animationCallbacks = null;
|
|
288
|
+
if (this.seiExtractor) {
|
|
289
|
+
this.seiExtractor.dispose();
|
|
290
|
+
this.seiExtractor = null;
|
|
291
|
+
}
|
|
292
|
+
for (const [uid, user] of this.remoteUsers) {
|
|
293
|
+
const videoTrack = user.videoTrack;
|
|
294
|
+
if (videoTrack) {
|
|
295
|
+
videoTrack.off("sei-received");
|
|
296
|
+
videoTrack.off("video-sei-received");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
for (const [uid] of this.videoContainers) {
|
|
300
|
+
this.removeVideoContainer(uid);
|
|
301
|
+
}
|
|
302
|
+
this.remoteUsers.clear();
|
|
303
|
+
}
|
|
304
|
+
async subscribeAudioTrack(callbacks) {
|
|
305
|
+
this.audioCallbacks = callbacks;
|
|
306
|
+
}
|
|
307
|
+
async unsubscribeAudioTrack() {
|
|
308
|
+
this.audioCallbacks = null;
|
|
309
|
+
this.remoteAudioTracks.forEach((track) => {
|
|
310
|
+
track.stop();
|
|
311
|
+
});
|
|
312
|
+
this.remoteAudioTracks.clear();
|
|
313
|
+
}
|
|
314
|
+
async publishAudioTrack(track) {
|
|
315
|
+
if (!this.client) {
|
|
316
|
+
throw new Error("Not connected to channel");
|
|
317
|
+
}
|
|
318
|
+
const AgoraRTC = await this.loadSDK();
|
|
319
|
+
if (track) {
|
|
320
|
+
this.localAudioTrack = AgoraRTC.createCustomAudioTrack({
|
|
321
|
+
mediaStreamTrack: track
|
|
322
|
+
});
|
|
323
|
+
} else {
|
|
324
|
+
this.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack({
|
|
325
|
+
encoderConfig: "music_standard",
|
|
326
|
+
AEC: true,
|
|
327
|
+
ANS: true,
|
|
328
|
+
AGC: true
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
await this.client.publish(this.localAudioTrack);
|
|
332
|
+
}
|
|
333
|
+
async unpublishAudioTrack() {
|
|
334
|
+
if (!this.client || !this.localAudioTrack) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
await this.client.unpublish(this.localAudioTrack);
|
|
338
|
+
this.localAudioTrack.close();
|
|
339
|
+
this.localAudioTrack = null;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Play remote audio (resume playback)
|
|
343
|
+
*/
|
|
344
|
+
playRemoteAudio() {
|
|
345
|
+
this.remoteAudioTracks.forEach((track) => {
|
|
346
|
+
track.play();
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Pause remote audio
|
|
351
|
+
*/
|
|
352
|
+
pauseRemoteAudio() {
|
|
353
|
+
this.remoteAudioTracks.forEach((track) => {
|
|
354
|
+
track.stop();
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Get the native Agora RTC Client instance.
|
|
359
|
+
*
|
|
360
|
+
* Allows advanced users to access Agora-specific features
|
|
361
|
+
* not exposed through the unified API.
|
|
362
|
+
*
|
|
363
|
+
* @returns The Agora IAgoraRTCClient instance, or null if not connected
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```typescript
|
|
367
|
+
* const client = provider.getNativeClient();
|
|
368
|
+
* if (client) {
|
|
369
|
+
* // Access Agora-specific features
|
|
370
|
+
* console.log('Connection state:', client.connectionState);
|
|
371
|
+
* }
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
getNativeClient() {
|
|
375
|
+
return this.client;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Cleanup resources
|
|
379
|
+
* @internal
|
|
380
|
+
*/
|
|
381
|
+
cleanup() {
|
|
382
|
+
this.remoteAudioTracks.forEach((track) => {
|
|
383
|
+
track.stop();
|
|
384
|
+
});
|
|
385
|
+
this.remoteAudioTracks.clear();
|
|
386
|
+
for (const [uid, user] of this.remoteUsers) {
|
|
387
|
+
const videoTrack = user.videoTrack;
|
|
388
|
+
if (videoTrack) {
|
|
389
|
+
videoTrack.off("sei-received");
|
|
390
|
+
videoTrack.off("video-sei-received");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
this.remoteUsers.clear();
|
|
394
|
+
for (const [uid] of this.videoContainers) {
|
|
395
|
+
this.removeVideoContainer(uid);
|
|
396
|
+
}
|
|
397
|
+
if (this.seiExtractor) {
|
|
398
|
+
this.seiExtractor.dispose();
|
|
399
|
+
this.seiExtractor = null;
|
|
400
|
+
}
|
|
401
|
+
if (this.localAudioTrack) {
|
|
402
|
+
this.localAudioTrack.close();
|
|
403
|
+
this.localAudioTrack = null;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
export {
|
|
408
|
+
AgoraProvider
|
|
409
|
+
};
|
|
410
|
+
//# sourceMappingURL=index4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index4.js","sources":["../src/providers/agora/AgoraProvider.ts"],"sourcesContent":["/**\n * Agora Provider Implementation.\n *\n * This provider uses Agora's H.264 SEI approach\n * to transport animation data.\n *\n * Key differences from LiveKit:\n * - Uses native SEI events instead of RTCRtpScriptTransform\n * - No ALR (Application-Level Redundancy) needed - Agora handles reliability\n * - Simpler data extraction - uses SEI header parsing\n *\n * @packageDocumentation\n */\n\nimport { BaseProvider } from '../base/BaseProvider';\nimport type { RTCConnectionConfig, AgoraConnectionConfig } from '../../types';\nimport { isAgoraConfig, ConnectionState } from '../../types';\nimport type { AnimationTrackCallbacks, AudioTrackCallbacks } from '../../core/types';\nimport { SEIExtractor } from './SEIExtractor';\nimport { logger } from '../../utils';\nimport type {\n AgoraClient,\n AgoraLocalAudioTrack,\n AgoraRemoteAudioTrack,\n AgoraRemoteVideoTrack,\n AgoraUID,\n} from './types';\n\n/**\n * Agora Provider options.\n * @internal Reserved for future use\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface AgoraProviderOptions {\n // Reserved for future configuration options\n}\n\n/**\n * Remote user info with tracks\n * @internal\n */\ninterface RemoteUserInfo {\n videoTrack?: AgoraRemoteVideoTrack;\n audioTrack?: AgoraRemoteAudioTrack;\n}\n\n/**\n * Agora Provider.\n *\n * Implements RTCProvider interface for Agora platform.\n * Uses native SEI events to receive animation data from H.264 video tracks.\n *\n * @example\n * ```typescript\n * import { AvatarPlayer } from '@spatialwalk/avatarkit-rtc';\n * import { AgoraProvider } from '@spatialwalk/avatarkit-rtc/providers/agora';\n *\n * const provider = new AgoraProvider();\n * const player = new AvatarPlayer(provider, renderer);\n *\n * await player.connect({\n * appId: 'your-agora-app-id',\n * channel: 'your-channel',\n * token: 'your-token',\n * });\n * ```\n */\nexport class AgoraProvider extends BaseProvider {\n /** Provider name identifier */\n readonly name = 'agora';\n\n /** @internal */\n private client: AgoraClient | null = null;\n /** @internal Dynamic SDK - type is any due to dynamic import */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private agoraSDK: any = null;\n\n // Animation track subscription (stored for cleanup, actual callbacks handled by SEIExtractor)\n /** @internal */\n private _animationCallbacks: AnimationTrackCallbacks | null = null;\n /** @internal */\n private seiExtractor: SEIExtractor | null = null;\n /** @internal */\n private remoteUsers: Map<AgoraUID, RemoteUserInfo> = new Map();\n /** @internal */\n private videoContainers: Map<AgoraUID, HTMLDivElement> = new Map();\n\n // Audio track subscription\n /** @internal */\n private audioCallbacks: AudioTrackCallbacks | null = null;\n /** @internal */\n private localAudioTrack: AgoraLocalAudioTrack | null = null;\n /** @internal */\n private remoteAudioTracks: Map<AgoraUID, AgoraRemoteAudioTrack> = new Map();\n\n // Debug mode\n /** @internal */\n private debugLogging = false;\n\n constructor(_options: AgoraProviderOptions = {}) {\n super();\n }\n\n /**\n * Enable or disable debug logging.\n * @param enabled - Whether to enable debug logging\n */\n setDebugLogging(enabled: boolean): void {\n this.debugLogging = enabled;\n if (this.seiExtractor) {\n this.seiExtractor.setDebugLogging(enabled);\n }\n }\n\n /**\n * Load Agora SDK dynamically.\n * @internal\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private async loadSDK(): Promise<any> {\n if (this.agoraSDK) {\n return this.agoraSDK;\n }\n\n try {\n // Direct dynamic import - Vite will handle this properly with optimizeDeps\n // Using 'any' type due to dynamic import type inference limitations\n const sdk = await import('agora-rtc-sdk-ng');\n // Agora SDK exports default as the main AgoraRTC object\n this.agoraSDK = sdk.default ?? sdk;\n return this.agoraSDK;\n } catch (error) {\n logger.error('Agora', 'Failed to load SDK:', error);\n throw new Error(\n '❌ Failed to load agora-rtc-sdk-ng.\\n' +\n 'Please ensure it is installed: pnpm add agora-rtc-sdk-ng'\n );\n }\n }\n\n async connect(config: RTCConnectionConfig): Promise<void> {\n if (!isAgoraConfig(config)) {\n throw new Error('AgoraProvider requires appId and channel in connection config');\n }\n\n const agoraConfig: AgoraConnectionConfig = config;\n\n const AgoraRTC = await this.loadSDK();\n\n // Enable SEI reception (required for animation data)\n AgoraRTC.setParameter('ENABLE_VIDEO_SEI', true);\n\n this.client = AgoraRTC.createClient({ \n mode: 'rtc', \n codec: 'h264' // Required for SEI support\n });\n\n this.setConnectionState('connecting');\n\n // Setup event listeners\n this.setupEventListeners(AgoraRTC);\n\n try {\n await this.client.join(\n agoraConfig.appId,\n agoraConfig.channel,\n agoraConfig.token || null,\n agoraConfig.uid ?? null\n );\n \n this.setConnectionState('connected');\n this.emit('connected');\n } catch (error) {\n this.setConnectionState('failed');\n this.emit('error', error as Error);\n throw error;\n }\n }\n\n /**\n * Setup Agora client event listeners\n * @internal\n */\n private setupEventListeners(_AgoraRTC: typeof import('agora-rtc-sdk-ng')): void {\n // Connection state changed\n this.client.on('connection-state-change', (curState: string, _revState: string) => {\n const mapConnectionState = (state: string): ConnectionState => {\n switch (state) {\n case 'DISCONNECTED':\n case 'DISCONNECTING':\n return ConnectionState.Disconnected;\n case 'CONNECTING':\n return ConnectionState.Connecting;\n case 'CONNECTED':\n return ConnectionState.Connected;\n case 'RECONNECTING':\n return ConnectionState.Reconnecting;\n default:\n return ConnectionState.Failed;\n }\n };\n \n this.setConnectionState(mapConnectionState(curState));\n \n if (curState === 'CONNECTED') {\n this.emit('connected');\n } else if (curState === 'DISCONNECTED') {\n this.cleanup();\n this.emit('disconnected');\n }\n });\n\n // User published (remote user joined and published tracks)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.client.on('user-published', async (user: any, mediaType: 'audio' | 'video') => {\n if (this.debugLogging) {\n logger.info('Agora', `User published: ${user.uid}, mediaType=${mediaType}`);\n }\n\n try {\n // Subscribe to the track\n await this.client.subscribe(user, mediaType);\n\n if (mediaType === 'video') {\n if (user.videoTrack) {\n this.handleVideoTrack(user, user.videoTrack);\n } else {\n logger.warn('Agora', `Video track is null after subscribe for user ${user.uid}`);\n }\n } else if (mediaType === 'audio') {\n if (user.audioTrack) {\n this.handleAudioTrack(user, user.audioTrack);\n } else {\n logger.warn('Agora', `Audio track is null after subscribe for user ${user.uid}`);\n }\n }\n } catch (error) {\n logger.error('Agora', `Failed to subscribe to ${mediaType} from ${user.uid}:`, error);\n this.emit('error', error as Error);\n }\n });\n\n // User unpublished (remote user stopped publishing)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.client.on('user-unpublished', (user: any, mediaType: 'audio' | 'video') => {\n if (this.debugLogging) {\n logger.info('Agora', `User unpublished: ${user.uid}, mediaType=${mediaType}`);\n }\n\n if (mediaType === 'video') {\n this.removeVideoContainer(user.uid);\n this.remoteUsers.delete(user.uid);\n } else if (mediaType === 'audio') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const track = this.remoteAudioTracks.get(user.uid) as any;\n if (track) {\n track.stop();\n this.remoteAudioTracks.delete(user.uid);\n }\n \n if (this.audioCallbacks) {\n this.audioCallbacks.onAudioLost?.(user);\n }\n }\n });\n\n // User joined\n this.client.on('user-joined', (user: any) => {\n logger.info('Agora', `User joined: ${user.uid}`);\n });\n\n // User left\n this.client.on('user-left', (user: any, reason: string) => {\n logger.info('Agora', `User left: ${user.uid}, reason: ${reason}`);\n this.remoteUsers.delete(user.uid);\n const audioTrack = this.remoteAudioTracks.get(user.uid);\n if (audioTrack) {\n audioTrack.stop();\n this.remoteAudioTracks.delete(user.uid);\n }\n });\n\n // Error\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.client.on('exception', (error: any) => {\n logger.error('Agora', 'Exception:', error);\n this.emit('error', new Error(error.msg || String(error)));\n });\n }\n\n /**\n * Handle video track from remote user.\n * Sets up SEI event listeners and plays to hidden container.\n * @internal\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private handleVideoTrack(user: any, track: any): void {\n if (this.debugLogging) {\n logger.info('Agora', `Handling video track from ${user.uid}`);\n }\n\n // Listen for SEI data (animation frames)\n // Support both event names for SDK compatibility\n const seiHandler = (seiData: Uint8Array) => {\n if (this.seiExtractor) {\n this.seiExtractor.handleSEIData(seiData);\n }\n };\n\n // Try primary event name\n track.on('sei-received', seiHandler);\n // Also try alternative event name used in some SDK versions\n track.on('video-sei-received', seiHandler);\n\n // Play video to hidden element to ensure data flows\n // This is required for SEI events to be received\n const container = document.createElement('div');\n container.style.display = 'none';\n container.style.position = 'absolute';\n container.style.left = '-9999px';\n container.id = `agora-video-${user.uid}`;\n document.body.appendChild(container);\n this.videoContainers.set(user.uid, container);\n track.play(container);\n\n if (this.debugLogging) {\n logger.info('Agora', `Video track playing, SEI listeners attached for user ${user.uid}`);\n }\n\n // Store track reference\n const existingUser = this.remoteUsers.get(user.uid);\n if (existingUser) {\n existingUser.videoTrack = track;\n } else {\n this.remoteUsers.set(user.uid, { videoTrack: track });\n }\n }\n\n /**\n * Handle audio track from remote user.\n * @internal\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private handleAudioTrack(user: any, track: any): void {\n if (this.debugLogging) {\n logger.info('Agora', `Handling audio track from ${user.uid}`);\n }\n\n // Play audio\n track.play();\n this.remoteAudioTracks.set(user.uid, track);\n\n if (this.debugLogging) {\n logger.info('Agora', `Audio track playing for user ${user.uid}`);\n }\n\n if (this.audioCallbacks) {\n this.audioCallbacks.onAudioReceived?.(user);\n }\n }\n\n /**\n * Remove video container for a user.\n * @internal\n */\n private removeVideoContainer(uid: number): void {\n const container = this.videoContainers.get(uid);\n if (container) {\n container.remove();\n this.videoContainers.delete(uid);\n }\n }\n\n async disconnect(): Promise<void> {\n this.cleanup();\n if (this.client) {\n await this.client.leave();\n this.client = null;\n }\n this.setConnectionState('disconnected');\n this.emit('disconnected');\n }\n\n getConnectionState(): string {\n if (!this.client) {\n return 'disconnected';\n }\n return this.connectionState;\n }\n\n async subscribeAnimationTrack(callbacks: AnimationTrackCallbacks): Promise<void> {\n this._animationCallbacks = callbacks;\n \n // Create SEI extractor\n this.seiExtractor = new SEIExtractor();\n this.seiExtractor.setDebugLogging(this.debugLogging);\n this.seiExtractor.initialize(callbacks);\n \n // If already connected, check for existing remote video tracks\n if (this.client) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const remoteUsers = (this.client as any).remoteUsers;\n for (const user of remoteUsers) {\n if (user.videoTrack) {\n // Subscribe to SEI events with both event names for compatibility\n const seiHandler = (seiData: Uint8Array) => {\n if (this.seiExtractor) {\n this.seiExtractor.handleSEIData(seiData);\n }\n };\n user.videoTrack.on('sei-received', seiHandler);\n user.videoTrack.on('video-sei-received', seiHandler);\n }\n }\n }\n }\n\n async unsubscribeAnimationTrack(): Promise<void> {\n this._animationCallbacks = null;\n if (this.seiExtractor) {\n this.seiExtractor.dispose();\n this.seiExtractor = null;\n }\n \n // Remove SEI listeners from remote tracks\n for (const [uid, user] of this.remoteUsers) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const videoTrack = user.videoTrack as any;\n if (videoTrack) {\n videoTrack.off('sei-received');\n videoTrack.off('video-sei-received');\n }\n }\n \n // Remove video containers\n for (const [uid] of this.videoContainers) {\n this.removeVideoContainer(uid as number);\n }\n \n this.remoteUsers.clear();\n }\n\n async subscribeAudioTrack(callbacks: AudioTrackCallbacks): Promise<void> {\n this.audioCallbacks = callbacks;\n // Audio tracks are automatically handled in user-published event\n }\n\n async unsubscribeAudioTrack(): Promise<void> {\n this.audioCallbacks = null;\n this.remoteAudioTracks.forEach((track) => {\n track.stop();\n });\n this.remoteAudioTracks.clear();\n }\n\n async publishAudioTrack(track?: MediaStreamTrack): Promise<void> {\n if (!this.client) {\n throw new Error('Not connected to channel');\n }\n\n const AgoraRTC = await this.loadSDK();\n\n if (track) {\n // Create local audio track from provided MediaStreamTrack\n this.localAudioTrack = AgoraRTC.createCustomAudioTrack({\n mediaStreamTrack: track,\n });\n } else {\n // Create local audio track from microphone\n this.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack({\n encoderConfig: 'music_standard',\n AEC: true,\n ANS: true,\n AGC: true,\n });\n }\n\n // Publish the track\n await this.client.publish(this.localAudioTrack);\n }\n\n async unpublishAudioTrack(): Promise<void> {\n if (!this.client || !this.localAudioTrack) {\n return;\n }\n\n await this.client.unpublish(this.localAudioTrack);\n this.localAudioTrack.close();\n this.localAudioTrack = null;\n }\n\n /**\n * Play remote audio (resume playback)\n */\n playRemoteAudio(): void {\n this.remoteAudioTracks.forEach((track) => {\n track.play();\n });\n }\n\n /**\n * Pause remote audio\n */\n pauseRemoteAudio(): void {\n this.remoteAudioTracks.forEach((track) => {\n track.stop();\n });\n }\n\n /**\n * Get the native Agora RTC Client instance.\n * \n * Allows advanced users to access Agora-specific features\n * not exposed through the unified API.\n * \n * @returns The Agora IAgoraRTCClient instance, or null if not connected\n * \n * @example\n * ```typescript\n * const client = provider.getNativeClient();\n * if (client) {\n * // Access Agora-specific features\n * console.log('Connection state:', client.connectionState);\n * }\n * ```\n */\n getNativeClient(): AgoraClient | null {\n return this.client;\n }\n\n /**\n * Cleanup resources\n * @internal\n */\n private cleanup(): void {\n // Cleanup remote audio tracks\n this.remoteAudioTracks.forEach((track) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (track as any).stop();\n });\n this.remoteAudioTracks.clear();\n \n // Cleanup remote video tracks and SEI listeners\n for (const [uid, user] of this.remoteUsers) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const videoTrack = user.videoTrack as any;\n if (videoTrack) {\n videoTrack.off('sei-received');\n videoTrack.off('video-sei-received');\n }\n }\n this.remoteUsers.clear();\n \n // Cleanup video containers\n for (const [uid] of this.videoContainers) {\n this.removeVideoContainer(uid as number);\n }\n \n // Cleanup SEI extractor\n if (this.seiExtractor) {\n this.seiExtractor.dispose();\n this.seiExtractor = null;\n }\n \n // Cleanup local audio track\n if (this.localAudioTrack) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this.localAudioTrack as any).close();\n this.localAudioTrack = null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index5.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
2
|
+
ConnectionState2["Disconnected"] = "disconnected";
|
|
3
|
+
ConnectionState2["Connecting"] = "connecting";
|
|
4
|
+
ConnectionState2["Connected"] = "connected";
|
|
5
|
+
ConnectionState2["Reconnecting"] = "reconnecting";
|
|
6
|
+
ConnectionState2["Failed"] = "failed";
|
|
7
|
+
return ConnectionState2;
|
|
8
|
+
})(ConnectionState || {});
|
|
9
|
+
function isLiveKitConfig(config) {
|
|
10
|
+
return "url" in config && "roomName" in config;
|
|
11
|
+
}
|
|
12
|
+
function isAgoraConfig(config) {
|
|
13
|
+
return "appId" in config && "channel" in config;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
ConnectionState,
|
|
17
|
+
isAgoraConfig,
|
|
18
|
+
isLiveKitConfig
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=index5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index5.js","sources":["../src/types/index.ts"],"sourcesContent":["/**\n * Core type definitions for RTC adapter\n * @packageDocumentation\n */\n\n/**\n * Connection state for RTC providers.\n * Represents the current state of the RTC connection.\n */\nexport enum ConnectionState {\n /** Not connected to any RTC server */\n Disconnected = 'disconnected',\n /** Currently connecting to RTC server */\n Connecting = 'connecting',\n /** Successfully connected to RTC server */\n Connected = 'connected',\n /** Reconnecting after connection loss */\n Reconnecting = 'reconnecting',\n /** Connection failed permanently */\n Failed = 'failed',\n}\n\n/**\n * Stream statistics for monitoring and debugging.\n * Contains frame counts and timing information.\n * @internal\n */\nexport interface StreamStats {\n /** Frames received per second */\n framesPerSec: number;\n /** Total frames received since connection */\n totalFrames: number;\n /** Frames successfully sent (for publisher) */\n framesSent: number;\n /** Frames lost in transmission */\n framesLost: number;\n /** Frames recovered via error correction */\n framesRecovered: number;\n /** Frames dropped due to buffer overflow */\n framesDropped: number;\n /** Frames received out of sequence order */\n framesOutOfOrder: number;\n /** Duplicate frames received */\n framesDuplicate: number;\n /** Sequence number of last rendered frame */\n lastRenderedSeq: number;\n}\n\n/**\n * Animation frame metadata.\n * Contains information about each received animation frame.\n * @internal\n */\nexport interface AnimationFrameMetadata {\n /** Frame sequence number for ordering */\n frameSeq?: number;\n /** True if this is the first frame of a speaking session */\n isStart?: boolean;\n /** True if this is the last frame of a speaking session */\n isEnd?: boolean;\n /** True if this is an idle state frame */\n isIdle?: boolean;\n /** True if this frame was recovered via ALR */\n isRecovered?: boolean;\n}\n\n/**\n * LiveKit connection configuration.\n * Used when connecting via LiveKitProvider.\n */\nexport interface LiveKitConnectionConfig {\n /** LiveKit server URL (e.g., wss://your-server.livekit.cloud) */\n url: string;\n \n /** Authentication token */\n token: string;\n \n /** Room name to join */\n roomName: string;\n}\n\n/**\n * Agora connection configuration.\n * Used when connecting via AgoraProvider.\n */\nexport interface AgoraConnectionConfig {\n /** Agora Application ID (from Agora Console) */\n appId: string;\n \n /** Channel name to join */\n channel: string;\n \n /** Authentication token (optional for testing, required for production) */\n token?: string;\n \n /** User ID (optional, 0 or undefined = auto-assign) */\n uid?: number;\n}\n\n/**\n * RTC connection configuration.\n * Union type supporting both LiveKit and Agora providers.\n * \n * @example\n * ```typescript\n * // LiveKit\n * await player.connect({\n * url: 'wss://your-server.livekit.cloud',\n * token: 'your-token',\n * roomName: 'my-room',\n * });\n * \n * // Agora\n * await player.connect({\n * appId: 'your-agora-app-id',\n * channel: 'my-channel',\n * token: 'your-agora-token', // optional\n * });\n * ```\n */\nexport type RTCConnectionConfig = LiveKitConnectionConfig | AgoraConnectionConfig;\n\n/**\n * Type guard to check if config is for LiveKit.\n */\nexport function isLiveKitConfig(config: RTCConnectionConfig): config is LiveKitConnectionConfig {\n return 'url' in config && 'roomName' in config;\n}\n\n/**\n * Type guard to check if config is for Agora.\n */\nexport function isAgoraConfig(config: RTCConnectionConfig): config is AgoraConnectionConfig {\n return 'appId' in config && 'channel' in config;\n}\n"],"names":["ConnectionState"],"mappings":"AASO,IAAK,oCAAAA,qBAAL;AAELA,mBAAA,cAAA,IAAe;AAEfA,mBAAA,YAAA,IAAa;AAEbA,mBAAA,WAAA,IAAY;AAEZA,mBAAA,cAAA,IAAe;AAEfA,mBAAA,QAAA,IAAS;AAVC,SAAAA;AAAA,GAAA,mBAAA,CAAA,CAAA;AAoHL,SAAS,gBAAgB,QAAgE;AAC9F,SAAO,SAAS,UAAU,cAAc;AAC1C;AAKO,SAAS,cAAc,QAA8D;AAC1F,SAAO,WAAW,UAAU,aAAa;AAC3C;"}
|