trtc-electron-sdk 12.2.115-beta.1 → 12.2.115-beta.10

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 (28) hide show
  1. package/liteav/MediaMixingDesigner/index.d.ts +10 -7
  2. package/liteav/MediaMixingDesigner/index.js +103 -75
  3. package/liteav/base/PromiseStore.d.ts +9 -0
  4. package/liteav/base/PromiseStore.js +46 -0
  5. package/liteav/constant.d.ts +1 -0
  6. package/liteav/constant.js +4 -0
  7. package/liteav/extensions/MediaMixingManager/StreamLayout/BaseStreamLayoutManager.d.ts +27 -0
  8. package/liteav/extensions/MediaMixingManager/StreamLayout/BaseStreamLayoutManager.js +99 -0
  9. package/liteav/extensions/MediaMixingManager/StreamLayout/CustomStreamLayoutManager.d.ts +11 -0
  10. package/liteav/extensions/MediaMixingManager/StreamLayout/CustomStreamLayoutManager.js +119 -0
  11. package/liteav/extensions/MediaMixingManager/StreamLayout/NoneStreamLayoutManager.d.ts +11 -0
  12. package/liteav/extensions/MediaMixingManager/StreamLayout/NoneStreamLayoutManager.js +64 -0
  13. package/liteav/extensions/MediaMixingManager/StreamLayout/index.d.ts +7 -0
  14. package/liteav/extensions/MediaMixingManager/StreamLayout/index.js +34 -0
  15. package/liteav/extensions/MediaMixingManager/StreamLayout/types.d.ts +21 -0
  16. package/liteav/extensions/MediaMixingManager/StreamLayout/types.js +2 -0
  17. package/liteav/extensions/MediaMixingManager/index.d.ts +220 -40
  18. package/liteav/extensions/MediaMixingManager/index.js +556 -54
  19. package/liteav/extensions/MediaMixingManager/types.d.ts +100 -0
  20. package/liteav/extensions/MediaMixingManager/types.js +26 -0
  21. package/liteav/trtc.d.ts +18 -0
  22. package/liteav/trtc.js +30 -9
  23. package/liteav/trtc_define.d.ts +25 -2
  24. package/liteav/trtc_define.js +27 -3
  25. package/liteav/utils.d.ts +27 -0
  26. package/liteav/utils.js +85 -1
  27. package/package.json +2 -2
  28. package/scripts/download.js +153 -169
@@ -1,4 +1,4 @@
1
- import { TRTCVideoResolution, TRTCVideoResolutionMode, Rect } from "../trtc_define";
1
+ import { Rect, TRTCVideoFillMode } from "../trtc_define";
2
2
  export declare type TRTCMediaInfo = {
3
3
  id: string;
4
4
  rect: Rect;
@@ -9,8 +9,6 @@ export declare type TRTCMediaInfo = {
9
9
  declare class TRTCMediaMixingDesigner {
10
10
  private logPrefix;
11
11
  private container;
12
- private videoResolution;
13
- private resMode;
14
12
  private mixingVideoWidth;
15
13
  private mixingVideoHeight;
16
14
  private canExceedContainer;
@@ -33,16 +31,20 @@ declare class TRTCMediaMixingDesigner {
33
31
  private mousedownTop;
34
32
  private eventButton;
35
33
  private resizeObserver;
34
+ private relativeWorkingArea;
35
+ private absoluteWorkingArea;
36
+ private fillMode;
36
37
  constructor(options: {
37
38
  view: HTMLElement;
38
- videoResolution: TRTCVideoResolution;
39
- resMode: TRTCVideoResolutionMode;
39
+ width: number;
40
+ height: number;
40
41
  canExceedContainer: boolean;
41
42
  });
42
43
  updateOptions(options: {
43
- videoResolution?: TRTCVideoResolution;
44
- resMode?: TRTCVideoResolutionMode;
44
+ width: number;
45
+ height: number;
45
46
  }): void;
47
+ setWorkingArea(relative: Rect | null | undefined, fillMode?: TRTCVideoFillMode): void;
46
48
  addMedia(media: TRTCMediaInfo): void;
47
49
  removeMedia(media: TRTCMediaInfo): void;
48
50
  updateMedia(media: TRTCMediaInfo): void;
@@ -54,6 +56,7 @@ declare class TRTCMediaMixingDesigner {
54
56
  private initContainerMouseEventHander;
55
57
  private initContainerResizeObserver;
56
58
  private onPreviewAreaResize;
59
+ private updateWorkingArea;
57
60
  private updatePreviewProperty;
58
61
  private updateOverlay;
59
62
  private onMove;
@@ -5,26 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const events_1 = require("events");
7
7
  const trtc_define_1 = require("../trtc_define");
8
- const utils_1 = require("../utils");
9
8
  const logger_1 = __importDefault(require("../logger"));
10
9
  const Movable_1 = __importDefault(require("./Movable"));
11
10
  const Resizable_1 = __importDefault(require("./Resizable"));
12
11
  const MIN_MOVE_DISTANCE = 5; // minimum moving distance
13
- const initResolutionMap = () => {
14
- const map = new Map();
15
- for (const key in trtc_define_1.TRTCVideoResolution) {
16
- if (isNaN(Number(key))) {
17
- const value = trtc_define_1.TRTCVideoResolution[key];
18
- const tmp = key.split('_');
19
- map.set(value, {
20
- width: parseInt(tmp[1]),
21
- height: parseInt(tmp[2]),
22
- });
23
- }
24
- }
25
- return map;
26
- };
27
- const resolutionMap = initResolutionMap();
28
12
  class TRTCMediaMixingDesigner {
29
13
  constructor(options) {
30
14
  this.logPrefix = '[TRTCMediaMixingDesigner]';
@@ -48,19 +32,12 @@ class TRTCMediaMixingDesigner {
48
32
  this.resizeObserver = null;
49
33
  this.container = options.view;
50
34
  this.container.style.position = 'absolute';
51
- this.videoResolution = options.videoResolution;
52
- this.resMode = options.resMode;
53
- if (resolutionMap.has(options.videoResolution)) {
54
- const { width, height } = resolutionMap.get(options.videoResolution);
55
- if (this.resMode === trtc_define_1.TRTCVideoResolutionMode.TRTCVideoResolutionModeLandscape) {
56
- this.mixingVideoWidth = width;
57
- this.mixingVideoHeight = height;
58
- }
59
- else {
60
- this.mixingVideoWidth = height;
61
- this.mixingVideoHeight = width;
62
- }
63
- }
35
+ this.relativeWorkingArea = { left: 0, top: 0, right: 1, bottom: 1 };
36
+ this.absoluteWorkingArea = {};
37
+ this.fillMode = trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit;
38
+ this.updateWorkingArea();
39
+ this.mixingVideoWidth = options.width;
40
+ this.mixingVideoHeight = options.height;
64
41
  this.updatePreviewProperty();
65
42
  this.canExceedContainer = options.canExceedContainer || false;
66
43
  this.eventEmitter = new events_1.EventEmitter();
@@ -75,24 +52,25 @@ class TRTCMediaMixingDesigner {
75
52
  this.initContainerResizeObserver();
76
53
  }
77
54
  updateOptions(options) {
78
- if (!(0, utils_1.isNullOrUndefined)(options.videoResolution) || !(0, utils_1.isNullOrUndefined)(options.resMode)) {
79
- this.resMode = !(0, utils_1.isNullOrUndefined)(options.resMode) ? options.resMode : this.resMode;
80
- if (options.videoResolution) {
81
- if (resolutionMap.has(options.videoResolution)) {
82
- const { width, height } = resolutionMap.get(options.videoResolution);
83
- if (this.resMode === trtc_define_1.TRTCVideoResolutionMode.TRTCVideoResolutionModeLandscape) {
84
- this.mixingVideoWidth = width;
85
- this.mixingVideoHeight = height;
86
- }
87
- else {
88
- this.mixingVideoWidth = height;
89
- this.mixingVideoHeight = width;
90
- }
91
- }
92
- }
55
+ if (this.mixingVideoWidth !== options.width || this.mixingVideoHeight !== options.height) {
56
+ this.mixingVideoWidth = options.width;
57
+ this.mixingVideoHeight = options.height;
58
+ this.updatePreviewProperty();
59
+ this.updateOverlay();
60
+ }
61
+ }
62
+ setWorkingArea(relative, fillMode = trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit) {
63
+ logger_1.default.log(`${this.logPrefix}setWorkingArea:`, JSON.stringify(relative), `fillMode:${fillMode}`);
64
+ if (relative) {
65
+ this.relativeWorkingArea = Object.assign({}, relative);
66
+ this.fillMode = fillMode;
67
+ this.updateWorkingArea();
93
68
  this.updatePreviewProperty();
94
69
  this.updateOverlay();
95
70
  }
71
+ else {
72
+ logger_1.default.error(`${this.logPrefix}setWorkingArea invalid parameter:`, relative);
73
+ }
96
74
  }
97
75
  addMedia(media) {
98
76
  this.mediaList.unshift(media);
@@ -194,50 +172,98 @@ class TRTCMediaMixingDesigner {
194
172
  logger_1.default.log(`${this.logPrefix}onPreviewAreaResize:`, entries);
195
173
  for (const entry of entries) {
196
174
  if (entry.target === this.container) {
175
+ this.updateWorkingArea();
197
176
  this.updatePreviewProperty();
198
177
  this.updateOverlay();
199
178
  break;
200
179
  }
201
180
  }
202
181
  }
182
+ updateWorkingArea() {
183
+ if (this.relativeWorkingArea && this.container) {
184
+ const containerRect = this.container.getBoundingClientRect();
185
+ this.absoluteWorkingArea = {
186
+ left: this.relativeWorkingArea.left * containerRect.width,
187
+ top: this.relativeWorkingArea.top * containerRect.height,
188
+ right: this.relativeWorkingArea.right * containerRect.width,
189
+ bottom: this.relativeWorkingArea.bottom * containerRect.height,
190
+ width: (this.relativeWorkingArea.right - this.relativeWorkingArea.left) * containerRect.width,
191
+ height: (this.relativeWorkingArea.bottom - this.relativeWorkingArea.top) * containerRect.height,
192
+ };
193
+ logger_1.default.log(`${this.logPrefix}updateWorkingArea absolute working area:`, JSON.stringify(this.absoluteWorkingArea));
194
+ }
195
+ else {
196
+ logger_1.default.error(`${this.logPrefix}updateWorkingArea no data:`, this.relativeWorkingArea, this.container);
197
+ }
198
+ }
203
199
  updatePreviewProperty() {
204
- if (this.container) {
205
- const containerWidth = this.container.offsetWidth;
206
- const containerHeight = this.container.offsetHeight;
207
- const widthScale = containerWidth / this.mixingVideoWidth;
208
- const heightScale = containerHeight / this.mixingVideoHeight;
209
- this.previewScale = widthScale > heightScale ? heightScale : widthScale;
200
+ if (this.absoluteWorkingArea) {
201
+ if (this.mixingVideoWidth <= 0 || this.mixingVideoHeight <= 0) {
202
+ logger_1.default.error(`${this.logPrefix}updatePreviewProperty failed, mixingVideoWidth or mixingVideoHeight is zero`);
203
+ return;
204
+ }
205
+ const workingAreaWidth = this.absoluteWorkingArea.width;
206
+ const workingAreaHeight = this.absoluteWorkingArea.height;
207
+ const widthScale = workingAreaWidth / this.mixingVideoWidth;
208
+ const heightScale = workingAreaHeight / this.mixingVideoHeight;
209
+ if (this.fillMode === trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fill) {
210
+ this.previewScale = widthScale > heightScale ? widthScale : heightScale;
211
+ }
212
+ else {
213
+ this.fillMode = trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit;
214
+ this.previewScale = widthScale > heightScale ? heightScale : widthScale;
215
+ }
210
216
  this.previewWidth = this.mixingVideoWidth * this.previewScale;
211
217
  this.previewHeight = this.mixingVideoHeight * this.previewScale;
212
- this.previewLeft = (containerWidth - this.previewWidth) / 2;
213
- this.previewTop = (containerHeight - this.previewHeight) / 2;
218
+ this.previewLeft = (workingAreaWidth - this.previewWidth) / 2;
219
+ this.previewTop = (workingAreaHeight - this.previewHeight) / 2;
220
+ logger_1.default.debug(`${this.logPrefix}updatePreviewProperty: fillMode: ${this.fillMode} previewScale: ${this.previewScale}, previewWidth: ${this.previewWidth}, previewHeight: ${this.previewHeight}, previewLeft: ${this.previewLeft}, previewTop: ${this.previewTop}`);
214
221
  }
215
222
  else {
216
- logger_1.default.error(`${this.logPrefix}calcPreviewScale failed, no HTML element to display`);
223
+ logger_1.default.error(`${this.logPrefix}updatePreviewProperty failed, no HTML element to display`);
217
224
  }
218
225
  }
219
226
  updateOverlay() {
220
227
  if (this.moveAndResizeOverlay) {
221
- let left = `${this.previewLeft}px`;
222
- let top = `${this.previewTop}px`;
223
- let width = '0px';
224
- let height = '0px';
228
+ let left = this.absoluteWorkingArea.left + this.previewLeft;
229
+ let top = this.absoluteWorkingArea.top + this.previewTop;
230
+ let width = 0;
231
+ let height = 0;
225
232
  if (this.selectedMediaIndex >= 0) {
233
+ logger_1.default.debug(`${this.logPrefix}updateOverlay: selected media:`, this.mediaList[this.selectedMediaIndex].rect);
226
234
  const selectedPreviewRect = {
227
235
  left: this.mediaList[this.selectedMediaIndex].rect.left * this.previewScale,
228
236
  top: this.mediaList[this.selectedMediaIndex].rect.top * this.previewScale,
229
237
  right: this.mediaList[this.selectedMediaIndex].rect.right * this.previewScale,
230
238
  bottom: this.mediaList[this.selectedMediaIndex].rect.bottom * this.previewScale
231
239
  };
232
- left = `${selectedPreviewRect.left + this.previewLeft}px`;
233
- top = `${selectedPreviewRect.top + this.previewTop}px`;
234
- width = `${selectedPreviewRect.right - selectedPreviewRect.left}px`;
235
- height = `${selectedPreviewRect.bottom - selectedPreviewRect.top}px`;
240
+ left = this.absoluteWorkingArea.left + this.previewLeft + selectedPreviewRect.left;
241
+ top = this.absoluteWorkingArea.top + this.previewTop + selectedPreviewRect.top;
242
+ width = selectedPreviewRect.right - selectedPreviewRect.left;
243
+ height = selectedPreviewRect.bottom - selectedPreviewRect.top;
244
+ }
245
+ let renderScale = 1;
246
+ if (this.container) {
247
+ const containerLayoutWidth = this.container.offsetWidth;
248
+ const containerRenderWidth = Math.round(this.container.getBoundingClientRect().width);
249
+ if (containerLayoutWidth !== containerRenderWidth) {
250
+ logger_1.default.warn(`${this.logPrefix}updateOverlay container layout width: ${containerLayoutWidth} container render width: ${containerRenderWidth}`);
251
+ renderScale = containerRenderWidth / containerLayoutWidth;
252
+ }
253
+ }
254
+ this.moveAndResizeOverlay.style.left = `${left}px`;
255
+ this.moveAndResizeOverlay.style.top = `${top}px`;
256
+ this.moveAndResizeOverlay.style.width = `${width}px`;
257
+ this.moveAndResizeOverlay.style.height = `${height}px`;
258
+ if (renderScale !== 1) {
259
+ this.moveAndResizeOverlay.style.transform = `scale(${1 / renderScale})`;
260
+ this.moveAndResizeOverlay.style.transformOrigin = `-${left}px -${top}px`; // Why?
261
+ }
262
+ else {
263
+ this.moveAndResizeOverlay.style.transform = 'none';
264
+ this.moveAndResizeOverlay.style.transformOrigin = 'none';
236
265
  }
237
- this.moveAndResizeOverlay.style.left = left;
238
- this.moveAndResizeOverlay.style.top = top;
239
- this.moveAndResizeOverlay.style.width = width;
240
- this.moveAndResizeOverlay.style.height = height;
266
+ logger_1.default.debug(`${this.logPrefix}updateOverlay: ${left} ${top} ${width} ${height} ${renderScale}`);
241
267
  }
242
268
  }
243
269
  onMove(left, top) {
@@ -247,10 +273,10 @@ class TRTCMediaMixingDesigner {
247
273
  if (target && this.moveAndResizeOverlay) {
248
274
  // calc new preview rect
249
275
  const newPreviewRect = {
250
- left: left - this.previewLeft,
251
- top: top - this.previewTop,
252
- right: left - this.previewLeft + this.moveAndResizeOverlay.offsetWidth,
253
- bottom: top - this.previewTop + this.moveAndResizeOverlay.offsetHeight,
276
+ left: left - this.absoluteWorkingArea.left - this.previewLeft,
277
+ top: top - this.absoluteWorkingArea.top - this.previewTop,
278
+ right: left - this.absoluteWorkingArea.left - this.previewLeft + this.moveAndResizeOverlay.offsetWidth,
279
+ bottom: top - this.absoluteWorkingArea.top - this.previewTop + this.moveAndResizeOverlay.offsetHeight,
254
280
  };
255
281
  this.doAdsorption(newPreviewRect);
256
282
  // calc new mixing rect
@@ -260,6 +286,8 @@ class TRTCMediaMixingDesigner {
260
286
  right: Math.round(newPreviewRect.right / this.previewScale),
261
287
  bottom: Math.round(newPreviewRect.bottom / this.previewScale),
262
288
  };
289
+ logger_1.default.debug(`${this.logPrefix}onMove new preview rect: ${JSON.stringify(newPreviewRect)}`);
290
+ logger_1.default.debug(`${this.logPrefix}onMove new rect in mixing: ${JSON.stringify(newRectInMixing)}`);
263
291
  (_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit('onSourceMoved', Object.assign({}, target), newRectInMixing);
264
292
  }
265
293
  else {
@@ -292,10 +320,10 @@ class TRTCMediaMixingDesigner {
292
320
  if (target) {
293
321
  // calc new preview rect
294
322
  const newPreviewRect = {
295
- left: left - this.previewLeft,
296
- top: top - this.previewTop,
297
- right: left - this.previewLeft + width,
298
- bottom: top - this.previewTop + height,
323
+ left: left - this.absoluteWorkingArea.left - this.previewLeft,
324
+ top: top - this.absoluteWorkingArea.top - this.previewTop,
325
+ right: left - this.absoluteWorkingArea.left - this.previewLeft + width,
326
+ bottom: top - this.absoluteWorkingArea.top - this.previewTop + height,
299
327
  };
300
328
  // calc new mixing rect
301
329
  const newRectInMixing = {
@@ -335,8 +363,8 @@ class TRTCMediaMixingDesigner {
335
363
  // calc click point coordinates in mix video image
336
364
  logger_1.default.log(`${this.logPrefix}onContainerMousedown mix video image clicked`);
337
365
  const containerBounds = this.container.getBoundingClientRect();
338
- const xInPreviewImage = event.clientX - containerBounds.x - this.previewLeft;
339
- const yInPreviewImage = event.clientY - containerBounds.y - this.previewTop;
366
+ const xInPreviewImage = event.clientX - containerBounds.left - this.absoluteWorkingArea.left - this.previewLeft;
367
+ const yInPreviewImage = event.clientY - containerBounds.top - this.absoluteWorkingArea.top - this.previewTop;
340
368
  const xInImage = xInPreviewImage / this.previewScale;
341
369
  const yInImage = yInPreviewImage / this.previewScale;
342
370
  logger_1.default.log(`${this.logPrefix}onContainerMousedown click point coordinates in mix video:`, xInPreviewImage, yInPreviewImage, xInImage, yInImage);
@@ -0,0 +1,9 @@
1
+ declare class PromiseStore {
2
+ private promiseStore;
3
+ constructor();
4
+ addPromise(key: string, resolve: (data: any) => void, reject: (data: any) => void): void;
5
+ resolvePromise(key: string, value: any): void;
6
+ rejectPromise(key: string, value: any): void;
7
+ destroy(): void;
8
+ }
9
+ export default PromiseStore;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class PromiseStore {
4
+ constructor() {
5
+ this.promiseStore = new Map();
6
+ }
7
+ addPromise(key, resolve, reject) {
8
+ if (!this.promiseStore.has(key)) {
9
+ this.promiseStore.set(key, []);
10
+ }
11
+ const storedPromises = this.promiseStore.get(key);
12
+ storedPromises === null || storedPromises === void 0 ? void 0 : storedPromises.push({
13
+ resolve,
14
+ reject
15
+ });
16
+ }
17
+ resolvePromise(key, value) {
18
+ var _a;
19
+ const storedPromises = (_a = this.promiseStore) === null || _a === void 0 ? void 0 : _a.get(key);
20
+ if (storedPromises) {
21
+ storedPromises.forEach(({ resolve }) => {
22
+ resolve(value);
23
+ });
24
+ this.promiseStore.delete(key);
25
+ }
26
+ }
27
+ rejectPromise(key, value) {
28
+ var _a;
29
+ const storedPromises = (_a = this.promiseStore) === null || _a === void 0 ? void 0 : _a.get(key);
30
+ if (storedPromises) {
31
+ storedPromises.forEach(({ reject }) => {
32
+ reject(value);
33
+ });
34
+ this.promiseStore.delete(key);
35
+ }
36
+ }
37
+ destroy() {
38
+ this.promiseStore.forEach((value) => {
39
+ value.forEach(({ reject }) => {
40
+ reject();
41
+ });
42
+ });
43
+ this.promiseStore.clear();
44
+ }
45
+ }
46
+ exports.default = PromiseStore;
@@ -0,0 +1 @@
1
+ export declare const LOCAL_USER_ID = "";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOCAL_USER_ID = void 0;
4
+ exports.LOCAL_USER_ID = '';
@@ -0,0 +1,27 @@
1
+ import { TRTCStreamLayout, TRTCStreamLayoutMode } from "../types";
2
+ import { ITRTCStreamLayoutManager, INativeStreamLayoutManager, TRTCStreamLayoutContext } from "./types";
3
+ declare class BaseStreamLayoutManager implements ITRTCStreamLayoutManager {
4
+ protected logPrefix: string;
5
+ protected nativeStreamLayoutManager: INativeStreamLayoutManager;
6
+ protected layout: TRTCStreamLayout;
7
+ protected context: TRTCStreamLayoutContext | null;
8
+ protected container: HTMLElement | null;
9
+ protected displayArea: {
10
+ left: number;
11
+ top: number;
12
+ right: number;
13
+ bottom: number;
14
+ width: number;
15
+ height: number;
16
+ };
17
+ protected resizeObserver: ResizeObserver | null;
18
+ constructor(nativeStreamLayoutManager: INativeStreamLayoutManager, context: TRTCStreamLayoutContext);
19
+ setLayout(layout: TRTCStreamLayout): void;
20
+ getLayoutMode(): TRTCStreamLayoutMode;
21
+ destroy(): void;
22
+ protected refreshLayout(): void;
23
+ private onResize;
24
+ private setResizeObserver;
25
+ private updateDisplayArea;
26
+ }
27
+ export default BaseStreamLayoutManager;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const types_1 = require("../types");
7
+ const utils_1 = require("../../../utils");
8
+ const logger_1 = __importDefault(require("../../../logger"));
9
+ class BaseStreamLayoutManager {
10
+ constructor(nativeStreamLayoutManager, context) {
11
+ this.logPrefix = "[BaseStreamLayoutManager]";
12
+ this.container = null;
13
+ this.displayArea = {
14
+ left: 0,
15
+ top: 0,
16
+ right: 0,
17
+ bottom: 0,
18
+ width: 0,
19
+ height: 0,
20
+ };
21
+ this.resizeObserver = null;
22
+ this.nativeStreamLayoutManager = nativeStreamLayoutManager;
23
+ this.layout = {
24
+ layoutMode: types_1.TRTCStreamLayoutMode.None,
25
+ };
26
+ this.context = context;
27
+ this.container = context.container;
28
+ this.onResize = (0, utils_1.debounce)(this.onResize.bind(this), 100);
29
+ if (this.container) {
30
+ this.setResizeObserver();
31
+ this.updateDisplayArea();
32
+ }
33
+ else {
34
+ logger_1.default.warn(`${this.logPrefix}constructor failed, no context.container.`);
35
+ }
36
+ }
37
+ setLayout(layout) {
38
+ this.layout = layout;
39
+ this.refreshLayout();
40
+ }
41
+ getLayoutMode() {
42
+ return this.layout.layoutMode;
43
+ }
44
+ destroy() {
45
+ this.layout = {
46
+ layoutMode: types_1.TRTCStreamLayoutMode.None,
47
+ };
48
+ this.container = null;
49
+ this.context = null;
50
+ if (this.resizeObserver) {
51
+ this.resizeObserver.disconnect();
52
+ this.resizeObserver = null;
53
+ }
54
+ }
55
+ refreshLayout() {
56
+ logger_1.default.warn(`${this.logPrefix}refreshLayout should be implemented by sub-class.`);
57
+ }
58
+ onResize(entries) {
59
+ logger_1.default.log(`${this.logPrefix}onResize entries:`, entries);
60
+ for (const entry of entries) {
61
+ if (entry.target === this.container) {
62
+ logger_1.default.debug(`${this.logPrefix}onResize:`, this.container.getBoundingClientRect());
63
+ this.updateDisplayArea();
64
+ this.refreshLayout();
65
+ break;
66
+ }
67
+ }
68
+ }
69
+ setResizeObserver() {
70
+ logger_1.default.debug(`${this.logPrefix}setResizeObserver container:`, this.container, ' resizeObserver:', this.resizeObserver);
71
+ if (this.resizeObserver) {
72
+ this.resizeObserver.disconnect();
73
+ }
74
+ if (this.container) {
75
+ this.resizeObserver = new ResizeObserver(this.onResize);
76
+ this.resizeObserver.observe(this.container);
77
+ }
78
+ else {
79
+ logger_1.default.warn(`${this.logPrefix}setResizeObserver failed, container is null.`);
80
+ }
81
+ }
82
+ updateDisplayArea() {
83
+ if (this.container) {
84
+ const containerRect = this.container.getBoundingClientRect();
85
+ this.displayArea = {
86
+ left: containerRect.left,
87
+ top: containerRect.top,
88
+ right: containerRect.right,
89
+ bottom: containerRect.bottom,
90
+ width: containerRect.width,
91
+ height: containerRect.height,
92
+ };
93
+ }
94
+ else {
95
+ logger_1.default.warn(`${this.logPrefix}updateDisplayArea failed, no container.`);
96
+ }
97
+ }
98
+ }
99
+ exports.default = BaseStreamLayoutManager;
@@ -0,0 +1,11 @@
1
+ import BaseStreamLayoutManager from "./BaseStreamLayoutManager";
2
+ import { TRTCStreamLayout } from "../types";
3
+ import { INativeStreamLayoutManager, TRTCStreamLayoutContext } from "./types";
4
+ declare class CustomStreamLayoutManager extends BaseStreamLayoutManager {
5
+ protected logPrefix: string;
6
+ constructor(nativeStreamLayoutManager: INativeStreamLayoutManager, context: TRTCStreamLayoutContext);
7
+ setLayout(layout: TRTCStreamLayout): void;
8
+ protected refreshLayout(): void;
9
+ private convertRelativeToAbsolute;
10
+ }
11
+ export default CustomStreamLayoutManager;
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const BaseStreamLayoutManager_1 = __importDefault(require("./BaseStreamLayoutManager"));
7
+ const types_1 = require("../types");
8
+ const trtc_define_1 = require("../../../trtc_define");
9
+ const logger_1 = __importDefault(require("../../../logger"));
10
+ const constant_1 = require("../../../constant");
11
+ class CustomStreamLayoutManager extends BaseStreamLayoutManager_1.default {
12
+ constructor(nativeStreamLayoutManager, context) {
13
+ super(nativeStreamLayoutManager, context);
14
+ this.logPrefix = "[TRTCCustomStreamLayoutManager]";
15
+ this.layout = {
16
+ layoutMode: types_1.TRTCStreamLayoutMode.Custom,
17
+ };
18
+ }
19
+ setLayout(layout) {
20
+ this.layout = Object.assign(Object.assign({}, layout), { layoutMode: types_1.TRTCStreamLayoutMode.Custom });
21
+ this.refreshLayout();
22
+ }
23
+ refreshLayout() {
24
+ var _a;
25
+ if (this.layout.userList) {
26
+ this.nativeStreamLayoutManager.setStreamLayout(this.layout.userList);
27
+ }
28
+ else if (this.layout.size && this.layout.streams) {
29
+ const userList = this.convertRelativeToAbsolute(this.layout);
30
+ if (userList) {
31
+ logger_1.default.debug(`${this.logPrefix}refreshLayout userList:`, userList);
32
+ const localUser = userList.filter(user => user.userId === constant_1.LOCAL_USER_ID)[0];
33
+ if ((localUser === null || localUser === void 0 ? void 0 : localUser.rect) && ((_a = this.context) === null || _a === void 0 ? void 0 : _a.mediaMixingDesigner)) {
34
+ const workingArea = localUser.rect;
35
+ this.context.mediaMixingDesigner.setWorkingArea({
36
+ left: workingArea.left / this.displayArea.width,
37
+ top: workingArea.top / this.displayArea.height,
38
+ right: workingArea.right / this.displayArea.width,
39
+ bottom: workingArea.bottom / this.displayArea.height,
40
+ }, localUser.fillMode);
41
+ }
42
+ userList.forEach(user => {
43
+ if (user.rect) {
44
+ user.rect = {
45
+ left: user.rect.left * window.devicePixelRatio,
46
+ right: user.rect.right * window.devicePixelRatio,
47
+ top: user.rect.top * window.devicePixelRatio,
48
+ bottom: user.rect.bottom * window.devicePixelRatio,
49
+ };
50
+ }
51
+ });
52
+ logger_1.default.debug(`${this.logPrefix}refreshLayout transfer layout to pixel unit::`, userList);
53
+ this.nativeStreamLayoutManager.setStreamLayout(userList);
54
+ }
55
+ else {
56
+ logger_1.default.error(`${this.logPrefix}refreshLayout invalid parameter, no 'streams' or 'size'`, JSON.stringify(this.layout));
57
+ }
58
+ }
59
+ else {
60
+ logger_1.default.error(`${this.logPrefix}refreshLayout invalid parameter:`, JSON.stringify(this.layout));
61
+ }
62
+ }
63
+ convertRelativeToAbsolute(serverMixingLayout) {
64
+ if (!serverMixingLayout.streams || !serverMixingLayout.size) {
65
+ return null;
66
+ }
67
+ // 1. calculate valid video content width and height
68
+ let minX = 1;
69
+ let minY = 1;
70
+ let maxX = 0;
71
+ let maxY = 0;
72
+ for (let i = 0; i < serverMixingLayout.streams.length; i++) {
73
+ const stream = serverMixingLayout.streams[i];
74
+ minX = Math.min(minX, stream.x);
75
+ minY = Math.min(minY, stream.y);
76
+ maxX = Math.max(maxX, stream.x + stream.w);
77
+ maxY = Math.max(maxY, stream.y + stream.h);
78
+ }
79
+ const xLength = maxX - minX;
80
+ const yLength = maxY - minY;
81
+ const contentWidth = xLength * serverMixingLayout.size.width;
82
+ const contentHeight = yLength * serverMixingLayout.size.height;
83
+ // 2. calculate fitting scale rate and fitting area
84
+ const scaleRate = Math.min(this.displayArea.width / contentWidth, this.displayArea.height / contentHeight);
85
+ const fittingArea = {
86
+ width: contentWidth * scaleRate,
87
+ height: contentHeight * scaleRate,
88
+ left: (this.displayArea.width - contentWidth * scaleRate) / 2,
89
+ top: (this.displayArea.height - contentHeight * scaleRate) / 2,
90
+ right: (this.displayArea.width + contentWidth * scaleRate) / 2,
91
+ bottom: (this.displayArea.height + contentHeight * scaleRate) / 2,
92
+ };
93
+ // 3. transfer relative coordinates to absolute coordinates
94
+ return serverMixingLayout.streams.map((stream, index, list) => {
95
+ // 3.1 cut left and top black area
96
+ // 3.2 transfer relative video ratio to valid video content ratio
97
+ // 3.3 fit valid video content to dispaying area, that is fitting area
98
+ const result = {
99
+ x: (stream.x - minX) / xLength * contentWidth * scaleRate + fittingArea.left,
100
+ y: (stream.y - minY) / yLength * contentHeight * scaleRate + fittingArea.top,
101
+ w: (stream.w) / xLength * contentWidth * scaleRate,
102
+ h: (stream.h) / yLength * contentHeight * scaleRate,
103
+ };
104
+ // 3.4 convert to TRTCStreamLayout.userList item
105
+ return {
106
+ userId: stream.userId,
107
+ fillMode: list.length >= 2 ? trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fill : trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit,
108
+ zOrder: index,
109
+ rect: {
110
+ left: Math.round(result.x),
111
+ top: Math.round(result.y),
112
+ right: Math.round(result.x + result.w),
113
+ bottom: Math.round(result.y + result.h),
114
+ }
115
+ };
116
+ });
117
+ }
118
+ }
119
+ exports.default = CustomStreamLayoutManager;
@@ -0,0 +1,11 @@
1
+ import BaseStreamLayoutManager from "./BaseStreamLayoutManager";
2
+ import { TRTCStreamLayout } from "../types";
3
+ import { INativeStreamLayoutManager, TRTCStreamLayoutContext } from "./types";
4
+ declare class NoneStreamLayoutManager extends BaseStreamLayoutManager {
5
+ protected logPrefix: string;
6
+ constructor(nativeStreamLayoutManager: INativeStreamLayoutManager, context: TRTCStreamLayoutContext);
7
+ setLayout(layout: TRTCStreamLayout): void;
8
+ protected refreshLayout(): void;
9
+ private centerLiveOwner;
10
+ }
11
+ export default NoneStreamLayoutManager;