@spatialwalk/avatarkit 1.0.0-beta.4 → 1.0.0-beta.41
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/CHANGELOG.md +378 -2
- package/README.md +261 -283
- package/dist/StreamingAudioPlayer-BXytpr5T.js +506 -0
- package/dist/animation/AnimationWebSocketClient.d.ts +9 -24
- package/dist/animation/utils/eventEmitter.d.ts +0 -4
- package/dist/animation/utils/flameConverter.d.ts +3 -11
- package/dist/audio/AnimationPlayer.d.ts +4 -32
- package/dist/audio/StreamingAudioPlayer.d.ts +12 -75
- package/dist/avatar_core_wasm-i0Ocpx6q.js +2693 -0
- package/dist/avatar_core_wasm.wasm +0 -0
- package/dist/config/app-config.d.ts +1 -6
- package/dist/config/constants.d.ts +5 -27
- package/dist/config/sdk-config-loader.d.ts +2 -9
- package/dist/core/Avatar.d.ts +0 -15
- package/dist/core/AvatarController.d.ts +35 -116
- package/dist/core/AvatarDownloader.d.ts +0 -95
- package/dist/core/AvatarManager.d.ts +10 -18
- package/dist/core/AvatarSDK.d.ts +21 -0
- package/dist/core/AvatarView.d.ts +24 -110
- package/dist/core/NetworkLayer.d.ts +1 -59
- package/dist/generated/common/v1/models.d.ts +29 -0
- package/dist/generated/driveningress/v1/driveningress.d.ts +1 -12
- package/dist/generated/driveningress/v2/driveningress.d.ts +81 -3
- package/dist/generated/google/protobuf/struct.d.ts +5 -39
- package/dist/generated/google/protobuf/timestamp.d.ts +1 -103
- package/dist/index-CRKYjlwp.js +14267 -0
- package/dist/index.d.ts +1 -6
- package/dist/index.js +17 -18
- package/dist/renderer/RenderSystem.d.ts +1 -79
- package/dist/renderer/covariance.d.ts +0 -12
- package/dist/renderer/renderer.d.ts +6 -2
- package/dist/renderer/sortSplats.d.ts +0 -11
- package/dist/renderer/webgl/reorderData.d.ts +0 -13
- package/dist/renderer/webgl/webglRenderer.d.ts +19 -42
- package/dist/renderer/webgpu/webgpuRenderer.d.ts +18 -31
- package/dist/types/character-settings.d.ts +0 -5
- package/dist/types/character.d.ts +3 -21
- package/dist/types/index.d.ts +72 -36
- package/dist/utils/animation-interpolation.d.ts +3 -13
- package/dist/utils/client-id.d.ts +1 -0
- package/dist/utils/conversationId.d.ts +1 -0
- package/dist/utils/error-utils.d.ts +1 -25
- package/dist/utils/heartbeat-manager.d.ts +18 -0
- package/dist/utils/id-manager.d.ts +38 -0
- package/dist/utils/logger.d.ts +5 -11
- package/dist/utils/posthog-tracker.d.ts +11 -0
- package/dist/utils/usage-tracker.d.ts +5 -0
- package/dist/vanilla/vite.config.d.ts +2 -0
- package/dist/wasm/avatarCoreAdapter.d.ts +11 -97
- package/dist/wasm/avatarCoreMemory.d.ts +5 -54
- package/package.json +15 -13
- package/dist/StreamingAudioPlayer-L87IFoao.js +0 -319
- package/dist/StreamingAudioPlayer-L87IFoao.js.map +0 -1
- package/dist/animation/AnimationWebSocketClient.d.ts.map +0 -1
- package/dist/animation/utils/eventEmitter.d.ts.map +0 -1
- package/dist/animation/utils/flameConverter.d.ts.map +0 -1
- package/dist/audio/AnimationPlayer.d.ts.map +0 -1
- package/dist/audio/StreamingAudioPlayer.d.ts.map +0 -1
- package/dist/avatar_core_wasm-D4eEi7Eh.js +0 -1666
- package/dist/avatar_core_wasm-D4eEi7Eh.js.map +0 -1
- package/dist/config/app-config.d.ts.map +0 -1
- package/dist/config/constants.d.ts.map +0 -1
- package/dist/config/sdk-config-loader.d.ts.map +0 -1
- package/dist/core/Avatar.d.ts.map +0 -1
- package/dist/core/AvatarController.d.ts.map +0 -1
- package/dist/core/AvatarDownloader.d.ts.map +0 -1
- package/dist/core/AvatarKit.d.ts +0 -66
- package/dist/core/AvatarKit.d.ts.map +0 -1
- package/dist/core/AvatarManager.d.ts.map +0 -1
- package/dist/core/AvatarView.d.ts.map +0 -1
- package/dist/core/NetworkLayer.d.ts.map +0 -1
- package/dist/generated/driveningress/v1/driveningress.d.ts.map +0 -1
- package/dist/generated/driveningress/v2/driveningress.d.ts.map +0 -1
- package/dist/generated/google/protobuf/struct.d.ts.map +0 -1
- package/dist/generated/google/protobuf/timestamp.d.ts.map +0 -1
- package/dist/index-BDxVrKwm.js +0 -5942
- package/dist/index-BDxVrKwm.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/renderer/RenderSystem.d.ts.map +0 -1
- package/dist/renderer/covariance.d.ts.map +0 -1
- package/dist/renderer/renderer.d.ts.map +0 -1
- package/dist/renderer/sortSplats.d.ts.map +0 -1
- package/dist/renderer/webgl/reorderData.d.ts.map +0 -1
- package/dist/renderer/webgl/webglRenderer.d.ts.map +0 -1
- package/dist/renderer/webgpu/webgpuRenderer.d.ts.map +0 -1
- package/dist/types/character-settings.d.ts.map +0 -1
- package/dist/types/character.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/animation-interpolation.d.ts.map +0 -1
- package/dist/utils/cls-tracker.d.ts +0 -17
- package/dist/utils/cls-tracker.d.ts.map +0 -1
- package/dist/utils/error-utils.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/reqId.d.ts +0 -20
- package/dist/utils/reqId.d.ts.map +0 -1
- package/dist/wasm/avatarCoreAdapter.d.ts.map +0 -1
- package/dist/wasm/avatarCoreMemory.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SPAvatarSDK SDK
|
|
2
2
|
|
|
3
3
|
Real-time virtual avatar rendering SDK based on 3D Gaussian Splatting, supporting audio-driven animation rendering and high-quality 3D rendering.
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ Real-time virtual avatar rendering SDK based on 3D Gaussian Splatting, supportin
|
|
|
6
6
|
|
|
7
7
|
- **3D Gaussian Splatting Rendering** - Based on the latest point cloud rendering technology, providing high-quality 3D virtual avatars
|
|
8
8
|
- **Audio-Driven Real-Time Animation Rendering** - Users provide audio data, SDK handles receiving animation data and rendering
|
|
9
|
+
- **Multi-Character Support** - Support multiple avatar instances simultaneously, each with independent state and rendering
|
|
9
10
|
- **WebGPU/WebGL Dual Rendering Backend** - Automatically selects the best rendering backend for compatibility
|
|
10
11
|
- **WASM High-Performance Computing** - Uses C++ compiled WebAssembly modules for geometric calculations
|
|
11
12
|
- **TypeScript Support** - Complete type definitions and IntelliSense
|
|
@@ -23,84 +24,85 @@ npm install @spatialwalk/avatarkit
|
|
|
23
24
|
|
|
24
25
|
```typescript
|
|
25
26
|
import {
|
|
26
|
-
|
|
27
|
+
AvatarSDK,
|
|
27
28
|
AvatarManager,
|
|
28
29
|
AvatarView,
|
|
29
30
|
Configuration,
|
|
30
|
-
Environment
|
|
31
|
+
Environment,
|
|
32
|
+
DrivingServiceMode,
|
|
33
|
+
LogLevel
|
|
31
34
|
} from '@spatialwalk/avatarkit'
|
|
32
35
|
|
|
33
36
|
// 1. Initialize SDK
|
|
37
|
+
|
|
34
38
|
const configuration: Configuration = {
|
|
35
|
-
environment: Environment.
|
|
39
|
+
environment: Environment.cn,
|
|
40
|
+
drivingServiceMode: DrivingServiceMode.sdk, // Optional, 'sdk' is default
|
|
41
|
+
// - DrivingServiceMode.sdk: SDK mode - SDK handles WebSocket communication
|
|
42
|
+
// - DrivingServiceMode.host: Host mode - Host app provides audio and animation data
|
|
43
|
+
logLevel: LogLevel.off, // Optional, 'off' is default
|
|
44
|
+
// - LogLevel.off: Disable all logs
|
|
45
|
+
// - LogLevel.error: Only error logs
|
|
46
|
+
// - LogLevel.warning: Warning and error logs
|
|
47
|
+
// - LogLevel.all: All logs (info, warning, error)
|
|
48
|
+
audioFormat: { // Optional, default is { channelCount: 1, sampleRate: 16000 }
|
|
49
|
+
channelCount: 1, // Fixed to 1 (mono)
|
|
50
|
+
sampleRate: 16000 // Supported: 8000, 16000, 22050, 24000, 32000, 44100, 48000 Hz
|
|
51
|
+
}
|
|
36
52
|
}
|
|
37
53
|
|
|
38
|
-
await
|
|
54
|
+
await AvatarSDK.initialize('your-app-id', configuration)
|
|
39
55
|
|
|
40
56
|
// Set sessionToken (if needed, call separately)
|
|
41
|
-
//
|
|
57
|
+
// AvatarSDK.setSessionToken('your-session-token')
|
|
42
58
|
|
|
43
59
|
// 2. Load character
|
|
44
|
-
const avatarManager =
|
|
60
|
+
const avatarManager = AvatarManager.shared
|
|
45
61
|
const avatar = await avatarManager.load('character-id', (progress) => {
|
|
46
62
|
console.log(`Loading progress: ${progress.progress}%`)
|
|
47
63
|
})
|
|
48
64
|
|
|
49
65
|
// 3. Create view (automatically creates Canvas and AvatarController)
|
|
50
|
-
//
|
|
66
|
+
// The playback mode is determined by drivingServiceMode in AvatarSDK configuration
|
|
67
|
+
// - DrivingServiceMode.sdk: SDK mode - SDK handles WebSocket communication
|
|
68
|
+
// - DrivingServiceMode.host: Host mode - Host app provides audio and animation data
|
|
51
69
|
const container = document.getElementById('avatar-container')
|
|
52
|
-
const avatarView = new AvatarView(avatar,
|
|
53
|
-
container: container,
|
|
54
|
-
playbackMode: 'network' // Optional, 'network' is default
|
|
55
|
-
})
|
|
70
|
+
const avatarView = new AvatarView(avatar, container)
|
|
56
71
|
|
|
57
|
-
// 4. Start real-time communication (
|
|
72
|
+
// 4. Start real-time communication (SDK mode only)
|
|
58
73
|
await avatarView.avatarController.start()
|
|
59
74
|
|
|
60
|
-
// 5. Send audio data (
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const audioData = audioUint8.slice().buffer // Simplified conversion, works for ArrayBuffer and SharedArrayBuffer
|
|
65
|
-
avatarView.avatarController.send(audioData, false) // Send audio data, will automatically start playing after accumulating enough data
|
|
66
|
-
avatarView.avatarController.send(audioData, true) // end=true means immediately return animation data, no longer accumulating
|
|
75
|
+
// 5. Send audio data (SDK mode, must be mono PCM16 format matching configured sample rate)
|
|
76
|
+
const audioData = new ArrayBuffer(1024) // Example: PCM16 audio data at configured sample rate
|
|
77
|
+
avatarView.avatarController.send(audioData, false) // Send audio data
|
|
78
|
+
avatarView.avatarController.send(audioData, true) // end=true marks the end of current conversation round
|
|
67
79
|
```
|
|
68
80
|
|
|
69
|
-
###
|
|
81
|
+
### Host Mode Example
|
|
70
82
|
|
|
71
83
|
```typescript
|
|
72
|
-
import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
|
|
73
84
|
|
|
74
|
-
// 1-3. Same as
|
|
85
|
+
// 1-3. Same as SDK mode (initialize SDK, load character)
|
|
75
86
|
|
|
76
|
-
// 3. Create view with
|
|
87
|
+
// 3. Create view with Host mode
|
|
77
88
|
const container = document.getElementById('avatar-container')
|
|
78
|
-
const avatarView = new AvatarView(avatar,
|
|
79
|
-
container: container,
|
|
80
|
-
playbackMode: AvatarPlaybackMode.external
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
// 4. Start playback with initial data (obtained from your service)
|
|
84
|
-
// Note: Audio and animation data should be obtained from your backend service
|
|
85
|
-
const initialAudioChunks = [{ data: audioData1, isLast: false }, { data: audioData2, isLast: false }]
|
|
86
|
-
const initialKeyframes = animationData1 // Animation keyframes from your service
|
|
87
|
-
|
|
88
|
-
await avatarView.avatarController.play(initialAudioChunks, initialKeyframes)
|
|
89
|
+
const avatarView = new AvatarView(avatar, container)
|
|
89
90
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
avatarView.avatarController.
|
|
91
|
+
// 4. Host Mode Workflow:
|
|
92
|
+
// Send audio data first to get conversationId, then use it to send animation data
|
|
93
|
+
const conversationId = avatarView.avatarController.yieldAudioData(audioData, false)
|
|
94
|
+
avatarView.avatarController.yieldFramesData(animationDataArray, conversationId) // animationDataArray: (Uint8Array | ArrayBuffer)[]
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
### Complete Examples
|
|
96
98
|
|
|
97
99
|
Check the example code in the GitHub repository for complete usage flows for both modes.
|
|
98
100
|
|
|
99
|
-
**Example Project:** [
|
|
101
|
+
**Example Project:** [AvatarSDK-Web-Demo](https://github.com/spatialwalk/AvatarSDK-Web-Demo)
|
|
100
102
|
|
|
101
103
|
This repository contains complete examples for Vanilla JS, Vue 3, and React, demonstrating:
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
+
- SDK mode: Real-time audio input with automatic animation data reception
|
|
105
|
+
- Host mode: Custom data sources with manual audio/animation data management
|
|
104
106
|
|
|
105
107
|
## 🏗️ Architecture Overview
|
|
106
108
|
|
|
@@ -110,47 +112,60 @@ The SDK uses a three-layer architecture for clear separation of concerns:
|
|
|
110
112
|
|
|
111
113
|
1. **Rendering Layer (AvatarView)** - Responsible for 3D rendering only
|
|
112
114
|
2. **Playback Layer (AvatarController)** - Manages audio/animation synchronization and playback
|
|
113
|
-
3. **Network Layer
|
|
115
|
+
3. **Network Layer** - Handles WebSocket communication (only in SDK mode, internal implementation)
|
|
114
116
|
|
|
115
117
|
### Core Components
|
|
116
118
|
|
|
117
|
-
- **
|
|
119
|
+
- **AvatarSDK** - SDK initialization and management
|
|
118
120
|
- **AvatarManager** - Character resource loading and management
|
|
119
121
|
- **AvatarView** - 3D rendering view (rendering layer)
|
|
120
122
|
- **AvatarController** - Audio/animation playback controller (playback layer)
|
|
121
|
-
- **NetworkLayer** - WebSocket communication (network layer, automatically composed in network mode)
|
|
122
|
-
- **AvatarCoreAdapter** - WASM module adapter
|
|
123
123
|
|
|
124
124
|
### Playback Modes
|
|
125
125
|
|
|
126
|
-
The SDK supports two playback modes, configured
|
|
126
|
+
The SDK supports two playback modes, configured in `AvatarSDK.initialize()`:
|
|
127
127
|
|
|
128
|
-
#### 1.
|
|
128
|
+
#### 1. SDK Mode (Default)
|
|
129
|
+
- Configured via `drivingServiceMode: DrivingServiceMode.sdk` in `AvatarSDK.initialize()`
|
|
129
130
|
- SDK handles WebSocket communication automatically
|
|
130
131
|
- Send audio data via `AvatarController.send()`
|
|
131
132
|
- SDK receives animation data from backend and synchronizes playback
|
|
132
133
|
- Best for: Real-time audio input scenarios
|
|
133
134
|
|
|
134
|
-
#### 2.
|
|
135
|
-
-
|
|
136
|
-
-
|
|
135
|
+
#### 2. Host Mode
|
|
136
|
+
- Configured via `drivingServiceMode: DrivingServiceMode.host` in `AvatarSDK.initialize()`
|
|
137
|
+
- Host application manages its own network/data fetching
|
|
138
|
+
- Host application provides both audio and animation data
|
|
137
139
|
- SDK only handles synchronized playback
|
|
138
140
|
- Best for: Custom data sources, pre-recorded content, or custom network implementations
|
|
139
141
|
|
|
142
|
+
**Note:** The playback mode is determined by `drivingServiceMode` in `AvatarSDK.initialize()` configuration.
|
|
143
|
+
|
|
144
|
+
### Fallback Mechanism
|
|
145
|
+
|
|
146
|
+
The SDK includes a fallback mechanism to ensure audio playback continues even when animation data is unavailable:
|
|
147
|
+
|
|
148
|
+
- **SDK Mode Connection Failure**: If WebSocket connection fails to establish within 15 seconds, the SDK automatically enters fallback mode. In this mode, audio data can still be sent and will play normally, even though no animation data will be received from the server. This ensures that audio playback is not interrupted even when the service connection fails.
|
|
149
|
+
- **SDK Mode Server Error**: If the server returns an error after connection is established, the SDK automatically enters audio-only mode for that session and continues playing audio independently.
|
|
150
|
+
- **Host Mode**: If empty animation data is provided (empty array or undefined), the SDK automatically enters audio-only mode.
|
|
151
|
+
- Once in audio-only mode, any subsequent animation data for that session will be ignored, and only audio will continue playing.
|
|
152
|
+
- The fallback mode is interruptible, just like normal playback mode.
|
|
153
|
+
- Connection state callbacks (`onConnectionState`) will notify you when connection fails or times out, allowing you to handle the fallback state appropriately.
|
|
154
|
+
|
|
140
155
|
### Data Flow
|
|
141
156
|
|
|
142
|
-
####
|
|
157
|
+
#### SDK Mode Flow
|
|
143
158
|
|
|
144
159
|
```
|
|
145
160
|
User audio input (16kHz mono PCM16)
|
|
146
161
|
↓
|
|
147
162
|
AvatarController.send()
|
|
148
163
|
↓
|
|
149
|
-
|
|
164
|
+
WebSocket → Backend processing
|
|
150
165
|
↓
|
|
151
166
|
Backend returns animation data (FLAME keyframes)
|
|
152
167
|
↓
|
|
153
|
-
|
|
168
|
+
AvatarController → AnimationPlayer
|
|
154
169
|
↓
|
|
155
170
|
FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
|
|
156
171
|
↓
|
|
@@ -159,15 +174,14 @@ AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
|
|
|
159
174
|
RenderSystem → WebGPU/WebGL → Canvas rendering
|
|
160
175
|
```
|
|
161
176
|
|
|
162
|
-
####
|
|
177
|
+
#### Host Mode Flow
|
|
163
178
|
|
|
164
179
|
```
|
|
165
180
|
External data source (audio + animation)
|
|
166
181
|
↓
|
|
167
|
-
AvatarController.
|
|
182
|
+
AvatarController.yieldAudioData(audioChunk) // Returns conversationId
|
|
168
183
|
↓
|
|
169
|
-
AvatarController.
|
|
170
|
-
AvatarController.sendKeyframes() // Stream additional animation
|
|
184
|
+
AvatarController.yieldFramesData(keyframesDataArray, conversationId) // keyframesDataArray: (Uint8Array | ArrayBuffer)[] - each element is a protobuf encoded Message
|
|
171
185
|
↓
|
|
172
186
|
AvatarController → AnimationPlayer (synchronized playback)
|
|
173
187
|
↓
|
|
@@ -178,52 +192,84 @@ AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
|
|
|
178
192
|
RenderSystem → WebGPU/WebGL → Canvas rendering
|
|
179
193
|
```
|
|
180
194
|
|
|
181
|
-
**Note:**
|
|
182
|
-
- In network mode, users provide audio data, SDK handles network communication and animation data reception
|
|
183
|
-
- In external data mode, users provide both audio and animation data, SDK handles synchronized playback only
|
|
184
|
-
|
|
185
195
|
### Audio Format Requirements
|
|
186
196
|
|
|
187
|
-
**⚠️ Important:** The SDK requires audio data to be in **
|
|
197
|
+
**⚠️ Important:** The SDK requires audio data to be in **mono PCM16** format:
|
|
188
198
|
|
|
189
|
-
- **Sample Rate**:
|
|
190
|
-
-
|
|
199
|
+
- **Sample Rate**: Configurable via `audioFormat.sampleRate` in SDK initialization (default: 16000 Hz)
|
|
200
|
+
- Supported sample rates: 8000, 16000, 22050, 24000, 32000, 44100, 48000 Hz
|
|
201
|
+
- The configured sample rate will be used for both audio recording and playback
|
|
202
|
+
- **Channels**: Mono (single channel) - Fixed to 1 channel
|
|
191
203
|
- **Format**: PCM16 (16-bit signed integer, little-endian)
|
|
192
204
|
- **Byte Order**: Little-endian
|
|
193
205
|
|
|
194
206
|
**Audio Data Format:**
|
|
195
207
|
- Each sample is 2 bytes (16-bit)
|
|
196
208
|
- Audio data should be provided as `ArrayBuffer` or `Uint8Array`
|
|
197
|
-
- For example: 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
|
|
209
|
+
- For example, with 16kHz sample rate: 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
|
|
210
|
+
- For 48kHz sample rate: 1 second of audio = 48000 samples × 2 bytes = 96000 bytes
|
|
198
211
|
|
|
199
212
|
**Resampling:**
|
|
200
|
-
- If your audio source is at a different sample rate
|
|
213
|
+
- If your audio source is at a different sample rate, you must resample it to match the configured sample rate before sending to the SDK
|
|
201
214
|
- For high-quality resampling, we recommend using Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
|
|
202
215
|
- See example projects for resampling implementation
|
|
203
216
|
|
|
217
|
+
**Configuration Example:**
|
|
218
|
+
```typescript
|
|
219
|
+
const configuration: Configuration = {
|
|
220
|
+
environment: Environment.cn,
|
|
221
|
+
audioFormat: {
|
|
222
|
+
channelCount: 1, // Fixed to 1 (mono)
|
|
223
|
+
sampleRate: 48000 // Choose from: 8000, 16000, 22050, 24000, 32000, 44100, 48000
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
204
228
|
## 📚 API Reference
|
|
205
229
|
|
|
206
|
-
###
|
|
230
|
+
### AvatarSDK
|
|
207
231
|
|
|
208
232
|
The core management class of the SDK, responsible for initialization and global configuration.
|
|
209
233
|
|
|
210
234
|
```typescript
|
|
211
235
|
// Initialize SDK
|
|
212
|
-
await
|
|
236
|
+
await AvatarSDK.initialize(appId: string, configuration: Configuration)
|
|
213
237
|
|
|
214
238
|
// Check initialization status
|
|
215
|
-
const isInitialized =
|
|
239
|
+
const isInitialized = AvatarSDK.isInitialized
|
|
240
|
+
|
|
241
|
+
// Get initialized app ID
|
|
242
|
+
const appId = AvatarSDK.appId
|
|
243
|
+
|
|
244
|
+
// Get configuration
|
|
245
|
+
const config = AvatarSDK.configuration
|
|
246
|
+
|
|
247
|
+
// Set sessionToken (if needed, call separately)
|
|
248
|
+
AvatarSDK.setSessionToken('your-session-token')
|
|
249
|
+
|
|
250
|
+
// Set userId (optional, for telemetry)
|
|
251
|
+
AvatarSDK.setUserId('user-id')
|
|
252
|
+
|
|
253
|
+
// Get sessionToken
|
|
254
|
+
const sessionToken = AvatarSDK.sessionToken
|
|
255
|
+
|
|
256
|
+
// Get userId
|
|
257
|
+
const userId = AvatarSDK.userId
|
|
258
|
+
|
|
259
|
+
// Get SDK version
|
|
260
|
+
const version = AvatarSDK.version
|
|
216
261
|
|
|
217
262
|
// Cleanup resources (must be called when no longer in use)
|
|
218
|
-
|
|
263
|
+
AvatarSDK.cleanup()
|
|
219
264
|
```
|
|
220
265
|
|
|
221
266
|
### AvatarManager
|
|
222
267
|
|
|
223
|
-
Character resource manager, responsible for downloading, caching, and loading character data.
|
|
268
|
+
Character resource manager, responsible for downloading, caching, and loading character data. Use the singleton instance via `AvatarManager.shared`.
|
|
224
269
|
|
|
225
270
|
```typescript
|
|
226
|
-
|
|
271
|
+
// Get singleton instance
|
|
272
|
+
const manager = AvatarManager.shared
|
|
227
273
|
|
|
228
274
|
// Load character
|
|
229
275
|
const avatar = await manager.load(
|
|
@@ -239,37 +285,40 @@ manager.clearCache()
|
|
|
239
285
|
|
|
240
286
|
3D rendering view (rendering layer), responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
|
|
241
287
|
|
|
242
|
-
|
|
288
|
+
```typescript
|
|
289
|
+
constructor(avatar: Avatar, container: HTMLElement)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Parameters:**
|
|
293
|
+
- `avatar`: Avatar instance
|
|
294
|
+
- `container`: Canvas container element (required)
|
|
295
|
+
- Canvas automatically uses the full size of the container (width and height)
|
|
296
|
+
- Canvas aspect ratio adapts to container size - set container size to control aspect ratio
|
|
297
|
+
- Canvas will be automatically added to the container
|
|
298
|
+
- SDK automatically handles resize events via ResizeObserver
|
|
243
299
|
|
|
244
|
-
**Playback Mode
|
|
300
|
+
**Playback Mode:**
|
|
301
|
+
- The playback mode is determined by `drivingServiceMode` in `AvatarSDK.initialize()` configuration
|
|
245
302
|
- The playback mode is fixed when creating `AvatarView` and persists throughout its lifecycle
|
|
246
303
|
- Cannot be changed after creation
|
|
247
304
|
|
|
248
305
|
```typescript
|
|
249
|
-
import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
|
|
250
|
-
|
|
251
306
|
// Create view (Canvas is automatically added to container)
|
|
252
|
-
// Network mode (default)
|
|
253
307
|
const container = document.getElementById('avatar-container')
|
|
254
|
-
const avatarView = new AvatarView(avatar
|
|
255
|
-
container: container,
|
|
256
|
-
playbackMode: AvatarPlaybackMode.network // Optional, default is 'network'
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
// External data mode
|
|
260
|
-
const avatarView = new AvatarView(avatar: Avatar, {
|
|
261
|
-
container: container,
|
|
262
|
-
playbackMode: AvatarPlaybackMode.external
|
|
263
|
-
})
|
|
308
|
+
const avatarView = new AvatarView(avatar, container)
|
|
264
309
|
|
|
265
|
-
//
|
|
266
|
-
|
|
310
|
+
// Wait for first frame to render
|
|
311
|
+
await avatarView.ready // Promise that resolves when the first frame is rendered
|
|
267
312
|
|
|
268
|
-
// Get
|
|
269
|
-
|
|
313
|
+
// Get or set avatar transform (position and scale)
|
|
314
|
+
// Get current transform
|
|
315
|
+
const currentTransform = avatarView.transform // { x: number, y: number, scale: number }
|
|
270
316
|
|
|
271
|
-
//
|
|
272
|
-
avatarView.
|
|
317
|
+
// Set transform
|
|
318
|
+
avatarView.transform = { x, y, scale }
|
|
319
|
+
// - x: Horizontal offset in normalized coordinates (-1 to 1, where -1 = left edge, 0 = center, 1 = right edge)
|
|
320
|
+
// - y: Vertical offset in normalized coordinates (-1 to 1, where -1 = bottom edge, 0 = center, 1 = top edge)
|
|
321
|
+
// - scale: Scale factor (1.0 = original size, 2.0 = double size, 0.5 = half size)
|
|
273
322
|
|
|
274
323
|
// Cleanup resources (must be called before switching characters)
|
|
275
324
|
avatarView.dispose()
|
|
@@ -278,105 +327,117 @@ avatarView.dispose()
|
|
|
278
327
|
**Character Switching Example:**
|
|
279
328
|
|
|
280
329
|
```typescript
|
|
281
|
-
//
|
|
330
|
+
// To switch characters, simply dispose the old view and create a new one
|
|
282
331
|
if (currentAvatarView) {
|
|
283
332
|
currentAvatarView.dispose()
|
|
284
|
-
currentAvatarView = null
|
|
285
333
|
}
|
|
286
334
|
|
|
287
335
|
// Load new character
|
|
288
336
|
const newAvatar = await avatarManager.load('new-character-id')
|
|
289
337
|
|
|
290
|
-
// Create new AvatarView
|
|
291
|
-
currentAvatarView = new AvatarView(newAvatar,
|
|
292
|
-
container: container,
|
|
293
|
-
playbackMode: AvatarPlaybackMode.network
|
|
294
|
-
})
|
|
338
|
+
// Create new AvatarView
|
|
339
|
+
currentAvatarView = new AvatarView(newAvatar, container)
|
|
295
340
|
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
await currentAvatarView.avatarController.start()
|
|
299
|
-
}
|
|
341
|
+
// SDK mode: start connection (will throw error if not in SDK mode)
|
|
342
|
+
await currentAvatarView.controller.start()
|
|
300
343
|
```
|
|
301
344
|
|
|
302
345
|
### AvatarController
|
|
303
346
|
|
|
304
|
-
Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically
|
|
347
|
+
Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically handles WebSocket communication in SDK mode.
|
|
305
348
|
|
|
306
349
|
**Two Usage Patterns:**
|
|
307
350
|
|
|
308
|
-
####
|
|
351
|
+
#### SDK Mode Methods
|
|
309
352
|
|
|
310
353
|
```typescript
|
|
311
354
|
// Start WebSocket service
|
|
312
355
|
await avatarView.avatarController.start()
|
|
313
356
|
|
|
314
|
-
// Send audio data (
|
|
315
|
-
avatarView.avatarController.send(audioData: ArrayBuffer, end: boolean)
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
// - Channels: Mono (single channel)
|
|
320
|
-
// - Example: 1 second = 16000 samples × 2 bytes = 32000 bytes
|
|
321
|
-
// end: false (default) - Normal audio data sending, server will accumulate audio data, automatically returns animation data and starts synchronized playback of animation and audio after accumulating enough data
|
|
322
|
-
// end: true - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
357
|
+
// Send audio data (must be 16kHz mono PCM16 format)
|
|
358
|
+
const conversationId = avatarView.avatarController.send(audioData: ArrayBuffer, end: boolean)
|
|
359
|
+
// Returns: conversationId - Conversation ID for this conversation session
|
|
360
|
+
// end: false (default) - Continue sending audio data for current conversation
|
|
361
|
+
// end: true - Mark the end of current conversation round. After end=true, sending new audio data will interrupt any ongoing playback from the previous conversation round
|
|
323
362
|
|
|
324
363
|
// Close WebSocket service
|
|
325
364
|
avatarView.avatarController.close()
|
|
326
365
|
```
|
|
327
366
|
|
|
328
|
-
####
|
|
367
|
+
#### Host Mode Methods
|
|
329
368
|
|
|
330
369
|
```typescript
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
initialAudioChunks?: Array<{ data: Uint8Array, isLast: boolean }>, // Initial audio chunks (16kHz mono PCM16)
|
|
334
|
-
initialKeyframes?: any[] // Initial animation keyframes (obtained from your service)
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
// Stream additional audio chunks (after play() is called)
|
|
338
|
-
avatarView.avatarController.sendAudioChunk(
|
|
370
|
+
// Stream audio chunks (must be 16kHz mono PCM16 format)
|
|
371
|
+
const conversationId = avatarView.avatarController.yieldAudioData(
|
|
339
372
|
data: Uint8Array, // Audio chunk data
|
|
340
373
|
isLast: boolean = false // Whether this is the last chunk
|
|
341
374
|
)
|
|
375
|
+
// Returns: conversationId - Conversation ID for this audio session
|
|
342
376
|
|
|
343
|
-
// Stream
|
|
344
|
-
avatarView.avatarController.
|
|
345
|
-
|
|
377
|
+
// Stream animation keyframes (requires conversationId from audio data)
|
|
378
|
+
avatarView.avatarController.yieldFramesData(
|
|
379
|
+
keyframesDataArray: (Uint8Array | ArrayBuffer)[], // Animation keyframes binary data array (each element is a protobuf encoded Message)
|
|
380
|
+
conversationId: string // Conversation ID (required)
|
|
346
381
|
)
|
|
347
382
|
```
|
|
348
383
|
|
|
384
|
+
**⚠️ Important: Conversation ID (conversationId) Management**
|
|
385
|
+
|
|
386
|
+
**SDK Mode:**
|
|
387
|
+
- `send()` returns a conversationId to distinguish each conversation round
|
|
388
|
+
- `end=true` marks the end of a conversation round
|
|
389
|
+
|
|
390
|
+
**Host Mode:**
|
|
391
|
+
- `yieldAudioData()` returns a conversationId (automatically generates if starting new session)
|
|
392
|
+
- `yieldFramesData()` requires a valid conversationId parameter
|
|
393
|
+
- Animation data with mismatched conversationId will be **discarded**
|
|
394
|
+
- Use `getCurrentConversationId()` to retrieve the current active conversationId
|
|
395
|
+
|
|
349
396
|
#### Common Methods (Both Modes)
|
|
350
397
|
|
|
351
398
|
```typescript
|
|
399
|
+
|
|
352
400
|
// Interrupt current playback (stops and clears data)
|
|
353
401
|
avatarView.avatarController.interrupt()
|
|
354
402
|
|
|
355
403
|
// Clear all data and resources
|
|
356
404
|
avatarView.avatarController.clear()
|
|
357
405
|
|
|
358
|
-
// Get
|
|
359
|
-
const
|
|
406
|
+
// Get current conversation ID (for Host mode)
|
|
407
|
+
const conversationId = avatarView.avatarController.getCurrentConversationId()
|
|
408
|
+
// Returns: Current conversationId for the active audio session, or null if no active session
|
|
360
409
|
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
// Close service (network mode only)
|
|
365
|
-
avatarView.avatarController.close()
|
|
366
|
-
|
|
367
|
-
// Get current avatar state
|
|
368
|
-
const state = avatarView.avatarController.state
|
|
410
|
+
// Volume control (affects only avatar audio player, not system volume)
|
|
411
|
+
avatarView.avatarController.setVolume(0.5) // Set volume to 50% (0.0 to 1.0)
|
|
412
|
+
const currentVolume = avatarView.avatarController.getVolume() // Get current volume (0.0 to 1.0)
|
|
369
413
|
|
|
370
414
|
// Set event callbacks
|
|
371
|
-
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {} //
|
|
372
|
-
avatarView.avatarController.
|
|
415
|
+
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {} // SDK mode only
|
|
416
|
+
avatarView.avatarController.onConversationState = (state: ConversationState) => {}
|
|
373
417
|
avatarView.avatarController.onError = (error: Error) => {}
|
|
374
418
|
```
|
|
375
419
|
|
|
420
|
+
#### Avatar Transform Methods
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Get or set avatar transform (position and scale in canvas)
|
|
424
|
+
// Get current transform
|
|
425
|
+
const currentTransform = avatarView.transform // { x: number, y: number, scale: number }
|
|
426
|
+
|
|
427
|
+
// Set transform
|
|
428
|
+
avatarView.transform = { x, y, scale }
|
|
429
|
+
// - x: Horizontal offset in normalized coordinates (-1 to 1, where -1 = left edge, 0 = center, 1 = right edge)
|
|
430
|
+
// - y: Vertical offset in normalized coordinates (-1 to 1, where -1 = bottom edge, 0 = center, 1 = top edge)
|
|
431
|
+
// - scale: Scale factor (1.0 = original size, 2.0 = double size, 0.5 = half size)
|
|
432
|
+
// Example:
|
|
433
|
+
avatarView.transform = { x: 0, y: 0, scale: 1.0 } // Center, original size
|
|
434
|
+
avatarView.transform = { x: 0.5, y: 0, scale: 2.0 } // Right half, double size
|
|
435
|
+
```
|
|
436
|
+
|
|
376
437
|
**Important Notes:**
|
|
377
|
-
- `start()` and `close()` are only available in
|
|
378
|
-
- `
|
|
379
|
-
- `interrupt()` and `
|
|
438
|
+
- `start()` and `close()` are only available in SDK mode
|
|
439
|
+
- `yieldAudioData()` and `yieldFramesData()` are only available in Host mode
|
|
440
|
+
- `pause()`, `resume()`, `interrupt()`, `clear()`, `getCurrentConversationId()`, `setVolume()`, and `getVolume()` are available in both modes
|
|
380
441
|
- The playback mode is determined when creating `AvatarView` and cannot be changed
|
|
381
442
|
|
|
382
443
|
## 🔧 Configuration
|
|
@@ -386,40 +447,53 @@ avatarView.avatarController.onError = (error: Error) => {}
|
|
|
386
447
|
```typescript
|
|
387
448
|
interface Configuration {
|
|
388
449
|
environment: Environment
|
|
450
|
+
drivingServiceMode?: DrivingServiceMode // Optional, default is 'sdk' (SDK mode)
|
|
451
|
+
logLevel?: LogLevel // Optional, default is 'off' (no logs)
|
|
452
|
+
audioFormat?: AudioFormat // Optional, default is { channelCount: 1, sampleRate: 16000 }
|
|
389
453
|
}
|
|
390
|
-
```
|
|
391
454
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
```typescript
|
|
397
|
-
enum Environment {
|
|
398
|
-
cn = 'cn', // China region
|
|
399
|
-
us = 'us', // US region
|
|
400
|
-
test = 'test' // Test environment
|
|
455
|
+
interface AudioFormat {
|
|
456
|
+
readonly channelCount: 1 // Fixed to 1 (mono)
|
|
457
|
+
readonly sampleRate: number // Supported: 8000, 16000, 22050, 24000, 32000, 44100, 48000 Hz, default: 16000
|
|
401
458
|
}
|
|
402
459
|
```
|
|
403
460
|
|
|
404
|
-
###
|
|
461
|
+
### LogLevel
|
|
462
|
+
|
|
463
|
+
Control the verbosity of SDK logs:
|
|
405
464
|
|
|
406
465
|
```typescript
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
466
|
+
enum LogLevel {
|
|
467
|
+
off = 'off', // Disable all logs
|
|
468
|
+
error = 'error', // Only error logs
|
|
469
|
+
warning = 'warning', // Warning and error logs
|
|
470
|
+
all = 'all' // All logs (info, warning, error) - default
|
|
410
471
|
}
|
|
411
472
|
```
|
|
412
473
|
|
|
474
|
+
**Note:** `LogLevel.off` completely disables all logging, including error logs. Use with caution in production environments.
|
|
475
|
+
|
|
413
476
|
**Description:**
|
|
414
|
-
- `
|
|
415
|
-
|
|
416
|
-
- `
|
|
417
|
-
- `
|
|
477
|
+
- `environment`: Specifies the environment (cn/intl), SDK will automatically use the corresponding API address and WebSocket address based on the environment
|
|
478
|
+
- `drivingServiceMode`: Specifies the driving service mode
|
|
479
|
+
- `DrivingServiceMode.sdk` (default): SDK mode - SDK handles WebSocket communication automatically
|
|
480
|
+
- `DrivingServiceMode.host`: Host mode - Host application provides audio and animation data
|
|
481
|
+
- `logLevel`: Controls the verbosity of SDK logs
|
|
482
|
+
- `LogLevel.off` (default): Disable all logs
|
|
483
|
+
- `LogLevel.error`: Only error logs
|
|
484
|
+
- `LogLevel.warning`: Warning and error logs
|
|
485
|
+
- `LogLevel.all`: All logs (info, warning, error)
|
|
486
|
+
- `audioFormat`: Configures audio sample rate and channel count
|
|
487
|
+
- `channelCount`: Fixed to 1 (mono channel)
|
|
488
|
+
- `sampleRate`: Audio sample rate in Hz (default: 16000)
|
|
489
|
+
- Supported values: 8000, 16000, 22050, 24000, 32000, 44100, 48000
|
|
490
|
+
- The configured sample rate will be used for both audio recording and playback
|
|
491
|
+
- `sessionToken`: Set separately via `AvatarSDK.setSessionToken()`, not in Configuration
|
|
418
492
|
|
|
419
493
|
```typescript
|
|
420
|
-
enum
|
|
421
|
-
|
|
422
|
-
|
|
494
|
+
enum Environment {
|
|
495
|
+
cn = 'cn', // China region
|
|
496
|
+
intl = 'intl', // International region
|
|
423
497
|
}
|
|
424
498
|
```
|
|
425
499
|
|
|
@@ -450,16 +524,25 @@ enum ConnectionState {
|
|
|
450
524
|
}
|
|
451
525
|
```
|
|
452
526
|
|
|
453
|
-
###
|
|
527
|
+
### ConversationState
|
|
454
528
|
|
|
455
529
|
```typescript
|
|
456
|
-
enum
|
|
457
|
-
idle = 'idle', // Idle state
|
|
458
|
-
|
|
459
|
-
|
|
530
|
+
enum ConversationState {
|
|
531
|
+
idle = 'idle', // Idle state (breathing animation)
|
|
532
|
+
playing = 'playing', // Playing state (active conversation)
|
|
533
|
+
pausing = 'pausing' // Pausing state (paused during playback)
|
|
460
534
|
}
|
|
461
535
|
```
|
|
462
536
|
|
|
537
|
+
**State Description:**
|
|
538
|
+
- `idle`: Avatar is in idle state (breathing animation), waiting for conversation to start
|
|
539
|
+
- `playing`: Avatar is playing conversation content (including during transition animations)
|
|
540
|
+
- `pausing`: Avatar playback is paused (e.g., when `end=false` and waiting for more audio data)
|
|
541
|
+
|
|
542
|
+
**Note:** During transition animations, the target state is notified immediately:
|
|
543
|
+
- When transitioning from `idle` to `playing`, the `playing` state is notified immediately
|
|
544
|
+
- When transitioning from `playing` to `idle`, the `idle` state is notified immediately
|
|
545
|
+
|
|
463
546
|
## 🎨 Rendering System
|
|
464
547
|
|
|
465
548
|
The SDK supports two rendering backends:
|
|
@@ -469,57 +552,6 @@ The SDK supports two rendering backends:
|
|
|
469
552
|
|
|
470
553
|
The rendering system automatically selects the best backend, no manual configuration needed.
|
|
471
554
|
|
|
472
|
-
## 🔍 Debugging and Monitoring
|
|
473
|
-
|
|
474
|
-
### Logging System
|
|
475
|
-
|
|
476
|
-
The SDK has a built-in complete logging system, supporting different levels of log output:
|
|
477
|
-
|
|
478
|
-
```typescript
|
|
479
|
-
import { logger } from '@spatialwalk/avatarkit'
|
|
480
|
-
|
|
481
|
-
// Set log level
|
|
482
|
-
logger.setLevel('verbose') // 'basic' | 'verbose'
|
|
483
|
-
|
|
484
|
-
// Manual log output
|
|
485
|
-
logger.log('Info message')
|
|
486
|
-
logger.warn('Warning message')
|
|
487
|
-
logger.error('Error message')
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Performance Monitoring
|
|
491
|
-
|
|
492
|
-
The SDK provides performance monitoring interfaces to monitor rendering performance:
|
|
493
|
-
|
|
494
|
-
```typescript
|
|
495
|
-
// Get rendering performance statistics
|
|
496
|
-
const stats = avatarView.getPerformanceStats()
|
|
497
|
-
|
|
498
|
-
if (stats) {
|
|
499
|
-
console.log(`Render time: ${stats.renderTime.toFixed(2)}ms`)
|
|
500
|
-
console.log(`Sort time: ${stats.sortTime.toFixed(2)}ms`)
|
|
501
|
-
console.log(`Rendering backend: ${stats.backend}`)
|
|
502
|
-
|
|
503
|
-
// Calculate frame rate
|
|
504
|
-
const fps = 1000 / stats.renderTime
|
|
505
|
-
console.log(`Frame rate: ${fps.toFixed(2)} FPS`)
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Regular performance monitoring
|
|
509
|
-
setInterval(() => {
|
|
510
|
-
const stats = avatarView.getPerformanceStats()
|
|
511
|
-
if (stats) {
|
|
512
|
-
// Send to monitoring service or display on UI
|
|
513
|
-
console.log('Performance:', stats)
|
|
514
|
-
}
|
|
515
|
-
}, 1000)
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
**Performance Statistics Description:**
|
|
519
|
-
- `renderTime`: Total rendering time (milliseconds), includes sorting and GPU rendering
|
|
520
|
-
- `sortTime`: Sorting time (milliseconds), uses Radix Sort algorithm to depth-sort point cloud
|
|
521
|
-
- `backend`: Currently used rendering backend (`'webgpu'` | `'webgl'` | `null`)
|
|
522
|
-
|
|
523
555
|
## 🚨 Error Handling
|
|
524
556
|
|
|
525
557
|
### SPAvatarError
|
|
@@ -553,15 +585,12 @@ avatarView.avatarController.onError = (error: Error) => {
|
|
|
553
585
|
|
|
554
586
|
### Lifecycle Management
|
|
555
587
|
|
|
556
|
-
####
|
|
588
|
+
#### SDK Mode Lifecycle
|
|
557
589
|
|
|
558
590
|
```typescript
|
|
559
591
|
// Initialize
|
|
560
592
|
const container = document.getElementById('avatar-container')
|
|
561
|
-
const avatarView = new AvatarView(avatar,
|
|
562
|
-
container: container,
|
|
563
|
-
playbackMode: AvatarPlaybackMode.network
|
|
564
|
-
})
|
|
593
|
+
const avatarView = new AvatarView(avatar, container)
|
|
565
594
|
await avatarView.avatarController.start()
|
|
566
595
|
|
|
567
596
|
// Use
|
|
@@ -572,21 +601,16 @@ avatarView.avatarController.close()
|
|
|
572
601
|
avatarView.dispose() // Automatically cleans up all resources
|
|
573
602
|
```
|
|
574
603
|
|
|
575
|
-
####
|
|
604
|
+
#### Host Mode Lifecycle
|
|
576
605
|
|
|
577
606
|
```typescript
|
|
578
607
|
// Initialize
|
|
579
608
|
const container = document.getElementById('avatar-container')
|
|
580
|
-
const avatarView = new AvatarView(avatar,
|
|
581
|
-
container: container,
|
|
582
|
-
playbackMode: AvatarPlaybackMode.external
|
|
583
|
-
})
|
|
609
|
+
const avatarView = new AvatarView(avatar, container)
|
|
584
610
|
|
|
585
611
|
// Use
|
|
586
|
-
const
|
|
587
|
-
|
|
588
|
-
avatarView.avatarController.sendAudioChunk(audioChunk, false)
|
|
589
|
-
avatarView.avatarController.sendKeyframes(keyframes)
|
|
612
|
+
const conversationId = avatarView.avatarController.yieldAudioData(audioChunk, false)
|
|
613
|
+
avatarView.avatarController.yieldFramesData(keyframesDataArray, conversationId) // keyframesDataArray: (Uint8Array | ArrayBuffer)[]
|
|
590
614
|
|
|
591
615
|
// Cleanup
|
|
592
616
|
avatarView.avatarController.clear() // Clear all data and resources
|
|
@@ -594,11 +618,10 @@ avatarView.dispose() // Automatically cleans up all resources
|
|
|
594
618
|
```
|
|
595
619
|
|
|
596
620
|
**⚠️ Important Notes:**
|
|
597
|
-
-
|
|
598
|
-
- When switching characters, must first call `dispose()` to clean up old AvatarView, then create new instance
|
|
621
|
+
- When disposing AvatarView instances, must call `dispose()` to properly clean up resources
|
|
599
622
|
- Not properly cleaning up may cause resource leaks and rendering errors
|
|
600
|
-
- In
|
|
601
|
-
- In
|
|
623
|
+
- In SDK mode, call `close()` before `dispose()` to properly close WebSocket connections
|
|
624
|
+
- In Host mode, call `clear()` before `dispose()` to clear all playback data
|
|
602
625
|
|
|
603
626
|
### Memory Optimization
|
|
604
627
|
|
|
@@ -606,51 +629,6 @@ avatarView.dispose() // Automatically cleans up all resources
|
|
|
606
629
|
- Supports dynamic loading/unloading of character and animation resources
|
|
607
630
|
- Provides memory usage monitoring interface
|
|
608
631
|
|
|
609
|
-
### Audio Data Sending
|
|
610
|
-
|
|
611
|
-
#### Network Mode
|
|
612
|
-
|
|
613
|
-
The `send()` method receives audio data in `ArrayBuffer` format:
|
|
614
|
-
|
|
615
|
-
**Audio Format Requirements:**
|
|
616
|
-
- **Sample Rate**: 16kHz (16000 Hz) - **Backend requirement, must be exactly 16kHz**
|
|
617
|
-
- **Format**: PCM16 (16-bit signed integer, little-endian)
|
|
618
|
-
- **Channels**: Mono (single channel)
|
|
619
|
-
- **Data Size**: Each sample is 2 bytes, so 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
|
|
620
|
-
|
|
621
|
-
**Usage:**
|
|
622
|
-
- `audioData`: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
|
|
623
|
-
- `end=false` (default) - Normal audio data sending, server will accumulate audio data, automatically returns animation data and starts synchronized playback of animation and audio after accumulating enough data
|
|
624
|
-
- `end=true` - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
625
|
-
- **Important**: No need to wait for `end=true` to start playing, it will automatically start playing after accumulating enough audio data
|
|
626
|
-
|
|
627
|
-
#### External Data Mode
|
|
628
|
-
|
|
629
|
-
The `play()` method starts playback with initial data, then use `sendAudioChunk()` to stream additional audio:
|
|
630
|
-
|
|
631
|
-
**Audio Format Requirements:**
|
|
632
|
-
- Same as network mode: 16kHz mono PCM16 format
|
|
633
|
-
- Audio data should be provided as `Uint8Array` in chunks with `isLast` flag
|
|
634
|
-
|
|
635
|
-
**Usage:**
|
|
636
|
-
```typescript
|
|
637
|
-
// Start playback with initial audio and animation data
|
|
638
|
-
// Note: Audio and animation data should be obtained from your backend service
|
|
639
|
-
const initialAudioChunks = [
|
|
640
|
-
{ data: audioData1, isLast: false },
|
|
641
|
-
{ data: audioData2, isLast: false }
|
|
642
|
-
]
|
|
643
|
-
await avatarController.play(initialAudioChunks, initialKeyframes)
|
|
644
|
-
|
|
645
|
-
// Stream additional audio chunks
|
|
646
|
-
avatarController.sendAudioChunk(audioChunk, isLast)
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
**Resampling (Both Modes):**
|
|
650
|
-
- If your audio source is at a different sample rate (e.g., 24kHz, 48kHz), you **must** resample it to 16kHz before sending
|
|
651
|
-
- For high-quality resampling, use Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
|
|
652
|
-
- See example projects (`vanilla`, `react`, `vue`) for complete resampling implementation
|
|
653
|
-
|
|
654
632
|
## 🌐 Browser Compatibility
|
|
655
633
|
|
|
656
634
|
- **Chrome/Edge** 90+ (WebGPU recommended)
|
|
@@ -670,5 +648,5 @@ Issues and Pull Requests are welcome!
|
|
|
670
648
|
|
|
671
649
|
For questions, please contact:
|
|
672
650
|
- Email: support@spavatar.com
|
|
673
|
-
- Documentation: https://docs.
|
|
651
|
+
- Documentation: https://docs.spatialreal.ai
|
|
674
652
|
- GitHub: https://github.com/spavatar/sdk
|