@xmov/avatar 2.4.0 → 2.5.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +34 -6
  2. package/package-dist/agent/avatar.cjs +1 -0
  3. package/package-dist/agent/avatar.modern.js +1 -0
  4. package/package-dist/agent/avatar.module.js +1 -0
  5. package/package-dist/agent/avatar.umd.js +1 -0
  6. package/package-dist/agent/index.d.ts +42 -0
  7. package/{dist/agent/types.d.ts → package-dist/agent/public-types.d.ts} +115 -116
  8. package/package-dist/index.cjs +3 -0
  9. package/package-dist/index.d.ts +34 -0
  10. package/package-dist/index.modern.js +1 -0
  11. package/package-dist/index.module.js +1 -0
  12. package/package-dist/index.umd.js +14 -0
  13. package/package-dist/public-types.d.ts +205 -0
  14. package/package.json +41 -33
  15. package/dist/agent/avatar.cjs +0 -1
  16. package/dist/agent/avatar.modern.js +0 -1
  17. package/dist/agent/avatar.module.js +0 -1
  18. package/dist/agent/avatar.umd.js +0 -1
  19. package/dist/agent/index.d.ts +0 -137
  20. package/dist/baseRender/AudioRenderer.d.ts +0 -46
  21. package/dist/baseRender/AudioWorklet.d.ts +0 -78
  22. package/dist/baseRender/AvatarRenderer.d.ts +0 -225
  23. package/dist/baseRender/MSEAudioPlayer.d.ts +0 -51
  24. package/dist/baseRender/UIRenderer.d.ts +0 -39
  25. package/dist/baseRender/pcm-audio-processor.d.ts +0 -63
  26. package/dist/control/APIForwarder.d.ts +0 -23
  27. package/dist/control/DataCacheQueue.d.ts +0 -69
  28. package/dist/control/EventDispatcher.d.ts +0 -35
  29. package/dist/control/RenderScheduler.d.ts +0 -171
  30. package/dist/control/SaveAndDownload.d.ts +0 -14
  31. package/dist/control/StreamingClient.d.ts +0 -33
  32. package/dist/control/VideoPlayer.d.ts +0 -47
  33. package/dist/control/ttsa.d.ts +0 -125
  34. package/dist/encoding/media-recorder-encoder.d.ts +0 -33
  35. package/dist/encoding/pcm-webm-encoder.d.ts +0 -13
  36. package/dist/encoding/webcodec-opus-encoder.d.ts +0 -41
  37. package/dist/encoding/webm-muxer.d.ts +0 -90
  38. package/dist/index.cjs +0 -2
  39. package/dist/index.cjs.map +0 -1
  40. package/dist/index.d.ts +0 -251
  41. package/dist/index.modern.js +0 -2
  42. package/dist/index.modern.js.map +0 -1
  43. package/dist/index.module.js +0 -2
  44. package/dist/index.module.js.map +0 -1
  45. package/dist/index.umd.js +0 -2
  46. package/dist/index.umd.js.map +0 -1
  47. package/dist/modules/Composition.d.ts +0 -28
  48. package/dist/modules/ResourceManager.d.ts +0 -299
  49. package/dist/modules/TrackRenderer/base-track.d.ts +0 -4
  50. package/dist/modules/TrackRenderer/index.d.ts +0 -12
  51. package/dist/modules/TrackRenderer/render-implements.d.ts +0 -19
  52. package/dist/modules/TrackRenderer/track-pic.d.ts +0 -8
  53. package/dist/modules/TrackRenderer/track-subtitle.d.ts +0 -8
  54. package/dist/modules/cache-manager.d.ts +0 -5
  55. package/dist/modules/decoder.d.ts +0 -84
  56. package/dist/modules/error-handle.d.ts +0 -17
  57. package/dist/modules/network.d.ts +0 -21
  58. package/dist/modules/sentry-reporter.d.ts +0 -58
  59. package/dist/proto/face_data_pb.d.ts +0 -0
  60. package/dist/types/capability.d.ts +0 -15
  61. package/dist/types/error.d.ts +0 -70
  62. package/dist/types/event.d.ts +0 -25
  63. package/dist/types/frame-data.d.ts +0 -107
  64. package/dist/types/index.d.ts +0 -196
  65. package/dist/types/render.d.ts +0 -18
  66. package/dist/utils/DataInterface.d.ts +0 -113
  67. package/dist/utils/GLDevice.d.ts +0 -46
  68. package/dist/utils/GLPipeline.d.ts +0 -84
  69. package/dist/utils/GLPipelineDebugTools.d.ts +0 -5
  70. package/dist/utils/Math.d.ts +0 -21
  71. package/dist/utils/__tests__/capability-checker.test.d.ts +0 -1
  72. package/dist/utils/audio-session.d.ts +0 -11
  73. package/dist/utils/audio.d.ts +0 -1
  74. package/dist/utils/capability-checker.d.ts +0 -28
  75. package/dist/utils/encodeToken.d.ts +0 -14
  76. package/dist/utils/face.d.ts +0 -1
  77. package/dist/utils/float32-decoder.d.ts +0 -26
  78. package/dist/utils/fpsTracker.d.ts +0 -27
  79. package/dist/utils/index.d.ts +0 -22
  80. package/dist/utils/logger.d.ts +0 -9
  81. package/dist/utils/media-recorder-timestamp.d.ts +0 -15
  82. package/dist/utils/pcmAnalyzer.d.ts +0 -40
  83. package/dist/utils/perfermance.d.ts +0 -15
  84. package/dist/utils/request.d.ts +0 -20
  85. package/dist/utils/requestAnimateFrames.d.ts +0 -31
  86. package/dist/utils/time.d.ts +0 -9
  87. package/dist/utils/video-probe-asset.d.ts +0 -28
  88. package/dist/view/DebugOverlay.d.ts +0 -54
  89. package/dist/worker/streaming-video.d.ts +0 -1
  90. package/src/baseRender/AudioRenderer.ts +0 -328
  91. package/src/baseRender/AudioWorklet.ts +0 -776
  92. package/src/baseRender/AvatarRenderer.ts +0 -1550
  93. package/src/baseRender/MSEAudioPlayer.ts +0 -254
  94. package/src/baseRender/UIRenderer.ts +0 -195
  95. package/src/baseRender/pcm-audio-processor.js +0 -267
  96. package/src/control/APIForwarder.ts +0 -67
  97. package/src/control/DataCacheQueue.ts +0 -372
  98. package/src/control/EventDispatcher.ts +0 -106
  99. package/src/control/RenderScheduler.ts +0 -1000
  100. package/src/control/SaveAndDownload.js +0 -77
  101. package/src/control/StreamingClient.ts +0 -138
  102. package/src/control/VideoPlayer.ts +0 -306
  103. package/src/control/ttsa.ts +0 -754
  104. package/src/encoding/media-recorder-encoder.ts +0 -175
  105. package/src/encoding/pcm-webm-encoder.ts +0 -72
  106. package/src/encoding/webcodec-opus-encoder.ts +0 -258
  107. package/src/encoding/webm-muxer.ts +0 -337
  108. package/src/global.d.ts +0 -112
  109. package/src/index.ts +0 -2053
  110. package/src/modules/Composition.ts +0 -79
  111. package/src/modules/ResourceManager.ts +0 -926
  112. package/src/modules/TrackRenderer/base-track.ts +0 -7
  113. package/src/modules/TrackRenderer/index.ts +0 -40
  114. package/src/modules/TrackRenderer/render-implements.ts +0 -269
  115. package/src/modules/TrackRenderer/track-pic.ts +0 -19
  116. package/src/modules/TrackRenderer/track-subtitle.ts +0 -16
  117. package/src/modules/cache-manager.ts +0 -10
  118. package/src/modules/decoder.ts +0 -548
  119. package/src/modules/error-handle.ts +0 -20
  120. package/src/modules/network.ts +0 -71
  121. package/src/modules/sentry-reporter.ts +0 -171
  122. package/src/proto/face_data.proto +0 -45
  123. package/src/proto/face_data_pb.js +0 -1297
  124. package/src/proto/protobuf.min.js +0 -8
  125. package/src/types/capability.ts +0 -24
  126. package/src/types/error.ts +0 -211
  127. package/src/types/event.ts +0 -38
  128. package/src/types/frame-data.ts +0 -121
  129. package/src/types/index.ts +0 -220
  130. package/src/types/render.ts +0 -18
  131. package/src/utils/DataInterface.ts +0 -746
  132. package/src/utils/GLDevice.ts +0 -286
  133. package/src/utils/GLPipeline.ts +0 -1293
  134. package/src/utils/GLPipelineDebugTools.ts +0 -174
  135. package/src/utils/Math.ts +0 -266
  136. package/src/utils/__tests__/capability-checker.test.ts +0 -159
  137. package/src/utils/audio-session.ts +0 -144
  138. package/src/utils/audio.ts +0 -44
  139. package/src/utils/blueimp-md5.d.ts +0 -3
  140. package/src/utils/capability-checker.ts +0 -762
  141. package/src/utils/encodeToken.ts +0 -115
  142. package/src/utils/face.ts +0 -29
  143. package/src/utils/float32-decoder.js +0 -130
  144. package/src/utils/fpsTracker.ts +0 -100
  145. package/src/utils/index.ts +0 -182
  146. package/src/utils/logger.js +0 -36
  147. package/src/utils/media-recorder-timestamp.ts +0 -79
  148. package/src/utils/pcmAnalyzer.ts +0 -154
  149. package/src/utils/perfermance.ts +0 -141
  150. package/src/utils/request.ts +0 -107
  151. package/src/utils/requestAnimateFrames.ts +0 -195
  152. package/src/utils/time.ts +0 -32
  153. package/src/utils/video-probe-asset.ts +0 -99
  154. package/src/view/DebugOverlay.ts +0 -409
  155. package/src/worker/streaming-video.ts +0 -4647
  156. /package/{dist → package-dist}/agent/index.cjs +0 -0
  157. /package/{dist → package-dist}/agent/index.umd.js +0 -0
@@ -1,254 +0,0 @@
1
- export default class MediaSourceAudioPlayer {
2
- private mediaSource: MediaSource | null = null;
3
- private audioElement: HTMLAudioElement | null = null;
4
- private sourceBuffer: SourceBuffer | null = null;
5
- public isInitialized = false;
6
- public isPlaying = false;
7
- private volume = 1.0;
8
- private readonly MIME_TYPE = 'audio/webm;codecs=opus';
9
- private queue: Array<{ data: ArrayBuffer }> = [];
10
- private isUpdating = false;
11
- private currentObjectURL: string | null = null;
12
- private isDestroyed = false;
13
-
14
- // 速度同步相关(保留不动)
15
- private playbackRate = 1.0;
16
- public firstFrameIndex = -1;
17
-
18
- // 单例
19
- private static instance: MediaSourceAudioPlayer;
20
- public static getInstance(sdk): MediaSourceAudioPlayer {
21
- if (!MediaSourceAudioPlayer.instance) {
22
- MediaSourceAudioPlayer.instance = new MediaSourceAudioPlayer(sdk);
23
- }
24
- return MediaSourceAudioPlayer.instance;
25
- }
26
-
27
- private constructor(sdk) {
28
- this.createAudioElement(sdk);
29
- this.createNewMediaSource();
30
- }
31
-
32
- /**
33
- * 只复用 audio 标签!!!
34
- */
35
- private createAudioElement(sdk) {
36
- if (this.audioElement) return;
37
- const el = document.getElementById("xmov-avatar-audio");
38
- if (el) {
39
- this.audioElement = el as HTMLAudioElement;
40
- return;
41
- }
42
- const audio = document.createElement("audio");
43
- audio.id = "xmov-avatar-audio";
44
- audio.preload = "auto";
45
- audio.style.position = "absolute";
46
- audio.style.width = "1px";
47
- audio.style.height = "1px";
48
- audio.style.opacity = "0";
49
- audio.style.pointerEvents = "none";
50
- audio.style.zIndex = "-9999";
51
- sdk.el.appendChild(audio);
52
- this.audioElement = audio;
53
- }
54
-
55
- /**
56
- * 每次都创建 NEW MediaSource
57
- * 不复用!不复用!不复用!
58
- */
59
- private createNewMediaSource(): Promise<void> {
60
- return new Promise((resolve, reject) => {
61
- try {
62
- if(!this.audioElement) return;
63
- this.mediaSource = new MediaSource();
64
- this.currentObjectURL = URL.createObjectURL(this.mediaSource);
65
- this.audioElement!.src = this.currentObjectURL;
66
-
67
- this.mediaSource.addEventListener("sourceopen", () => {
68
- try {
69
- if (!this.mediaSource) return;
70
- this.sourceBuffer = this.mediaSource.addSourceBuffer(this.MIME_TYPE);
71
- this.sourceBuffer.mode = "sequence";
72
-
73
- this.sourceBuffer.addEventListener("updateend", () => {
74
- this.isUpdating = false;
75
- this.processQueue();
76
- });
77
-
78
- this.isInitialized = true;
79
- resolve();
80
- } catch (e) {
81
- reject(e);
82
- }
83
- });
84
-
85
- this.mediaSource.addEventListener("sourceclose", () => {
86
- this.isInitialized = false;
87
- });
88
- } catch (e) {
89
- reject(e);
90
- }
91
- });
92
- }
93
-
94
- /**
95
- * 销毁当前 MediaSource 所有资源
96
- * stop 时调用
97
- */
98
- private async destroyCurrentMediaSource(callback: () => void) {
99
- try {
100
- if (this.audioElement) {
101
- this.audioElement.pause();
102
- this.audioElement.removeAttribute("src");
103
- this.audioElement.load();
104
- }
105
- } catch {}
106
-
107
- try {
108
- if (this.currentObjectURL) {
109
- URL.revokeObjectURL(this.currentObjectURL);
110
- this.currentObjectURL = null;
111
- }
112
- } catch {}
113
-
114
- this.mediaSource = null;
115
- this.sourceBuffer = null;
116
- this.isInitialized = false;
117
- this.isPlaying = false;
118
- this.queue = [];
119
- this.isUpdating = false;
120
- await this.createNewMediaSource();
121
- callback();
122
- }
123
-
124
- // ==========================
125
- // 核心:stop 清空一切,只留 audio
126
- // ==========================
127
- public stop(callback: () => void) {
128
- this.destroyCurrentMediaSource(callback);
129
- }
130
-
131
- // ==========================
132
- // 添加数据(自动初始化)
133
- // ==========================
134
- async addAudioSegment(audioData: ArrayBuffer): Promise<void> {
135
- if (this.isDestroyed) return;
136
- this.queue.push({ data: audioData });
137
- this.processQueue();
138
- }
139
-
140
- private processQueue() {
141
- if (this.isDestroyed) return;
142
- if (!this.sourceBuffer || !this.mediaSource) return;
143
- if (this.isUpdating || this.queue.length === 0) return;
144
- if (this.sourceBuffer.updating || this.mediaSource.readyState !== "open") return;
145
-
146
- this.isUpdating = true;
147
- const item = this.queue.shift()!;
148
- try {
149
- this.sourceBuffer.appendBuffer(item.data);
150
- } catch (e) {
151
- this.isUpdating = false;
152
- }
153
- }
154
-
155
- // ==========================
156
- // 播放
157
- // ==========================
158
- async start(): Promise<void> {
159
- if (this.isDestroyed || !this.audioElement || this.isPlaying) return;
160
-
161
- try {
162
- this.audioElement.currentTime = 0;
163
- this.isPlaying = true;
164
- await this.audioElement.play();
165
- (window as any).avatarSDKLogger.log("mseAudioPlayer开始播放", this.getStats(), Date.now());
166
- } catch {}
167
- }
168
-
169
- getStats() {
170
- return {
171
- isPlaying: this.isPlaying,
172
- isInitialized: this.isInitialized,
173
- queueLength: this.queue.length,
174
- bufferedRanges: this.getBufferedRanges(),
175
- mediaSourceReadyState: this.mediaSource?.readyState || 'null',
176
- };
177
- }
178
-
179
- setSpeed(speed: number) {
180
- this.setPlaybackRate(speed);
181
- }
182
-
183
- /**
184
- * 获取缓冲范围
185
- */
186
- private getBufferedRanges(): string {
187
- try {
188
- // stop/destroy 流程中浏览器会先移除 SourceBuffer 再置空引用,
189
- // 此时访问 .buffered 会抛 InvalidStateError,需要 readyState 校验 + 兜底
190
- if (
191
- this.sourceBuffer &&
192
- this.mediaSource?.readyState === "open" &&
193
- this.sourceBuffer.buffered.length > 0
194
- ) {
195
- const ranges: string[] = [];
196
- for (let i = 0; i < this.sourceBuffer.buffered.length; i++) {
197
- const start = this.sourceBuffer.buffered.start(i).toFixed(2);
198
- const end = this.sourceBuffer.buffered.end(i).toFixed(2);
199
- ranges.push(`[${start}-${end}]`);
200
- }
201
- return ranges.join(", ");
202
- }
203
- } catch (e) {
204
- // SourceBuffer 已被移除(stop/destroy 竞态),视为无缓冲数据
205
- return "-";
206
- }
207
- return "-";
208
- }
209
-
210
- setVolume(volume: number): void {
211
- this.volume = Math.max(0, Math.min(1, volume));
212
- if (this.audioElement) this.audioElement.volume = this.volume;
213
- }
214
-
215
- setPlaybackRate(rate: number): void {
216
- this.playbackRate = Math.max(0.5, Math.min(4.0, rate));
217
- if (this.audioElement) this.audioElement.playbackRate = this.playbackRate;
218
- }
219
-
220
- destroy() {
221
- // 0. 标记已销毁,阻止异步操作继续执行
222
- this.isDestroyed = true;
223
-
224
- // 1. 停止播放并清除 audio 元素的 src(解除对 blob URL 的引用)
225
- if (this.audioElement) {
226
- this.audioElement.pause();
227
- this.audioElement.removeAttribute("src");
228
- this.audioElement.load();
229
- }
230
-
231
- // 2. 释放 blob URL(必须在 audio 元素清除 src 之后)
232
- if (this.currentObjectURL) {
233
- try { URL.revokeObjectURL(this.currentObjectURL); } catch {}
234
- this.currentObjectURL = null;
235
- }
236
-
237
- // 3. 移除 audio 元素
238
- if (this.audioElement) {
239
- this.audioElement.remove();
240
- this.audioElement = null;
241
- }
242
-
243
- // 4. 重置所有状态
244
- this.mediaSource = null;
245
- this.sourceBuffer = null;
246
- this.isInitialized = false;
247
- this.isPlaying = false;
248
- this.queue = [];
249
- this.isUpdating = false;
250
-
251
- // 5. 重置单例,下次 getInstance() 会重新创建
252
- MediaSourceAudioPlayer.instance = null as any;
253
- }
254
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * UI 控件渲染,所有轨道的元素
3
- */
4
- import { DataCacheQueue } from "../control/DataCacheQueue";
5
- import DefaultWidgetRenderer from "../modules/TrackRenderer/render-implements";
6
- import TrackerRenderer from "../modules/TrackRenderer/index";
7
- import ResourceManager from "../modules/ResourceManager";
8
- import { performanceConstant } from "../utils/perfermance";
9
- import XmovAvatar from "../index";
10
- import { EErrorCode } from "../types/error";
11
-
12
- type Option = {
13
- sdk: XmovAvatar;
14
- dataCacheQueue: DataCacheQueue;
15
- resourceManager: ResourceManager;
16
- enableClientInterrupt: boolean;
17
- onVoiceEnd: (client_speak_id: number | string, speech_id: number) => void;
18
- onVoiceStart: (duration: number, client_speak_id: number | string) => void;
19
- onWalkStateChange: (state: string) => void;
20
- sendSdkPoint: (type: string, data: any, extra?: any) => void;
21
- onSpeakStateChange: (state: string, client_speak_id: number | string, speech_id: number) => void;
22
- };
23
- export default class UIRenderer {
24
- private TAG = "[UIRenderer]";
25
- options: Option;
26
- trackerRenderer: TrackerRenderer[] = [];
27
- root = document.createElement("div");
28
- lastFrameIndex: number = -1;
29
- onVoiceEnd: (client_speak_id: number | string, speech_id: number) => void;
30
- onVoiceStart: (duration: number, client_speak_id: number | string) => void;
31
- onWalkStateChange: (state: string) => void;
32
- initEventsRendered: boolean = false;
33
- lastSpeechId: number = -1;
34
- interruptSpeechId: number = -1;
35
- enableClientInterrupt: boolean = false;
36
- onSpeakStateChange: (state: string, client_speak_id: number | string, speech_id: number) => void;
37
- constructor(options: Option) {
38
- this.options = options;
39
- this.root.setAttribute("style", "position:absolute;");
40
- this.onVoiceStart = options.onVoiceStart;
41
- this.onVoiceEnd = options.onVoiceEnd;
42
- this.initEventsRendered = false;
43
- this.onWalkStateChange = options.onWalkStateChange;
44
- this.enableClientInterrupt = options.enableClientInterrupt;
45
- this.onSpeakStateChange = options.onSpeakStateChange;
46
- }
47
-
48
- render(frame: number) {
49
- // if(this.options.sdk.getStatus() === AvatarStatus.offline) return;
50
- let initEvents: any[] = [];
51
- if (this.lastFrameIndex === -1) {
52
- const config = this.options.resourceManager.getConfig();
53
- if(config.init_events && config.init_events.length > 0){
54
- initEvents = config.init_events.map(item => ({...item, speech_id:0}));
55
- }
56
- }
57
- let event: any = null;
58
- if (frame - this.lastFrameIndex > 1) {
59
- event = this.options.dataCacheQueue._getEventInterval(
60
- this.lastFrameIndex,
61
- frame
62
- );
63
- } else {
64
- event = this.options.dataCacheQueue._getEvent(frame);
65
- }
66
- this.lastFrameIndex = frame;
67
- // 仅执行一次
68
- if(!this.initEventsRendered){
69
- this.initEventsRendered = true;
70
- if(event){
71
- event.e = event.e.concat(initEvents);
72
- } else {
73
- event = {
74
- e: initEvents,
75
- };
76
- }
77
- }
78
- if (!event?.e) {
79
- return;
80
- }
81
- (window as any).avatarSDKLogger.log("当前帧", frame, "获取到的事件", JSON.stringify(event));
82
- // 过滤出不包含speechId的事件list
83
- const noSpeechIdEvents = event.e?.filter(item => item?.speech_id === undefined || item?.speech_id === null);
84
- if(noSpeechIdEvents?.length) {
85
- const typesStr = noSpeechIdEvents.map(item => item.type).join(',');
86
- this.options.sdk.onMessage({
87
- code: EErrorCode.EVENT_WITHOUT_SPEECH_ID,
88
- message: `Error: 事件中存在不包含speech_id的事件${typesStr}`,
89
- e: noSpeechIdEvents
90
- })
91
- }
92
- if(this.enableClientInterrupt) {
93
- // 根据interruptSpeechId过滤旧的数据,加入前端interrupt事件后,可能在前端打断后,服务仍下发数据 如果type是以_end结尾的,不过滤
94
- event.e = event.e?.filter(item => (item.speech_id > this.interruptSpeechId || item.speech_id === undefined || item.speech_id === null) || item.type.endsWith('_end') || item.type === 'subtitle_off');
95
- }
96
- // 过滤出当前语音的事件
97
- if(this.lastSpeechId !== -1 && this.lastSpeechId) {
98
- event.e = event.e?.filter(item => item?.speech_id >= this.lastSpeechId);
99
- }
100
-
101
- // 1. 处理 speak_start
102
- if (event.e?.some(item => item.type === "speak_start")) {
103
- const speakStart = event.e.find(item => item.type === "speak_start");
104
- this.lastSpeechId = speakStart?.speech_id;
105
- this.onSpeakStateChange("speak_start", speakStart.client_speak_id, speakStart?.speech_id || 0);
106
- }
107
- // 2. 处理 walk_start / voice_start / speak_walk_start
108
- if (event.e?.some(item => item.type === "walk_start") || event.e?.some(item => item.type === "speak_walk_start")) {
109
- this.onWalkStateChange("walk_start");
110
- }
111
- if(event.e?.some(item => item.type === "voice_start")) {
112
- const voiceStart = event.e.find(item => item.type === "voice_start");
113
- const duration = (window as any).performanceTracker.markEnd(performanceConstant.voice_response_play, 'speak');
114
- this.options.sendSdkPoint('rendering_display', {multi_turn_conversation_id: voiceStart?.multi_turn_conversation_id});
115
- this.onVoiceStart(duration, voiceStart?.client_speak_id);
116
- }
117
- // 3. 处理 walk_end / speak_walk_end / voice_end
118
- if (event.e?.some(item => item.type === "walk_end") || event.e?.some(item => item.type === "speak_walk_end")) {
119
- this.onWalkStateChange("walk_end");
120
- }
121
- if (event.e?.some(item => item.type === "voice_end")) {
122
- const voiceEnd = event.e.find(item => item.type === "voice_end");
123
- this.onVoiceEnd(voiceEnd?.client_speak_id || '', voiceEnd?.speech_id || 0);
124
- }
125
- // 4. 处理 speak_end / speak_error
126
- const speakEndEventTypes = ["speak_end", "speak_error"];
127
- speakEndEventTypes.forEach(eventType => {
128
- const speakEvent = event.e.find(item => item.type === eventType);
129
- if (speakEvent) {
130
- this.onSpeakStateChange(eventType, speakEvent.client_speak_id, speakEvent?.speech_id || 0);
131
- }
132
- });
133
-
134
-
135
- const remainingWidgets = [...event.e];
136
-
137
- // 循环遍历 event.e 数组中的所有元素
138
- for (let i = 0; i < event.e.length; i++) {
139
- const widgetData = event.e[i];
140
- if (Object.prototype.hasOwnProperty.call(widgetData, "event_type")) {
141
- // 先不处理 ka/ka_intent
142
- continue;
143
- }
144
- // 如果有自定义的渲染器,则所有事件都交给自定义的渲染器处理
145
- if (DefaultWidgetRenderer.CUSTOM_WIDGET) {
146
- DefaultWidgetRenderer.CUSTOM_WIDGET(widgetData);
147
- // 从剩余元素中删除已处理的元素
148
- const index = remainingWidgets.indexOf(widgetData);
149
- if (index > -1) {
150
- remainingWidgets.splice(index, 1);
151
- }
152
- continue;
153
- }
154
- // 如果有代理的渲染器,则根据类型执行代理的渲染器
155
- if (DefaultWidgetRenderer.PROXY_WIDGET && DefaultWidgetRenderer.PROXY_WIDGET[widgetData.type]) {
156
- DefaultWidgetRenderer.PROXY_WIDGET[widgetData.type](widgetData);
157
-
158
- // 从剩余元素中删除已处理的元素
159
- const index = remainingWidgets.indexOf(widgetData);
160
- if (index > -1) {
161
- remainingWidgets.splice(index, 1);
162
- }
163
- continue;
164
- }
165
- }
166
- // 对剩余未自定义的元素执行 TrackerRenderer
167
- if (remainingWidgets.length > 0) {
168
- // 遍历剩余的元素,每个单独执行 TrackerRenderer
169
- // 传递 SDK 实例引用,用于区分不同数字人实例的 widget
170
- for (const widgetData of remainingWidgets) {
171
- const tracker = new TrackerRenderer(widgetData, this.options.sdk);
172
- this.trackerRenderer.push(tracker);
173
- }
174
- }
175
- return this.trackerRenderer;
176
- }
177
-
178
- clearTrackerRenderer() {
179
- this.trackerRenderer = [];
180
- }
181
-
182
- setInterrupt(speech_id: number) {
183
- this.interruptSpeechId = speech_id;
184
- }
185
-
186
- destroy() {
187
- this.lastSpeechId = -1;
188
- this.interruptSpeechId = -1;
189
- this.lastFrameIndex = -1;
190
- this.initEventsRendered = false;
191
- // 传递 SDK 实例引用,只清除当前实例的 widget
192
- DefaultWidgetRenderer.destroy(this.options.sdk);
193
- this.trackerRenderer.forEach((tracker) => tracker.destroy());
194
- }
195
- }