@spatialwalk/avatarkit 1.0.0-beta.28 → 1.0.0-beta.29

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +6 -7
  3. package/dist/StreamingAudioPlayer-C-_1X8K-.js +398 -0
  4. package/dist/animation/AnimationWebSocketClient.d.ts +0 -20
  5. package/dist/animation/utils/eventEmitter.d.ts +0 -3
  6. package/dist/animation/utils/flameConverter.d.ts +3 -10
  7. package/dist/audio/AnimationPlayer.d.ts +0 -46
  8. package/dist/audio/StreamingAudioPlayer.d.ts +0 -81
  9. package/dist/avatar_core_wasm-i0Ocpx6q.js +2693 -0
  10. package/dist/config/app-config.d.ts +1 -5
  11. package/dist/config/constants.d.ts +2 -10
  12. package/dist/config/sdk-config-loader.d.ts +2 -8
  13. package/dist/core/Avatar.d.ts +0 -6
  14. package/dist/core/AvatarController.d.ts +0 -111
  15. package/dist/core/AvatarDownloader.d.ts +0 -75
  16. package/dist/core/AvatarManager.d.ts +6 -13
  17. package/dist/core/AvatarSDK.d.ts +0 -27
  18. package/dist/core/AvatarView.d.ts +4 -103
  19. package/dist/core/NetworkLayer.d.ts +0 -6
  20. package/dist/generated/driveningress/v1/driveningress.d.ts +1 -11
  21. package/dist/generated/driveningress/v2/driveningress.d.ts +0 -2
  22. package/dist/generated/google/protobuf/struct.d.ts +5 -38
  23. package/dist/generated/google/protobuf/timestamp.d.ts +1 -102
  24. package/dist/index-BpVIIm3g.js +7921 -0
  25. package/dist/index.d.ts +0 -3
  26. package/dist/index.js +17 -17
  27. package/dist/renderer/RenderSystem.d.ts +0 -8
  28. package/dist/renderer/covariance.d.ts +0 -11
  29. package/dist/renderer/sortSplats.d.ts +0 -10
  30. package/dist/renderer/webgl/reorderData.d.ts +0 -12
  31. package/dist/renderer/webgl/webglRenderer.d.ts +3 -39
  32. package/dist/renderer/webgpu/webgpuRenderer.d.ts +3 -27
  33. package/dist/types/character-settings.d.ts +0 -4
  34. package/dist/types/character.d.ts +3 -9
  35. package/dist/types/index.d.ts +14 -21
  36. package/dist/utils/animation-interpolation.d.ts +3 -12
  37. package/dist/utils/client-id.d.ts +0 -5
  38. package/dist/utils/cls-tracker.d.ts +5 -26
  39. package/dist/utils/conversationId.d.ts +0 -18
  40. package/dist/utils/error-utils.d.ts +1 -24
  41. package/dist/utils/heartbeat-manager.d.ts +0 -26
  42. package/dist/utils/id-manager.d.ts +0 -23
  43. package/dist/utils/logger.d.ts +1 -4
  44. package/dist/utils/usage-tracker.d.ts +2 -17
  45. package/dist/wasm/avatarCoreAdapter.d.ts +0 -134
  46. package/dist/wasm/avatarCoreMemory.d.ts +0 -52
  47. package/package.json +1 -1
  48. package/dist/StreamingAudioPlayer-DLwlYvg8.js +0 -352
  49. package/dist/avatar_core_wasm-BPIbbUx_.js +0 -1663
  50. package/dist/index-ByaJBTpA.js +0 -6780
package/CHANGELOG.md CHANGED
@@ -5,7 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [1.0.0-beta.29] - 2025-12-15
9
+
10
+ ### 🔄 Breaking Changes
11
+ - **Environment Enum** - Removed `Environment.test`. Only `Environment.cn` and `Environment.intl` are now supported. Environment configuration must be explicitly provided.
12
+ - **Log Level Default** - Default log level changed from `LogLevel.all` to `LogLevel.off`. Set `logLevel: LogLevel.all` in configuration to enable all logs.
13
+
14
+ ### ✨ New Features
15
+ - **Avatar Caching** - Added avatar caching methods in `AvatarManager`:
16
+ - `retrieve(id: string): Avatar | undefined` - Get cached avatar by ID
17
+ - `clear(id: string): void` - Clear cached avatar for specific ID
18
+ - `clearAll(): void` - Clear all cached avatars
19
+ - `clearCache()` is now deprecated, use `clearAll()` instead
20
+ - **Background Image Support** - Added background image control in `AvatarView`:
21
+ - `isOpaque: boolean` - Getter/setter to control canvas background transparency
22
+ - `setBackgroundImage(image: HTMLImageElement | string | null): void` - Set or remove background image
23
+
24
+ ### 🔧 Improvements
25
+ - **Avatar Version Checking** - Avatar cache now automatically checks version and reloads if cached avatar version differs from latest metadata
26
+ - **Concurrent Loading** - Multiple concurrent `load()` calls for the same avatar ID now reuse the same loading promise
9
27
 
10
28
  ## [1.0.0-beta.28] - 2025-12-08
11
29
 
package/README.md CHANGED
@@ -36,11 +36,11 @@ import {
36
36
  // 1. Initialize SDK
37
37
 
38
38
  const configuration: Configuration = {
39
- environment: Environment.test,
39
+ environment: Environment.cn,
40
40
  drivingServiceMode: DrivingServiceMode.sdk, // Optional, 'sdk' is default
41
41
  // - DrivingServiceMode.sdk: SDK mode - SDK handles WebSocket communication
42
42
  // - DrivingServiceMode.host: Host mode - Host app provides audio and animation data
43
- logLevel: LogLevel.all, // Optional, 'all' is default
43
+ logLevel: LogLevel.off, // Optional, 'off' is default
44
44
  // - LogLevel.off: Disable all logs
45
45
  // - LogLevel.error: Only error logs
46
46
  // - LogLevel.warning: Warning and error logs
@@ -403,7 +403,7 @@ avatarView.avatarController.onError = (error: Error) => {}
403
403
  interface Configuration {
404
404
  environment: Environment
405
405
  drivingServiceMode?: DrivingServiceMode // Optional, default is 'sdk' (SDK mode)
406
- logLevel?: LogLevel // Optional, default is 'all' (all logs)
406
+ logLevel?: LogLevel // Optional, default is 'off' (no logs)
407
407
  }
408
408
  ```
409
409
 
@@ -423,22 +423,21 @@ enum LogLevel {
423
423
  **Note:** `LogLevel.off` completely disables all logging, including error logs. Use with caution in production environments.
424
424
 
425
425
  **Description:**
426
- - `environment`: Specifies the environment (cn/intl/test), SDK will automatically use the corresponding API address and WebSocket address based on the environment
426
+ - `environment`: Specifies the environment (cn/intl), SDK will automatically use the corresponding API address and WebSocket address based on the environment
427
427
  - `drivingServiceMode`: Specifies the driving service mode
428
428
  - `DrivingServiceMode.sdk` (default): SDK mode - SDK handles WebSocket communication automatically
429
429
  - `DrivingServiceMode.host`: Host mode - Host application provides audio and animation data
430
430
  - `logLevel`: Controls the verbosity of SDK logs
431
- - `LogLevel.off`: Disable all logs
431
+ - `LogLevel.off` (default): Disable all logs
432
432
  - `LogLevel.error`: Only error logs
433
433
  - `LogLevel.warning`: Warning and error logs
434
- - `LogLevel.all` (default): All logs (info, warning, error)
434
+ - `LogLevel.all`: All logs (info, warning, error)
435
435
  - `sessionToken`: Set separately via `AvatarSDK.setSessionToken()`, not in Configuration
436
436
 
437
437
  ```typescript
438
438
  enum Environment {
439
439
  cn = 'cn', // China region
440
440
  intl = 'intl', // International region
441
- test = 'test' // Test environment
442
441
  }
443
442
  ```
444
443
 
@@ -0,0 +1,398 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { A as APP_CONFIG, e as errorToMessage, l as logEvent, a as logger } from "./index-BpVIIm3g.js";
5
+ class StreamingAudioPlayer {
6
+ constructor(options) {
7
+ __publicField(this, "audioContext", null);
8
+ __publicField(this, "sampleRate");
9
+ __publicField(this, "channelCount");
10
+ __publicField(this, "debug");
11
+ __publicField(this, "sessionId");
12
+ __publicField(this, "sessionStartTime", 0);
13
+ __publicField(this, "pausedTimeOffset", 0);
14
+ __publicField(this, "pausedAt", 0);
15
+ __publicField(this, "pausedAudioContextTime", 0);
16
+ __publicField(this, "scheduledTime", 0);
17
+ __publicField(this, "isPlaying", false);
18
+ __publicField(this, "isPaused", false);
19
+ __publicField(this, "autoStartEnabled", true);
20
+ __publicField(this, "audioChunks", []);
21
+ __publicField(this, "scheduledChunks", 0);
22
+ __publicField(this, "activeSources", /* @__PURE__ */ new Set());
23
+ __publicField(this, "gainNode", null);
24
+ __publicField(this, "volume", 1);
25
+ __publicField(this, "onEndedCallback");
26
+ this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
27
+ this.sampleRate = (options == null ? void 0 : options.sampleRate) ?? APP_CONFIG.audio.sampleRate;
28
+ this.channelCount = (options == null ? void 0 : options.channelCount) ?? 1;
29
+ this.debug = (options == null ? void 0 : options.debug) ?? false;
30
+ }
31
+ async initialize() {
32
+ if (this.audioContext) {
33
+ return;
34
+ }
35
+ try {
36
+ this.audioContext = new AudioContext({
37
+ sampleRate: this.sampleRate
38
+ });
39
+ this.gainNode = this.audioContext.createGain();
40
+ this.gainNode.gain.value = this.volume;
41
+ this.gainNode.connect(this.audioContext.destination);
42
+ if (this.audioContext.state === "suspended") {
43
+ await this.audioContext.resume();
44
+ }
45
+ this.log("AudioContext initialized", {
46
+ sessionId: this.sessionId,
47
+ sampleRate: this.audioContext.sampleRate,
48
+ state: this.audioContext.state
49
+ });
50
+ } catch (error) {
51
+ const message = errorToMessage(error);
52
+ logEvent("activeAudioSessionFailed", "warning", {
53
+ sessionId: this.sessionId,
54
+ reason: message
55
+ });
56
+ logger.error("Failed to initialize AudioContext:", message);
57
+ throw error instanceof Error ? error : new Error(message);
58
+ }
59
+ }
60
+ addChunk(pcmData, isLast = false) {
61
+ if (!this.audioContext) {
62
+ logger.error("AudioContext not initialized");
63
+ return;
64
+ }
65
+ this.audioChunks.push({ data: pcmData, isLast });
66
+ this.log(`Added chunk ${this.audioChunks.length}`, {
67
+ size: pcmData.length,
68
+ totalChunks: this.audioChunks.length,
69
+ isLast,
70
+ isPlaying: this.isPlaying,
71
+ scheduledChunks: this.scheduledChunks
72
+ });
73
+ if (!this.isPlaying && this.autoStartEnabled && this.audioChunks.length > 0) {
74
+ this.log("[StreamingAudioPlayer] Auto-starting playback from addChunk");
75
+ this.startPlayback();
76
+ } else if (this.isPlaying && !this.isPaused) {
77
+ this.log("[StreamingAudioPlayer] Already playing, scheduling next chunk");
78
+ this.scheduleNextChunk();
79
+ } else {
80
+ this.log("[StreamingAudioPlayer] Not playing and no chunks, waiting for more chunks");
81
+ }
82
+ }
83
+ async startNewSession(audioChunks) {
84
+ this.stop();
85
+ this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
86
+ this.audioChunks = [];
87
+ this.scheduledChunks = 0;
88
+ this.pausedTimeOffset = 0;
89
+ this.pausedAt = 0;
90
+ this.pausedAudioContextTime = 0;
91
+ this.log("Starting new session", {
92
+ chunks: audioChunks.length
93
+ });
94
+ for (const chunk of audioChunks) {
95
+ this.addChunk(chunk.data, chunk.isLast);
96
+ }
97
+ }
98
+ startPlayback() {
99
+ if (!this.audioContext) {
100
+ this.log("[StreamingAudioPlayer] Cannot start playback: AudioContext not initialized");
101
+ return;
102
+ }
103
+ if (this.isPlaying) {
104
+ this.log("[StreamingAudioPlayer] Cannot start playback: Already playing");
105
+ return;
106
+ }
107
+ this.isPlaying = true;
108
+ this.sessionStartTime = this.audioContext.currentTime;
109
+ this.scheduledTime = this.sessionStartTime;
110
+ this.log("[StreamingAudioPlayer] Starting playback", {
111
+ sessionStartTime: this.sessionStartTime,
112
+ bufferedChunks: this.audioChunks.length,
113
+ scheduledChunks: this.scheduledChunks,
114
+ activeSources: this.activeSources.size
115
+ });
116
+ this.scheduleAllChunks();
117
+ }
118
+ scheduleAllChunks() {
119
+ while (this.scheduledChunks < this.audioChunks.length) {
120
+ this.scheduleNextChunk();
121
+ }
122
+ }
123
+ scheduleNextChunk() {
124
+ if (!this.audioContext) {
125
+ this.log("[StreamingAudioPlayer] Cannot schedule chunk: AudioContext not initialized");
126
+ return;
127
+ }
128
+ if (!this.isPlaying || this.isPaused) {
129
+ this.log("[StreamingAudioPlayer] Cannot schedule chunk: Not playing or paused");
130
+ return;
131
+ }
132
+ const chunkIndex = this.scheduledChunks;
133
+ if (chunkIndex >= this.audioChunks.length) {
134
+ this.log(`[StreamingAudioPlayer] No more chunks to schedule (chunkIndex: ${chunkIndex}, totalChunks: ${this.audioChunks.length})`);
135
+ return;
136
+ }
137
+ const chunk = this.audioChunks[chunkIndex];
138
+ if (chunk.data.length === 0 && !chunk.isLast) {
139
+ this.scheduledChunks++;
140
+ return;
141
+ }
142
+ const pcmData = chunk.data;
143
+ const isLast = chunk.isLast;
144
+ const audioBuffer = this.pcmToAudioBuffer(pcmData);
145
+ if (!audioBuffer) {
146
+ const errorMessage = "Failed to create AudioBuffer from PCM data";
147
+ logger.error(errorMessage);
148
+ logEvent("character_player", "error", {
149
+ sessionId: this.sessionId,
150
+ event: "audio_buffer_creation_failed"
151
+ });
152
+ return;
153
+ }
154
+ try {
155
+ const source = this.audioContext.createBufferSource();
156
+ source.buffer = audioBuffer;
157
+ source.connect(this.gainNode);
158
+ source.start(this.scheduledTime);
159
+ this.activeSources.add(source);
160
+ source.onended = () => {
161
+ this.activeSources.delete(source);
162
+ if (isLast && this.activeSources.size === 0) {
163
+ this.log("Last audio chunk ended, marking playback as ended");
164
+ this.markEnded();
165
+ }
166
+ };
167
+ this.scheduledTime += audioBuffer.duration;
168
+ this.scheduledChunks++;
169
+ this.log(`[StreamingAudioPlayer] Scheduled chunk ${chunkIndex + 1}/${this.audioChunks.length}`, {
170
+ startTime: this.scheduledTime - audioBuffer.duration,
171
+ duration: audioBuffer.duration,
172
+ nextScheduleTime: this.scheduledTime,
173
+ isLast,
174
+ activeSources: this.activeSources.size
175
+ });
176
+ } catch (err) {
177
+ logger.errorWithError("Failed to schedule audio chunk:", err);
178
+ logEvent("character_player", "error", {
179
+ sessionId: this.sessionId,
180
+ event: "schedule_chunk_failed",
181
+ reason: err instanceof Error ? err.message : String(err)
182
+ });
183
+ }
184
+ }
185
+ pcmToAudioBuffer(pcmData) {
186
+ if (!this.audioContext) {
187
+ return null;
188
+ }
189
+ if (pcmData.length === 0) {
190
+ const silenceDuration = 0.01;
191
+ const numSamples2 = Math.floor(this.sampleRate * silenceDuration);
192
+ const audioBuffer2 = this.audioContext.createBuffer(
193
+ this.channelCount,
194
+ numSamples2,
195
+ this.sampleRate
196
+ );
197
+ for (let channel = 0; channel < this.channelCount; channel++) {
198
+ const channelData = audioBuffer2.getChannelData(channel);
199
+ channelData.fill(0);
200
+ }
201
+ return audioBuffer2;
202
+ }
203
+ const alignedData = new Uint8Array(pcmData);
204
+ const int16Array = new Int16Array(alignedData.buffer, 0, alignedData.length / 2);
205
+ const numSamples = int16Array.length / this.channelCount;
206
+ const audioBuffer = this.audioContext.createBuffer(
207
+ this.channelCount,
208
+ numSamples,
209
+ this.sampleRate
210
+ );
211
+ for (let channel = 0; channel < this.channelCount; channel++) {
212
+ const channelData = audioBuffer.getChannelData(channel);
213
+ for (let i = 0; i < numSamples; i++) {
214
+ const sampleIndex = i * this.channelCount + channel;
215
+ channelData[i] = int16Array[sampleIndex] / 32768;
216
+ }
217
+ }
218
+ return audioBuffer;
219
+ }
220
+ getCurrentTime() {
221
+ if (!this.audioContext || !this.isPlaying) {
222
+ return 0;
223
+ }
224
+ if (this.isPaused) {
225
+ return this.pausedAt;
226
+ }
227
+ const currentAudioTime = this.audioContext.currentTime;
228
+ const elapsed = currentAudioTime - this.sessionStartTime - this.pausedTimeOffset;
229
+ return Math.max(0, elapsed);
230
+ }
231
+ pause() {
232
+ if (!this.isPlaying || this.isPaused || !this.audioContext) {
233
+ return;
234
+ }
235
+ this.pausedAt = this.getCurrentTime();
236
+ this.pausedAudioContextTime = this.audioContext.currentTime;
237
+ this.isPaused = true;
238
+ if (this.audioContext.state === "running") {
239
+ this.audioContext.suspend().catch((err) => {
240
+ logger.errorWithError("Failed to suspend AudioContext:", err);
241
+ this.isPaused = false;
242
+ });
243
+ }
244
+ this.log("Playback paused", {
245
+ pausedAt: this.pausedAt,
246
+ pausedAudioContextTime: this.pausedAudioContextTime,
247
+ audioContextState: this.audioContext.state
248
+ });
249
+ }
250
+ async resume() {
251
+ if (!this.isPaused || !this.audioContext || !this.isPlaying) {
252
+ return;
253
+ }
254
+ if (this.audioContext.state === "suspended") {
255
+ try {
256
+ await this.audioContext.resume();
257
+ } catch (err) {
258
+ logger.errorWithError("Failed to resume AudioContext:", err);
259
+ throw err;
260
+ }
261
+ }
262
+ const currentAudioTime = this.audioContext.currentTime;
263
+ this.sessionStartTime = this.pausedAudioContextTime - this.pausedAt - this.pausedTimeOffset;
264
+ this.isPaused = false;
265
+ if (this.scheduledChunks < this.audioChunks.length) {
266
+ this.scheduleAllChunks();
267
+ }
268
+ this.log("Playback resumed", {
269
+ pausedAt: this.pausedAt,
270
+ pausedAudioContextTime: this.pausedAudioContextTime,
271
+ currentAudioContextTime: currentAudioTime,
272
+ adjustedSessionStartTime: this.sessionStartTime,
273
+ audioContextState: this.audioContext.state
274
+ });
275
+ }
276
+ stop() {
277
+ if (!this.audioContext) {
278
+ return;
279
+ }
280
+ if (this.isPaused && this.audioContext.state === "suspended") {
281
+ this.audioContext.resume().catch(() => {
282
+ });
283
+ this.isPaused = false;
284
+ }
285
+ this.isPlaying = false;
286
+ this.isPaused = false;
287
+ this.sessionStartTime = 0;
288
+ this.scheduledTime = 0;
289
+ for (const source of this.activeSources) {
290
+ source.onended = null;
291
+ try {
292
+ source.stop(0);
293
+ } catch {
294
+ }
295
+ try {
296
+ source.disconnect();
297
+ } catch {
298
+ }
299
+ }
300
+ this.activeSources.clear();
301
+ this.audioChunks = [];
302
+ this.scheduledChunks = 0;
303
+ this.log("[StreamingAudioPlayer] Playback stopped, state reset");
304
+ }
305
+ setAutoStart(enabled) {
306
+ this.autoStartEnabled = enabled;
307
+ this.log(`Auto-start ${enabled ? "enabled" : "disabled"}`);
308
+ }
309
+ play() {
310
+ if (this.isPlaying) {
311
+ return;
312
+ }
313
+ this.autoStartEnabled = true;
314
+ this.startPlayback();
315
+ }
316
+ markEnded() {
317
+ var _a;
318
+ this.log("Playback ended");
319
+ this.isPlaying = false;
320
+ (_a = this.onEndedCallback) == null ? void 0 : _a.call(this);
321
+ }
322
+ onEnded(callback) {
323
+ this.onEndedCallback = callback;
324
+ }
325
+ isPlayingNow() {
326
+ return this.isPlaying && !this.isPaused;
327
+ }
328
+ getBufferedDuration() {
329
+ if (!this.audioContext) {
330
+ return 0;
331
+ }
332
+ let totalSamples = 0;
333
+ for (const chunk of this.audioChunks) {
334
+ totalSamples += chunk.data.length / 2 / this.channelCount;
335
+ }
336
+ return totalSamples / this.sampleRate;
337
+ }
338
+ getRemainingDuration() {
339
+ const total = this.getBufferedDuration();
340
+ const played = this.getCurrentTime();
341
+ return Math.max(0, total - played);
342
+ }
343
+ dispose() {
344
+ this.stop();
345
+ if (this.audioContext) {
346
+ this.audioContext.close();
347
+ this.audioContext = null;
348
+ this.gainNode = null;
349
+ }
350
+ this.audioChunks = [];
351
+ this.scheduledChunks = 0;
352
+ this.sessionStartTime = 0;
353
+ this.pausedTimeOffset = 0;
354
+ this.pausedAt = 0;
355
+ this.pausedAudioContextTime = 0;
356
+ this.scheduledTime = 0;
357
+ this.onEndedCallback = void 0;
358
+ this.log("StreamingAudioPlayer disposed");
359
+ }
360
+ flush(options) {
361
+ const hard = (options == null ? void 0 : options.hard) === true;
362
+ if (hard) {
363
+ this.stop();
364
+ this.audioChunks = [];
365
+ this.scheduledChunks = 0;
366
+ this.sessionStartTime = 0;
367
+ this.pausedAt = 0;
368
+ this.scheduledTime = 0;
369
+ this.log("Flushed (hard)");
370
+ return;
371
+ }
372
+ if (this.scheduledChunks < this.audioChunks.length) {
373
+ this.audioChunks.splice(this.scheduledChunks);
374
+ }
375
+ this.log("Flushed (soft)", { remainingScheduled: this.scheduledChunks });
376
+ }
377
+ setVolume(volume) {
378
+ if (volume < 0 || volume > 1) {
379
+ logger.warn(`[StreamingAudioPlayer] Volume out of range: ${volume}, clamping to [0, 1]`);
380
+ volume = Math.max(0, Math.min(1, volume));
381
+ }
382
+ this.volume = volume;
383
+ if (this.gainNode) {
384
+ this.gainNode.gain.value = volume;
385
+ }
386
+ }
387
+ getVolume() {
388
+ return this.volume;
389
+ }
390
+ log(message, data) {
391
+ if (this.debug) {
392
+ logger.log(`[StreamingAudioPlayer] ${message}`, data || "");
393
+ }
394
+ }
395
+ }
396
+ export {
397
+ StreamingAudioPlayer
398
+ };
@@ -19,31 +19,11 @@ export declare class AnimationWebSocketClient extends EventEmitter {
19
19
  private isManuallyDisconnected;
20
20
  private reconnectTimer;
21
21
  constructor(options: AnimationWebSocketClientOptions);
22
- /**
23
- * 连接WebSocket
24
- */
25
22
  connect(characterId: string): Promise<void>;
26
- /**
27
- * 断开连接
28
- */
29
23
  disconnect(): void;
30
- /**
31
- * 发送音频数据
32
- * @param conversationId - 会话ID(在 protobuf 协议中映射为 reqId 字段)
33
- */
34
24
  sendAudioData(conversationId: string, audioData: ArrayBuffer, end: boolean): boolean;
35
- /**
36
- * 生成会话ID
37
- * 使用统一的会话ID生成规则:YYYYMMDDHHmmss_nanoid
38
- */
39
25
  generateConversationId(): string;
40
- /**
41
- * 获取连接状态
42
- */
43
26
  isConnected(): boolean;
44
- /**
45
- * 获取当前角色ID
46
- */
47
27
  getCurrentCharacterId(): string;
48
28
  private buildWebSocketUrl;
49
29
  private connectWebSocket;
@@ -1,6 +1,3 @@
1
- /**
2
- * Simple Event Emitter
3
- */
4
1
  type EventHandler = (...args: any[]) => void;
5
2
  export declare class EventEmitter {
6
3
  private events;
@@ -10,16 +10,9 @@ export interface FlameParams {
10
10
  eyelid?: number[];
11
11
  has_eyelid?: boolean;
12
12
  }
13
- /**
14
- * Convert proto Flame to WASM FlameParams format
15
- */
13
+
16
14
  export declare function convertProtoFlameToWasmParams(protoFlame: Flame): FlameParams;
17
- /**
18
- * Convert WASM FlameParams to proto Flame format
19
- * Used for transition animation from idle to speaking
20
- */
15
+
21
16
  export declare function convertWasmParamsToProtoFlame(wasmParams: FlameParams): Flame;
22
- /**
23
- * Create a neutral proto Flame (zero pose)
24
- */
17
+
25
18
  export declare function createNeutralFlameProto(): Flame;
@@ -7,69 +7,23 @@ export declare class AnimationPlayer {
7
7
  private onEndedCallback?;
8
8
  private static audioUnlocked;
9
9
  private useStreaming;
10
- /**
11
- * 解锁音频上下文(Safari 自动播放策略)
12
- * 必须在用户交互事件(如 click)中调用
13
- */
14
10
  static unlockAudioContext(): Promise<void>;
15
- /**
16
- * Initialize with HTMLAudioElement (traditional way)
17
- */
18
11
  initialize(audioUrl: string, onEnded?: () => void): Promise<void>;
19
- /**
20
- * Initialize with StreamingAudioPlayer (streaming way)
21
- * @deprecated 使用 prepareStreamingPlayer() 代替
22
- */
23
12
  initializeStreaming(streamingPlayer: StreamingAudioPlayer, onEnded?: () => void): Promise<void>;
24
- /**
25
- * 检查流式播放器是否已准备好
26
- */
27
13
  isStreamingReady(): boolean;
28
- /**
29
- * 获取流式播放器实例
30
- */
31
14
  getStreamingPlayer(): StreamingAudioPlayer | null;
32
- /**
33
- * 创建并初始化流式播放器
34
- * 在服务连接建立时调用
35
- */
36
15
  createAndInitializeStreamingPlayer(): Promise<void>;
37
- /**
38
- * 准备流式播放器(如果未创建则创建并初始化)
39
- * 停止之前的播放并更新结束回调
40
- */
41
16
  prepareStreamingPlayer(onEnded?: () => void): Promise<void>;
42
17
  private setupEventListeners;
43
18
  play(): Promise<void>;
44
19
  stop(): void;
45
20
  isPlaying(): boolean;
46
21
  getCurrentFrameIndex(): number;
47
- /**
48
- * Get current playback time
49
- */
50
22
  getCurrentTime(): number;
51
- /**
52
- * 添加音频块(仅用于流式播放)
53
- */
54
23
  addAudioChunk(audio: Uint8Array, isLast?: boolean): void;
55
- /**
56
- * 暂停播放
57
- */
58
24
  pause(): void;
59
- /**
60
- * 继续播放
61
- */
62
25
  resume(): Promise<void>;
63
- /**
64
- * 设置音量 (0.0 - 1.0)
65
- * 注意:这仅控制数字人音频播放器的音量,不影响系统音量
66
- * @param volume 音量值,范围 0.0 到 1.0(0.0 为静音,1.0 为最大音量)
67
- */
68
26
  setVolume(volume: number): void;
69
- /**
70
- * 获取当前音量
71
- * @returns 当前音量值 (0.0 - 1.0)
72
- */
73
27
  getVolume(): number;
74
28
  dispose(): void;
75
29
  }