@xmov/avatar 2.0.0-alpha.38

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 (160) hide show
  1. package/README.md +139 -0
  2. package/dist/agent/__tests__/agent.test.d.ts +1 -0
  3. package/dist/agent/audio-debug.d.ts +3 -0
  4. package/dist/agent/audio-uplink.d.ts +62 -0
  5. package/dist/agent/avatar.cjs +2 -0
  6. package/dist/agent/avatar.cjs.map +1 -0
  7. package/dist/agent/avatar.modern.js +2 -0
  8. package/dist/agent/avatar.modern.js.map +1 -0
  9. package/dist/agent/avatar.module.js +2 -0
  10. package/dist/agent/avatar.module.js.map +1 -0
  11. package/dist/agent/avatar.umd.js +2 -0
  12. package/dist/agent/avatar.umd.js.map +1 -0
  13. package/dist/agent/e2e-client.d.ts +32 -0
  14. package/dist/agent/fixed-audio-track.d.ts +48 -0
  15. package/dist/agent/index.cjs +5 -0
  16. package/dist/agent/index.d.ts +104 -0
  17. package/dist/agent/index.umd.js +10 -0
  18. package/dist/agent/microphone.d.ts +49 -0
  19. package/dist/agent/types.d.ts +153 -0
  20. package/dist/baseRender/AudioRenderer.d.ts +46 -0
  21. package/dist/baseRender/AudioWorklet.d.ts +78 -0
  22. package/dist/baseRender/AvatarRenderer.d.ts +226 -0
  23. package/dist/baseRender/MSEAudioPlayer.d.ts +51 -0
  24. package/dist/baseRender/UIRenderer.d.ts +39 -0
  25. package/dist/baseRender/pcm-audio-processor.d.ts +63 -0
  26. package/dist/control/APIForwarder.d.ts +23 -0
  27. package/dist/control/DataCacheQueue.d.ts +69 -0
  28. package/dist/control/EventDispatcher.d.ts +35 -0
  29. package/dist/control/RenderScheduler.d.ts +162 -0
  30. package/dist/control/SaveAndDownload.d.ts +14 -0
  31. package/dist/control/StreamingClient.d.ts +33 -0
  32. package/dist/control/VideoPlayer.d.ts +47 -0
  33. package/dist/control/ttsa.d.ts +111 -0
  34. package/dist/encoding/media-recorder-encoder.d.ts +33 -0
  35. package/dist/encoding/pcm-webm-encoder.d.ts +13 -0
  36. package/dist/encoding/webcodec-opus-encoder.d.ts +41 -0
  37. package/dist/encoding/webm-muxer.d.ts +90 -0
  38. package/dist/index.cjs +2 -0
  39. package/dist/index.cjs.map +1 -0
  40. package/dist/index.d.ts +231 -0
  41. package/dist/index.modern.js +2 -0
  42. package/dist/index.modern.js.map +1 -0
  43. package/dist/index.module.js +2 -0
  44. package/dist/index.module.js.map +1 -0
  45. package/dist/index.umd.js +2 -0
  46. package/dist/index.umd.js.map +1 -0
  47. package/dist/modules/Composition.d.ts +28 -0
  48. package/dist/modules/ResourceManager.d.ts +295 -0
  49. package/dist/modules/TrackRenderer/base-track.d.ts +4 -0
  50. package/dist/modules/TrackRenderer/index.d.ts +12 -0
  51. package/dist/modules/TrackRenderer/render-implements.d.ts +19 -0
  52. package/dist/modules/TrackRenderer/track-pic.d.ts +8 -0
  53. package/dist/modules/TrackRenderer/track-subtitle.d.ts +8 -0
  54. package/dist/modules/cache-manager.d.ts +5 -0
  55. package/dist/modules/decoder.d.ts +84 -0
  56. package/dist/modules/error-handle.d.ts +17 -0
  57. package/dist/modules/network.d.ts +21 -0
  58. package/dist/proto/face_data_pb.d.ts +0 -0
  59. package/dist/types/capability.d.ts +15 -0
  60. package/dist/types/error.d.ts +70 -0
  61. package/dist/types/event.d.ts +25 -0
  62. package/dist/types/frame-data.d.ts +107 -0
  63. package/dist/types/index.d.ts +187 -0
  64. package/dist/types/render.d.ts +18 -0
  65. package/dist/utils/DataInterface.d.ts +113 -0
  66. package/dist/utils/GLDevice.d.ts +46 -0
  67. package/dist/utils/GLPipeline.d.ts +84 -0
  68. package/dist/utils/GLPipelineDebugTools.d.ts +5 -0
  69. package/dist/utils/Math.d.ts +21 -0
  70. package/dist/utils/__tests__/capability-checker.test.d.ts +1 -0
  71. package/dist/utils/audio-session.d.ts +11 -0
  72. package/dist/utils/audio.d.ts +1 -0
  73. package/dist/utils/capability-checker.d.ts +23 -0
  74. package/dist/utils/encodeToken.d.ts +7 -0
  75. package/dist/utils/face.d.ts +1 -0
  76. package/dist/utils/float32-decoder.d.ts +26 -0
  77. package/dist/utils/fpsTracker.d.ts +27 -0
  78. package/dist/utils/index.d.ts +22 -0
  79. package/dist/utils/logger.d.ts +9 -0
  80. package/dist/utils/media-recorder-timestamp.d.ts +15 -0
  81. package/dist/utils/pcmAnalyzer.d.ts +40 -0
  82. package/dist/utils/perfermance.d.ts +15 -0
  83. package/dist/utils/request.d.ts +19 -0
  84. package/dist/utils/requestAnimateFrames.d.ts +31 -0
  85. package/dist/utils/time.d.ts +9 -0
  86. package/dist/view/DebugOverlay.d.ts +54 -0
  87. package/dist/worker/streaming-video.d.ts +1 -0
  88. package/package.json +82 -0
  89. package/src/agent/__tests__/agent.test.ts +3787 -0
  90. package/src/agent/audio-debug.ts +36 -0
  91. package/src/agent/audio-uplink.ts +392 -0
  92. package/src/agent/e2e-client.ts +215 -0
  93. package/src/agent/fixed-audio-track.ts +547 -0
  94. package/src/agent/index.ts +1393 -0
  95. package/src/agent/microphone.ts +534 -0
  96. package/src/agent/types.ts +197 -0
  97. package/src/baseRender/AudioRenderer.ts +317 -0
  98. package/src/baseRender/AudioWorklet.ts +776 -0
  99. package/src/baseRender/AvatarRenderer.ts +1559 -0
  100. package/src/baseRender/MSEAudioPlayer.ts +243 -0
  101. package/src/baseRender/UIRenderer.ts +195 -0
  102. package/src/baseRender/pcm-audio-processor.js +267 -0
  103. package/src/control/APIForwarder.ts +67 -0
  104. package/src/control/DataCacheQueue.ts +372 -0
  105. package/src/control/EventDispatcher.ts +106 -0
  106. package/src/control/RenderScheduler.ts +945 -0
  107. package/src/control/SaveAndDownload.js +77 -0
  108. package/src/control/StreamingClient.ts +138 -0
  109. package/src/control/VideoPlayer.ts +306 -0
  110. package/src/control/ttsa.ts +676 -0
  111. package/src/encoding/media-recorder-encoder.ts +175 -0
  112. package/src/encoding/pcm-webm-encoder.ts +72 -0
  113. package/src/encoding/webcodec-opus-encoder.ts +258 -0
  114. package/src/encoding/webm-muxer.ts +337 -0
  115. package/src/global.d.ts +105 -0
  116. package/src/index.ts +1920 -0
  117. package/src/modules/Composition.ts +79 -0
  118. package/src/modules/ResourceManager.ts +899 -0
  119. package/src/modules/TrackRenderer/base-track.ts +7 -0
  120. package/src/modules/TrackRenderer/index.ts +40 -0
  121. package/src/modules/TrackRenderer/render-implements.ts +269 -0
  122. package/src/modules/TrackRenderer/track-pic.ts +19 -0
  123. package/src/modules/TrackRenderer/track-subtitle.ts +16 -0
  124. package/src/modules/cache-manager.ts +10 -0
  125. package/src/modules/decoder.ts +515 -0
  126. package/src/modules/error-handle.ts +20 -0
  127. package/src/modules/network.ts +71 -0
  128. package/src/proto/face_data.proto +45 -0
  129. package/src/proto/face_data_pb.js +1297 -0
  130. package/src/proto/protobuf.min.js +8 -0
  131. package/src/types/capability.ts +23 -0
  132. package/src/types/error.ts +211 -0
  133. package/src/types/event.ts +38 -0
  134. package/src/types/frame-data.ts +121 -0
  135. package/src/types/index.ts +207 -0
  136. package/src/types/render.ts +18 -0
  137. package/src/utils/DataInterface.ts +746 -0
  138. package/src/utils/GLDevice.ts +286 -0
  139. package/src/utils/GLPipeline.ts +1293 -0
  140. package/src/utils/GLPipelineDebugTools.ts +174 -0
  141. package/src/utils/Math.ts +266 -0
  142. package/src/utils/__tests__/capability-checker.test.ts +159 -0
  143. package/src/utils/audio-session.ts +144 -0
  144. package/src/utils/audio.ts +44 -0
  145. package/src/utils/blueimp-md5.d.ts +3 -0
  146. package/src/utils/capability-checker.ts +379 -0
  147. package/src/utils/encodeToken.ts +100 -0
  148. package/src/utils/face.ts +29 -0
  149. package/src/utils/float32-decoder.js +130 -0
  150. package/src/utils/fpsTracker.ts +100 -0
  151. package/src/utils/index.ts +182 -0
  152. package/src/utils/logger.js +36 -0
  153. package/src/utils/media-recorder-timestamp.ts +79 -0
  154. package/src/utils/pcmAnalyzer.ts +154 -0
  155. package/src/utils/perfermance.ts +141 -0
  156. package/src/utils/request.ts +95 -0
  157. package/src/utils/requestAnimateFrames.ts +195 -0
  158. package/src/utils/time.ts +32 -0
  159. package/src/view/DebugOverlay.ts +404 -0
  160. package/src/worker/streaming-video.ts +4647 -0
@@ -0,0 +1,7 @@
1
+ export default class BaseTrack {
2
+ render() {
3
+ }
4
+
5
+ stop() {
6
+ }
7
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 具体的 track 内容渲染
3
+ */
4
+ import {
5
+ IWidgetPic,
6
+ IWidgetSubtitle,
7
+ } from '../../types/event';
8
+ import { IRawWidgetData } from '../../types/frame-data';
9
+ import TrackPic from './track-pic';
10
+ import TrackSubtitle from './track-subtitle';
11
+ import DefaultRender from './render-implements';
12
+
13
+ export default class TrackRenderer {
14
+ private TAG = '[TrackRenderer]';
15
+ tracker!: TrackPic | TrackSubtitle;
16
+ private instance?: any; // 实例引用,用于区分不同数字人实例
17
+
18
+ constructor(event: IRawWidgetData, instance?: any) {
19
+ this.instance = instance;
20
+ const { type, data, text = '' } = event
21
+ if (type === 'widget_pic') {
22
+ this.tracker = new TrackPic(data as IWidgetPic, instance);
23
+ }
24
+ if (type === 'subtitle_on' || type === 'subtitle_off') {
25
+ this.tracker = new TrackSubtitle({type, text, axis_id: data?.axis_id ?? 1000} as IWidgetSubtitle, instance);
26
+ }
27
+ }
28
+
29
+ render() {
30
+ return this.tracker?.render()
31
+ }
32
+
33
+ stop() {
34
+ this.tracker.stop()
35
+ }
36
+
37
+ destroy() {
38
+ DefaultRender.destroy(this.instance);
39
+ }
40
+ }
@@ -0,0 +1,269 @@
1
+ /**
2
+ * widget_xx 的默认实现
3
+ */
4
+ import {
5
+ IWidgetPic,
6
+ IWidgetSubtitle,
7
+ IWidget,
8
+ } from "../../types/event";
9
+ import { IRawWidgetData } from "../../types/frame-data";
10
+
11
+ // 用于跟踪已创建的widget,键格式为"type-axisId"
12
+ // 使用容器元素的ID作为key(固定字符串),避免WeakMap对象引用问题
13
+ const containerWidgetMaps = new Map<string, Map<string, HTMLDivElement>>();
14
+ let containerIdCounter = 0;
15
+
16
+ // 获取容器元素
17
+ function getContainerElement(instance: any): HTMLElement | null {
18
+ if (!instance) return null;
19
+ // 优先从 instance.el 获取容器元素
20
+ if (instance.el && instance.el instanceof HTMLElement) {
21
+ return instance.el;
22
+ }
23
+ return null;
24
+ }
25
+
26
+ // 获取或生成容器的唯一ID
27
+ function getContainerId(container: HTMLElement): string {
28
+ // 如果容器已有ID,直接使用
29
+ if (container.id) {
30
+ return container.id;
31
+ }
32
+ // 如果容器有 data-widget-container-id 属性,使用它
33
+ const existingId = container.getAttribute('data-widget-container-id');
34
+ if (existingId) {
35
+ return existingId;
36
+ }
37
+ // 生成新的唯一ID并设置
38
+ const newId = `widget-container-${++containerIdCounter}`;
39
+ container.setAttribute('data-widget-container-id', newId);
40
+ return newId;
41
+ }
42
+
43
+ // 获取或创建容器元素的 widget Map(使用容器ID作为key)
44
+ function getContainerWidgetMap(container: HTMLElement): Map<string, HTMLDivElement> {
45
+ const containerId = getContainerId(container);
46
+ if (!containerWidgetMaps.has(containerId)) {
47
+ containerWidgetMaps.set(containerId, new Map<string, HTMLDivElement>());
48
+ }
49
+ return containerWidgetMaps.get(containerId)!;
50
+ }
51
+
52
+ // 检查 Map 中是否包含指定的容器
53
+ function hasContainerInMap(container: HTMLElement): boolean {
54
+ const containerId = getContainerId(container);
55
+ return containerWidgetMaps.has(containerId);
56
+ }
57
+
58
+ const subtitleStyle =
59
+ `bottom: 50px;
60
+ left: 50%;
61
+ transform: translateX(-50%);
62
+ background: rgba(0, 0, 0, 0.8);
63
+ color: white;
64
+ padding: 12px 20px;
65
+ border-radius: 8px;
66
+ font-size: 16px;
67
+ font-weight: 500;
68
+ z-index: 1000;
69
+ max-width: 80%;
70
+ min-width: 200px;
71
+ word-break: break-word;
72
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
73
+ text-align: center;`;
74
+
75
+ const WidgetDefaultRenderer: {
76
+ _el(data: IWidget): HTMLDivElement;
77
+ WIDGET_PIC(data: IWidgetPic, instance?: any): HTMLDivElement;
78
+ // WIDGET_SLIDESHOW(data: IWidgetSlideshow): HTMLDivElement;
79
+ WIDGET_SUBTITLE(data: IWidgetSubtitle, instance?: any): HTMLDivElement | null;
80
+ // WIDGET_TEXT(data: IWidgetText): HTMLDivElement;
81
+ // WIDGET_VIDEO(data: IWidgetVideo): HTMLDivElement;
82
+ CUSTOM_WIDGET?(data: IRawWidgetData): void;
83
+ PROXY_WIDGET?: {
84
+ [key: string]: (data: any) => void
85
+ }
86
+ destroy(instance?: any): void;
87
+ _getWidgetKey(type: string, axisId?: number): string;
88
+ _replaceWidget(type: string, axisId: number, newElement: HTMLDivElement, instance?: any): void;
89
+ _currentInstance?: any; // 当前实例引用
90
+ } = {
91
+ /**
92
+ * 生成基础容器元素
93
+ * @param axis_id 用于设置z-index的层级ID
94
+ */
95
+ _el(data: IWidget) {
96
+ const { axis_id, x_location, y_location, width, height } = data;
97
+ const _div = document.createElement('div');
98
+ _div.setAttribute('class', 'avatar-sdk-widget-container');
99
+ let style = 'position:absolute;';
100
+ style += axis_id !== undefined ? `z-index:${axis_id};` : 'z-index:1;';
101
+ if(x_location !== undefined && y_location !== undefined) {
102
+ style += `top:${y_location * 100}%;left:${x_location * 100}%;`;
103
+ }
104
+ if(width !== undefined && height !== undefined) {
105
+ style += `width:${width * 100}%;height:${height * 100}%;`;
106
+ }
107
+ _div.setAttribute('style', style);
108
+ return _div;
109
+ },
110
+
111
+ /**
112
+ * 生成widget的唯一标识键
113
+ * @param type widget类型
114
+ * @param axisId 层级ID
115
+ * @returns 唯一标识字符串
116
+ */
117
+ _getWidgetKey(type: string, axisId?: number): string {
118
+ // 使用默认值确保即使没有axisId也能正常工作
119
+ const id = axisId ?? 'default';
120
+ return `${type}-${id}`;
121
+ },
122
+
123
+ /**
124
+ * 替换相同类型和层级的widget
125
+ * @param type widget类型
126
+ * @param axisId 层级ID
127
+ * @param newElement 新的widget元素
128
+ * @param instance 实例引用(用于区分不同数字人实例)
129
+ */
130
+ _replaceWidget(type: string, axisId: number, newElement: HTMLDivElement, instance?: any): void {
131
+ const key = this._getWidgetKey(type, axisId);
132
+ const actualInstance = instance || this._currentInstance;
133
+ const container = getContainerElement(actualInstance);
134
+ if (!container) {
135
+ return;
136
+ }
137
+ const widgetMap = getContainerWidgetMap(container);
138
+ if (widgetMap.has(key)) {
139
+ const oldElement = widgetMap.get(key);
140
+ if (oldElement && oldElement.parentNode) {
141
+ oldElement.remove();
142
+ }
143
+ }
144
+ widgetMap.set(key, newElement);
145
+ },
146
+
147
+ /**
148
+ * 渲染图片widget
149
+ */
150
+ WIDGET_PIC(data: IWidgetPic, instance?: any): HTMLDivElement {
151
+ const div = this._el(data);
152
+ const img = document.createElement('img');
153
+ img.crossOrigin = 'anonymous';
154
+ img.setAttribute('style', 'width:100%;height:100%;');
155
+ img.src = data.image;
156
+ div.appendChild(img);
157
+
158
+ this._replaceWidget('WIDGET_PIC', data.axis_id, div, instance);
159
+ return div;
160
+ },
161
+
162
+ /**
163
+ * 渲染幻灯片widget
164
+ */
165
+ // WIDGET_SLIDESHOW(data: IWidgetSlideshow): HTMLDivElement {
166
+ // const div = this._el(data.axis_id);
167
+ // const img = document.createElement('img');
168
+ // img.src = data.images[0];
169
+ // div.appendChild(img);
170
+
171
+ // this._replaceWidget('WIDGET_SLIDESHOW', data.axis_id, div);
172
+ // return div;
173
+ // },
174
+
175
+ /**
176
+ * 渲染字幕widget
177
+ */
178
+ WIDGET_SUBTITLE(data: IWidgetSubtitle, instance?: any): HTMLDivElement | null {
179
+ const { type, text, axis_id } = data;
180
+ const actualInstance = instance || this._currentInstance;
181
+ const container = getContainerElement(actualInstance);
182
+ if(type === 'subtitle_off') {
183
+ // 移除对应的div
184
+ if (container) {
185
+ const widgetMap = getContainerWidgetMap(container);
186
+ const key = this._getWidgetKey('WIDGET_SUBTITLE', axis_id);
187
+ if(widgetMap.has(key)) {
188
+ const oldElement = widgetMap.get(key);
189
+ if (oldElement && oldElement.parentNode) {
190
+ oldElement.remove();
191
+ }
192
+ widgetMap.delete(key);
193
+ }
194
+ }
195
+ return null;
196
+ }
197
+ const div = this._el(data);
198
+ div.innerHTML = text;
199
+ div.setAttribute('style', div.style.cssText + subtitleStyle);
200
+ this._replaceWidget('WIDGET_SUBTITLE', axis_id, div, instance);
201
+ return div;
202
+ },
203
+
204
+ /**
205
+ * 渲染文本widget
206
+ */
207
+ // WIDGET_TEXT(data: IWidgetText): HTMLDivElement {
208
+ // const div = this._el(data.axis_id);
209
+ // div.innerHTML = data.text_content;
210
+
211
+ // this._replaceWidget('WIDGET_TEXT', data.axis_id, div);
212
+ // return div;
213
+ // },
214
+
215
+ /**
216
+ * 渲染视频widget
217
+ */
218
+ // WIDGET_VIDEO(data: IWidgetVideo): HTMLDivElement {
219
+ // const div = this._el(data.axis_id);
220
+ // const video = document.createElement('video');
221
+ // video.setAttribute('style', 'width:100%;height:100%;object-fit:cover;');
222
+ // video.src = data.video;
223
+ // video.autoplay = true;
224
+ // video.loop = true;
225
+ // video.muted = true;
226
+ // div.appendChild(video);
227
+
228
+ // this._replaceWidget('WIDGET_VIDEO', data.axis_id, div);
229
+ // return div;
230
+ // },
231
+
232
+ /**
233
+ * 销毁指定实例的widget
234
+ * @param instance 实例引用(用于区分不同数字人实例)
235
+ */
236
+ destroy(instance?: any) {
237
+ // 使用与 _replaceWidget 相同的逻辑,通过容器元素来查找和清理
238
+ const actualInstance = instance || this._currentInstance;
239
+ const container = getContainerElement(actualInstance);
240
+
241
+ if (container) {
242
+ const containerId = getContainerId(container);
243
+
244
+ // 检查 Map 中是否存在该容器
245
+ if (containerWidgetMaps.has(containerId)) {
246
+ // 从容器对应的 widgetMap 中清理
247
+ const widgetMap = containerWidgetMaps.get(containerId)!;
248
+ widgetMap.forEach((element, key) => {
249
+ if(key.startsWith('WIDGET_SUBTITLE') || key.startsWith('WIDGET_PIC')) {
250
+ // 使用 remove() 方法更可靠,会自动检查元素是否在 DOM 中
251
+ if (element && element.parentNode) {
252
+ element.remove();
253
+ }
254
+ }
255
+ });
256
+ widgetMap.clear();
257
+ containerWidgetMaps.delete(containerId);
258
+ } else {
259
+ // 备用清理方法:从容器 DOM 中查找并删除所有 widget 元素
260
+ const widgets = container.querySelectorAll('.avatar-sdk-widget-container');
261
+ widgets.forEach((widget) => {
262
+ widget.remove();
263
+ });
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ export default WidgetDefaultRenderer;
@@ -0,0 +1,19 @@
1
+ import { IWidgetPic } from "../../types/event";
2
+ import BaseTrack from "./base-track";
3
+ import DefaultRender from './render-implements';
4
+
5
+ export default class ImageTrack extends BaseTrack {
6
+ data: IWidgetPic;
7
+ private instance?: any; // 实例引用,用于区分不同数字人实例
8
+
9
+ constructor(data: IWidgetPic, instance?: any) {
10
+ super();
11
+ this.data = data;
12
+ this.instance = instance;
13
+ }
14
+
15
+ render() {
16
+ if(!this.data?.image) return null;
17
+ return DefaultRender.WIDGET_PIC(this.data, this.instance);
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ import { IWidgetSubtitle } from "../../types/event";
2
+ import BaseTrack from "./base-track";
3
+ import DefaultRender from './render-implements';
4
+
5
+ export default class SubtitleTrack extends BaseTrack {
6
+ data: IWidgetSubtitle;
7
+ private instance?: any; // 实例引用,用于区分不同数字人实例
8
+ constructor(data: IWidgetSubtitle, instance?: any) {
9
+ super();
10
+ this.data = data;
11
+ this.instance = instance;
12
+ }
13
+ render() {
14
+ return DefaultRender.WIDGET_SUBTITLE(this.data, this.instance);
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ export default class CacheManager {
2
+ cacheServer: string;
3
+ constructor(cacheServer: string) {
4
+ this.cacheServer = cacheServer;
5
+ }
6
+
7
+ getVideo(url: string): string {
8
+ return `${this.cacheServer}/get_video?url=${encodeURIComponent(url)}`
9
+ }
10
+ }