trtc-electron-sdk 12.2.115-beta.2 → 12.2.115-beta.21

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 (34) hide show
  1. package/liteav/MediaMixingDesigner/index.d.ts +12 -8
  2. package/liteav/MediaMixingDesigner/index.js +135 -79
  3. package/liteav/base/DevicePixelRatioObserver.d.ts +12 -0
  4. package/liteav/base/DevicePixelRatioObserver.js +32 -0
  5. package/liteav/base/PromiseStore.d.ts +10 -0
  6. package/liteav/base/PromiseStore.js +58 -0
  7. package/liteav/constant.d.ts +1 -0
  8. package/liteav/constant.js +4 -0
  9. package/liteav/extensions/MediaMixingManager/MediaMixingManager.d.ts +429 -0
  10. package/liteav/extensions/MediaMixingManager/MediaMixingManager.js +1290 -0
  11. package/liteav/extensions/MediaMixingManager/MediaMixingService.d.ts +60 -0
  12. package/liteav/extensions/MediaMixingManager/MediaMixingService.js +80 -0
  13. package/liteav/extensions/MediaMixingManager/StreamLayout/BaseStreamLayoutManager.d.ts +32 -0
  14. package/liteav/extensions/MediaMixingManager/StreamLayout/BaseStreamLayoutManager.js +114 -0
  15. package/liteav/extensions/MediaMixingManager/StreamLayout/CustomStreamLayoutManager.d.ts +11 -0
  16. package/liteav/extensions/MediaMixingManager/StreamLayout/CustomStreamLayoutManager.js +135 -0
  17. package/liteav/extensions/MediaMixingManager/StreamLayout/NoneStreamLayoutManager.d.ts +11 -0
  18. package/liteav/extensions/MediaMixingManager/StreamLayout/NoneStreamLayoutManager.js +73 -0
  19. package/liteav/extensions/MediaMixingManager/StreamLayout/index.d.ts +7 -0
  20. package/liteav/extensions/MediaMixingManager/StreamLayout/index.js +34 -0
  21. package/liteav/extensions/MediaMixingManager/StreamLayout/types.d.ts +25 -0
  22. package/liteav/extensions/MediaMixingManager/StreamLayout/types.js +2 -0
  23. package/liteav/extensions/MediaMixingManager/index.d.ts +4 -227
  24. package/liteav/extensions/MediaMixingManager/index.js +30 -589
  25. package/liteav/extensions/MediaMixingManager/types.d.ts +107 -0
  26. package/liteav/extensions/MediaMixingManager/types.js +26 -0
  27. package/liteav/trtc.d.ts +67 -13
  28. package/liteav/trtc.js +159 -61
  29. package/liteav/trtc_define.d.ts +29 -3
  30. package/liteav/trtc_define.js +97 -29
  31. package/liteav/utils.d.ts +27 -0
  32. package/liteav/utils.js +85 -1
  33. package/package.json +2 -2
  34. package/scripts/download.js +153 -169
@@ -0,0 +1,1290 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TRTCMediaMixingManager = exports.TRTCMediaMixingEvent = void 0;
16
+ const events_1 = require("events");
17
+ const trtc_define_1 = require("../../trtc_define");
18
+ const utils_1 = require("../../utils");
19
+ const constant_1 = require("../../constant");
20
+ const index_1 = __importDefault(require("../../MediaMixingDesigner/index"));
21
+ const StreamLayout_1 = require("./StreamLayout");
22
+ const PromiseStore_1 = __importDefault(require("../../base/PromiseStore"));
23
+ const DevicePixelRatioObserver_1 = __importDefault(require("../../base/DevicePixelRatioObserver"));
24
+ const logger_1 = __importDefault(require("../../logger"));
25
+ const NodeTRTCEngine = require('../../../build/Release/trtc_electron_sdk.node');
26
+ /**
27
+ * 媒体源本地混流错误码
28
+ * @enum {Number}
29
+ */
30
+ const TRTCMediaMixingErrorCode_HACK_JSDOC = {
31
+ /** 成功 */
32
+ Success: 0,
33
+ /** 通用错误码 */
34
+ Error: -1,
35
+ /** 参数非法 */
36
+ InvalidParams: 2,
37
+ /** 找不到媒体源 */
38
+ NotFoundSource: 3,
39
+ /** 图片加载失败 */
40
+ ImageSourceLoadFailed: 4,
41
+ /** 摄像头未授权 */
42
+ CameraNotAuthorized: 5,
43
+ /** 摄像头被占用 */
44
+ CameraIsOccupied: 6,
45
+ /** 摄像头断开连接 */
46
+ CameraDisconnected: 7,
47
+ };
48
+ /**
49
+ * 媒体源类型
50
+ * @enum {Number}
51
+ */
52
+ const TRTCMediaSourceType_HACK_JSDOC = {
53
+ /** 摄像头 */
54
+ kCamera: 0,
55
+ /** 屏幕/窗口分享 */
56
+ kScreen: 1,
57
+ /** 图片 */
58
+ kImage: 2,
59
+ /** 手机投屏 */
60
+ kPhoneMirror: 4,
61
+ };
62
+ /**
63
+ * 手机投屏媒体源参数
64
+ *
65
+ * @typedef {Object} TRTCPhoneMirrorParam
66
+ * @property {Number} platformType -1:未知类型, 0:安卓系统, 1:iOS 系统
67
+ * @property {Number} connectType -1:未知类型, 0:USB有线投屏, 1:WIFI无线投屏
68
+ * @property {String} deviceId 设备 ID
69
+ * @property {String} deviceName 设备名称
70
+ * @property {String} placeholderImagePath 垫片图路径
71
+ * @property {Number} frameRate 视频帧率
72
+ * @property {Number} bitrateKbps 音频码率
73
+ *
74
+ */
75
+ const TRTCPhoneMirrorParam_HACK_JSDOC = null;
76
+ /**
77
+ * 媒体源数据
78
+ *
79
+ * @typedef {Object} TRTCMediaSource
80
+ * @property {TRTCMediaSourceType} sourceType 媒体源类型
81
+ * @property {String} sourceId 媒体源唯一 ID
82
+ * @property {Number} zOrder 媒体源展示层级,取值 0 - 15
83
+ * @property {Rect} rect 媒体源显示区域
84
+ * @property {Boolean} isSelected 媒体源是否选中,可选属性,默认:false
85
+ * @property {TRTCVideoRotation} rotation 媒体源选中角度,可选属性
86
+ * @property {TRTCVideoFillMode} fillMode 媒体源显示模式,可选属性,默认 `TRTCVideoFillMode_Fit`
87
+ * @property {TRTCVideoMirrorType} mirrorType 媒体源是否镜像,可选属性,默认不镜像
88
+ * @property {TRTCPhoneMirrorConnectionParam} connectionParam 手机投屏类型媒体源,连接参数
89
+ */
90
+ const TRTCMediaSource_HACK_JSDOC = null;
91
+ /**
92
+ * 媒体源本地混流编码参数
93
+ *
94
+ * @typedef {Object} TRTCMediaMixingEncParam
95
+ * @property {TRTCVideoEncParam} videoEncoderParams 本地混流编码参数
96
+ * @property {Number} canvasColor 混流视频背景色,默认值:0x0 代表黑色。格式为十六进制数字,比如:`0x61B9F1` 代表 RGB 颜色(97、158、241)。
97
+ * @property {Number} selectedBorderColor 选中媒体源的高亮边框颜色,默认黄色:0xFFFF00。
98
+ */
99
+ const TRTCMediaMixingEncParam_HACK_JSDOC = null;
100
+ /**
101
+ * 连麦视频流布局模式
102
+ *
103
+ * 本地混流高性能渲染模式下,多路视频流布局模式
104
+ *
105
+ * @enum {String}
106
+ */
107
+ const TRTCStreamLayoutMode_HACK_JSDOC = {
108
+ /** 自定义布局 */
109
+ Custom: 'Custom',
110
+ /** 无布局,恢复默认 */
111
+ None: 'None',
112
+ };
113
+ /**
114
+ * 单路连麦视频流布局信息
115
+ *
116
+ * 本地混流高性能渲染模式下,单路视频流布局信息
117
+ * @typedef {Object} TRTCStreamInfo
118
+ * @property {String} userId 用户 ID,本地用户需填空字符长
119
+ * @property {TRTCVideoFillMode} fillMode 视频填充模式
120
+ * @property {Rect} rect 视频流显示区域
121
+ * @property {Number} zOrder 视频流展示层级,取值 0 - 15
122
+ */
123
+ const TRTCStreamInfo_HACK_JSDOC = null;
124
+ /**
125
+ * 连麦视频流布局信息
126
+ *
127
+ * 本地混流高性能渲染模式下,所有视频流布局信息
128
+ * @typedef {Object} TRTCStreamLayout
129
+ * @property {TRTCStreamLayoutMode} layoutMode 布局模式
130
+ * @property {Array<TRTCStreamInfo>} userList 非必填,用户视频流布局
131
+ */
132
+ const TRTCStreamLayout_HACK_JSDOC = null;
133
+ const initResolutionMap = () => {
134
+ const map = new Map();
135
+ for (const key in trtc_define_1.TRTCVideoResolution) {
136
+ if (isNaN(Number(key))) {
137
+ const value = trtc_define_1.TRTCVideoResolution[key];
138
+ const tmp = key.split('_');
139
+ map.set(value, {
140
+ width: parseInt(tmp[1]),
141
+ height: parseInt(tmp[2]),
142
+ });
143
+ }
144
+ }
145
+ return map;
146
+ };
147
+ const resolutionMap = initResolutionMap();
148
+ /**
149
+ * @namespace TRTCMediaMixingEvent
150
+ * @description 目前只支持 `Windows` 操作系统
151
+ */
152
+ var TRTCMediaMixingEvent;
153
+ (function (TRTCMediaMixingEvent) {
154
+ /**
155
+ * @description 媒体源选中事件
156
+ *
157
+ * @event TRTCMediaMixingEvent#onSourceSelected
158
+ * @param {TRTCMediaInfo | null} mediaSource 新选中的媒体源数据,取消选中则为`null`
159
+ */
160
+ TRTCMediaMixingEvent["onSourceSelected"] = "onSourceSelected";
161
+ /**
162
+ * @description 媒体源移动事件
163
+ *
164
+ * @event TRTCMediaMixingEvent#onSourceMoved
165
+ * @param {TRTCMediaInfo} mediaSource 被移动的媒体源
166
+ * @param {Rect} rect 移动后的位置、区域数据
167
+ */
168
+ TRTCMediaMixingEvent["onSourceMoved"] = "onSourceMoved";
169
+ /**
170
+ * @description 媒体源尺寸变化事件
171
+ *
172
+ * @event TRTCMediaMixingEvent#onSourceResized
173
+ * @param {TRTCMediaInfo} mediaSource 尺寸变化的媒体源
174
+ * @param {Rect} rect 尺寸变化后的位置、区域数据
175
+ */
176
+ TRTCMediaMixingEvent["onSourceResized"] = "onSourceResized";
177
+ /**
178
+ * @description 媒体源鼠标右键事件
179
+ *
180
+ * @event TRTCMediaMixingEvent#onRightButtonClicked
181
+ * @param {TRTCMediaInfo} mediaSource 鼠标右键点击的媒体源
182
+ * @param {Object} clickPoint 鼠标右键点击的位置
183
+ * @param {Number} clickPoint.windowX 鼠标右键点击相对窗口的 X 坐标
184
+ * @param {Number} clickPoint.windowY 鼠标右键点击相对窗口的 Y 坐标
185
+ * @param {Number} clickPoint.screenX 鼠标右键点击相对屏幕的 X 坐标
186
+ * @param {Number} clickPoint.screenY 鼠标右键点击相对屏幕的 Y 坐标
187
+ */
188
+ TRTCMediaMixingEvent["onRightButtonClicked"] = "onRightButtonClicked";
189
+ /**
190
+ * @description 错误事件
191
+ *
192
+ * @event TRTCMediaMixingEvent#onError
193
+ * @param {TRTCMediaMixingErrorCode} errorCode 错误码
194
+ * @param {String} errorMessage 错误信息
195
+ * @param {TRTCMediaSource|undefined} 错误涉及的媒体源,可能为空
196
+ *
197
+ */
198
+ TRTCMediaMixingEvent["onError"] = "onError";
199
+ /**
200
+ * @description 设备插入事件
201
+ *
202
+ * @event TRTCMediaMixingEvent#onSourcePlugged
203
+ * @param {TRTCPhoneMirrorParam} source 投屏手机状态信息
204
+ * @param {String} detail 投屏手机状态变化详情
205
+ */
206
+ TRTCMediaMixingEvent["onSourcePlugged"] = "onSourcePlugged";
207
+ /**
208
+ * @description 设备链接事件
209
+ *
210
+ * @event TRTCMediaMixingEvent#onSourceConnected
211
+ * @param {TRTCPhoneMirrorParam} source 投屏手机状态信息
212
+ * @param {String} detail 投屏手机状态变化详情
213
+ */
214
+ TRTCMediaMixingEvent["onSourceConnected"] = "onSourceConnected";
215
+ /**
216
+ * @description 设备断开链接事件
217
+ *
218
+ * @event TRTCMediaMixingEvent#onSourceDisconnected
219
+ * @param {TRTCPhoneMirrorParam} source 投屏手机状态信息
220
+ * @param {String} detail 投屏手机状态变化详情
221
+ */
222
+ TRTCMediaMixingEvent["onSourceDisconnected"] = "onSourceDisconnected";
223
+ /**
224
+ * @description 设备拔出事件
225
+ *
226
+ * @event TRTCMediaMixingEvent#onSourceUnplugged
227
+ * @param {TRTCPhoneMirrorParam} source 投屏手机状态信息
228
+ * @param {String} detail 投屏手机状态变化详情
229
+ */
230
+ TRTCMediaMixingEvent["onSourceUnplugged"] = "onSourceUnplugged";
231
+ /**
232
+ * @description 媒体源画面大小发生变化
233
+ *
234
+ * 当输入媒体源的画面大小发生变化时,会通过该接口返回该输入源最新的尺寸,您可以根据该尺寸来动态调整画面的比例。
235
+ * @event TRTCMediaMixingEvent#onMediaSourceSizeChanged
236
+ * @param {TRTCMediaSource} mediasource 媒体源信息
237
+ * @param {Object} size 媒体源最新的画面大小
238
+ * @param {Number} size.width 媒体源最新宽度
239
+ * @param {Number} size.height 媒体源最新高度
240
+ */
241
+ TRTCMediaMixingEvent["onMediaSourceSizeChanged"] = "onMediaSourceSizeChanged";
242
+ TRTCMediaMixingEvent["onMediaMixingServerLost"] = "onMediaMixingServerLost";
243
+ })(TRTCMediaMixingEvent = exports.TRTCMediaMixingEvent || (exports.TRTCMediaMixingEvent = {}));
244
+ const promiseKeys = {
245
+ startMediaMixingServer: 'startMediaMixingServer',
246
+ stopMediaMixingServer: 'stopMediaMixingServer',
247
+ setStreamLayout: 'setStreamLayout',
248
+ addMediaSource: 'addMediaSource',
249
+ removeMediaSource: 'removeMediaSource',
250
+ updateMediaSource: 'updateMediaSource',
251
+ setCameraCaptureParam: 'setCameraCaptureParam',
252
+ setPhoneMirrorParam: 'setPhoneMirrorParam',
253
+ setScreenCaptureProperty: 'setScreenCaptureProperty',
254
+ startPublish: 'startPublish',
255
+ stopPublish: 'stopPublish',
256
+ updatePublishParams: 'updatePublishParams',
257
+ };
258
+ /**
259
+ * 本地混流管理器
260
+ *
261
+ * 目前只支持 `Windows` 操作系统
262
+ */
263
+ class TRTCMediaMixingManager {
264
+ constructor(options) {
265
+ this.logPrefix = '[TRTCMediaMixingManager]';
266
+ this.mediaMixingDesigner = null;
267
+ this.windowID = 0;
268
+ this.view = null;
269
+ this.resizeObserver = null;
270
+ this.mixingVideoWidth = 0;
271
+ this.mixingVideoHeight = 0;
272
+ this.sourceList = [];
273
+ this.streamLayoutManager = null;
274
+ this.eventEmitter = new events_1.EventEmitter();
275
+ this.promiseStore = new PromiseStore_1.default();
276
+ this.handleCppCallbackEvent = this.handleCppCallbackEvent.bind(this);
277
+ this.nodeMediaMixingPlugin = new NodeTRTCEngine.NodeRemoteMultiSourcePlugin();
278
+ this.nodeMediaMixingPlugin.setRemoteMultiSourcePluginCallback(this.handleCppCallbackEvent);
279
+ this.deviceManager = options.deviceManager;
280
+ this.nodeTRTCCloud = options.nodeTRTCCloud;
281
+ this.trtcParamsStore = options.trtcParamsStore;
282
+ this.autoControlServer = options.autoControlServer;
283
+ this.paramsStore = {};
284
+ if (this.autoControlServer) {
285
+ this.startMediaMixingServer()
286
+ .then(() => {
287
+ logger_1.default.info(`${this.logPrefix}startMediaMixingServer success.`);
288
+ })
289
+ .catch((err) => {
290
+ logger_1.default.error(`${this.logPrefix}startMediaMixingServer failed.`, err);
291
+ });
292
+ }
293
+ this.publishParams = {
294
+ videoEncoderParams: {
295
+ videoResolution: trtc_define_1.TRTCVideoResolution.TRTCVideoResolution_1920_1080,
296
+ resMode: trtc_define_1.TRTCVideoResolutionMode.TRTCVideoResolutionModeLandscape,
297
+ videoFps: 30,
298
+ videoBitrate: 3000,
299
+ minVideoBitrate: 3000,
300
+ enableAdjustRes: true,
301
+ },
302
+ canvasColor: 0x0
303
+ };
304
+ this.onSourceSelected = this.onSourceSelected.bind(this);
305
+ this.onSourceMoved = this.onSourceMoved.bind(this);
306
+ this.onSourceResized = this.onSourceResized.bind(this);
307
+ this.onRightButtonClicked = this.onRightButtonClicked.bind(this);
308
+ this.onPreviewAreaResize = this.onPreviewAreaResize.bind(this);
309
+ this.onVisibilityChange = this.onVisibilityChange.bind(this);
310
+ document.addEventListener('visibilitychange', this.onVisibilityChange);
311
+ this.onDevicePixelRatioChange = this.onDevicePixelRatioChange.bind(this);
312
+ DevicePixelRatioObserver_1.default.on('change', this.onDevicePixelRatioChange);
313
+ }
314
+ destroy() {
315
+ return __awaiter(this, void 0, void 0, function* () {
316
+ DevicePixelRatioObserver_1.default.off('change', this.onDevicePixelRatioChange);
317
+ document.removeEventListener('visibilitychange', this.onVisibilityChange);
318
+ if (this.resizeObserver && this.view) {
319
+ this.resizeObserver.unobserve(this.view);
320
+ this.resizeObserver.disconnect();
321
+ }
322
+ this.view = null;
323
+ this.windowID = 0;
324
+ this.destroyDesigner();
325
+ if (this.autoControlServer) {
326
+ try {
327
+ yield this.stopMediaMixingServer();
328
+ logger_1.default.info(`${this.logPrefix}stopMediaMixingServer success.`);
329
+ }
330
+ catch (err) {
331
+ logger_1.default.error(`${this.logPrefix}stopMediaMixingServer failed.`, err);
332
+ }
333
+ }
334
+ this.nodeTRTCCloud = null;
335
+ this.deviceManager = null;
336
+ this.nodeMediaMixingPlugin = null;
337
+ this.eventEmitter = null;
338
+ this.promiseStore.destroy();
339
+ this.paramsStore = null;
340
+ this.trtcParamsStore = null;
341
+ });
342
+ }
343
+ /**
344
+ * @deprecated
345
+ * @private
346
+ * 设置视频流预览参数
347
+ *
348
+ * @param windowID {Number|Uint8Array} - 操作系统层的窗口 ID,Electron 下可以通过 Electron API [BrowserWindow.getNativeWindowHandle()]{@link https://www.electronjs.org/docs/latest/api/browser-window#wingetnativewindowhandle} 接口获取
349
+ * @param viewOrRegion {HTMLElement | Rect | null} - 本地混流视频显示位置
350
+ * - 传入 HTMLElement 元素,则 SDK 将本地混流视频显示在 HTMLElement 元素内,同时支持点击选中、移动、缩放媒体源,支持触发右键菜单事件。HTMLElement 元素必须是块元素。
351
+ * - 传入 Rect 显示区域,则 SDK 将本地混流视频显示在 Rect 指定区域内,不支持点击选中、移动、缩放媒体源,不支持触发右键菜单事件,这些功能您可以在 Web 页面中自行实现。
352
+ * - 传入 null 则 SDK 将停止显示本地混流视频。
353
+ *
354
+ * @example
355
+ * // Display in HTML Element
356
+ * import TRTCCloud from 'trtc-electron-sdk';
357
+ *
358
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
359
+ * isIPCMode: true
360
+ * });
361
+ *
362
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
363
+ *
364
+ * const windowID = 0; // Use Electron API BrowserWindow.getNativeWindowHandle()
365
+ * const previewDOM = document.getElementById("preview-local-mixed-media-stream");
366
+ * mediaMixingManager.setDisplayParams(windowID, previewDOM);
367
+ *
368
+ * @example
369
+ * // Display in a rectangle section
370
+ * import TRTCCloud from 'trtc-electron-sdk';
371
+ *
372
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
373
+ * isIPCMode: true
374
+ * });
375
+ *
376
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
377
+ *
378
+ * const windowID = 0; // Use Electron API BrowserWindow.getNativeWindowHandle()
379
+ * const previewDOM = document.getElementById("preview-local-mixed-media-stream");
380
+ * const domRect = previewDOM.getBoundingClientRect();
381
+ * const rect = {
382
+ * left: domRect.left * window.devicePixelRatio,
383
+ * right: domRect.right * window.devicePixelRatio,
384
+ * top: domRect.top * window.devicePixelRatio,
385
+ * bottom: domRect.bottom * window.devicePixelRatio
386
+ * };
387
+ *
388
+ * mediaMixingManager.setDisplayParams(windowID, rect);
389
+ */
390
+ setDisplayParams(windowID, viewOrRegion) {
391
+ logger_1.default.log(`${this.logPrefix}setDisplayParams:`, windowID, viewOrRegion);
392
+ this.bindPreviewArea(windowID, viewOrRegion);
393
+ }
394
+ /**
395
+ * 设置视频流预览区域
396
+ *
397
+ * @param windowID {Uint8Array|Number} - 操作系统层的窗口 ID,Electron 下可以通过 Electron API [BrowserWindow.getNativeWindowHandle()]{@link https://www.electronjs.org/docs/latest/api/browser-window#wingetnativewindowhandle} 接口获取
398
+ * @param viewOrRegion {HTMLElement | Rect | null} - 本地混流视频显示位置
399
+ * - 传入 HTMLElement 元素,则 SDK 将本地混流视频显示在 HTMLElement 元素内,同时支持点击选中、移动、缩放媒体源,支持触发右键菜单事件。HTMLElement 元素必须是块元素。
400
+ * - 传入 Rect 显示区域,则 SDK 将本地混流视频显示在 Rect 指定区域内,不支持点击选中、移动、缩放媒体源,不支持触发右键菜单事件,这些功能您可以在 Web 页面中自行实现。
401
+ * - 传入 null 则 SDK 将停止显示本地混流视频。
402
+ *
403
+ * @example
404
+ * // Display in HTML Element
405
+ * import TRTCCloud from 'trtc-electron-sdk';
406
+ *
407
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
408
+ * isIPCMode: true
409
+ * });
410
+ *
411
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
412
+ *
413
+ * const windowID = 0; // Use Electron API BrowserWindow.getNativeWindowHandle()
414
+ * const previewDOM = document.getElementById("preview-local-mixed-media-stream");
415
+ * mediaMixingManager.bindPreviewArea(windowID, previewDOM);
416
+ *
417
+ * @example
418
+ * // Display in a rectangle section
419
+ * import TRTCCloud from 'trtc-electron-sdk';
420
+ *
421
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
422
+ * isIPCMode: true
423
+ * });
424
+ *
425
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
426
+ *
427
+ * const windowID = 0; // Use Electron API BrowserWindow.getNativeWindowHandle()
428
+ * const previewDOM = document.getElementById("preview-local-mixed-media-stream");
429
+ * const domRect = previewDOM.getBoundingClientRect();
430
+ * const rect = {
431
+ * left: domRect.left * window.devicePixelRatio,
432
+ * right: domRect.right * window.devicePixelRatio,
433
+ * top: domRect.top * window.devicePixelRatio,
434
+ * bottom: domRect.bottom * window.devicePixelRatio
435
+ * };
436
+ *
437
+ * mediaMixingManager.bindPreviewArea(windowID, rect);
438
+ */
439
+ bindPreviewArea(windowID, viewOrRegion) {
440
+ logger_1.default.log(`${this.logPrefix}bindPreviewArea:`, windowID, viewOrRegion);
441
+ let realWindowID = 0;
442
+ if (windowID instanceof Uint8Array) {
443
+ realWindowID = (0, utils_1.convertUint8ArrayToNumber)(windowID);
444
+ }
445
+ else {
446
+ realWindowID = windowID;
447
+ }
448
+ this.windowID = realWindowID;
449
+ if (realWindowID !== 0 && viewOrRegion !== null) {
450
+ if (viewOrRegion instanceof HTMLElement) {
451
+ if (this.view !== viewOrRegion) {
452
+ this.destroyDesigner();
453
+ this.view = viewOrRegion;
454
+ this.setDisplayRect();
455
+ this.initResizeObserver();
456
+ this.createDesigner();
457
+ }
458
+ else {
459
+ this.setDisplayRect();
460
+ if (!this.mediaMixingDesigner) {
461
+ this.createDesigner();
462
+ }
463
+ }
464
+ }
465
+ else {
466
+ // Rect
467
+ this.destroyLayoutManager();
468
+ this.destroyDesigner();
469
+ this.nodeMediaMixingPlugin.setDisplayParams(realWindowID, viewOrRegion);
470
+ }
471
+ }
472
+ else {
473
+ this.destroyLayoutManager();
474
+ this.destroyDesigner();
475
+ this.nodeMediaMixingPlugin.setDisplayParams(realWindowID, { left: 0, right: 0, top: 0, bottom: 0 });
476
+ }
477
+ }
478
+ /**
479
+ * 添加本地混流媒体源
480
+ * @param mediaSource {TRTCMediaSource} - 媒体源信息
481
+ * @returns {Promise<void>}
482
+ */
483
+ addMediaSource(mediaSource) {
484
+ logger_1.default.log(`${this.logPrefix}addMediaSource:`, mediaSource);
485
+ const index = this.findMediaSourceIndex(mediaSource);
486
+ if (index !== -1) {
487
+ throw new Error("Media source already existed");
488
+ }
489
+ const newMediaSource = (0, utils_1.safelyParse)(JSON.stringify(mediaSource));
490
+ if (newMediaSource.isSelected) {
491
+ const oldSelectedIndex = this.findSelectedMediaSource();
492
+ if (oldSelectedIndex !== -1) {
493
+ this.unselectMediaSource(oldSelectedIndex);
494
+ }
495
+ }
496
+ return new Promise((resolve, reject) => {
497
+ var _a;
498
+ const key = `${promiseKeys.addMediaSource}-${newMediaSource.sourceType}-${newMediaSource.sourceId}`;
499
+ this.promiseStore.addPromise(key, resolve, reject);
500
+ this.nodeMediaMixingPlugin.addMediaSource(newMediaSource);
501
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.addMedia({
502
+ id: `${newMediaSource.sourceType}__${newMediaSource.sourceId}`,
503
+ rect: newMediaSource.rect,
504
+ isSelected: newMediaSource.isSelected || false,
505
+ zOrder: newMediaSource.zOrder,
506
+ origin: newMediaSource
507
+ });
508
+ this.sourceList.push(newMediaSource);
509
+ });
510
+ }
511
+ /**
512
+ * 删除本地混流媒体源
513
+ * @param mediaSource {TRTCMediaSource} - 媒体源信息
514
+ * @returns {Promise<void>}
515
+ */
516
+ removeMediaSource(mediaSource) {
517
+ logger_1.default.log(`${this.logPrefix}removeMediaSource:`, mediaSource);
518
+ const index = this.findMediaSourceIndex(mediaSource);
519
+ if (index === -1) {
520
+ throw new Error("Not existing media source to remove");
521
+ }
522
+ return new Promise((resolve, reject) => {
523
+ const key = `${promiseKeys.removeMediaSource}-${mediaSource.sourceType}-${mediaSource.sourceId}`;
524
+ this.promiseStore.addPromise(key, resolve, reject);
525
+ this.nodeMediaMixingPlugin.removeMediaSource(mediaSource);
526
+ });
527
+ }
528
+ /**
529
+ * 更新本地混流媒体源
530
+ * @param mediaSource {TRTCMediaSource} - 媒体源信息
531
+ * @returns {Promise<void>}
532
+ */
533
+ updateMediaSource(mediaSource) {
534
+ var _a;
535
+ return __awaiter(this, void 0, void 0, function* () {
536
+ logger_1.default.log(`${this.logPrefix}updateMediaSource:`, mediaSource);
537
+ const index = this.findMediaSourceIndex(mediaSource);
538
+ if (index === -1) {
539
+ throw new Error("Not existing media source to update");
540
+ }
541
+ const newMediaSource = Object.assign(Object.assign({}, this.sourceList[index]), (0, utils_1.safelyParse)(JSON.stringify(mediaSource)));
542
+ if (mediaSource.isSelected) {
543
+ const oldSelectedIndex = this.findSelectedMediaSource();
544
+ if (oldSelectedIndex !== -1 && oldSelectedIndex !== index) {
545
+ this.unselectMediaSource(oldSelectedIndex);
546
+ }
547
+ }
548
+ yield this.nodeMediaMixingPlugin.updateMediaSource(newMediaSource);
549
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.updateMedia({
550
+ id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
551
+ rect: mediaSource.rect,
552
+ isSelected: mediaSource.isSelected || false,
553
+ zOrder: mediaSource.zOrder,
554
+ origin: (0, utils_1.safelyParse)(JSON.stringify(mediaSource))
555
+ });
556
+ this.sourceList[index] = newMediaSource;
557
+ });
558
+ }
559
+ /**
560
+ * 设置摄像头采集参数
561
+ * @param cameraID {string} - 摄像头 ID
562
+ * @param params {TRTCCameraCaptureParams} - 摄像头采集参数
563
+ */
564
+ setCameraCaptureParam(cameraID, params) {
565
+ this.nodeMediaMixingPlugin.setCameraCaptureParam(cameraID, params);
566
+ if (params.colorRange !== undefined || params.colorSpace !== undefined) {
567
+ this.nodeMediaMixingPlugin.callExperimentalAPI(JSON.stringify({
568
+ "api": "setCameraCaptureParamEx",
569
+ "params": {
570
+ "cameraId": cameraID,
571
+ "colorRange": params.colorRange || trtc_define_1.TRTCVideoColorRange.TRTCVideoColorRange_Auto,
572
+ "colorSpace": params.colorSpace || trtc_define_1.TRTCVideoColorSpace.TRTCVideoColorSpace_Auto,
573
+ }
574
+ }));
575
+ }
576
+ }
577
+ /**
578
+ * 设置手机投屏参数
579
+ * @param phoneMirrorSourceId {string} - 手机投屏媒体源 ID
580
+ * @param param {TRTCPhoneMirrorParam} - 手机投屏参数
581
+ */
582
+ setPhoneMirrorParam(phoneMirrorSourceId, param) {
583
+ this.nodeMediaMixingPlugin.setPhoneMirrorParam(phoneMirrorSourceId, param);
584
+ }
585
+ /**
586
+ * 设置屏幕采集参数
587
+ * @param screenOrWindowID {String} - 屏幕 ID 或 窗口 ID
588
+ * @param property {TRTCScreenCaptureProperty} - 屏幕采集属性
589
+ */
590
+ setScreenCaptureProperty(screenOrWindowID, property) {
591
+ this.nodeMediaMixingPlugin.setScreenCaptureProperty(screenOrWindowID, property);
592
+ }
593
+ /**
594
+ * 本地混流开始推流
595
+ * @returns {Promise<void>}
596
+ */
597
+ startPublish() {
598
+ return __awaiter(this, void 0, void 0, function* () {
599
+ logger_1.default.log(`${this.logPrefix}startPublish`);
600
+ return yield this.nodeMediaMixingPlugin.startPublish();
601
+ });
602
+ }
603
+ /**
604
+ * 本地混流停止推流
605
+ * @returns {Promise<void>}
606
+ */
607
+ stopPublish() {
608
+ return __awaiter(this, void 0, void 0, function* () {
609
+ logger_1.default.log(`${this.logPrefix}stopPublish`);
610
+ return yield this.nodeMediaMixingPlugin.stopPublish();
611
+ });
612
+ }
613
+ /**
614
+ * 更新本地混流编码参数
615
+ * @param params {TRTCMediaMixingEncParam} - 推流视频编码参数、背景色等参数
616
+ * @returns {Promise<void>}
617
+ */
618
+ updatePublishParams(params) {
619
+ var _a, _b;
620
+ return __awaiter(this, void 0, void 0, function* () {
621
+ logger_1.default.log(`${this.logPrefix}updatePublishParams:`, params);
622
+ this.publishParams = params;
623
+ this.updateMixingVideoSize(params.videoEncoderParams);
624
+ (_a = this.streamLayoutManager) === null || _a === void 0 ? void 0 : _a.updateOptions({
625
+ width: this.mixingVideoWidth,
626
+ height: this.mixingVideoHeight
627
+ });
628
+ (_b = this.mediaMixingDesigner) === null || _b === void 0 ? void 0 : _b.updateOptions({
629
+ width: this.mixingVideoWidth,
630
+ height: this.mixingVideoHeight
631
+ });
632
+ const result = yield this.nodeMediaMixingPlugin.updatePublishParams(Object.assign(Object.assign({}, params), { videoEncoderParams: {
633
+ videoResolution: 0,
634
+ resMode: 0,
635
+ videoFps: params.videoEncoderParams.videoFps,
636
+ videoBitrate: 0,
637
+ minVideoBitrate: 0,
638
+ enableAdjustRes: 0,
639
+ } }));
640
+ const encodeParamEx = {
641
+ videoWidth: this.mixingVideoWidth > this.mixingVideoHeight ? this.mixingVideoWidth : this.mixingVideoHeight,
642
+ videoHeight: this.mixingVideoWidth > this.mixingVideoHeight ? this.mixingVideoHeight : this.mixingVideoWidth,
643
+ videoFps: params.videoEncoderParams.videoFps,
644
+ videoBitrate: params.videoEncoderParams.videoBitrate,
645
+ gop: 1,
646
+ resolutionMode: params.videoEncoderParams.resMode,
647
+ streamType: trtc_define_1.TRTCVideoStreamType.TRTCVideoStreamTypeBig,
648
+ };
649
+ if (params.videoEncoderParams.colorRange !== undefined
650
+ || params.videoEncoderParams.colorSpace !== undefined
651
+ || params.videoEncoderParams.complexity !== undefined) {
652
+ encodeParamEx.colorRange = params.videoEncoderParams.colorRange || trtc_define_1.TRTCVideoColorRange.TRTCVideoColorRange_Auto;
653
+ encodeParamEx.colorSpace = params.videoEncoderParams.colorSpace || trtc_define_1.TRTCVideoColorSpace.TRTCVideoColorSpace_Auto;
654
+ encodeParamEx.complexity = params.videoEncoderParams.complexity || trtc_define_1.TRTCVideoEncodeComplexity.TRTCVideoEncodeComplexity_Fastest;
655
+ }
656
+ this.nodeMediaMixingPlugin.callExperimentalAPI(JSON.stringify({
657
+ api: 'setVideoEncodeParamEx',
658
+ params: encodeParamEx
659
+ }));
660
+ return result;
661
+ });
662
+ }
663
+ /**
664
+ * 设置连麦视频流布局
665
+ *
666
+ * @param layout {TRTCStreamLayout} - 视频流布局信息
667
+ *
668
+ * @example
669
+ * // 设置自定义连麦布局
670
+ * import TRTCCloud, { TRTCStreamLayout, TRTCStreamLayoutMode, TRTCVideoFillMode } from 'trtc-electron-sdk';
671
+ *
672
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
673
+ * isIPCMode: true
674
+ * });
675
+ *
676
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
677
+ * if (mediaMixingManager) {
678
+ * const streamLayout: TRTCStreamLayout = {
679
+ * "layoutMode": TRTCStreamLayoutMode.Custom,
680
+ * "userList": [
681
+ * {
682
+ * "userId": "", // 本地用户 userId
683
+ * "rect": {
684
+ * "left": 0,
685
+ * "top": 0,
686
+ * "right": 296,
687
+ * "bottom": 494
688
+ * },
689
+ * "fillMode": TRTCVideoFillMode.TRTCVideoFillMode_Fill, // 视频填满显示区
690
+ * "zOrder": 0
691
+ * },
692
+ * {
693
+ * "userId": "849014",
694
+ * "rect": {
695
+ * "left": 296,
696
+ * "top": 0,
697
+ * "right": 592,
698
+ * "bottom": 247
699
+ * },
700
+ * "fillMode": TRTCVideoFillMode.TRTCVideoFillMode_Fill,
701
+ * "zOrder": 1
702
+ * },
703
+ * {
704
+ * "userId": "p20",
705
+ * "rect": {
706
+ * "left": 296,
707
+ * "top": 247,
708
+ * "right": 592,
709
+ * "bottom": 494
710
+ * },
711
+ * "fillMode": TRTCVideoFillMode.TRTCVideoFillMode_Fill,
712
+ * "zOrder": 2
713
+ * }
714
+ * ]
715
+ * };
716
+ * mediaMixingManager.setStreamLayout(streamLayout);
717
+ * }
718
+ *
719
+ * @example
720
+ * // 清除连麦布局,本地混流恢复居中填充显示(默认效果)
721
+ * import TRTCCloud, { TRTCStreamLayout, TRTCStreamLayoutMode, TRTCVideoFillMode } from 'trtc-electron-sdk';
722
+ *
723
+ * const trtcCloud = TRTCCloud.getTRTCShareInstance({
724
+ * isIPCMode: true
725
+ * });
726
+ *
727
+ * const mediaMixingManager = trtcCloud.getMediaMixingManager();
728
+ * if (mediaMixingManager) {
729
+ * const streamLayout: TRTCStreamLayout = {
730
+ * "layoutMode": TRTCStreamLayoutMode.None
731
+ * };
732
+ * mediaMixingManager.setStreamLayout(streamLayout);
733
+ * }
734
+ */
735
+ setStreamLayout(layout) {
736
+ var _a, _b, _c;
737
+ logger_1.default.log(`${this.logPrefix}setStreamLayout:`, layout);
738
+ if (this.paramsStore) {
739
+ try {
740
+ this.paramsStore.streamLayout = JSON.parse(JSON.stringify(layout));
741
+ }
742
+ catch (err) {
743
+ this.paramsStore.streamLayout = undefined;
744
+ }
745
+ }
746
+ this.createOrUpdateLayoutManager(layout);
747
+ if (this.view) {
748
+ const viewRect = this.view.getBoundingClientRect();
749
+ if ((_a = layout.userList) === null || _a === void 0 ? void 0 : _a.length) {
750
+ const localUser = layout.userList.filter(user => user.userId === constant_1.LOCAL_USER_ID)[0];
751
+ if (localUser === null || localUser === void 0 ? void 0 : localUser.rect) {
752
+ const workingArea = localUser.rect;
753
+ (_b = this.mediaMixingDesigner) === null || _b === void 0 ? void 0 : _b.setWorkingArea({
754
+ left: workingArea.left / viewRect.width,
755
+ top: workingArea.top / viewRect.height,
756
+ right: workingArea.right / viewRect.width,
757
+ bottom: workingArea.bottom / viewRect.height,
758
+ }, localUser.fillMode);
759
+ }
760
+ logger_1.default.log(`${this.logPrefix}setStreamLayout transfer layout to pixel unit:`, JSON.stringify(layout));
761
+ }
762
+ }
763
+ else {
764
+ logger_1.default.warn(`${this.logPrefix}setStreamLayout: view is null, no container HTML element. User control the layout manually in device pixel unit.`);
765
+ }
766
+ (_c = this.streamLayoutManager) === null || _c === void 0 ? void 0 : _c.setLayout(layout);
767
+ }
768
+ /**
769
+ * @private
770
+ * @deprecated
771
+ */
772
+ setMediaServerPath(path) {
773
+ return __awaiter(this, void 0, void 0, function* () {
774
+ return this.startMediaMixingServer(path);
775
+ });
776
+ }
777
+ /**
778
+ * @private
779
+ * 启动独立混流渲染进程
780
+ *
781
+ * 开发模式,默认路径:node_modules\\trtc-electron-sdk\\build\\Release\\liteav_media_server.exe
782
+ * 构建模式,默认路径:${resourcesPath}\\liteav_media_server.exe
783
+ *
784
+ * 如果用户应用有特殊配置,默认路径可能找不到服务进程程序,需要自行传入路径。
785
+ *
786
+ * @param path {string} - 混流渲染程序路径,不传入参数时,SDK 内部按照默认路径启动服务进程。
787
+ *
788
+ * @returns {Promise<void>}
789
+ */
790
+ startMediaMixingServer(path) {
791
+ return __awaiter(this, void 0, void 0, function* () {
792
+ let serverPath = '';
793
+ if (path && path.trim() !== '') {
794
+ serverPath = path;
795
+ }
796
+ else {
797
+ const { resourcesPath, execPath } = globalThis.process;
798
+ if (execPath.endsWith('electron.exe')) {
799
+ serverPath = 'node_modules\\trtc-electron-sdk\\build\\Release\\liteav_media_server.exe';
800
+ }
801
+ else {
802
+ serverPath = `${resourcesPath}\\liteav_media_server.exe`;
803
+ }
804
+ }
805
+ logger_1.default.info(`${this.logPrefix}startMediaMixingServer path:${serverPath}`);
806
+ return new Promise((resolve, reject) => {
807
+ const key = promiseKeys.startMediaMixingServer;
808
+ this.promiseStore.addPromise(key, resolve, reject);
809
+ this.nodeMediaMixingPlugin.startMediaServer(serverPath);
810
+ });
811
+ });
812
+ }
813
+ /**
814
+ * @private
815
+ * 关闭独立混流渲染进程
816
+ *
817
+ * @returns {Promise<void>}
818
+ */
819
+ stopMediaMixingServer() {
820
+ return __awaiter(this, void 0, void 0, function* () {
821
+ logger_1.default.info(`${this.logPrefix}stopMediaMixingServer`);
822
+ return new Promise((resolve, reject) => {
823
+ const key = promiseKeys.stopMediaMixingServer;
824
+ this.promiseStore.addPromise(key, resolve, reject);
825
+ this.nodeMediaMixingPlugin.stopMediaServer();
826
+ });
827
+ });
828
+ }
829
+ /**
830
+ * 注册事件监听
831
+ *
832
+ * @param event {TRTCMediaMixingEvent} - 事件名称
833
+ * @param func {Function} - 事件回调函数
834
+ */
835
+ on(event, func) {
836
+ var _a;
837
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.on(event, func);
838
+ }
839
+ /**
840
+ * 取消事件监听
841
+ *
842
+ * @param event {TRTCMediaMixingEvent} - 事件名
843
+ * @param func {Function} - 事件回调函数
844
+ */
845
+ off(event, func) {
846
+ var _a;
847
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.off(event, func);
848
+ }
849
+ initResizeObserver() {
850
+ if (this.view) {
851
+ this.resizeObserver = new ResizeObserver(this.onPreviewAreaResize);
852
+ this.resizeObserver.observe(this.view);
853
+ }
854
+ }
855
+ onPreviewAreaResize(entries) {
856
+ logger_1.default.log(`${this.logPrefix}onPreviewAreaResize:`, entries);
857
+ for (const entry of entries) {
858
+ if (this.windowID && entry.target === this.view) {
859
+ this.setDisplayRect();
860
+ break;
861
+ }
862
+ }
863
+ }
864
+ onVisibilityChange() {
865
+ logger_1.default.log(`${this.logPrefix}onVisibilityChange document.hidden:${document.hidden}`);
866
+ if (document.hidden) {
867
+ this.nodeMediaMixingPlugin.setDisplayParams(this.windowID, { left: 0, right: 0, top: 0, bottom: 0 });
868
+ }
869
+ else {
870
+ this.setDisplayRect();
871
+ }
872
+ }
873
+ setDisplayRect() {
874
+ if (this.windowID && this.view) {
875
+ const clientRect = this.view.getBoundingClientRect();
876
+ const rect = {
877
+ left: clientRect.left * window.devicePixelRatio,
878
+ right: clientRect.right * window.devicePixelRatio,
879
+ top: clientRect.top * window.devicePixelRatio,
880
+ bottom: clientRect.bottom * window.devicePixelRatio,
881
+ };
882
+ this.nodeMediaMixingPlugin.setDisplayParams(this.windowID, rect);
883
+ }
884
+ }
885
+ createDesigner() {
886
+ if (this.view) {
887
+ this.updateMixingVideoSize(this.publishParams.videoEncoderParams);
888
+ this.mediaMixingDesigner = new index_1.default({
889
+ view: this.view,
890
+ width: this.mixingVideoWidth,
891
+ height: this.mixingVideoHeight,
892
+ canExceedContainer: true,
893
+ });
894
+ this.listenDesignerEvent();
895
+ if (this.sourceList.length >= 1) {
896
+ this.sourceList.forEach((mediaSource => {
897
+ var _a;
898
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.addMedia({
899
+ id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
900
+ rect: mediaSource.rect,
901
+ isSelected: mediaSource.isSelected || false,
902
+ zOrder: mediaSource.zOrder,
903
+ origin: mediaSource
904
+ });
905
+ }));
906
+ }
907
+ }
908
+ }
909
+ destroyDesigner() {
910
+ var _a;
911
+ if (this.mediaMixingDesigner) {
912
+ this.unlistenDesignerEvent();
913
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.destroy();
914
+ this.mediaMixingDesigner = null;
915
+ }
916
+ }
917
+ createOrUpdateLayoutManager(layout) {
918
+ const context = {
919
+ container: this.view,
920
+ mixingVideoSize: {
921
+ width: this.mixingVideoWidth,
922
+ height: this.mixingVideoHeight
923
+ },
924
+ mediaMixingDesigner: this.mediaMixingDesigner
925
+ };
926
+ if (!this.streamLayoutManager) {
927
+ this.streamLayoutManager = StreamLayout_1.StreamLayoutFactory.create(layout.layoutMode, this.nodeMediaMixingPlugin, context);
928
+ }
929
+ else if (this.streamLayoutManager.getLayoutMode() !== layout.layoutMode) {
930
+ this.streamLayoutManager.destroy();
931
+ this.streamLayoutManager = StreamLayout_1.StreamLayoutFactory.create(layout.layoutMode, this.nodeMediaMixingPlugin, context);
932
+ }
933
+ }
934
+ destroyLayoutManager() {
935
+ if (this.streamLayoutManager) {
936
+ this.streamLayoutManager.destroy();
937
+ this.streamLayoutManager = null;
938
+ }
939
+ }
940
+ updateMixingVideoSize(params) {
941
+ if (resolutionMap.has(params.videoResolution)) {
942
+ const { width, height } = resolutionMap.get(params.videoResolution);
943
+ if (params.resMode === trtc_define_1.TRTCVideoResolutionMode.TRTCVideoResolutionModeLandscape) {
944
+ this.mixingVideoWidth = width;
945
+ this.mixingVideoHeight = height;
946
+ }
947
+ else {
948
+ this.mixingVideoWidth = height;
949
+ this.mixingVideoHeight = width;
950
+ }
951
+ }
952
+ }
953
+ listenDesignerEvent() {
954
+ var _a, _b, _c, _d, _e;
955
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.on('onError', this.onError);
956
+ (_b = this.mediaMixingDesigner) === null || _b === void 0 ? void 0 : _b.on('onSourceSelected', this.onSourceSelected);
957
+ (_c = this.mediaMixingDesigner) === null || _c === void 0 ? void 0 : _c.on('onSourceMoved', this.onSourceMoved);
958
+ (_d = this.mediaMixingDesigner) === null || _d === void 0 ? void 0 : _d.on('onSourceResized', this.onSourceResized);
959
+ (_e = this.mediaMixingDesigner) === null || _e === void 0 ? void 0 : _e.on('onRightButtonClicked', this.onRightButtonClicked);
960
+ }
961
+ unlistenDesignerEvent() {
962
+ var _a, _b, _c, _d, _e;
963
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.off('onError', this.onError);
964
+ (_b = this.mediaMixingDesigner) === null || _b === void 0 ? void 0 : _b.off('onSourceSelected', this.onSourceSelected);
965
+ (_c = this.mediaMixingDesigner) === null || _c === void 0 ? void 0 : _c.off('onSourceMoved', this.onSourceMoved);
966
+ (_d = this.mediaMixingDesigner) === null || _d === void 0 ? void 0 : _d.off('onSourceResized', this.onSourceResized);
967
+ (_e = this.mediaMixingDesigner) === null || _e === void 0 ? void 0 : _e.off('onRightButtonClicked', this.onRightButtonClicked);
968
+ }
969
+ onError(errorCode, errorMessage) {
970
+ logger_1.default.log(`${this.logPrefix}onError:`, errorCode, errorMessage);
971
+ }
972
+ onSourceSelected(media) {
973
+ var _a;
974
+ logger_1.default.log(`${this.logPrefix}onSourceSelected:`, media);
975
+ if (media === null || media === void 0 ? void 0 : media.origin) {
976
+ this.updateMediaSource(Object.assign(Object.assign({}, media.origin), { isSelected: true }));
977
+ }
978
+ else {
979
+ const selected = this.sourceList.find(item => item.isSelected);
980
+ if (selected) {
981
+ this.updateMediaSource(Object.assign(Object.assign({}, selected), { isSelected: false }));
982
+ }
983
+ }
984
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit('onSourceSelected', media ? media.origin : null);
985
+ }
986
+ onSourceMoved(media, rect) {
987
+ var _a;
988
+ logger_1.default.log(`${this.logPrefix}onSourceMoved:`, media, rect);
989
+ if (media === null || media === void 0 ? void 0 : media.origin) {
990
+ this.updateMediaSource(Object.assign(Object.assign({}, media.origin), { rect }));
991
+ }
992
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit('onSourceMoved', media.origin, rect);
993
+ }
994
+ onSourceResized(media, rect) {
995
+ var _a;
996
+ logger_1.default.log(`${this.logPrefix}onSourceResized:`, media, rect);
997
+ if (media === null || media === void 0 ? void 0 : media.origin) {
998
+ this.updateMediaSource(Object.assign(Object.assign({}, media.origin), { rect }));
999
+ }
1000
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit('onSourceResized', media.origin, rect);
1001
+ }
1002
+ onRightButtonClicked(media, clickPoint) {
1003
+ var _a;
1004
+ logger_1.default.log(`${this.logPrefix}onRightButtonClicked:`, media, clickPoint);
1005
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit('onRightButtonClicked', media.origin, clickPoint);
1006
+ }
1007
+ isSameMediaSource(mediaSource1, mediaSource2) {
1008
+ return mediaSource1.sourceId === mediaSource2.sourceId && mediaSource1.sourceType === mediaSource2.sourceType;
1009
+ }
1010
+ isMediaSourceExisted(mediaSource) {
1011
+ return this.sourceList.some(item => this.isSameMediaSource(item, mediaSource));
1012
+ }
1013
+ findMediaSourceIndex(mediaSource) {
1014
+ return this.sourceList.findIndex(item => item.sourceId === mediaSource.sourceId && item.sourceType === mediaSource.sourceType);
1015
+ }
1016
+ findSelectedMediaSource() {
1017
+ let index = -1;
1018
+ const length = this.sourceList.length;
1019
+ for (let i = 0; i < length; i++) {
1020
+ if (this.sourceList[i].isSelected) {
1021
+ index = i;
1022
+ break;
1023
+ }
1024
+ }
1025
+ return index;
1026
+ }
1027
+ unselectMediaSource(index) {
1028
+ var _a;
1029
+ return __awaiter(this, void 0, void 0, function* () {
1030
+ this.sourceList[index].isSelected = false;
1031
+ yield this.nodeMediaMixingPlugin.updateMediaSource(this.sourceList[index]);
1032
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.updateMedia({
1033
+ id: `${this.sourceList[index].sourceType}__${this.sourceList[index].sourceId}`,
1034
+ rect: this.sourceList[index].rect,
1035
+ isSelected: this.sourceList[index].isSelected || false,
1036
+ zOrder: this.sourceList[index].zOrder,
1037
+ origin: (0, utils_1.safelyParse)(JSON.stringify(this.sourceList[index]))
1038
+ });
1039
+ });
1040
+ }
1041
+ handleCppCallbackEvent(args) {
1042
+ logger_1.default.info(`${this.logPrefix} event:`, args);
1043
+ const key = args[0];
1044
+ const data = args[1];
1045
+ // To do: 待完善
1046
+ switch (key) {
1047
+ case "onMediaSourceAdded":
1048
+ this.onMediaSourceAdded(data);
1049
+ break;
1050
+ case "onMediaSourceRemoved":
1051
+ this.onMediaSourceRemoved(data);
1052
+ break;
1053
+ case TRTCMediaMixingEvent.onMediaSourceSizeChanged:
1054
+ this.onMediaSourceSizeChanged(data);
1055
+ break;
1056
+ case "onPhoneMirrorSourceChanged":
1057
+ this.onPhoneMirrorSourceChanged(data);
1058
+ break;
1059
+ case "onMediaServerState":
1060
+ this.onMediaServerState(data);
1061
+ break;
1062
+ case "onCallExperimentalAPIFinish":
1063
+ this.onCallExperimentalAPIFinish(data);
1064
+ break;
1065
+ default:
1066
+ logger_1.default.warn(`${this.logPrefix} event not supported:`, key, data);
1067
+ break;
1068
+ }
1069
+ }
1070
+ onMediaSourceAdded(data) {
1071
+ var _a, _b;
1072
+ const promiseKey = `${promiseKeys.addMediaSource}-${data.sourceType}-${data.sourceId}`;
1073
+ let flag = false;
1074
+ if (data.errCode === 0) {
1075
+ flag = this.promiseStore.resolvePromise(promiseKey, undefined);
1076
+ }
1077
+ else {
1078
+ const newSourceIndex = this.findMediaSourceIndex({
1079
+ sourceId: data.sourceId,
1080
+ sourceType: data.sourceType,
1081
+ });
1082
+ if (newSourceIndex !== -1) {
1083
+ const newMediaSource = this.sourceList[newSourceIndex];
1084
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.removeMedia({
1085
+ id: `${newMediaSource.sourceType}__${newMediaSource.sourceId}`,
1086
+ rect: newMediaSource.rect,
1087
+ isSelected: newMediaSource.isSelected || false,
1088
+ zOrder: newMediaSource.zOrder,
1089
+ origin: newMediaSource
1090
+ });
1091
+ this.sourceList.splice(newSourceIndex, 1);
1092
+ }
1093
+ flag = this.promiseStore.rejectPromise(promiseKey, {
1094
+ code: data.errCode,
1095
+ message: data.errMsg,
1096
+ });
1097
+ }
1098
+ if (data.errCode !== 0 && !flag) {
1099
+ // event triggered internally, not by method invoked by user
1100
+ const index = this.findMediaSourceIndex(data);
1101
+ let mediaSource = undefined;
1102
+ if (index !== -1) {
1103
+ mediaSource = Object.assign({}, this.sourceList[index]);
1104
+ }
1105
+ (_b = this.eventEmitter) === null || _b === void 0 ? void 0 : _b.emit(TRTCMediaMixingEvent.onError, data.errCode, data.errMsg, mediaSource);
1106
+ }
1107
+ }
1108
+ onMediaSourceRemoved(data) {
1109
+ var _a, _b;
1110
+ const promiseKey = `${promiseKeys.removeMediaSource}-${data.sourceType}-${data.sourceId}`;
1111
+ let flag = false;
1112
+ if (data.errCode === 0) {
1113
+ const sourceIndex = this.findMediaSourceIndex({
1114
+ sourceId: data.sourceId,
1115
+ sourceType: data.sourceType
1116
+ });
1117
+ if (sourceIndex !== -1) {
1118
+ const mediaSource = this.sourceList[sourceIndex];
1119
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.removeMedia({
1120
+ id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
1121
+ rect: mediaSource.rect,
1122
+ isSelected: mediaSource.isSelected || false,
1123
+ zOrder: mediaSource.zOrder,
1124
+ origin: (0, utils_1.safelyParse)(JSON.stringify(mediaSource))
1125
+ });
1126
+ this.sourceList.splice(sourceIndex, 1);
1127
+ }
1128
+ flag = this.promiseStore.resolvePromise(promiseKey, undefined);
1129
+ }
1130
+ else {
1131
+ flag = this.promiseStore.rejectPromise(promiseKey, {
1132
+ code: data.errCode,
1133
+ message: data.errMsg,
1134
+ });
1135
+ }
1136
+ if (data.errCode !== 0 && !flag) {
1137
+ // event triggered internally, not by method invoked by user
1138
+ const index = this.findMediaSourceIndex(data);
1139
+ let mediaSource = undefined;
1140
+ if (index !== -1) {
1141
+ mediaSource = Object.assign({}, this.sourceList[index]);
1142
+ }
1143
+ (_b = this.eventEmitter) === null || _b === void 0 ? void 0 : _b.emit(TRTCMediaMixingEvent.onError, data.errCode, data.errMsg, mediaSource);
1144
+ }
1145
+ }
1146
+ onMediaSourceSizeChanged(data) {
1147
+ var _a;
1148
+ const index = this.findMediaSourceIndex(data);
1149
+ if (index !== -1) {
1150
+ let mediaSource = this.sourceList[index];
1151
+ mediaSource = (0, utils_1.safelyParse)(JSON.stringify(mediaSource));
1152
+ const size = {
1153
+ width: data.width,
1154
+ height: data.height,
1155
+ };
1156
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit(TRTCMediaMixingEvent.onMediaSourceSizeChanged, mediaSource, size);
1157
+ }
1158
+ else {
1159
+ logger_1.default.warn(`${this.logPrefix}onMediaSourceSizeChanged media source not existed:`, data);
1160
+ }
1161
+ }
1162
+ onPhoneMirrorSourceChanged(data) {
1163
+ var _a, _b, _c, _d;
1164
+ const { phoneMirrorSource, state } = data;
1165
+ if (state !== undefined && state !== null) {
1166
+ switch (state) {
1167
+ case 0:
1168
+ (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit(TRTCMediaMixingEvent.onSourcePlugged, phoneMirrorSource, 'Plugged');
1169
+ break;
1170
+ case 1:
1171
+ (_b = this.eventEmitter) === null || _b === void 0 ? void 0 : _b.emit(TRTCMediaMixingEvent.onSourceConnected, phoneMirrorSource, 'Connected');
1172
+ break;
1173
+ case 2:
1174
+ (_c = this.eventEmitter) === null || _c === void 0 ? void 0 : _c.emit(TRTCMediaMixingEvent.onSourceDisconnected, phoneMirrorSource, 'Disconnected');
1175
+ break;
1176
+ case 3:
1177
+ (_d = this.eventEmitter) === null || _d === void 0 ? void 0 : _d.emit(TRTCMediaMixingEvent.onSourceUnplugged, phoneMirrorSource, 'Unplugged');
1178
+ break;
1179
+ default:
1180
+ logger_1.default.warn(`${this.logPrefix}onPhoneMirrorSourceChanged invalid data:`, data);
1181
+ break;
1182
+ }
1183
+ }
1184
+ else {
1185
+ logger_1.default.warn(`${this.logPrefix}onPhoneMirrorSourceChanged invalid data:`, data);
1186
+ }
1187
+ }
1188
+ onMediaServerState(data) {
1189
+ return __awaiter(this, void 0, void 0, function* () {
1190
+ const { state } = data;
1191
+ let key = '';
1192
+ switch (state) {
1193
+ case 0:
1194
+ // idle
1195
+ key = promiseKeys.stopMediaMixingServer;
1196
+ this.promiseStore.resolvePromise(key, undefined);
1197
+ break;
1198
+ case 1:
1199
+ // connecting, nothing to do
1200
+ break;
1201
+ case 2:
1202
+ key = promiseKeys.startMediaMixingServer;
1203
+ this.promiseStore.resolvePromise(key, undefined);
1204
+ // connected
1205
+ break;
1206
+ case 3:
1207
+ // error
1208
+ yield this.onMediaMixingServerLost();
1209
+ break;
1210
+ default:
1211
+ logger_1.default.warn(`${this.logPrefix}onMediaServerState invalid data:`, data);
1212
+ }
1213
+ });
1214
+ }
1215
+ onMediaMixingServerLost() {
1216
+ var _a, _b;
1217
+ return __awaiter(this, void 0, void 0, function* () {
1218
+ if (this.autoControlServer) {
1219
+ yield this.recoverMediaMixingServer();
1220
+ }
1221
+ else {
1222
+ this.sourceList = [];
1223
+ (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.removeAllMedia();
1224
+ (_b = this.eventEmitter) === null || _b === void 0 ? void 0 : _b.emit(TRTCMediaMixingEvent.onMediaMixingServerLost);
1225
+ }
1226
+ });
1227
+ }
1228
+ onCallExperimentalAPIFinish(data) {
1229
+ logger_1.default.log(`${this.logPrefix}onCallExperimentalAPIFinish:`, data);
1230
+ }
1231
+ recoverMediaMixingServer() {
1232
+ var _a, _b, _c;
1233
+ return __awaiter(this, void 0, void 0, function* () {
1234
+ try {
1235
+ yield this.startMediaMixingServer();
1236
+ this.bindPreviewArea(this.windowID, this.view);
1237
+ yield this.startPublish();
1238
+ yield this.nodeMediaMixingPlugin.updatePublishParams(this.publishParams);
1239
+ if ((_a = this.paramsStore) === null || _a === void 0 ? void 0 : _a.streamLayout) {
1240
+ this.setStreamLayout(this.paramsStore.streamLayout);
1241
+ }
1242
+ this.sourceList.forEach((item) => {
1243
+ this.nodeMediaMixingPlugin.addMediaSource(item);
1244
+ });
1245
+ if (((_b = this.trtcParamsStore) === null || _b === void 0 ? void 0 : _b.enterRoomParams) && ((_c = this.trtcParamsStore) === null || _c === void 0 ? void 0 : _c.enterRoomScene)) {
1246
+ this.nodeTRTCCloud.enterRoom(this.trtcParamsStore.enterRoomParams, this.trtcParamsStore.enterRoomScene);
1247
+ }
1248
+ logger_1.default.log(`${this.logPrefix}recoverMediaMixingServer recovery from crash success`);
1249
+ }
1250
+ catch (err) {
1251
+ logger_1.default.error(`${this.logPrefix}recoverMediaMixingServer recovery from crash failed:`, err);
1252
+ }
1253
+ });
1254
+ }
1255
+ onDevicePixelRatioChange() {
1256
+ logger_1.default.debug(`${this.logPrefix}onDevicePixelRatioChange:`, window.devicePixelRatio);
1257
+ this.setDisplayRect();
1258
+ }
1259
+ // ****** 这一部分接口暴露不合理,暂时不对暴露在 API 文档上 **************/
1260
+ startCameraDeviceTest(windowID, rect) {
1261
+ var _a;
1262
+ return ((_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.startCameraDeviceTest(windowID, rect)) || Promise.reject();
1263
+ }
1264
+ stopCameraDeviceTest() {
1265
+ var _a;
1266
+ return ((_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.stopCameraDeviceTest()) || Promise.reject();
1267
+ }
1268
+ setCameraTestRenderMirror(mirror) {
1269
+ var _a;
1270
+ (_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.setCameraTestRenderMirror(mirror);
1271
+ }
1272
+ setCameraTestDeviceId(cameraId) {
1273
+ var _a;
1274
+ (_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.setCameraTestDeviceId(cameraId);
1275
+ }
1276
+ setCameraTestResolution(width, height) {
1277
+ var _a;
1278
+ (_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.setCameraTestResolution(width, height);
1279
+ }
1280
+ setCameraTestVideoPluginPath(path) {
1281
+ var _a;
1282
+ (_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.setCameraTestVideoPluginPath(path);
1283
+ }
1284
+ setCameraTestVideoPluginParameter(params) {
1285
+ var _a;
1286
+ (_a = this.deviceManager) === null || _a === void 0 ? void 0 : _a.setCameraTestVideoPluginParameter(params);
1287
+ }
1288
+ }
1289
+ exports.TRTCMediaMixingManager = TRTCMediaMixingManager;
1290
+ exports.default = TRTCMediaMixingManager;