@spatialwalk/avatarkit-rtc 1.0.0-beta.8 → 1.0.0-beta.9
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 +2 -571
- package/dist/assets/animation-worker-DOGeTjF0.js.map +1 -0
- package/dist/core/AvatarPlayer.d.ts +8 -3
- package/dist/core/AvatarPlayer.d.ts.map +1 -1
- package/dist/core/RTCProvider.d.ts +12 -5
- package/dist/core/RTCProvider.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index10.js +86 -47
- package/dist/index10.js.map +1 -1
- package/dist/index11.js +14 -104
- package/dist/index11.js.map +1 -1
- package/dist/index12.js +390 -14
- package/dist/index12.js.map +1 -1
- package/dist/index13.js +137 -349
- package/dist/index13.js.map +1 -1
- package/dist/index14.js.map +1 -1
- package/dist/index15.js +1 -1
- package/dist/index2.js +38 -17
- package/dist/index2.js.map +1 -1
- package/dist/index3.js +141 -42
- package/dist/index3.js.map +1 -1
- package/dist/index4.js +101 -70
- package/dist/index4.js.map +1 -1
- package/dist/index5.js +6 -2
- package/dist/index5.js.map +1 -1
- package/dist/index6.js +73 -18
- package/dist/index6.js.map +1 -1
- package/dist/index8.js +5 -2
- package/dist/index8.js.map +1 -1
- package/dist/index9.js +65 -164
- package/dist/index9.js.map +1 -1
- package/dist/providers/agora/AgoraProvider.d.ts.map +1 -1
- package/dist/providers/agora/types.d.ts.map +1 -1
- package/dist/providers/base/BaseProvider.d.ts +9 -13
- package/dist/providers/base/BaseProvider.d.ts.map +1 -1
- package/dist/providers/livekit/LiveKitProvider.d.ts +4 -2
- package/dist/providers/livekit/LiveKitProvider.d.ts.map +1 -1
- package/dist/providers/livekit/animation-worker.d.ts.map +1 -1
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +12 -3
- package/dist/assets/animation-worker-CdhDm7lL.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,577 +1,8 @@
|
|
|
1
1
|
# @spatialwalk/avatarkit-rtc
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
RTC adapter for [avatarkit](https://www.npmjs.com/package/@spatialwalk/avatarkit) - currently supports LiveKit and Agora.
|
|
4
4
|
|
|
5
|
-
📚 **Documentation**: [https://docs.spatialreal.ai/
|
|
6
|
-
|
|
7
|
-
> For server-side RTC SDK integration, please refer to the [online documentation](https://docs.spatialreal.ai/web-sdk/introduction).
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
**⚠️ IMPORTANT: This package does NOT work standalone. You MUST install the dependencies below.**
|
|
12
|
-
|
|
13
|
-
### Required Dependencies
|
|
14
|
-
|
|
15
|
-
| Package | Purpose | Required |
|
|
16
|
-
|---------|---------|----------|
|
|
17
|
-
| `@spatialwalk/avatarkit` | Web SDK for avatar rendering | ✅ Yes |
|
|
18
|
-
| `@spatialwalk/avatarkit-rtc` | This package - RTC adapter | ✅ Yes |
|
|
19
|
-
| `livekit-client@2.16.1` | LiveKit RTC SDK (must be exact version) | ⚡ Choose one |
|
|
20
|
-
| `agora-rtc-sdk-ng` | Agora RTC SDK | ⚡ Choose one |
|
|
21
|
-
|
|
22
|
-
### One-line Installation (Recommended)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# With LiveKit (version 2.16.1 required)
|
|
26
|
-
pnpm add @spatialwalk/avatarkit @spatialwalk/avatarkit-rtc livekit-client@2.16.1
|
|
27
|
-
|
|
28
|
-
# With Agora
|
|
29
|
-
pnpm add @spatialwalk/avatarkit @spatialwalk/avatarkit-rtc agora-rtc-sdk-ng
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Step-by-step Installation
|
|
33
|
-
|
|
34
|
-
**Step 1:** Install the Web SDK (required dependency)
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pnpm add @spatialwalk/avatarkit
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Step 2:** Install the RTC adapter
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
pnpm add @spatialwalk/avatarkit-rtc
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Step 3:** Install your chosen RTC provider SDK
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
# For LiveKit (version 2.16.1 required)
|
|
50
|
-
pnpm add livekit-client@2.16.1
|
|
51
|
-
|
|
52
|
-
# For Agora
|
|
53
|
-
pnpm add agora-rtc-sdk-ng
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Common Installation Errors
|
|
57
|
-
|
|
58
|
-
| Error | Cause | Solution |
|
|
59
|
-
|-------|-------|----------|
|
|
60
|
-
| `No matching version found for @spatialwalk/avatarkit-rtc@^0.x.x` | Wrong version number | Use `pnpm add @spatialwalk/avatarkit-rtc` (no version) |
|
|
61
|
-
| `No matching version found for @spatialwalk/avatarkit@^0.x.x` | Wrong version number | Use `pnpm add @spatialwalk/avatarkit` (no version) |
|
|
62
|
-
| `Cannot find module '@spatialwalk/avatarkit'` | Missing dependency | Install it: `pnpm add @spatialwalk/avatarkit` |
|
|
63
|
-
| `Avatar placeholder - SDK integration required` | SDK not initialized | Call `AvatarSDK.initialize()` before creating AvatarView |
|
|
64
|
-
|
|
65
|
-
## Get Credentials
|
|
66
|
-
|
|
67
|
-
Before using the SDK, you need to obtain authentication credentials:
|
|
68
|
-
|
|
69
|
-
### App ID
|
|
70
|
-
|
|
71
|
-
- Visit the [Developer Platform](https://dash.spatialreal.ai) to create your App
|
|
72
|
-
- Get your App ID from the platform dashboard
|
|
73
|
-
- The App ID is required for SDK initialization
|
|
74
|
-
|
|
75
|
-
### Session Token
|
|
76
|
-
|
|
77
|
-
- Session Token is required for avatar loading and SDK authentication
|
|
78
|
-
- Session Token should be obtained from **your backend server**
|
|
79
|
-
- Your backend server should request the Session Token from the AvatarKit Server
|
|
80
|
-
- Session Token has a **maximum validity of 1 hour**
|
|
81
|
-
|
|
82
|
-
### Authentication Flow
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
Your Client → Your Backend Server → AvatarKit Server → returns Session Token (max 1 hour)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
> **Note:** App ID and Session Token are paired and must be used together. Each App ID corresponds to a specific list of avatars that can be driven.
|
|
89
|
-
|
|
90
|
-
## Quick Start
|
|
91
|
-
|
|
92
|
-
When initializing `@spatialwalk/avatarkit`, use `DrivingServiceMode.host` since network communication is managed by this SDK.
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { AvatarPlayer, LiveKitProvider, AgoraProvider } from '@spatialwalk/avatarkit-rtc';
|
|
96
|
-
import { AvatarSDK, AvatarView, AvatarManager, DrivingServiceMode, Environment } from '@spatialwalk/avatarkit';
|
|
97
|
-
|
|
98
|
-
// 0. Initialize SDK (use host mode)
|
|
99
|
-
await AvatarSDK.initialize(appId, {
|
|
100
|
-
environment: Environment.cn, // or Environment.intl
|
|
101
|
-
drivingServiceMode: DrivingServiceMode.host,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// 1. Set session token (required for avatar loading)
|
|
105
|
-
AvatarSDK.setSessionToken(sessionToken);
|
|
106
|
-
|
|
107
|
-
// 2. Create Avatar and AvatarView
|
|
108
|
-
const avatar = await AvatarManager.shared.load(characterId);
|
|
109
|
-
const avatarView = new AvatarView(avatar, container);
|
|
110
|
-
|
|
111
|
-
// 3. Create Provider (choose LiveKit or Agora)
|
|
112
|
-
const provider = new LiveKitProvider(); // or new AgoraProvider()
|
|
113
|
-
|
|
114
|
-
// 4. Create Player
|
|
115
|
-
const player = new AvatarPlayer(provider, avatarView, {
|
|
116
|
-
logLevel: 'warning', // optional
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// 5. Connect to RTC server
|
|
120
|
-
await player.connect({
|
|
121
|
-
url: 'wss://your-livekit-server.com',
|
|
122
|
-
token: 'your-token',
|
|
123
|
-
roomName: 'room-name',
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// 6. Start microphone
|
|
127
|
-
await player.startPublishing();
|
|
128
|
-
|
|
129
|
-
// 7. Stop microphone
|
|
130
|
-
await player.stopPublishing();
|
|
131
|
-
|
|
132
|
-
// 8. Disconnect
|
|
133
|
-
await player.disconnect();
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## API Reference
|
|
137
|
-
|
|
138
|
-
### AvatarPlayer
|
|
139
|
-
|
|
140
|
-
Main entry class that manages RTC connection and avatar rendering.
|
|
141
|
-
|
|
142
|
-
#### Constructor
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
new AvatarPlayer(provider: RTCProvider, avatarView: AvatarView, options?: AvatarPlayerOptions)
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
**Parameters:**
|
|
149
|
-
|
|
150
|
-
| Parameter | Type | Description |
|
|
151
|
-
|-----------|------|-------------|
|
|
152
|
-
| `provider` | `LiveKitProvider \| AgoraProvider` | RTC provider instance |
|
|
153
|
-
| `avatarView` | `AvatarView` | AvatarView instance from avatarkit |
|
|
154
|
-
| `options` | `AvatarPlayerOptions` | Optional configuration |
|
|
155
|
-
|
|
156
|
-
#### AvatarPlayerOptions
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
interface AvatarPlayerOptions {
|
|
160
|
-
/** Start speaking transition frames, default 5 (~200ms at 25fps) */
|
|
161
|
-
transitionStartFrameCount?: number;
|
|
162
|
-
|
|
163
|
-
/** End speaking transition frames, default 40 (~1600ms at 25fps) */
|
|
164
|
-
transitionEndFrameCount?: number;
|
|
165
|
-
|
|
166
|
-
/** Log level: 'info' | 'warning' | 'error' | 'none', default 'warning' */
|
|
167
|
-
logLevel?: LogLevel;
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
#### Properties
|
|
172
|
-
|
|
173
|
-
| Property | Type | Description |
|
|
174
|
-
|----------|------|-------------|
|
|
175
|
-
| `isConnected` | `boolean` | Whether connected to RTC server |
|
|
176
|
-
|
|
177
|
-
#### Methods
|
|
178
|
-
|
|
179
|
-
##### connect(config)
|
|
180
|
-
|
|
181
|
-
Connect to RTC server.
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
await player.connect(config: RTCConnectionConfig): Promise<void>
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**LiveKit Config:**
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
interface LiveKitConnectionConfig {
|
|
191
|
-
url: string; // LiveKit server URL (wss://...)
|
|
192
|
-
token: string; // Auth token
|
|
193
|
-
roomName: string; // Room name
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**Agora Config:**
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
interface AgoraConnectionConfig {
|
|
201
|
-
appId: string; // Agora App ID
|
|
202
|
-
channel: string; // Channel name
|
|
203
|
-
token?: string; // Auth token (required in production)
|
|
204
|
-
uid?: number; // User ID (optional, 0 = auto assign)
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
##### disconnect()
|
|
209
|
-
|
|
210
|
-
Disconnect RTC connection and clean up all resources.
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
await player.disconnect(): Promise<void>
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
##### reconnect()
|
|
217
|
-
|
|
218
|
-
Reconnect to RTC server using the last connection configuration. Useful for recovering from connection issues or stream stalls.
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
await player.reconnect(): Promise<void>
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Note:** Throws an error if no previous connection exists. Call `connect()` first.
|
|
225
|
-
|
|
226
|
-
##### startPublishing()
|
|
227
|
-
|
|
228
|
-
Start publishing microphone audio. Automatically requests microphone permission.
|
|
229
|
-
|
|
230
|
-
```typescript
|
|
231
|
-
await player.startPublishing(): Promise<void>
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
##### stopPublishing()
|
|
235
|
-
|
|
236
|
-
Stop publishing microphone audio and release the device.
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
await player.stopPublishing(): Promise<void>
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
##### publishAudio(track)
|
|
243
|
-
|
|
244
|
-
Publish custom audio track (advanced usage). For non-microphone audio sources like audio file playback.
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
await player.publishAudio(track: MediaStreamTrack): Promise<void>
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
**Supported audio sources:**
|
|
251
|
-
|
|
252
|
-
| Source | How to obtain |
|
|
253
|
-
|--------|---------------|
|
|
254
|
-
| 🎤 Microphone | Use `startPublishing()` for convenience |
|
|
255
|
-
| 🎵 `<audio>` element | `audioElement.captureStream()` |
|
|
256
|
-
| 🖥️ Screen share audio | `getDisplayMedia({ audio: true })` |
|
|
257
|
-
| 🎹 Web Audio API | `audioContext.createMediaStreamDestination().stream` |
|
|
258
|
-
|
|
259
|
-
**Example:**
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
// Play audio from browser <audio> element
|
|
263
|
-
const audioEl = document.querySelector('audio');
|
|
264
|
-
const stream = audioEl.captureStream();
|
|
265
|
-
await player.publishAudio(stream.getAudioTracks()[0]);
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
##### unpublishAudio()
|
|
269
|
-
|
|
270
|
-
Stop publishing custom audio track.
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
await player.unpublishAudio(): Promise<void>
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
**Note:** `unpublishAudio()` does not stop the track - caller is responsible for managing track lifecycle:
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
await player.unpublishAudio();
|
|
280
|
-
stream.getTracks().forEach(t => t.stop()); // Clean up externally
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
##### getConnectionState()
|
|
284
|
-
|
|
285
|
-
Get current connection state.
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
player.getConnectionState(): ConnectionState
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
**ConnectionState enum:**
|
|
292
|
-
|
|
293
|
-
| Value | Description |
|
|
294
|
-
|-------|-------------|
|
|
295
|
-
| `'disconnected'` | Not connected |
|
|
296
|
-
| `'connecting'` | Connecting |
|
|
297
|
-
| `'connected'` | Connected |
|
|
298
|
-
| `'reconnecting'` | Reconnecting |
|
|
299
|
-
| `'failed'` | Connection failed |
|
|
300
|
-
|
|
301
|
-
##### getNativeClient()
|
|
302
|
-
|
|
303
|
-
Get underlying RTC client object for platform-specific features.
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
player.getNativeClient(): unknown
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
**Return value:**
|
|
310
|
-
|
|
311
|
-
| Provider | Return type |
|
|
312
|
-
|----------|-------------|
|
|
313
|
-
| LiveKit | `Room` instance (exported as `LiveKitRoom`) |
|
|
314
|
-
| Agora | `IAgoraRTCClient` instance (exported as `AgoraClient`) |
|
|
315
|
-
|
|
316
|
-
**Type safety notes:**
|
|
317
|
-
|
|
318
|
-
- **Direct Provider usage**: Returns concrete type, no assertion needed
|
|
319
|
-
- **Via AvatarPlayer**: Returns `unknown`, requires manual type assertion
|
|
320
|
-
|
|
321
|
-
**Example:**
|
|
322
|
-
|
|
323
|
-
```typescript
|
|
324
|
-
// Method 1: Use Provider directly (recommended, full type hints)
|
|
325
|
-
import { LiveKitProvider, LiveKitRoom } from '@spatialwalk/avatarkit-rtc';
|
|
326
|
-
|
|
327
|
-
const provider = new LiveKitProvider();
|
|
328
|
-
const room = provider.getNativeClient(); // Type: LiveKitRoom | null
|
|
329
|
-
console.log('Remote participants:', room?.remoteParticipants.size);
|
|
330
|
-
|
|
331
|
-
// Method 2: Via AvatarPlayer (requires assertion)
|
|
332
|
-
import { AvatarPlayer, LiveKitRoom } from '@spatialwalk/avatarkit-rtc';
|
|
333
|
-
|
|
334
|
-
const room = player.getNativeClient() as LiveKitRoom | null;
|
|
335
|
-
console.log('Remote participants:', room?.remoteParticipants.size);
|
|
336
|
-
|
|
337
|
-
// Agora example
|
|
338
|
-
import { AgoraProvider, AgoraClient } from '@spatialwalk/avatarkit-rtc';
|
|
339
|
-
|
|
340
|
-
const provider = new AgoraProvider();
|
|
341
|
-
const client = provider.getNativeClient(); // Type: AgoraClient | null
|
|
342
|
-
console.log('Connection state:', client?.connectionState);
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
##### on(event, handler)
|
|
346
|
-
|
|
347
|
-
Listen to events.
|
|
348
|
-
|
|
349
|
-
```typescript
|
|
350
|
-
player.on(event: string, handler: Function): void
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
**Supported events:**
|
|
354
|
-
|
|
355
|
-
| Event | Callback params | Description |
|
|
356
|
-
|-------|-----------------|-------------|
|
|
357
|
-
| `'connected'` | `()` | Connection successful |
|
|
358
|
-
| `'disconnected'` | `()` | Disconnected |
|
|
359
|
-
| `'error'` | `(error: Error)` | Error occurred |
|
|
360
|
-
| `'connection-state-changed'` | `(state: ConnectionState)` | Connection state changed |
|
|
361
|
-
| `'stalled'` | `()` | Data stream stalled (no frames for 3s). Avatar auto-transitions to idle. |
|
|
362
|
-
|
|
363
|
-
**Example: Handling stream stalls**
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
player.on('stalled', async () => {
|
|
367
|
-
console.log('Stream stalled, attempting reconnection...');
|
|
368
|
-
try {
|
|
369
|
-
await player.reconnect();
|
|
370
|
-
} catch (error) {
|
|
371
|
-
console.error('Reconnection failed:', error);
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
##### off(event, handler)
|
|
377
|
-
|
|
378
|
-
Remove event listener.
|
|
379
|
-
|
|
380
|
-
```typescript
|
|
381
|
-
player.off(event: string, handler: Function): void
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
---
|
|
385
|
-
|
|
386
|
-
### LiveKitProvider
|
|
387
|
-
|
|
388
|
-
LiveKit RTC provider implementation.
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
import { LiveKitProvider } from '@spatialwalk/avatarkit-rtc';
|
|
392
|
-
|
|
393
|
-
const provider = new LiveKitProvider();
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
### AgoraProvider
|
|
399
|
-
|
|
400
|
-
Agora RTC provider implementation.
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
import { AgoraProvider } from '@spatialwalk/avatarkit-rtc';
|
|
404
|
-
|
|
405
|
-
const provider = new AgoraProvider({
|
|
406
|
-
debugLogging: true, // optional: enable debug logs
|
|
407
|
-
});
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
**AgoraProviderOptions:**
|
|
411
|
-
|
|
412
|
-
```typescript
|
|
413
|
-
interface AgoraProviderOptions {
|
|
414
|
-
/** Enable verbose debug logging, default false */
|
|
415
|
-
debugLogging?: boolean;
|
|
416
|
-
}
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
---
|
|
420
|
-
|
|
421
|
-
### Type Guards
|
|
422
|
-
|
|
423
|
-
Type guard functions for config type checking.
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
import { isLiveKitConfig, isAgoraConfig } from '@spatialwalk/avatarkit-rtc';
|
|
427
|
-
|
|
428
|
-
if (isLiveKitConfig(config)) {
|
|
429
|
-
// config is LiveKitConnectionConfig
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (isAgoraConfig(config)) {
|
|
433
|
-
// config is AgoraConnectionConfig
|
|
434
|
-
}
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
---
|
|
438
|
-
|
|
439
|
-
### Native Client Types
|
|
440
|
-
|
|
441
|
-
SDK exports type aliases for underlying RTC clients, useful when using `getNativeClient()`:
|
|
442
|
-
|
|
443
|
-
```typescript
|
|
444
|
-
import type { LiveKitRoom, AgoraClient } from '@spatialwalk/avatarkit-rtc';
|
|
445
|
-
|
|
446
|
-
// LiveKitRoom = Room type from livekit-client
|
|
447
|
-
// AgoraClient = IAgoraRTCClient type from agora-rtc-sdk-ng
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
---
|
|
451
|
-
|
|
452
|
-
## Log Levels
|
|
453
|
-
|
|
454
|
-
SDK log level is configured via `AvatarPlayerOptions.logLevel`:
|
|
455
|
-
|
|
456
|
-
| Level | Output |
|
|
457
|
-
|-------|--------|
|
|
458
|
-
| `'info'` | All logs (connection state, frame processing, debug info) |
|
|
459
|
-
| `'warning'` | Warnings + errors (**default**) |
|
|
460
|
-
| `'error'` | Errors only |
|
|
461
|
-
| `'none'` | Disable all logs |
|
|
462
|
-
|
|
463
|
-
```typescript
|
|
464
|
-
const player = new AvatarPlayer(provider, avatarView, {
|
|
465
|
-
logLevel: 'info', // Enable for debugging
|
|
466
|
-
});
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|
|
471
|
-
## Complete Example
|
|
472
|
-
|
|
473
|
-
### LiveKit Integration
|
|
474
|
-
|
|
475
|
-
```typescript
|
|
476
|
-
import { AvatarPlayer, LiveKitProvider } from '@spatialwalk/avatarkit-rtc';
|
|
477
|
-
import { AvatarSDK, AvatarView, AvatarManager, DrivingServiceMode, Environment } from '@spatialwalk/avatarkit';
|
|
478
|
-
|
|
479
|
-
async function initLiveKit() {
|
|
480
|
-
// Initialize SDK (use host mode)
|
|
481
|
-
await AvatarSDK.initialize('your-app-id', {
|
|
482
|
-
environment: Environment.cn,
|
|
483
|
-
drivingServiceMode: DrivingServiceMode.host,
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
// Set session token (required)
|
|
487
|
-
AvatarSDK.setSessionToken('your-session-token');
|
|
488
|
-
|
|
489
|
-
// Create Avatar
|
|
490
|
-
const avatar = await AvatarManager.shared.load('character-id');
|
|
491
|
-
const container = document.getElementById('avatar-container')!;
|
|
492
|
-
const avatarView = new AvatarView(avatar, container);
|
|
493
|
-
|
|
494
|
-
// Create Player
|
|
495
|
-
const provider = new LiveKitProvider();
|
|
496
|
-
const player = new AvatarPlayer(provider, avatarView, {
|
|
497
|
-
logLevel: 'info',
|
|
498
|
-
transitionStartFrameCount: 5,
|
|
499
|
-
transitionEndFrameCount: 40,
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
// Listen to events
|
|
503
|
-
player.on('connected', () => console.log('Connected!'));
|
|
504
|
-
player.on('disconnected', () => console.log('Disconnected!'));
|
|
505
|
-
player.on('error', (err) => console.error('Error:', err));
|
|
506
|
-
|
|
507
|
-
// Connect
|
|
508
|
-
await player.connect({
|
|
509
|
-
url: 'wss://your-livekit-server.com',
|
|
510
|
-
token: 'your-token',
|
|
511
|
-
roomName: 'my-room',
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
// Start microphone
|
|
515
|
-
await player.startPublishing();
|
|
516
|
-
|
|
517
|
-
// Stop microphone
|
|
518
|
-
// await player.stopPublishing();
|
|
519
|
-
|
|
520
|
-
// Disconnect
|
|
521
|
-
// await player.disconnect();
|
|
522
|
-
}
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
### Agora Integration
|
|
526
|
-
|
|
527
|
-
```typescript
|
|
528
|
-
import { AvatarPlayer, AgoraProvider } from '@spatialwalk/avatarkit-rtc';
|
|
529
|
-
import { AvatarSDK, AvatarView, AvatarManager, DrivingServiceMode, Environment } from '@spatialwalk/avatarkit';
|
|
530
|
-
|
|
531
|
-
async function initAgora() {
|
|
532
|
-
// Initialize SDK (use host mode)
|
|
533
|
-
await AvatarSDK.initialize('your-app-id', {
|
|
534
|
-
environment: Environment.cn,
|
|
535
|
-
drivingServiceMode: DrivingServiceMode.host,
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
// Set session token (required)
|
|
539
|
-
AvatarSDK.setSessionToken('your-session-token');
|
|
540
|
-
|
|
541
|
-
// Create Avatar
|
|
542
|
-
const avatar = await AvatarManager.shared.load('character-id');
|
|
543
|
-
const container = document.getElementById('avatar-container')!;
|
|
544
|
-
const avatarView = new AvatarView(avatar, container);
|
|
545
|
-
|
|
546
|
-
// Create Player
|
|
547
|
-
const provider = new AgoraProvider({ debugLogging: true });
|
|
548
|
-
const player = new AvatarPlayer(provider, avatarView);
|
|
549
|
-
|
|
550
|
-
// Connect
|
|
551
|
-
await player.connect({
|
|
552
|
-
appId: 'your-agora-app-id',
|
|
553
|
-
channel: 'my-channel',
|
|
554
|
-
token: 'your-token', // Required in production
|
|
555
|
-
uid: 0, // 0 = auto assign
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
// Start microphone
|
|
559
|
-
await player.startPublishing();
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
---
|
|
564
|
-
|
|
565
|
-
## Browser Compatibility
|
|
566
|
-
|
|
567
|
-
| Feature | Chrome | Firefox | Safari | Edge |
|
|
568
|
-
|---------|--------|---------|--------|------|
|
|
569
|
-
| LiveKit (VP8 + RTCRtpScriptTransform) | ✅ 94+ | ✅ 117+ | ✅ 15.4+ | ✅ 94+ |
|
|
570
|
-
| Agora (H.264 + SEI) | ✅ 74+ | ✅ 78+ | ✅ 14.1+ | ✅ 79+ |
|
|
571
|
-
|
|
572
|
-
**Note:** LiveKit requires browser support for `RTCRtpScriptTransform` API (Safari 15.4+ supported).
|
|
573
|
-
|
|
574
|
-
---
|
|
5
|
+
📚 **Documentation**: [https://docs.spatialreal.ai/guide/rtc-mode](https://docs.spatialreal.ai/guide/rtc-mode)
|
|
575
6
|
|
|
576
7
|
## License
|
|
577
8
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animation-worker-DOGeTjF0.js","sources":["../src/providers/livekit/animation-worker.ts"],"sourcesContent":["/**\n * RTCRtpScriptTransform Worker for Animation Track (VP8 Video)\n *\n * This worker handles extracting animation data from VP8 video frames.\n * The server prepends a minimal VP8 header to trick the browser's depacketizer.\n *\n * Frame format after depacketization (VP8 descriptor is stripped by depacketizer):\n * [0-9] VP8 frame header (10 bytes) - minimal keyframe structure, skipped\n * [10] flags (uint8) - packet flags\n * [11-14] msgLen (little-endian u32) - length of protobuf message\n * [15..15+msgLen) protobuf Message binary\n */\n\n// Type declarations for RTCRtpScriptTransform API (experimental)\ndeclare interface RTCTransformEvent extends Event {\n transformer: {\n readable: ReadableStream;\n writable: WritableStream;\n options?: unknown;\n };\n}\n\n// Worker global scope with RTCRtpScriptTransform support\ndeclare const self: DedicatedWorkerGlobalScope & {\n onrtctransform?: ((event: RTCTransformEvent) => void) | null;\n};\n\n// VP8 header size (frame tag + sync code + dimensions, descriptor already stripped)\nconst VP8_FRAME_HEADER_SIZE = 10;\n\n// Protocol constants (must match egress-server/metadata_track.go)\nconst METADATA_FIXED_HEADER_SIZE = 5; // 1B flags + 4B length\n\n// Packet flags\nconst PACKET_FLAG_IDLE = 0x01;\nconst PACKET_FLAG_START = 0x02;\nconst PACKET_FLAG_END = 0x04;\nconst PACKET_FLAG_GZIPPED = 0x08;\nconst PACKET_FLAG_TRANSITION = 0x10; // Transition packet - contains target frame for generating transition from idle\nconst PACKET_FLAG_TRANSITION_END = 0x20; // Transition end packet - contains last frame for generating transition back to idle\nconst PACKET_FLAG_REDUNDANT = 0x40; // Packet contains redundant previous frame for ALR loss recovery\n\ninterface FrameMetadata {\n flags: number;\n protobufLength: number;\n protobufData: Uint8Array;\n // ALR (Application-Level Redundancy) data\n hasRedundant: boolean;\n redundantLength: number;\n redundantData: Uint8Array | null;\n}\n\ninterface TransformOptions {\n operation: 'receiver';\n}\n\n// State for receiver\nlet receiverMetaCount = 0;\nlet lastLogTime = 0;\nlet totalFrames = 0;\nlet framesWithMeta = 0;\nlet wasIdle = false; // Track idle state for transition detection\nlet isInStartTransition = false; // Dedup consecutive transition-start packets\nlet isInEndTransition = false; // Dedup consecutive transition-end packets\n\n// ALR (Application-Level Redundancy) state for loss detection\nlet lastReceivedTimestamp: number | null = null;\nlet framesRecovered = 0;\nlet framesLost = 0;\n// Expected timestamp increment per animation frame (90000 Hz * 40ms = 3600)\n// Animation is sent every 2nd audio frame (40ms intervals)\nconst EXPECTED_TIMESTAMP_INCREMENT = 3600;\n\n// Sequence tracking for out-of-order detection\nlet lastRenderedSeq: number = -1; // Last sequence number sent to main thread\nlet framesOutOfOrder = 0; // Count of out-of-order frames detected\nlet framesDuplicate = 0; // Count of duplicate frames skipped\nlet framesDropped = 0; // Count of frames that were permanently lost (gaps in sequence)\nlet framesSent = 0; // Total frames successfully sent to main thread\n\nfunction parseMetadataHeader(\n data: Uint8Array,\n): { meta: FrameMetadata; headerSize: number } | null {\n if (data.byteLength < METADATA_FIXED_HEADER_SIZE) return null;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const flags = data[0];\n const msgLen = view.getUint32(1, true); // little-endian\n\n // Calculate minimum size needed\n const headerSize = METADATA_FIXED_HEADER_SIZE + msgLen;\n if (data.byteLength < headerSize) return null;\n\n // The compressed payload (will be decompressed later)\n const compressedData = data.slice(\n METADATA_FIXED_HEADER_SIZE,\n METADATA_FIXED_HEADER_SIZE + msgLen,\n );\n\n // Note: With the new ALR optimization, both frames are gzipped together\n // The format INSIDE the gzip (after decompression) is:\n // - ALR: [currentLen (4B)][currentData][prevLen (4B)][prevData]\n // - Non-ALR: just the raw protobuf data\n // We return the compressed data here; decompression and ALR parsing happens in receiverTransform\n\n const hasRedundant = (flags & PACKET_FLAG_REDUNDANT) !== 0;\n\n return {\n meta: {\n flags,\n protobufLength: msgLen,\n protobufData: compressedData, // This is still compressed at this point\n hasRedundant,\n redundantLength: 0, // Will be determined after decompression\n redundantData: null, // Will be extracted after decompression\n },\n headerSize,\n };\n}\n\nfunction isIdlePacket(flags: number): boolean {\n return (flags & PACKET_FLAG_IDLE) !== 0;\n}\n\nfunction isStartPacket(flags: number): boolean {\n return (flags & PACKET_FLAG_START) !== 0;\n}\n\nfunction isEndPacket(flags: number): boolean {\n return (flags & PACKET_FLAG_END) !== 0;\n}\n\nfunction isGzipped(flags: number): boolean {\n return (flags & PACKET_FLAG_GZIPPED) !== 0;\n}\n\nfunction isTransitionPacket(flags: number): boolean {\n return (flags & PACKET_FLAG_TRANSITION) !== 0;\n}\n\nfunction isTransitionEndPacket(flags: number): boolean {\n return (flags & PACKET_FLAG_TRANSITION_END) !== 0;\n}\n\n// Decompress gzipped data using DecompressionStream API\nasync function decompressGzip(data: Uint8Array): Promise<Uint8Array> {\n const ds = new DecompressionStream('gzip');\n const writer = ds.writable.getWriter();\n // Create a copy to ensure we have a plain ArrayBuffer, not SharedArrayBuffer\n const copy = new Uint8Array(data);\n writer.write(copy);\n writer.close();\n\n const reader = ds.readable.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n\n return result;\n}\n\n// Compression stats for logging\nlet totalCompressedBytes = 0;\nlet totalUncompressedBytes = 0;\n\n// ALR payload structure after decompression\ninterface ALRPayload {\n frameSeq: number; // Sequence number of current frame\n currentData: Uint8Array; // Current frame (N)\n prev1Data: Uint8Array | null; // Previous frame (N-1)\n prev2Data: Uint8Array | null; // Frame before previous (N-2)\n}\n\n// Parse ALR payload after decompression\n// ALR format: [frameSeq (4B)][currentLen (4B)][currentData][prev1Len (4B)][prev1Data][prev2Len (4B)][prev2Data]\n// Non-ALR format: [frameSeq (4B)][raw protobuf data]\n// Returns { frameSeq, currentData, prev1Data, prev2Data } or null if parsing fails\nfunction parseALRPayload(\n decompressed: Uint8Array,\n hasRedundant: boolean,\n): ALRPayload | null {\n if (decompressed.byteLength < 4) return null;\n\n const view = new DataView(\n decompressed.buffer,\n decompressed.byteOffset,\n decompressed.byteLength,\n );\n let offset = 0;\n\n // Parse frame sequence number\n const frameSeq = view.getUint32(offset, true);\n offset += 4;\n\n if (!hasRedundant) {\n // Non-ALR: rest is raw protobuf\n const currentData = decompressed.slice(offset);\n return { frameSeq, currentData, prev1Data: null, prev2Data: null };\n }\n\n // ALR format: parse current frame\n if (decompressed.byteLength < offset + 4) return null;\n const currentLen = view.getUint32(offset, true);\n offset += 4;\n if (decompressed.byteLength < offset + currentLen) return null;\n const currentData = decompressed.slice(offset, offset + currentLen);\n offset += currentLen;\n\n // Parse prev1 (N-1) if available\n let prev1Data: Uint8Array | null = null;\n if (decompressed.byteLength >= offset + 4) {\n const prev1Len = view.getUint32(offset, true);\n offset += 4;\n if (prev1Len > 0 && decompressed.byteLength >= offset + prev1Len) {\n prev1Data = decompressed.slice(offset, offset + prev1Len);\n offset += prev1Len;\n }\n }\n\n // Parse prev2 (N-2) if available\n let prev2Data: Uint8Array | null = null;\n if (decompressed.byteLength >= offset + 4) {\n const prev2Len = view.getUint32(offset, true);\n offset += 4;\n if (prev2Len > 0 && decompressed.byteLength >= offset + prev2Len) {\n prev2Data = decompressed.slice(offset, offset + prev2Len);\n }\n }\n\n return { frameSeq, currentData, prev1Data, prev2Data };\n}\n\n// Helper to send animation data to main thread with sequence tracking\n// Returns true if frame was sent, false if skipped (duplicate/out-of-order)\nfunction sendAnimationToMainThread(\n protobufData: Uint8Array,\n flags: number,\n frameSeq: number,\n isRecovered: boolean = false,\n): boolean {\n const isIdle = isIdlePacket(flags);\n const isStart = isStartPacket(flags);\n const isEnd = isEndPacket(flags);\n\n // Check for out-of-order or duplicate frames\n if (frameSeq <= lastRenderedSeq && lastRenderedSeq !== -1 && !isStart) {\n if (frameSeq === lastRenderedSeq) {\n framesDuplicate++;\n } else {\n framesOutOfOrder++;\n }\n return false;\n }\n\n // Check for gap (frames we never received and couldn't recover) - these are DROPPED\n if (lastRenderedSeq !== -1 && frameSeq > lastRenderedSeq + 1 && !isStart) {\n const gap = frameSeq - lastRenderedSeq - 1;\n framesDropped += gap;\n }\n\n framesSent++;\n\n lastRenderedSeq = frameSeq;\n\n const protobufBuffer = new ArrayBuffer(protobufData.byteLength);\n new Uint8Array(protobufBuffer).set(protobufData);\n\n self.postMessage(\n {\n type: 'animation',\n flags,\n isIdle,\n isStart,\n isEnd,\n isRecovered,\n frameSeq,\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n\n return true;\n}\n\n// Receiver transform: extract animation data from video frames\n// Uses ALR (Application-Level Redundancy) to recover lost frames\nfunction receiverTransform(\n frame: RTCEncodedVideoFrame,\n _controller: TransformStreamDefaultController<RTCEncodedVideoFrame>,\n) {\n totalFrames++;\n const data = new Uint8Array(frame.data);\n const currentTimestamp = frame.timestamp;\n\n // Skip the VP8 frame header (10 bytes) - the VP8 descriptor is already stripped by depacketizer\n // Check if we have enough data for VP8 header + at least 1 byte of animation data\n if (data.length <= VP8_FRAME_HEADER_SIZE) {\n return; // Frame too small, skip\n }\n\n // Extract animation data after VP8 header\n const animData = data.subarray(VP8_FRAME_HEADER_SIZE);\n\n const parsed = parseMetadataHeader(animData);\n\n if (parsed) {\n const { meta } = parsed;\n framesWithMeta++;\n receiverMetaCount++;\n\n const isIdle = isIdlePacket(meta.flags);\n const isStart = isStartPacket(meta.flags);\n const isEnd = isEndPacket(meta.flags);\n\n // ALR: Detect frame loss and recover using redundant data\n // Check if we missed frames by looking at timestamp gap\n if (lastReceivedTimestamp !== null && !isIdle && !isStart) {\n const timestampDelta = currentTimestamp - lastReceivedTimestamp;\n // Allow some tolerance (1.5x expected increment) for timing variations\n if (timestampDelta > EXPECTED_TIMESTAMP_INCREMENT * 1.5) {\n const missedFrames =\n Math.round(timestampDelta / EXPECTED_TIMESTAMP_INCREMENT) - 1;\n framesLost += missedFrames;\n\n // Try to recover using redundant data from current packet\n // With ALR optimization, up to 3 frames are gzipped together\n if (meta.hasRedundant && isGzipped(meta.flags)) {\n // Decompress to get all frames, then recover\n totalCompressedBytes += meta.protobufData.byteLength;\n\n decompressGzip(meta.protobufData)\n .then((decompressed) => {\n totalUncompressedBytes += decompressed.byteLength;\n\n const parsed = parseALRPayload(decompressed, true);\n if (parsed) {\n const currentSeq = parsed.frameSeq;\n\n // Determine how many frames we can recover based on how many were lost\n // and how many redundant frames we have\n const framesToRecover: Array<{\n data: Uint8Array;\n seq: number;\n }> = [];\n\n if (missedFrames >= 2 && parsed.prev2Data) {\n framesToRecover.push({\n data: parsed.prev2Data,\n seq: currentSeq - 2,\n });\n }\n if (missedFrames >= 1 && parsed.prev1Data) {\n framesToRecover.push({\n data: parsed.prev1Data,\n seq: currentSeq - 1,\n });\n }\n\n const recovered = framesToRecover.length;\n if (recovered > 0) {\n framesRecovered += recovered;\n\n // Send recovered frames in chronological order (oldest first)\n for (const frame of framesToRecover) {\n sendAnimationToMainThread(\n frame.data,\n meta.flags & ~PACKET_FLAG_REDUNDANT,\n frame.seq,\n true,\n );\n }\n }\n\n // Then send current frame\n sendAnimationToMainThread(\n parsed.currentData,\n meta.flags & ~PACKET_FLAG_REDUNDANT,\n currentSeq,\n false,\n );\n }\n })\n .catch((err) => {\n console.error(`[Animation Worker] ALR decompression error:`, err);\n });\n\n // Update timestamp and return early (we've handled this frame)\n lastReceivedTimestamp = currentTimestamp;\n return;\n }\n }\n }\n\n // Update last received timestamp (skip for idle packets to avoid false loss detection)\n if (!isIdle) {\n lastReceivedTimestamp = currentTimestamp;\n }\n\n // Reset state on session start\n if (isStart) {\n lastReceivedTimestamp = currentTimestamp;\n framesRecovered = 0;\n framesLost = 0;\n lastRenderedSeq = -1;\n framesOutOfOrder = 0;\n framesDuplicate = 0;\n framesDropped = 0;\n framesSent = 0;\n }\n\n const isTransition = isTransitionPacket(meta.flags);\n const isTransitionEnd = isTransitionEndPacket(meta.flags);\n\n if (isIdle) {\n // First idle packet - post idleStart event\n if (!wasIdle) {\n self.postMessage({ type: 'idleStart' });\n wasIdle = true;\n }\n isInStartTransition = false;\n isInEndTransition = false;\n } else if (isTransition && meta.protobufLength > 0) {\n // Transition packet - contains target frame for smooth transition from idle\n wasIdle = false;\n\n // Dedup: only emit first packet in a consecutive transition-start run.\n if (!isInStartTransition) {\n isInStartTransition = true;\n isInEndTransition = false;\n\n // Decompress if gzipped (transition packets are always gzipped)\n const gzipped = isGzipped(meta.flags);\n if (gzipped) {\n totalCompressedBytes += meta.protobufData.byteLength;\n\n decompressGzip(meta.protobufData)\n .then((decompressed) => {\n totalUncompressedBytes += decompressed.byteLength;\n\n const protobufBuffer = new ArrayBuffer(decompressed.byteLength);\n new Uint8Array(protobufBuffer).set(decompressed);\n\n // Post transition event - main thread will generate transition frames\n self.postMessage(\n {\n type: 'transition',\n flags: meta.flags,\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n })\n .catch((err) => {\n console.error(\n `[Animation Worker] Gzip decompress error (transition):`,\n err,\n );\n });\n } else {\n const protobufBuffer = new ArrayBuffer(meta.protobufData.byteLength);\n new Uint8Array(protobufBuffer).set(meta.protobufData);\n\n self.postMessage(\n {\n type: 'transition',\n flags: meta.flags,\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n }\n }\n } else if (isTransitionEnd && meta.protobufLength > 0) {\n // Transition end packet - contains last frame for smooth transition back to idle\n\n // Dedup: only emit first packet in a consecutive transition-end run.\n if (!isInEndTransition) {\n isInEndTransition = true;\n isInStartTransition = false;\n\n // Decompress if gzipped (transition end packets are always gzipped)\n const gzipped = isGzipped(meta.flags);\n if (gzipped) {\n totalCompressedBytes += meta.protobufData.byteLength;\n\n decompressGzip(meta.protobufData)\n .then((decompressed) => {\n totalUncompressedBytes += decompressed.byteLength;\n\n const protobufBuffer = new ArrayBuffer(decompressed.byteLength);\n new Uint8Array(protobufBuffer).set(decompressed);\n\n // Post transition end event - main thread will generate reverse transition frames\n self.postMessage(\n {\n type: 'transitionEnd',\n flags: meta.flags,\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n })\n .catch((err) => {\n console.error(\n `[Animation Worker] Gzip decompress error (transitionEnd):`,\n err,\n );\n });\n } else {\n const protobufBuffer = new ArrayBuffer(meta.protobufData.byteLength);\n new Uint8Array(protobufBuffer).set(meta.protobufData);\n\n self.postMessage(\n {\n type: 'transitionEnd',\n flags: meta.flags,\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n }\n }\n } else if (meta.protobufLength > 0) {\n // Normal animation packet\n // Transition from idle to streaming (if not already transitioned via transition packet)\n if (wasIdle) {\n wasIdle = false;\n }\n isInStartTransition = false;\n isInEndTransition = false;\n\n // Decompress if gzipped\n const gzipped = isGzipped(meta.flags);\n if (gzipped) {\n // Track compression stats\n totalCompressedBytes += meta.protobufData.byteLength;\n\n // Async decompression\n decompressGzip(meta.protobufData)\n .then((decompressed) => {\n totalUncompressedBytes += decompressed.byteLength;\n\n // Parse ALR format to get frame sequence and data\n // Format: [frameSeq (4B)][currentLen (4B)][currentData]... or [frameSeq (4B)][raw protobuf]\n const parsed = parseALRPayload(decompressed, meta.hasRedundant);\n if (parsed) {\n sendAnimationToMainThread(\n parsed.currentData,\n meta.flags & ~PACKET_FLAG_REDUNDANT,\n parsed.frameSeq,\n false,\n );\n }\n })\n .catch(() => {});\n } else {\n // Uncompressed - this shouldn't happen in normal operation but handle it\n const protobufBuffer = new ArrayBuffer(meta.protobufData.byteLength);\n new Uint8Array(protobufBuffer).set(meta.protobufData);\n\n self.postMessage(\n {\n type: 'animation',\n flags: meta.flags,\n isIdle: false,\n isStart,\n isEnd,\n frameSeq: -1, // Unknown sequence\n protobufData: protobufBuffer,\n },\n { transfer: [protobufBuffer] },\n );\n }\n }\n\n // Report stats every second\n const now = performance.now();\n if (now - lastLogTime > 1000) {\n lastLogTime = now;\n self.postMessage({\n type: 'metadata',\n protobufLength: meta.protobufLength,\n framesPerSec: receiverMetaCount,\n totalFrames,\n framesWithMeta,\n framesLost,\n framesRecovered,\n totalCompressedBytes,\n totalUncompressedBytes,\n framesOutOfOrder,\n framesDuplicate,\n framesDropped,\n framesSent,\n lastRenderedSeq,\n });\n receiverMetaCount = 0;\n }\n }\n\n // For video, we don't enqueue the frame since it's not real video\n // The browser's VP8 decoder would fail on our custom data anyway\n // controller.enqueue(frame);\n}\n\n// Handle rtctransform event (RTCRtpScriptTransform)\nself.onrtctransform = (event: RTCTransformEvent) => {\n const transformer = event.transformer;\n const options = transformer.options as TransformOptions;\n\n try {\n if (options.operation === 'receiver') {\n // Reset state\n receiverMetaCount = 0;\n lastLogTime = 0;\n totalFrames = 0;\n framesWithMeta = 0;\n wasIdle = false;\n isInStartTransition = false;\n isInEndTransition = false;\n lastReceivedTimestamp = null;\n framesRecovered = 0;\n framesLost = 0;\n lastRenderedSeq = -1;\n framesOutOfOrder = 0;\n framesDuplicate = 0;\n framesDropped = 0;\n framesSent = 0;\n\n transformer.readable\n .pipeThrough(new TransformStream({ transform: receiverTransform }))\n .pipeTo(transformer.writable)\n .catch((err: unknown) => {\n console.error('[Animation Worker] Pipeline error:', err);\n self.postMessage({\n type: 'error',\n error: `Animation receiver pipe error: ${err}`,\n });\n });\n\n self.postMessage({ type: 'ready', operation: 'receiver' });\n }\n } catch (err) {\n console.error('[Animation Worker] Setup error:', err);\n self.postMessage({\n type: 'error',\n error: `Animation transform setup error: ${err}`,\n });\n }\n};\n\n// Handle message-based initialization for fallback\nself.onmessage = (event: MessageEvent) => {\n const { type } = event.data;\n if (type === 'init') {\n self.postMessage({ type: 'initialized' });\n }\n};\n\nexport {};\n"],"names":["currentData","parsed","frame"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RTCProvider } from './RTCProvider';
|
|
2
|
-
import { RTCConnectionConfig } from '../types';
|
|
2
|
+
import { RTCConnectionConfig, RTCPrepareConnectionConfig } from '../types';
|
|
3
3
|
import { LogLevel } from '../utils';
|
|
4
4
|
import { AvatarView } from '@spatialwalk/avatarkit';
|
|
5
5
|
/**
|
|
@@ -83,6 +83,11 @@ export declare class AvatarPlayer {
|
|
|
83
83
|
* @throws Error if already connected or connection fails
|
|
84
84
|
*/
|
|
85
85
|
connect(config: RTCConnectionConfig): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Pre-warm a future RTC connection when the provider supports it.
|
|
88
|
+
* This is best-effort and does not change the connected state.
|
|
89
|
+
*/
|
|
90
|
+
prepareConnection(config: RTCPrepareConnectionConfig): Promise<void>;
|
|
86
91
|
/**
|
|
87
92
|
* Disconnect from RTC server.
|
|
88
93
|
* Stops all tracks and cleans up resources.
|
|
@@ -172,13 +177,13 @@ export declare class AvatarPlayer {
|
|
|
172
177
|
* @param event - Event name ('connected', 'disconnected', 'error', 'stalled', etc.)
|
|
173
178
|
* @param handler - Event handler function
|
|
174
179
|
*/
|
|
175
|
-
on(event: string, handler:
|
|
180
|
+
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
176
181
|
/**
|
|
177
182
|
* Remove event listener.
|
|
178
183
|
* @param event - Event name
|
|
179
184
|
* @param handler - Event handler function (must be same reference as added)
|
|
180
185
|
*/
|
|
181
|
-
off(event: string, handler:
|
|
186
|
+
off(event: string, handler: (...args: unknown[]) => void): void;
|
|
182
187
|
/**
|
|
183
188
|
* Reconnect to RTC server using the last connection configuration.
|
|
184
189
|
* Useful for recovering from connection issues or stream stalls.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AvatarPlayer.d.ts","sourceRoot":"","sources":["../../src/core/AvatarPlayer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AvatarPlayer.d.ts","sourceRoot":"","sources":["../../src/core/AvatarPlayer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAGhF,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,wBAAwB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,YAAY;IAmCvB;;;;;OAKG;gBAED,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,mBAAmB;IA6B/B;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAczD;;;OAGG;IACG,iBAAiB,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1E;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1D;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IASrC;;;;;;;;;;;;;;OAcG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBtC;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAYrC;;;OAGG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,IAAI,OAAO;IAI1B;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAa9D;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAyB/D;;;;;;;;;;;;;OAaG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAiLjC"}
|