@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/index2.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
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 { AnimationHandler } from "./index6.js";
|
|
5
|
+
import { configureLogger } from "./index7.js";
|
|
6
|
+
class AvatarPlayer {
|
|
7
|
+
/**
|
|
8
|
+
* Create a new AvatarPlayer instance.
|
|
9
|
+
* @param provider - RTC provider implementation (e.g., LiveKitProvider)
|
|
10
|
+
* @param avatarView - AvatarView instance from @spatialwalk/avatarkit
|
|
11
|
+
* @param options - Optional configuration for transitions
|
|
12
|
+
*/
|
|
13
|
+
constructor(provider, avatarView, options) {
|
|
14
|
+
/** @internal */
|
|
15
|
+
__publicField(this, "provider");
|
|
16
|
+
/** @internal */
|
|
17
|
+
__publicField(this, "avatarView");
|
|
18
|
+
/** @internal */
|
|
19
|
+
__publicField(this, "animationHandler");
|
|
20
|
+
/** @internal */
|
|
21
|
+
__publicField(this, "_isConnected", false);
|
|
22
|
+
/** @internal */
|
|
23
|
+
__publicField(this, "localAudioTrack", null);
|
|
24
|
+
/** @internal */
|
|
25
|
+
__publicField(this, "mediaStream", null);
|
|
26
|
+
this.provider = provider;
|
|
27
|
+
this.avatarView = avatarView;
|
|
28
|
+
if ((options == null ? void 0 : options.logLevel) !== void 0) {
|
|
29
|
+
configureLogger({ level: options.logLevel });
|
|
30
|
+
}
|
|
31
|
+
const renderer = this.createRendererAdapter();
|
|
32
|
+
this.animationHandler = new AnimationHandler(renderer);
|
|
33
|
+
this.setupProviderEvents();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if currently connected to RTC server.
|
|
37
|
+
*/
|
|
38
|
+
get isConnected() {
|
|
39
|
+
return this._isConnected;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Connect to RTC server.
|
|
43
|
+
* @param config - Connection configuration (URL, token, room name, etc.)
|
|
44
|
+
* @throws Error if already connected or connection fails
|
|
45
|
+
*/
|
|
46
|
+
async connect(config) {
|
|
47
|
+
if (this._isConnected) {
|
|
48
|
+
throw new Error("Already connected. Please disconnect first.");
|
|
49
|
+
}
|
|
50
|
+
await this.setupAnimationCallbacks();
|
|
51
|
+
await this.provider.connect(config);
|
|
52
|
+
this._isConnected = true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Disconnect from RTC server.
|
|
56
|
+
* Stops all tracks and cleans up resources.
|
|
57
|
+
*/
|
|
58
|
+
async disconnect() {
|
|
59
|
+
if (!this._isConnected) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.localAudioTrack) {
|
|
63
|
+
await this.stopPublishing();
|
|
64
|
+
}
|
|
65
|
+
await this.provider.disconnect();
|
|
66
|
+
this.animationHandler.dispose();
|
|
67
|
+
this._isConnected = false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Start publishing microphone audio to the RTC server.
|
|
71
|
+
* Requests microphone permission and starts publishing.
|
|
72
|
+
* @throws Error if permission denied or no microphone found
|
|
73
|
+
*/
|
|
74
|
+
async startPublishing() {
|
|
75
|
+
if (this.localAudioTrack) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
79
|
+
this.localAudioTrack = this.mediaStream.getAudioTracks()[0];
|
|
80
|
+
await this.provider.publishAudioTrack(this.localAudioTrack);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Stop publishing microphone audio.
|
|
84
|
+
*/
|
|
85
|
+
async stopPublishing() {
|
|
86
|
+
if (!this.localAudioTrack) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
await this.provider.unpublishAudioTrack();
|
|
90
|
+
this.localAudioTrack.stop();
|
|
91
|
+
this.localAudioTrack = null;
|
|
92
|
+
if (this.mediaStream) {
|
|
93
|
+
this.mediaStream.getTracks().forEach((track) => track.stop());
|
|
94
|
+
this.mediaStream = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get current connection state.
|
|
99
|
+
* @returns Connection state string (e.g., 'connected', 'disconnected')
|
|
100
|
+
*/
|
|
101
|
+
getConnectionState() {
|
|
102
|
+
return this.provider.getConnectionState();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the native RTC client object.
|
|
106
|
+
*
|
|
107
|
+
* Returns the underlying RTC client for advanced use cases:
|
|
108
|
+
* - LiveKit: Returns the Room instance
|
|
109
|
+
* - Agora: Returns the IAgoraRTCClient instance
|
|
110
|
+
*
|
|
111
|
+
* @returns The native RTC client object, or null if not connected
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* // Access LiveKit Room
|
|
116
|
+
* const room = player.getNativeClient() as Room;
|
|
117
|
+
* console.log('Participants:', room?.remoteParticipants.size);
|
|
118
|
+
*
|
|
119
|
+
* // Access Agora Client
|
|
120
|
+
* const client = player.getNativeClient() as IAgoraRTCClient;
|
|
121
|
+
* console.log('State:', client?.connectionState);
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
getNativeClient() {
|
|
125
|
+
return this.provider.getNativeClient();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Add event listener.
|
|
129
|
+
* @param event - Event name ('connected', 'disconnected', 'error', etc.)
|
|
130
|
+
* @param handler - Event handler function
|
|
131
|
+
*/
|
|
132
|
+
on(event, handler) {
|
|
133
|
+
this.provider.on(event, handler);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Remove event listener.
|
|
137
|
+
* @param event - Event name
|
|
138
|
+
* @param handler - Event handler function (must be same reference as added)
|
|
139
|
+
*/
|
|
140
|
+
off(event, handler) {
|
|
141
|
+
this.provider.off(event, handler);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create internal renderer adapter that bridges AnimationHandler to AvatarView.
|
|
145
|
+
* @internal
|
|
146
|
+
*/
|
|
147
|
+
createRendererAdapter() {
|
|
148
|
+
const avatarView = this.avatarView;
|
|
149
|
+
return {
|
|
150
|
+
renderFrame(flame, startIdle) {
|
|
151
|
+
if (startIdle) {
|
|
152
|
+
avatarView.renderFlame(void 0, true);
|
|
153
|
+
} else if (flame) {
|
|
154
|
+
avatarView.renderFlame(flame);
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
async generateTransitionFromIdle(targetFrame, frameCount) {
|
|
158
|
+
return avatarView.generateTransition({
|
|
159
|
+
to: targetFrame,
|
|
160
|
+
frameCount,
|
|
161
|
+
useLinear: true
|
|
162
|
+
// Linear interpolation for idle->speaking
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
isReady() {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Setup animation track callbacks.
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
async setupAnimationCallbacks() {
|
|
175
|
+
const callbacks = {
|
|
176
|
+
onAnimationData: (protobufData, metadata) => {
|
|
177
|
+
if (metadata.isStart) {
|
|
178
|
+
this.animationHandler.resetTracking();
|
|
179
|
+
this.provider.playRemoteAudio();
|
|
180
|
+
}
|
|
181
|
+
this.animationHandler.handleAnimationData(
|
|
182
|
+
protobufData,
|
|
183
|
+
metadata.frameSeq,
|
|
184
|
+
metadata.isRecovered
|
|
185
|
+
);
|
|
186
|
+
},
|
|
187
|
+
onTransition: (protobufData, transitionFrameCount) => {
|
|
188
|
+
this.provider.pauseRemoteAudio();
|
|
189
|
+
this.animationHandler.handleTransitionData(protobufData, transitionFrameCount);
|
|
190
|
+
},
|
|
191
|
+
onTransitionEnd: (protobufData, transitionFrameCount) => {
|
|
192
|
+
this.animationHandler.handleTransitionToIdle(protobufData, transitionFrameCount);
|
|
193
|
+
},
|
|
194
|
+
onSessionStart: () => {
|
|
195
|
+
},
|
|
196
|
+
onSessionEnd: () => {
|
|
197
|
+
},
|
|
198
|
+
onIdleStart: () => {
|
|
199
|
+
this.animationHandler.startIdle();
|
|
200
|
+
},
|
|
201
|
+
onStreamStats: () => {
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
await this.provider.subscribeAnimationTrack(callbacks);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Setup provider event handlers.
|
|
208
|
+
* @internal
|
|
209
|
+
*/
|
|
210
|
+
setupProviderEvents() {
|
|
211
|
+
this.provider.on("disconnected", () => {
|
|
212
|
+
this._isConnected = false;
|
|
213
|
+
this.animationHandler.startIdle();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
export {
|
|
218
|
+
AvatarPlayer
|
|
219
|
+
};
|
|
220
|
+
//# sourceMappingURL=index2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.js","sources":["../src/core/AvatarPlayer.ts"],"sourcesContent":["/**\n * AvatarPlayer - Unified entry point for RTC avatar streaming.\n *\n * This class provides a unified API that shields applications from\n * differences between different RTC providers (LiveKit, Agora, etc.)\n * and integrates seamlessly with @spatialwalk/avatarkit for rendering.\n *\n * @packageDocumentation\n */\n\nimport type { RTCProvider } from './RTCProvider';\nimport type { RTCConnectionConfig } from '../types';\nimport { AnimationHandler } from './AnimationHandler';\nimport type { AnimationTrackCallbacks, RTCProviderEvents } from './types';\nimport { configureLogger, type LogLevel } from '../utils';\n\n// Import AvatarView type from avatarkit\nimport type { AvatarView, KeyframeData } from '@spatialwalk/avatarkit';\n\n/**\n * Options for configuring AvatarPlayer.\n */\nexport interface AvatarPlayerOptions {\n /**\n * Log level for SDK output.\n * - 'info': Show all logs (debug mode)\n * - 'warning': Show warnings and errors (default)\n * - 'error': Show only errors\n * - 'none': Disable all logs\n */\n logLevel?: LogLevel;\n}\n\n/**\n * Unified Avatar Player.\n *\n * Main entry point for applications to interact with RTC avatar streaming.\n * Handles connection management, audio publishing, animation rendering,\n * and coordinates with avatarkit for display.\n *\n * @example\n * ```typescript\n * import { AvatarPlayer, LiveKitProvider } from '@spatialwalk/avatarkit-rtc';\n * import { AvatarView, Avatar } from '@spatialwalk/avatarkit';\n *\n * // Create avatar and view (from avatarkit)\n * const avatar = await Avatar.create(characterId);\n * const avatarView = new AvatarView(avatar, container);\n *\n * // Create player\n * const provider = new LiveKitProvider();\n * const player = new AvatarPlayer(provider, avatarView);\n *\n * // Connect and start\n * await player.connect({ url: 'wss://...', token: '...' });\n * await player.startPublishing(); // Start microphone\n *\n * // Disconnect when done\n * await player.disconnect();\n * ```\n */\nexport class AvatarPlayer {\n /** @internal */\n private provider: RTCProvider;\n\n /** @internal */\n private avatarView: AvatarView;\n\n /** @internal */\n private animationHandler: AnimationHandler;\n\n /** @internal */\n private _isConnected = false;\n\n /** @internal */\n private localAudioTrack: MediaStreamTrack | null = null;\n\n /** @internal */\n private mediaStream: MediaStream | null = null;\n\n /**\n * Create a new AvatarPlayer instance.\n * @param provider - RTC provider implementation (e.g., LiveKitProvider)\n * @param avatarView - AvatarView instance from @spatialwalk/avatarkit\n * @param options - Optional configuration for transitions\n */\n constructor(\n provider: RTCProvider,\n avatarView: AvatarView,\n options?: AvatarPlayerOptions\n ) {\n this.provider = provider;\n this.avatarView = avatarView;\n\n // Configure logging if specified\n if (options?.logLevel !== undefined) {\n configureLogger({ level: options.logLevel });\n }\n\n // Create internal renderer adapter\n const renderer = this.createRendererAdapter();\n\n this.animationHandler = new AnimationHandler(renderer);\n\n // Setup provider event handlers\n this.setupProviderEvents();\n }\n\n /**\n * Check if currently connected to RTC server.\n */\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /**\n * Connect to RTC server.\n * @param config - Connection configuration (URL, token, room name, etc.)\n * @throws Error if already connected or connection fails\n */\n async connect(config: RTCConnectionConfig): Promise<void> {\n if (this._isConnected) {\n throw new Error('Already connected. Please disconnect first.');\n }\n\n // Setup animation callbacks before connecting\n await this.setupAnimationCallbacks();\n await this.provider.connect(config);\n this._isConnected = true;\n }\n\n /**\n * Disconnect from RTC server.\n * Stops all tracks and cleans up resources.\n */\n async disconnect(): Promise<void> {\n if (!this._isConnected) {\n return;\n }\n\n // Stop publishing if active\n if (this.localAudioTrack) {\n await this.stopPublishing();\n }\n\n await this.provider.disconnect();\n this.animationHandler.dispose();\n this._isConnected = false;\n }\n\n /**\n * Start publishing microphone audio to the RTC server.\n * Requests microphone permission and starts publishing.\n * @throws Error if permission denied or no microphone found\n */\n async startPublishing(): Promise<void> {\n if (this.localAudioTrack) {\n return; // Already publishing\n }\n\n // Request microphone permission\n this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n this.localAudioTrack = this.mediaStream.getAudioTracks()[0];\n\n await this.provider.publishAudioTrack(this.localAudioTrack);\n }\n\n /**\n * Stop publishing microphone audio.\n */\n async stopPublishing(): Promise<void> {\n if (!this.localAudioTrack) {\n return;\n }\n\n await this.provider.unpublishAudioTrack();\n\n // Stop and cleanup tracks\n this.localAudioTrack.stop();\n this.localAudioTrack = null;\n\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => track.stop());\n this.mediaStream = null;\n }\n }\n\n /**\n * Get current connection state.\n * @returns Connection state string (e.g., 'connected', 'disconnected')\n */\n getConnectionState(): string {\n return this.provider.getConnectionState();\n }\n\n /**\n * Get the native RTC client object.\n * \n * Returns the underlying RTC client for advanced use cases:\n * - LiveKit: Returns the Room instance\n * - Agora: Returns the IAgoraRTCClient instance\n * \n * @returns The native RTC client object, or null if not connected\n * \n * @example\n * ```typescript\n * // Access LiveKit Room\n * const room = player.getNativeClient() as Room;\n * console.log('Participants:', room?.remoteParticipants.size);\n * \n * // Access Agora Client\n * const client = player.getNativeClient() as IAgoraRTCClient;\n * console.log('State:', client?.connectionState);\n * ```\n */\n getNativeClient(): unknown {\n return this.provider.getNativeClient();\n }\n\n /**\n * Add event listener.\n * @param event - Event name ('connected', 'disconnected', 'error', etc.)\n * @param handler - Event handler function\n */\n on<K extends keyof RTCProviderEvents>(\n event: K,\n handler: RTCProviderEvents[K]\n ): void {\n this.provider.on(event, handler);\n }\n\n /**\n * Remove event listener.\n * @param event - Event name\n * @param handler - Event handler function (must be same reference as added)\n */\n off<K extends keyof RTCProviderEvents>(\n event: K,\n handler: RTCProviderEvents[K]\n ): void {\n this.provider.off(event, handler);\n }\n\n /**\n * Create internal renderer adapter that bridges AnimationHandler to AvatarView.\n * @internal\n */\n private createRendererAdapter() {\n const avatarView = this.avatarView;\n\n return {\n renderFrame(flame: KeyframeData | undefined, startIdle?: boolean): void {\n if (startIdle) {\n // Enable idle rendering mode\n avatarView.renderFlame(undefined as unknown as KeyframeData, true);\n } else if (flame) {\n // Render the animation frame\n avatarView.renderFlame(flame);\n }\n },\n\n async generateTransitionFromIdle(\n targetFrame: KeyframeData,\n frameCount: number\n ): Promise<KeyframeData[]> {\n // Use avatarkit's generateTransition with from=undefined (current idle frame)\n return avatarView.generateTransition({\n to: targetFrame,\n frameCount,\n useLinear: true, // Linear interpolation for idle->speaking\n });\n },\n\n isReady(): boolean {\n return true; // AvatarView is always ready once created\n },\n };\n }\n\n /**\n * Setup animation track callbacks.\n * @internal\n */\n private async setupAnimationCallbacks(): Promise<void> {\n const callbacks: AnimationTrackCallbacks = {\n onAnimationData: (protobufData, metadata) => {\n // Reset tracking on session start\n if (metadata.isStart) {\n this.animationHandler.resetTracking();\n // Start audio playback on session start (fallback if transition didn't trigger it)\n this.provider.playRemoteAudio();\n }\n\n this.animationHandler.handleAnimationData(\n protobufData,\n metadata.frameSeq,\n metadata.isRecovered\n );\n },\n onTransition: (protobufData, transitionFrameCount) => {\n this.provider.pauseRemoteAudio();\n this.animationHandler.handleTransitionData(protobufData, transitionFrameCount);\n },\n onTransitionEnd: (protobufData, transitionFrameCount) => {\n this.animationHandler.handleTransitionToIdle(protobufData, transitionFrameCount);\n },\n onSessionStart: () => {\n // Session started - can be used for UI feedback\n },\n onSessionEnd: () => {\n // Session ended - can be used for UI feedback\n },\n onIdleStart: () => {\n this.animationHandler.startIdle();\n },\n onStreamStats: () => {\n // Stats can be forwarded to application layer if needed\n },\n };\n\n await this.provider.subscribeAnimationTrack(callbacks);\n }\n\n /**\n * Setup provider event handlers.\n * @internal\n */\n private setupProviderEvents(): void {\n this.provider.on('disconnected', () => {\n this._isConnected = false;\n // Return to idle animation when disconnected\n this.animationHandler.startIdle();\n });\n }\n}\n"],"names":[],"mappings":"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"}
|