@spatialwalk/avatarkit 1.0.0-beta.3 → 1.0.0-beta.5
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 +127 -0
- package/README.md +306 -36
- package/dist/{StreamingAudioPlayer-BeLlDiwE.js → StreamingAudioPlayer-8Dz_aHCW.js} +89 -58
- package/dist/StreamingAudioPlayer-8Dz_aHCW.js.map +1 -0
- package/dist/animation/AnimationWebSocketClient.d.ts.map +1 -1
- package/dist/audio/AnimationPlayer.d.ts +4 -0
- package/dist/audio/AnimationPlayer.d.ts.map +1 -1
- package/dist/audio/StreamingAudioPlayer.d.ts +10 -0
- package/dist/audio/StreamingAudioPlayer.d.ts.map +1 -1
- package/dist/avatar_core_wasm-D4eEi7Eh.js +1666 -0
- package/dist/{avatar_core_wasm-DmkU6dYn.js.map → avatar_core_wasm-D4eEi7Eh.js.map} +1 -1
- package/dist/avatar_core_wasm.wasm +0 -0
- package/dist/config/app-config.d.ts +3 -7
- package/dist/config/app-config.d.ts.map +1 -1
- package/dist/config/constants.d.ts +19 -3
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/core/AvatarController.d.ts +91 -64
- package/dist/core/AvatarController.d.ts.map +1 -1
- package/dist/core/AvatarDownloader.d.ts.map +1 -1
- package/dist/core/AvatarKit.d.ts +6 -0
- package/dist/core/AvatarKit.d.ts.map +1 -1
- package/dist/core/AvatarManager.d.ts.map +1 -1
- package/dist/core/AvatarView.d.ts +28 -30
- package/dist/core/AvatarView.d.ts.map +1 -1
- package/dist/core/NetworkLayer.d.ts +59 -0
- package/dist/core/NetworkLayer.d.ts.map +1 -0
- package/dist/index-bbc7bE-q.js +5942 -0
- package/dist/index-bbc7bE-q.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -11
- package/dist/renderer/RenderSystem.d.ts +4 -2
- package/dist/renderer/RenderSystem.d.ts.map +1 -1
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/cls-tracker.d.ts +17 -0
- package/dist/utils/cls-tracker.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/package.json +8 -4
- package/dist/StreamingAudioPlayer-BeLlDiwE.js.map +0 -1
- package/dist/avatar_core_wasm-DmkU6dYn.js +0 -1666
- package/dist/index-NmYXWJnL.js +0 -9712
- package/dist/index-NmYXWJnL.js.map +0 -1
- package/dist/utils/posthog-tracker.d.ts +0 -82
- package/dist/utils/posthog-tracker.d.ts.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0-beta.5] - 2025-11-14
|
|
9
|
+
|
|
10
|
+
### 🐛 Bug Fixes
|
|
11
|
+
- Fixed missing `AvatarPlaybackMode` enum export in published package
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## [1.0.0-beta.4] - 2025-11-14
|
|
16
|
+
|
|
17
|
+
### 🔄 Updates
|
|
18
|
+
- Updated WASM module (avatar_core_wasm.wasm)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## [1.0.0-beta.3] - 2025-11-13
|
|
23
|
+
|
|
24
|
+
### 🎉 Major Changes
|
|
25
|
+
|
|
26
|
+
#### Architecture Refactoring - Three-Layer Architecture
|
|
27
|
+
- **Rendering Layer (AvatarView)**: Pure rendering responsibility, receives rendering instructions from the playback layer
|
|
28
|
+
- **Playback Layer (AvatarController)**: Unified data controller responsible for audio playback and animation rendering synchronization
|
|
29
|
+
- **Network Layer (NetworkLayer)**: Optional network communication layer, automatically composed only in network mode
|
|
30
|
+
|
|
31
|
+
#### Dual Playback Mode Support
|
|
32
|
+
- **Network Mode**:
|
|
33
|
+
- Send audio data to server via WebSocket
|
|
34
|
+
- Automatically receive and play animation data returned from server
|
|
35
|
+
- Use `controller.start()` and `controller.send()` methods
|
|
36
|
+
|
|
37
|
+
- **External Data Mode**:
|
|
38
|
+
- External components fully control audio and animation data acquisition
|
|
39
|
+
- SDK only responsible for synchronized playback of externally provided data
|
|
40
|
+
- Use `controller.play()`, `controller.sendAudioChunk()` and `controller.sendKeyframes()` methods
|
|
41
|
+
|
|
42
|
+
### ✨ New Features
|
|
43
|
+
|
|
44
|
+
- **Transition Animation Optimization**:
|
|
45
|
+
- Transition animation duration adjusted to 200ms
|
|
46
|
+
- Improved audio-animation synchronization logic, ensuring audio and animation start playing together after transition animation ends
|
|
47
|
+
- Optimized transition frame generation and alignment logic
|
|
48
|
+
|
|
49
|
+
- **Camera Configuration Enhancement**:
|
|
50
|
+
- Default transparent background, background rendering functionality removed
|
|
51
|
+
- Camera configuration aligned with iOS (Reversed-Z projection, near=0.01, far=100)
|
|
52
|
+
- Support dynamic camera configuration loading from characterSettings and camera.json
|
|
53
|
+
|
|
54
|
+
- **Audio Sample Rate Configuration**:
|
|
55
|
+
- Updated default audio sample rate to 16kHz (previously 24kHz) to match backend requirements
|
|
56
|
+
- Audio format requirement: 16kHz mono PCM16
|
|
57
|
+
|
|
58
|
+
- **Telemetry Migration**:
|
|
59
|
+
- Migrated from PostHog to Tencent Cloud CLS (Cloud Log Service)
|
|
60
|
+
- Support environment-based dynamic configuration (cn/test/us)
|
|
61
|
+
- Support both Token and SecretId/SecretKey authentication methods
|
|
62
|
+
- Aligned with iOS SDK configuration
|
|
63
|
+
|
|
64
|
+
### 🔧 API Changes
|
|
65
|
+
|
|
66
|
+
#### Breaking Changes
|
|
67
|
+
|
|
68
|
+
- **AvatarView Constructor**:
|
|
69
|
+
```typescript
|
|
70
|
+
// Old API
|
|
71
|
+
new AvatarView(avatar, container)
|
|
72
|
+
|
|
73
|
+
// New API
|
|
74
|
+
new AvatarView(avatar, {
|
|
75
|
+
container: container,
|
|
76
|
+
playbackMode: AvatarPlaybackMode.network // or AvatarPlaybackMode.external
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- **AvatarController Methods**:
|
|
81
|
+
- Network Mode: `start()` / `close()` / `send()`
|
|
82
|
+
- External Data Mode: `play()` / `sendAudioChunk()` / `sendKeyframes()`
|
|
83
|
+
- Common Methods: `interrupt()` / `clear()` / `dispose()`
|
|
84
|
+
|
|
85
|
+
- **Removed Properties**:
|
|
86
|
+
- `realtimeStartTime` property removed (no longer needed)
|
|
87
|
+
|
|
88
|
+
### 🐛 Bug Fixes
|
|
89
|
+
|
|
90
|
+
- Fixed audio-animation desynchronization during transition animation
|
|
91
|
+
- Fixed animation freezing issue in external data mode
|
|
92
|
+
- Fixed audio playback speed abnormality caused by sample rate mismatch
|
|
93
|
+
- Fixed camera configuration priority logic
|
|
94
|
+
- Fixed WebSocket connection state callback timing issues
|
|
95
|
+
|
|
96
|
+
### 📚 Documentation
|
|
97
|
+
|
|
98
|
+
- Updated README.md with detailed explanation of three-layer architecture and two playback modes
|
|
99
|
+
- Added audio format requirements documentation (16kHz mono PCM16)
|
|
100
|
+
- Updated API reference documentation and code examples
|
|
101
|
+
- Added architecture diagrams and flowcharts
|
|
102
|
+
|
|
103
|
+
### 🧪 Testing
|
|
104
|
+
|
|
105
|
+
- Updated unit tests to cover new architecture
|
|
106
|
+
- Added unit tests for external data mode
|
|
107
|
+
- Updated E2E tests to use new API
|
|
108
|
+
- All tests passing (69 unit tests + 24 E2E tests)
|
|
109
|
+
|
|
110
|
+
### 🔄 Internal Changes
|
|
111
|
+
|
|
112
|
+
- Refactored `AvatarController` into unified playback layer
|
|
113
|
+
- Extracted `NetworkLayer` as independent component
|
|
114
|
+
- Optimized animation playback loop and audio-animation synchronization logic
|
|
115
|
+
- Updated WASM module (avatar_core_wasm.wasm)
|
|
116
|
+
- Improved error handling and logging
|
|
117
|
+
|
|
118
|
+
### 📦 Dependencies
|
|
119
|
+
|
|
120
|
+
- No new dependencies added
|
|
121
|
+
- Maintained existing dependency versions
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## [1.0.0-beta.2] - Previous Version
|
|
126
|
+
|
|
127
|
+
(Previous version changelog entries...)
|
package/README.md
CHANGED
|
@@ -47,51 +47,159 @@ const avatar = await avatarManager.load('character-id', (progress) => {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
// 3. Create view (automatically creates Canvas and AvatarController)
|
|
50
|
+
// Network mode (default)
|
|
50
51
|
const container = document.getElementById('avatar-container')
|
|
51
|
-
const avatarView = new AvatarView(avatar,
|
|
52
|
+
const avatarView = new AvatarView(avatar, {
|
|
53
|
+
container: container,
|
|
54
|
+
playbackMode: 'network' // Optional, 'network' is default
|
|
55
|
+
})
|
|
52
56
|
|
|
53
|
-
// 4. Start real-time communication
|
|
57
|
+
// 4. Start real-time communication (network mode only)
|
|
54
58
|
await avatarView.avatarController.start()
|
|
55
59
|
|
|
56
|
-
// 5. Send audio data
|
|
60
|
+
// 5. Send audio data (network mode)
|
|
61
|
+
// ⚠️ Important: Audio must be 16kHz mono PCM16 format
|
|
57
62
|
// If audio is Uint8Array, you can use slice().buffer to convert to ArrayBuffer
|
|
58
|
-
const audioUint8 = new Uint8Array(1024) // Example: audio data
|
|
63
|
+
const audioUint8 = new Uint8Array(1024) // Example: 16kHz PCM16 audio data (512 samples = 1024 bytes)
|
|
59
64
|
const audioData = audioUint8.slice().buffer // Simplified conversion, works for ArrayBuffer and SharedArrayBuffer
|
|
60
65
|
avatarView.avatarController.send(audioData, false) // Send audio data, will automatically start playing after accumulating enough data
|
|
61
66
|
avatarView.avatarController.send(audioData, true) // end=true means immediately return animation data, no longer accumulating
|
|
62
67
|
```
|
|
63
68
|
|
|
64
|
-
###
|
|
69
|
+
### External Data Mode Example
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
|
|
73
|
+
|
|
74
|
+
// 1-3. Same as network mode (initialize SDK, load character)
|
|
75
|
+
|
|
76
|
+
// 3. Create view with external data mode
|
|
77
|
+
const container = document.getElementById('avatar-container')
|
|
78
|
+
const avatarView = new AvatarView(avatar, {
|
|
79
|
+
container: container,
|
|
80
|
+
playbackMode: AvatarPlaybackMode.external
|
|
81
|
+
})
|
|
65
82
|
|
|
66
|
-
|
|
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
|
+
|
|
90
|
+
// 5. Stream additional data as needed
|
|
91
|
+
avatarView.avatarController.sendAudioChunk(audioData3, false)
|
|
92
|
+
avatarView.avatarController.sendKeyframes(animationData2)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Complete Examples
|
|
96
|
+
|
|
97
|
+
Check the example code in the GitHub repository for complete usage flows for both modes.
|
|
67
98
|
|
|
68
99
|
**Example Project:** [Avatarkit-web-demo](https://github.com/spatialwalk/Avatarkit-web-demo)
|
|
69
100
|
|
|
70
|
-
This repository contains complete examples for Vanilla JS, Vue 3, and React, demonstrating
|
|
101
|
+
This repository contains complete examples for Vanilla JS, Vue 3, and React, demonstrating:
|
|
102
|
+
- Network mode: Real-time audio input with automatic animation data reception
|
|
103
|
+
- External data mode: Custom data sources with manual audio/animation data management
|
|
71
104
|
|
|
72
105
|
## 🏗️ Architecture Overview
|
|
73
106
|
|
|
107
|
+
### Three-Layer Architecture
|
|
108
|
+
|
|
109
|
+
The SDK uses a three-layer architecture for clear separation of concerns:
|
|
110
|
+
|
|
111
|
+
1. **Rendering Layer (AvatarView)** - Responsible for 3D rendering only
|
|
112
|
+
2. **Playback Layer (AvatarController)** - Manages audio/animation synchronization and playback
|
|
113
|
+
3. **Network Layer (NetworkLayer)** - Handles WebSocket communication (only in network mode)
|
|
114
|
+
|
|
74
115
|
### Core Components
|
|
75
116
|
|
|
76
117
|
- **AvatarKit** - SDK initialization and management
|
|
77
118
|
- **AvatarManager** - Character resource loading and management
|
|
78
|
-
- **AvatarView** - 3D rendering view (
|
|
79
|
-
- **AvatarController** -
|
|
119
|
+
- **AvatarView** - 3D rendering view (rendering layer)
|
|
120
|
+
- **AvatarController** - Audio/animation playback controller (playback layer)
|
|
121
|
+
- **NetworkLayer** - WebSocket communication (network layer, automatically composed in network mode)
|
|
80
122
|
- **AvatarCoreAdapter** - WASM module adapter
|
|
81
123
|
|
|
124
|
+
### Playback Modes
|
|
125
|
+
|
|
126
|
+
The SDK supports two playback modes, configured when creating `AvatarView`:
|
|
127
|
+
|
|
128
|
+
#### 1. Network Mode (Default)
|
|
129
|
+
- SDK handles WebSocket communication automatically
|
|
130
|
+
- Send audio data via `AvatarController.send()`
|
|
131
|
+
- SDK receives animation data from backend and synchronizes playback
|
|
132
|
+
- Best for: Real-time audio input scenarios
|
|
133
|
+
|
|
134
|
+
#### 2. External Data Mode
|
|
135
|
+
- External components manage their own network/data fetching
|
|
136
|
+
- External components provide both audio and animation data
|
|
137
|
+
- SDK only handles synchronized playback
|
|
138
|
+
- Best for: Custom data sources, pre-recorded content, or custom network implementations
|
|
139
|
+
|
|
82
140
|
### Data Flow
|
|
83
141
|
|
|
142
|
+
#### Network Mode Flow
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
User audio input (16kHz mono PCM16)
|
|
146
|
+
↓
|
|
147
|
+
AvatarController.send()
|
|
148
|
+
↓
|
|
149
|
+
NetworkLayer → WebSocket → Backend processing
|
|
150
|
+
↓
|
|
151
|
+
Backend returns animation data (FLAME keyframes)
|
|
152
|
+
↓
|
|
153
|
+
NetworkLayer → AvatarController → AnimationPlayer
|
|
154
|
+
↓
|
|
155
|
+
FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
|
|
156
|
+
↓
|
|
157
|
+
AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
|
|
158
|
+
↓
|
|
159
|
+
RenderSystem → WebGPU/WebGL → Canvas rendering
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### External Data Mode Flow
|
|
163
|
+
|
|
84
164
|
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
165
|
+
External data source (audio + animation)
|
|
166
|
+
↓
|
|
167
|
+
AvatarController.play(initialAudio, initialKeyframes) // Start playback
|
|
168
|
+
↓
|
|
169
|
+
AvatarController.sendAudioChunk() // Stream additional audio
|
|
170
|
+
AvatarController.sendKeyframes() // Stream additional animation
|
|
171
|
+
↓
|
|
172
|
+
AvatarController → AnimationPlayer (synchronized playback)
|
|
173
|
+
↓
|
|
89
174
|
FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
|
|
90
|
-
|
|
91
|
-
|
|
175
|
+
↓
|
|
176
|
+
AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
|
|
177
|
+
↓
|
|
178
|
+
RenderSystem → WebGPU/WebGL → Canvas rendering
|
|
92
179
|
```
|
|
93
180
|
|
|
94
|
-
**Note:**
|
|
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
|
+
### Audio Format Requirements
|
|
186
|
+
|
|
187
|
+
**⚠️ Important:** The SDK requires audio data to be in **16kHz mono PCM16** format:
|
|
188
|
+
|
|
189
|
+
- **Sample Rate**: 16kHz (16000 Hz) - This is a backend requirement
|
|
190
|
+
- **Channels**: Mono (single channel)
|
|
191
|
+
- **Format**: PCM16 (16-bit signed integer, little-endian)
|
|
192
|
+
- **Byte Order**: Little-endian
|
|
193
|
+
|
|
194
|
+
**Audio Data Format:**
|
|
195
|
+
- Each sample is 2 bytes (16-bit)
|
|
196
|
+
- Audio data should be provided as `ArrayBuffer` or `Uint8Array`
|
|
197
|
+
- For example: 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
|
|
198
|
+
|
|
199
|
+
**Resampling:**
|
|
200
|
+
- If your audio source is at a different sample rate (e.g., 24kHz, 48kHz), you must resample it to 16kHz before sending to the SDK
|
|
201
|
+
- For high-quality resampling, we recommend using Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
|
|
202
|
+
- See example projects for resampling implementation
|
|
95
203
|
|
|
96
204
|
## 📚 API Reference
|
|
97
205
|
|
|
@@ -129,20 +237,36 @@ manager.clearCache()
|
|
|
129
237
|
|
|
130
238
|
### AvatarView
|
|
131
239
|
|
|
132
|
-
3D rendering view,
|
|
240
|
+
3D rendering view (rendering layer), responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
|
|
133
241
|
|
|
134
242
|
**⚠️ Important Limitation:** Currently, the SDK only supports one AvatarView instance at a time. If you need to switch characters, you must first call the `dispose()` method to clean up the current AvatarView, then create a new instance.
|
|
135
243
|
|
|
244
|
+
**Playback Mode Configuration:**
|
|
245
|
+
- The playback mode is fixed when creating `AvatarView` and persists throughout its lifecycle
|
|
246
|
+
- Cannot be changed after creation
|
|
247
|
+
|
|
136
248
|
```typescript
|
|
249
|
+
import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
|
|
250
|
+
|
|
137
251
|
// Create view (Canvas is automatically added to container)
|
|
138
|
-
|
|
252
|
+
// Network mode (default)
|
|
253
|
+
const container = document.getElementById('avatar-container')
|
|
254
|
+
const avatarView = new AvatarView(avatar: 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
|
+
})
|
|
139
264
|
|
|
140
265
|
// Get Canvas element
|
|
141
266
|
const canvas = avatarView.getCanvas()
|
|
142
267
|
|
|
143
|
-
//
|
|
144
|
-
avatarView.
|
|
145
|
-
avatarView.setBackgroundOpaque(true)
|
|
268
|
+
// Get playback mode
|
|
269
|
+
const mode = avatarView.playbackMode // 'network' | 'external'
|
|
146
270
|
|
|
147
271
|
// Update camera configuration
|
|
148
272
|
avatarView.updateCameraConfig(cameraConfig: CameraConfig)
|
|
@@ -163,39 +287,98 @@ if (currentAvatarView) {
|
|
|
163
287
|
// Load new character
|
|
164
288
|
const newAvatar = await avatarManager.load('new-character-id')
|
|
165
289
|
|
|
166
|
-
// Create new AvatarView
|
|
167
|
-
currentAvatarView = new AvatarView(newAvatar,
|
|
168
|
-
|
|
290
|
+
// Create new AvatarView (with same or different playback mode)
|
|
291
|
+
currentAvatarView = new AvatarView(newAvatar, {
|
|
292
|
+
container: container,
|
|
293
|
+
playbackMode: AvatarPlaybackMode.network
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
// Network mode: start connection
|
|
297
|
+
if (currentAvatarView.playbackMode === AvatarPlaybackMode.network) {
|
|
298
|
+
await currentAvatarView.avatarController.start()
|
|
299
|
+
}
|
|
169
300
|
```
|
|
170
301
|
|
|
171
302
|
### AvatarController
|
|
172
303
|
|
|
173
|
-
|
|
304
|
+
Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically composes `NetworkLayer` in network mode.
|
|
305
|
+
|
|
306
|
+
**Two Usage Patterns:**
|
|
307
|
+
|
|
308
|
+
#### Network Mode Methods
|
|
174
309
|
|
|
175
310
|
```typescript
|
|
176
|
-
// Start
|
|
311
|
+
// Start WebSocket service
|
|
177
312
|
await avatarView.avatarController.start()
|
|
178
313
|
|
|
179
|
-
// Send audio data
|
|
314
|
+
// Send audio data (SDK handles receiving animation data automatically)
|
|
180
315
|
avatarView.avatarController.send(audioData: ArrayBuffer, end: boolean)
|
|
181
|
-
// audioData: Audio data (ArrayBuffer format)
|
|
316
|
+
// audioData: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
|
|
317
|
+
// - Sample rate: 16kHz (16000 Hz) - backend requirement
|
|
318
|
+
// - Format: PCM16 (16-bit signed integer, little-endian)
|
|
319
|
+
// - Channels: Mono (single channel)
|
|
320
|
+
// - Example: 1 second = 16000 samples × 2 bytes = 32000 bytes
|
|
182
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
|
|
183
322
|
// end: true - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
184
323
|
|
|
185
|
-
//
|
|
324
|
+
// Close WebSocket service
|
|
325
|
+
avatarView.avatarController.close()
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### External Data Mode Methods
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Start playback with initial audio and animation data
|
|
332
|
+
await avatarView.avatarController.play(
|
|
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(
|
|
339
|
+
data: Uint8Array, // Audio chunk data
|
|
340
|
+
isLast: boolean = false // Whether this is the last chunk
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
// Stream additional animation keyframes (after play() is called)
|
|
344
|
+
avatarView.avatarController.sendKeyframes(
|
|
345
|
+
keyframes: any[] // Additional animation keyframes (obtained from your service)
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Common Methods (Both Modes)
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// Interrupt current playback (stops and clears data)
|
|
186
353
|
avatarView.avatarController.interrupt()
|
|
187
354
|
|
|
188
|
-
//
|
|
355
|
+
// Clear all data and resources
|
|
356
|
+
avatarView.avatarController.clear()
|
|
357
|
+
|
|
358
|
+
// Get connection state (network mode only)
|
|
359
|
+
const isConnected = avatarView.avatarController.connected
|
|
360
|
+
|
|
361
|
+
// Start service (network mode only)
|
|
362
|
+
await avatarView.avatarController.start()
|
|
363
|
+
|
|
364
|
+
// Close service (network mode only)
|
|
189
365
|
avatarView.avatarController.close()
|
|
190
366
|
|
|
367
|
+
// Get current avatar state
|
|
368
|
+
const state = avatarView.avatarController.state
|
|
369
|
+
|
|
191
370
|
// Set event callbacks
|
|
192
|
-
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {}
|
|
371
|
+
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {} // Network mode only
|
|
193
372
|
avatarView.avatarController.onAvatarState = (state: AvatarState) => {}
|
|
194
373
|
avatarView.avatarController.onError = (error: Error) => {}
|
|
195
|
-
|
|
196
|
-
// Note: sendText() method is not supported, calling it will throw an error
|
|
197
374
|
```
|
|
198
375
|
|
|
376
|
+
**Important Notes:**
|
|
377
|
+
- `start()` and `close()` are only available in network mode
|
|
378
|
+
- `play()`, `sendAudioChunk()`, and `sendKeyframes()` are only available in external data mode
|
|
379
|
+
- `interrupt()` and `clear()` are available in both modes
|
|
380
|
+
- The playback mode is determined when creating `AvatarView` and cannot be changed
|
|
381
|
+
|
|
199
382
|
## 🔧 Configuration
|
|
200
383
|
|
|
201
384
|
### Configuration
|
|
@@ -218,6 +401,28 @@ enum Environment {
|
|
|
218
401
|
}
|
|
219
402
|
```
|
|
220
403
|
|
|
404
|
+
### AvatarViewOptions
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
interface AvatarViewOptions {
|
|
408
|
+
playbackMode?: AvatarPlaybackMode // Playback mode, default is 'network'
|
|
409
|
+
container?: HTMLElement // Canvas container element
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Description:**
|
|
414
|
+
- `playbackMode`: Specifies the playback mode (`'network'` or `'external'`), default is `'network'`
|
|
415
|
+
- `'network'`: SDK handles WebSocket communication, send audio via `send()`
|
|
416
|
+
- `'external'`: External components provide audio and animation data, SDK handles synchronized playback
|
|
417
|
+
- `container`: Optional container element for Canvas, if not provided, Canvas will be created but not added to DOM
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
enum AvatarPlaybackMode {
|
|
421
|
+
network = 'network', // Network mode: SDK handles WebSocket communication
|
|
422
|
+
external = 'external' // External data mode: External provides data, SDK handles playback
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
221
426
|
### CameraConfig
|
|
222
427
|
|
|
223
428
|
```typescript
|
|
@@ -348,15 +553,43 @@ avatarView.avatarController.onError = (error: Error) => {
|
|
|
348
553
|
|
|
349
554
|
### Lifecycle Management
|
|
350
555
|
|
|
556
|
+
#### Network Mode Lifecycle
|
|
557
|
+
|
|
351
558
|
```typescript
|
|
352
559
|
// Initialize
|
|
353
|
-
const
|
|
560
|
+
const container = document.getElementById('avatar-container')
|
|
561
|
+
const avatarView = new AvatarView(avatar, {
|
|
562
|
+
container: container,
|
|
563
|
+
playbackMode: AvatarPlaybackMode.network
|
|
564
|
+
})
|
|
354
565
|
await avatarView.avatarController.start()
|
|
355
566
|
|
|
356
567
|
// Use
|
|
357
568
|
avatarView.avatarController.send(audioData, false)
|
|
358
569
|
|
|
359
|
-
// Cleanup
|
|
570
|
+
// Cleanup
|
|
571
|
+
avatarView.avatarController.close()
|
|
572
|
+
avatarView.dispose() // Automatically cleans up all resources
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
#### External Data Mode Lifecycle
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
// Initialize
|
|
579
|
+
const container = document.getElementById('avatar-container')
|
|
580
|
+
const avatarView = new AvatarView(avatar, {
|
|
581
|
+
container: container,
|
|
582
|
+
playbackMode: AvatarPlaybackMode.external
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
// Use
|
|
586
|
+
const initialAudioChunks = [{ data: audioData1, isLast: false }]
|
|
587
|
+
await avatarView.avatarController.play(initialAudioChunks, initialKeyframes)
|
|
588
|
+
avatarView.avatarController.sendAudioChunk(audioChunk, false)
|
|
589
|
+
avatarView.avatarController.sendKeyframes(keyframes)
|
|
590
|
+
|
|
591
|
+
// Cleanup
|
|
592
|
+
avatarView.avatarController.clear() // Clear all data and resources
|
|
360
593
|
avatarView.dispose() // Automatically cleans up all resources
|
|
361
594
|
```
|
|
362
595
|
|
|
@@ -364,6 +597,8 @@ avatarView.dispose() // Automatically cleans up all resources
|
|
|
364
597
|
- SDK currently only supports one AvatarView instance at a time
|
|
365
598
|
- When switching characters, must first call `dispose()` to clean up old AvatarView, then create new instance
|
|
366
599
|
- Not properly cleaning up may cause resource leaks and rendering errors
|
|
600
|
+
- In network mode, call `close()` before `dispose()` to properly close WebSocket connections
|
|
601
|
+
- In external data mode, call `clear()` before `dispose()` to clear all playback data
|
|
367
602
|
|
|
368
603
|
### Memory Optimization
|
|
369
604
|
|
|
@@ -373,14 +608,49 @@ avatarView.dispose() // Automatically cleans up all resources
|
|
|
373
608
|
|
|
374
609
|
### Audio Data Sending
|
|
375
610
|
|
|
611
|
+
#### Network Mode
|
|
612
|
+
|
|
376
613
|
The `send()` method receives audio data in `ArrayBuffer` format:
|
|
377
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
|
+
|
|
378
621
|
**Usage:**
|
|
379
|
-
- `audioData`: Audio data (ArrayBuffer format)
|
|
622
|
+
- `audioData`: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
|
|
380
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
|
|
381
624
|
- `end=true` - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
382
625
|
- **Important**: No need to wait for `end=true` to start playing, it will automatically start playing after accumulating enough audio data
|
|
383
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
|
+
|
|
384
654
|
## 🌐 Browser Compatibility
|
|
385
655
|
|
|
386
656
|
- **Chrome/Edge** 90+ (WebGPU recommended)
|