trtc-electron-sdk 13.5.802-beta.0 → 13.5.802-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ export declare type TRTCMediaInfo = {
3
3
  id: string;
4
4
  rect: Rect;
5
5
  isSelected: boolean;
6
+ isLocked?: boolean;
6
7
  zOrder: number;
7
8
  origin: any;
8
9
  };
@@ -272,12 +272,16 @@ class TRTCMediaMixingDesigner {
272
272
  }
273
273
  }
274
274
  updateOverlay() {
275
+ var _a;
275
276
  if (this.moveAndResizeOverlay) {
276
277
  let left = this.absoluteWorkingArea.left + this.previewLeft;
277
278
  let top = this.absoluteWorkingArea.top + this.previewTop;
278
279
  let width = 0;
279
280
  let height = 0;
280
- if (this.selectedMediaIndex >= 0) {
281
+ // Even if a locked media source is forced into "selected" state (e.g. via
282
+ // an external list panel selection), the move/resize overlay must stay
283
+ // hidden so it cannot be dragged or resized from the canvas.
284
+ if (this.selectedMediaIndex >= 0 && !((_a = this.mediaList[this.selectedMediaIndex]) === null || _a === void 0 ? void 0 : _a.isLocked)) {
281
285
  this.moveAndResizeOverlay.style.display = 'block';
282
286
  const selectedPreviewRect = {
283
287
  left: this.mediaList[this.selectedMediaIndex].rect.left * this.previewScale,
@@ -415,6 +419,10 @@ class TRTCMediaMixingDesigner {
415
419
  for (let i = 0; i < this.mediaList.length; i++) {
416
420
  const item = this.mediaList[i];
417
421
  if (item.rect &&
422
+ // Locked media sources are excluded from hit test, so a click on a
423
+ // locked source falls through to the next (lower zOrder) hit, and
424
+ // it can never be selected/dragged/resized via canvas interaction.
425
+ !item.isLocked &&
418
426
  xInImage >= item.rect.left &&
419
427
  xInImage <= item.rect.right &&
420
428
  yInImage >= item.rect.top &&
@@ -146,6 +146,7 @@ export declare class TRTCMediaMixingManager implements ITRTCMediaMixingManager {
146
146
  private serverStatus;
147
147
  private serverMode;
148
148
  private addMediaSourceTimers;
149
+ private screenCaptureRectRestartCounts;
149
150
  private webRenderer;
150
151
  private pixelFormat;
151
152
  private pixelLength;
@@ -540,6 +541,67 @@ export declare class TRTCMediaMixingManager implements ITRTCMediaMixingManager {
540
541
  * setter call.
541
542
  */
542
543
  private _isSameCaptureParams;
544
+ private _omitIsPaused;
545
+ /**
546
+ * @private
547
+ * Strip `captureRect` from a screen param so that the remaining object maps
548
+ * 1:1 onto the native `TRTCScreenCaptureProperty` structure.
549
+ *
550
+ * The capture region travels with the media source payload of
551
+ * add/updateMediaSource (and is consumed by the native `startScreenSource`),
552
+ * not through `setScreenCaptureProperty`. Keeping it out of the property
553
+ * object avoids both sending a field the native setter ignores and a false
554
+ * "changed" verdict from `_isSameCaptureParams`.
555
+ */
556
+ private _omitCaptureRect;
557
+ /**
558
+ * @private
559
+ * Whether the capture region actually changed between two screen params.
560
+ *
561
+ * An absent `captureRect` means "leave the current capture region alone", so
562
+ * it never counts as a change. This mirrors the cpp-side diff, which only
563
+ * restarts the capture when a region is explicitly provided AND differs from
564
+ * the one currently applied.
565
+ */
566
+ private _isScreenCaptureRectChanged;
567
+ private _screenCaptureRectRestartKey;
568
+ /**
569
+ * @private
570
+ * Record that one screen-capture restart has been requested for this source,
571
+ * so the resulting `onMediaSourceAdded` echo can be recognized and skipped.
572
+ */
573
+ private _markScreenCaptureRectRestart;
574
+ /**
575
+ * @private
576
+ * Consume one pending restart marker. Returns true when the incoming
577
+ * notification is an echo of a capture-region restart we triggered ourselves.
578
+ */
579
+ private _consumeScreenCaptureRectRestart;
580
+ /**
581
+ * @private
582
+ * Drop any pending restart markers for this source.
583
+ *
584
+ * Called whenever a source is added or removed: a marker only makes sense for
585
+ * the lifetime of one particular capture session. Should the native layer ever
586
+ * fail to echo a restart, a stale marker left behind would otherwise swallow
587
+ * the genuine insertion notification of a later re-add.
588
+ */
589
+ private _clearScreenCaptureRectRestart;
590
+ /**
591
+ * @private
592
+ * Validate and normalize `screen.captureRect` in place.
593
+ *
594
+ * A rect is accepted when it is either all-zero (meaning "capture the whole
595
+ * target", matching the native default) or a well-formed region with a
596
+ * positive width and height. Anything else is dropped with a warning so that
597
+ * a malformed value never reaches the native layer and never disturbs the
598
+ * currently applied capture region.
599
+ *
600
+ * Only applies to kScreen sources; `captureRect` on any other source type is
601
+ * meaningless and is removed as well.
602
+ */
603
+ private _normalizeScreenCaptureRect;
604
+ private _setVideoFilePaused;
543
605
  private previewInNativeWindow;
544
606
  private previewInWebElement;
545
607
  private previewInNone;
@@ -8,12 +8,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
11
22
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
23
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
24
  };
14
25
  Object.defineProperty(exports, "__esModule", { value: true });
15
26
  exports.TRTCMediaMixingManager = exports.TRTCMediaMixingEvent = void 0;
16
27
  const events_1 = require("events");
28
+ const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
17
29
  const trtc_define_1 = require("../../trtc_define");
18
30
  const types_1 = require("./types");
19
31
  const utils_1 = require("../../utils");
@@ -107,6 +119,33 @@ const TRTCOnlineVideoParam_HACK_JSDOC = null;
107
119
  * @property {Number} playoutVolume 播放音量,取值 0 - 100
108
120
  */
109
121
  const TRTCVideoFileParam_HACK_JSDOC = null;
122
+ /**
123
+ * 本地视频文件媒体源参数
124
+ *
125
+ * 继承 `TRTCVideoFileParam` 的全部属性,并额外支持控制播放/暂停。
126
+ *
127
+ * @typedef {Object} TRTCMediaMixingLocalVideoParam
128
+ * @property {Number} playoutVolume 播放音量,取值 0 - 100
129
+ * @property {Boolean} isPaused 是否暂停播放,可选属性,默认 false(即播放)。
130
+ * `updateMediaSource` 时仅在该属性变化时才会下发暂停/恢复操作。
131
+ */
132
+ const TRTCMediaMixingLocalVideoParam_HACK_JSDOC = null;
133
+ /**
134
+ * 屏幕/窗口采集参数
135
+ *
136
+ * 继承 `TRTCScreenCaptureProperty` 的全部属性,并额外支持指定采集区域。
137
+ *
138
+ * @typedef {Object} TRTCMediaMixingScreenParam
139
+ * @property {Boolean} enableCaptureMouse 是否采集目标内容的同时采集鼠标,可选属性,默认 true
140
+ * @property {Boolean} enableHighLight 是否高亮正在共享的窗口,可选属性,默认 true
141
+ * @property {Boolean} enableHighPerformance 是否开启高性能模式(仅分享屏幕时生效),可选属性,默认 true
142
+ * @property {Number} highLightColor 高亮边框颜色,RGB 格式,可选属性,传 0 使用默认颜色
143
+ * @property {Number} highLightWidth 高亮边框宽度,可选属性,传 0 使用默认宽度
144
+ * @property {Boolean} enableCaptureChildWindow 窗口采集时是否采集子窗口,可选属性,默认 false
145
+ * @property {Rect} captureRect 采集区域,单位:像素,可选属性。不传或传入全零表示采集完整画面;
146
+ * 传入合法区域(`right > left` 且 `bottom > top`)表示仅采集指定区域,非法区域会被忽略。
147
+ */
148
+ const TRTCMediaMixingScreenParam_HACK_JSDOC = null;
110
149
  /**
111
150
  * 媒体源数据
112
151
  *
@@ -117,12 +156,14 @@ const TRTCVideoFileParam_HACK_JSDOC = null;
117
156
  * @property {Boolean} enableGreenScreen 是否开启绿幕(仅在 sourceType 为 kCamera 时生效),可选属性
118
157
  * @property {Rect} rect 媒体源显示区域
119
158
  * @property {Boolean} isSelected 媒体源是否选中,可选属性,默认:false
120
- * @property {TRTCVideoRotation} rotation 媒体源选中角度,可选属性
159
+ * @property {Boolean} isLocked 媒体源是否锁定,可选属性,默认:false。锁定后该媒体源无法通过预览画布上的
160
+ * 点击、拖拽、缩放进行交互(即使被外部列表强制置为选中状态,也不会显示移动/缩放控件)。
161
+ * @property {TRTCVideoRotation} rotation 媒体源旋转角度,可选属性
121
162
  * @property {TRTCVideoFillMode} fillMode 媒体源显示模式,可选属性,默认 `TRTCVideoFillMode_Fit`
122
163
  * @property {TRTCVideoMirrorType} mirrorType 媒体源是否镜像,可选属性,默认不镜像
123
164
  * @property {TRTCCameraCaptureParams} camera 摄像头采集参数,仅在 sourceType 为 kCamera 时生效,可选属性
124
- * @property {TRTCScreenCaptureProperty} screen 屏幕/窗口采集属性,仅在 sourceType 为 kScreen 时生效,可选属性
125
- * @property {TRTCVideoFileParam} localVideo 本地视频文件播放参数,仅在 sourceType 为 kVideoFile 时生效,可选属性
165
+ * @property {TRTCMediaMixingScreenParam} screen 屏幕/窗口采集参数,仅在 sourceType 为 kScreen 时生效,可选属性
166
+ * @property {TRTCMediaMixingLocalVideoParam} localVideo 本地视频文件播放参数,仅在 sourceType 为 kVideoFile 时生效,可选属性
126
167
  * @property {TRTCOnlineVideoParam} onlineVideo 在线视频播放参数,仅在 sourceType 为 kOnlineVideo 时生效,可选属性
127
168
  */
128
169
  const TRTCMediaSource_HACK_JSDOC = null;
@@ -344,6 +385,17 @@ class TRTCMediaMixingManager {
344
385
  // state machine stuck after a previous failure), which would otherwise leave
345
386
  // the returned Promise pending forever and the UI stuck on "loading".
346
387
  this.addMediaSourceTimers = new Map();
388
+ // Number of screen-capture restarts we have deliberately triggered per
389
+ // source, keyed by `${sourceType}-${sourceId}`.
390
+ //
391
+ // Changing `screen.captureRect` can only take effect by re-invoking the
392
+ // native `startScreenSource`, which makes the underlying SDK emit another
393
+ // `onScreenSourceStarted` -> `SM_OnSourceInserted`. That notification is an
394
+ // echo of an already-added source, not a new insertion, so it must not be
395
+ // mistaken for one. We count the restarts we asked for and swallow exactly
396
+ // that many successful notifications. A counter (rather than a flag) keeps
397
+ // rapid successive updates correct, since every restart echoes back once.
398
+ this.screenCaptureRectRestartCounts = new Map();
347
399
  this.webRenderer = null;
348
400
  this.pixelFormat = trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32;
349
401
  this.pixelLength = 4;
@@ -431,6 +483,7 @@ class TRTCMediaMixingManager {
431
483
  // callbacks touching a destroyed instance.
432
484
  this.addMediaSourceTimers.forEach(timer => clearTimeout(timer));
433
485
  this.addMediaSourceTimers.clear();
486
+ this.screenCaptureRectRestartCounts.clear();
434
487
  this.paramsStore = null;
435
488
  this.trtcParamsStore = null;
436
489
  // 仅解除引用,pluginManager 生命周期由 TRTCCloud 统一管理
@@ -573,6 +626,7 @@ class TRTCMediaMixingManager {
573
626
  });
574
627
  }
575
628
  const newMediaSource = (0, utils_1.safelyParse)(JSON.stringify(mediaSource));
629
+ this._normalizeScreenCaptureRect(newMediaSource);
576
630
  if (newMediaSource.isSelected) {
577
631
  const oldSelectedIndex = this.findSelectedMediaSource();
578
632
  if (oldSelectedIndex !== -1) {
@@ -639,11 +693,15 @@ class TRTCMediaMixingManager {
639
693
  // extra camera restart on first add. Other source types are handled in
640
694
  // the onMediaSourceAdded callback once the C++ layer reports success.
641
695
  this._applyCameraParamsBeforeAdd(newMediaSource);
696
+ // A fresh capture session starts here, so no restart echo can still be
697
+ // outstanding from a previous one.
698
+ this._clearScreenCaptureRectRestart(newMediaSource.sourceType, newMediaSource.sourceId);
642
699
  this.nodeMediaMixingPlugin.addMediaSource(newMediaSource);
643
700
  (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.addMedia({
644
701
  id: `${newMediaSource.sourceType}__${newMediaSource.sourceId}`,
645
702
  rect: newMediaSource.rect,
646
703
  isSelected: newMediaSource.isSelected || false,
704
+ isLocked: newMediaSource.isLocked || false,
647
705
  zOrder: newMediaSource.zOrder,
648
706
  origin: newMediaSource
649
707
  });
@@ -657,6 +715,8 @@ class TRTCMediaMixingManager {
657
715
  return 11000;
658
716
  case types_1.TRTCMediaSourceType.kVideoFile:
659
717
  return 6000;
718
+ case types_1.TRTCMediaSourceType.kCamera:
719
+ return 8000; // camera maybe very slow
660
720
  default:
661
721
  return 5000;
662
722
  }
@@ -702,10 +762,12 @@ class TRTCMediaMixingManager {
702
762
  }
703
763
  jsRemoveMediaSource(mediaSource, index) {
704
764
  var _a;
765
+ this._clearScreenCaptureRectRestart(mediaSource.sourceType, mediaSource.sourceId);
705
766
  (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.removeMedia({
706
767
  id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
707
768
  rect: mediaSource.rect,
708
769
  isSelected: mediaSource.isSelected || false,
770
+ isLocked: mediaSource.isLocked || false,
709
771
  zOrder: mediaSource.zOrder,
710
772
  origin: (0, utils_1.safelyParse)(JSON.stringify(mediaSource))
711
773
  });
@@ -717,7 +779,7 @@ class TRTCMediaMixingManager {
717
779
  * @returns {Promise<void>}
718
780
  */
719
781
  updateMediaSource(mediaSource) {
720
- var _a;
782
+ var _a, _b;
721
783
  return __awaiter(this, void 0, void 0, function* () {
722
784
  logger_1.default.log(`${this.logPrefix}updateMediaSource:`, mediaSource);
723
785
  const index = this.findMediaSourceIndex(mediaSource);
@@ -728,18 +790,40 @@ class TRTCMediaMixingManager {
728
790
  });
729
791
  }
730
792
  const newMediaSource = Object.assign(Object.assign({}, this.sourceList[index]), (0, utils_1.safelyParse)(JSON.stringify(mediaSource)));
793
+ this._normalizeScreenCaptureRect(newMediaSource);
731
794
  if (mediaSource.isSelected) {
732
795
  const oldSelectedIndex = this.findSelectedMediaSource();
733
796
  if (oldSelectedIndex !== -1 && oldSelectedIndex !== index) {
734
797
  yield this.unselectMediaSource(oldSelectedIndex);
735
798
  }
736
799
  }
737
- yield this.nodeMediaMixingPlugin.updateMediaSource(newMediaSource);
800
+ // The cpp layer re-invokes `startScreenSource` when the capture region
801
+ // changes, which echoes back one extra `SM_OnSourceInserted`. Record it
802
+ // before the call so the echo can be recognized instead of being handled
803
+ // as a brand-new insertion.
804
+ const captureRectChanged = newMediaSource.sourceType === types_1.TRTCMediaSourceType.kScreen
805
+ && this._isScreenCaptureRectChanged(newMediaSource.screen, (_a = this.sourceList[index]) === null || _a === void 0 ? void 0 : _a.screen);
806
+ if (captureRectChanged) {
807
+ this._markScreenCaptureRectRestart(newMediaSource.sourceType, newMediaSource.sourceId);
808
+ }
809
+ try {
810
+ yield this.nodeMediaMixingPlugin.updateMediaSource(newMediaSource);
811
+ }
812
+ catch (err) {
813
+ // The native call failed before the capture restart could happen, so
814
+ // the expected echo will never arrive. Roll the marker back, otherwise
815
+ // the stale one would swallow a genuine insertion notification later.
816
+ if (captureRectChanged) {
817
+ this._clearScreenCaptureRectRestart(newMediaSource.sourceType, newMediaSource.sourceId);
818
+ }
819
+ throw err;
820
+ }
738
821
  this._applyMediaSourceParams(newMediaSource, this.sourceList[index]);
739
- (_a = this.mediaMixingDesigner) === null || _a === void 0 ? void 0 : _a.updateMedia({
822
+ (_b = this.mediaMixingDesigner) === null || _b === void 0 ? void 0 : _b.updateMedia({
740
823
  id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
741
824
  rect: mediaSource.rect,
742
825
  isSelected: mediaSource.isSelected || false,
826
+ isLocked: mediaSource.isLocked || false,
743
827
  zOrder: mediaSource.zOrder,
744
828
  origin: (0, utils_1.safelyParse)(JSON.stringify(mediaSource))
745
829
  });
@@ -1168,6 +1252,7 @@ class TRTCMediaMixingManager {
1168
1252
  id: `${mediaSource.sourceType}__${mediaSource.sourceId}`,
1169
1253
  rect: mediaSource.rect,
1170
1254
  isSelected: mediaSource.isSelected || false,
1255
+ isLocked: mediaSource.isLocked || false,
1171
1256
  zOrder: mediaSource.zOrder,
1172
1257
  origin: mediaSource
1173
1258
  });
@@ -1308,6 +1393,7 @@ class TRTCMediaMixingManager {
1308
1393
  id: `${this.sourceList[index].sourceType}__${this.sourceList[index].sourceId}`,
1309
1394
  rect: this.sourceList[index].rect,
1310
1395
  isSelected: this.sourceList[index].isSelected || false,
1396
+ isLocked: this.sourceList[index].isLocked || false,
1311
1397
  zOrder: this.sourceList[index].zOrder,
1312
1398
  origin: (0, utils_1.safelyParse)(JSON.stringify(this.sourceList[index]))
1313
1399
  });
@@ -1350,6 +1436,19 @@ class TRTCMediaMixingManager {
1350
1436
  clearTimeout(timer);
1351
1437
  this.addMediaSourceTimers.delete(promiseKey);
1352
1438
  }
1439
+ // Deduplicate the echo of a capture-region restart that we triggered from
1440
+ // updateMediaSource: the source is already tracked and its params are
1441
+ // already applied, so re-running the add bookkeeping would only issue a
1442
+ // redundant setScreenCaptureProperty. Failures are deliberately NOT
1443
+ // swallowed - they still need to reach the caller through the normal
1444
+ // error path below.
1445
+ if (data.errCode === 0 && this._consumeScreenCaptureRectRestart(data.sourceType, data.sourceId)) {
1446
+ logger_1.default.log(`${this.logPrefix}screen capture rect restarted for sourceId:${data.sourceId}, skip duplicated onMediaSourceAdded`);
1447
+ return;
1448
+ }
1449
+ if (data.errCode !== 0) {
1450
+ this._clearScreenCaptureRectRestart(data.sourceType, data.sourceId);
1451
+ }
1353
1452
  let flag = false;
1354
1453
  if (data.errCode === 0) {
1355
1454
  const addedIndex = this.findMediaSourceIndex({
@@ -1548,6 +1647,11 @@ class TRTCMediaMixingManager {
1548
1647
  if ((_b = this.paramsStore) === null || _b === void 0 ? void 0 : _b.streamLayout) {
1549
1648
  this.setStreamLayout(this.paramsStore.streamLayout);
1550
1649
  }
1650
+ // The restarted media server holds no capture session yet, so every
1651
+ // source below is a genuine insertion. Drop restart markers left over
1652
+ // from before the crash, otherwise a stale one would swallow a recovery
1653
+ // notification and skip re-applying that source's capture params.
1654
+ this.screenCaptureRectRestartCounts.clear();
1551
1655
  this.sourceList.forEach((item) => {
1552
1656
  this._applyCameraParamsBeforeAdd(item);
1553
1657
  this.nodeMediaMixingPlugin.addMediaSource(item);
@@ -1629,6 +1733,7 @@ class TRTCMediaMixingManager {
1629
1733
  * setter is always invoked when params are present).
1630
1734
  */
1631
1735
  _applyMediaSourceParams(mediaSource, oldMediaSource) {
1736
+ var _a;
1632
1737
  switch (mediaSource.sourceType) {
1633
1738
  case types_1.TRTCMediaSourceType.kCamera:
1634
1739
  // Skip kCamera on the add path to avoid an extra camera restart;
@@ -1637,21 +1742,37 @@ class TRTCMediaMixingManager {
1637
1742
  this.setCameraCaptureParam(mediaSource.sourceId, mediaSource.camera);
1638
1743
  }
1639
1744
  break;
1640
- case types_1.TRTCMediaSourceType.kScreen:
1641
- if (mediaSource.screen && !this._isSameCaptureParams(mediaSource.screen, oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.screen)) {
1642
- this.setScreenCaptureProperty(mediaSource.sourceId, mediaSource.screen);
1745
+ case types_1.TRTCMediaSourceType.kScreen: {
1746
+ const nextProperty = this._omitCaptureRect(mediaSource.screen);
1747
+ const prevProperty = this._omitCaptureRect(oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.screen);
1748
+ if (nextProperty && Object.keys(nextProperty).length > 0
1749
+ && !this._isSameCaptureParams(nextProperty, prevProperty)) {
1750
+ this.setScreenCaptureProperty(mediaSource.sourceId, nextProperty);
1643
1751
  }
1644
1752
  break;
1753
+ }
1645
1754
  case types_1.TRTCMediaSourceType.kOnlineVideo:
1646
1755
  if (mediaSource.onlineVideo && !this._isSameCaptureParams(mediaSource.onlineVideo, oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.onlineVideo)) {
1647
1756
  this.setOnlineVideoParam(mediaSource.sourceId, mediaSource.onlineVideo);
1648
1757
  }
1649
1758
  break;
1650
1759
  case types_1.TRTCMediaSourceType.kVideoFile:
1651
- if (mediaSource.localVideo && !this._isSameCaptureParams(mediaSource.localVideo, oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.localVideo)) {
1652
- this.setVideoFileParam(mediaSource.sourceId, mediaSource.localVideo);
1760
+ if (mediaSource.localVideo) {
1761
+ const nextParam = this._omitIsPaused(mediaSource.localVideo);
1762
+ const prevParam = this._omitIsPaused(oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.localVideo);
1763
+ if (!this._isSameCaptureParams(nextParam, prevParam)) {
1764
+ this.setVideoFileParam(mediaSource.sourceId, mediaSource.localVideo);
1765
+ }
1766
+ const nextIsPaused = !!mediaSource.localVideo.isPaused;
1767
+ const prevIsPaused = !!((_a = oldMediaSource === null || oldMediaSource === void 0 ? void 0 : oldMediaSource.localVideo) === null || _a === void 0 ? void 0 : _a.isPaused);
1768
+ if (nextIsPaused !== prevIsPaused) {
1769
+ this._setVideoFilePaused(mediaSource.sourceId, nextIsPaused);
1770
+ }
1653
1771
  }
1654
1772
  break;
1773
+ default:
1774
+ logger_1.default.warn(`[TRTC] Unknown media source type: ${mediaSource.sourceType}`);
1775
+ break;
1655
1776
  }
1656
1777
  }
1657
1778
  /**
@@ -1683,13 +1804,138 @@ class TRTCMediaMixingManager {
1683
1804
  if (nextEmpty || prevEmpty) {
1684
1805
  return false;
1685
1806
  }
1686
- try {
1687
- return JSON.stringify(next) === JSON.stringify(prev);
1807
+ return (0, lodash_isequal_1.default)(next, prev);
1808
+ }
1809
+ _omitIsPaused(param) {
1810
+ if (!param) {
1811
+ return undefined;
1812
+ }
1813
+ const { isPaused } = param, rest = __rest(param, ["isPaused"]);
1814
+ return rest;
1815
+ }
1816
+ /**
1817
+ * @private
1818
+ * Strip `captureRect` from a screen param so that the remaining object maps
1819
+ * 1:1 onto the native `TRTCScreenCaptureProperty` structure.
1820
+ *
1821
+ * The capture region travels with the media source payload of
1822
+ * add/updateMediaSource (and is consumed by the native `startScreenSource`),
1823
+ * not through `setScreenCaptureProperty`. Keeping it out of the property
1824
+ * object avoids both sending a field the native setter ignores and a false
1825
+ * "changed" verdict from `_isSameCaptureParams`.
1826
+ */
1827
+ _omitCaptureRect(param) {
1828
+ if (!param) {
1829
+ return undefined;
1688
1830
  }
1689
- catch (err) {
1690
- logger_1.default.warn(`${this.logPrefix}_isSameCaptureParams: stringify failed, treat as different.`, err);
1831
+ const { captureRect } = param, rest = __rest(param, ["captureRect"]);
1832
+ return rest;
1833
+ }
1834
+ /**
1835
+ * @private
1836
+ * Whether the capture region actually changed between two screen params.
1837
+ *
1838
+ * An absent `captureRect` means "leave the current capture region alone", so
1839
+ * it never counts as a change. This mirrors the cpp-side diff, which only
1840
+ * restarts the capture when a region is explicitly provided AND differs from
1841
+ * the one currently applied.
1842
+ */
1843
+ _isScreenCaptureRectChanged(next, prev) {
1844
+ const nextRect = next === null || next === void 0 ? void 0 : next.captureRect;
1845
+ if (nextRect === undefined || nextRect === null) {
1846
+ return false;
1847
+ }
1848
+ return !(0, lodash_isequal_1.default)(nextRect, prev === null || prev === void 0 ? void 0 : prev.captureRect);
1849
+ }
1850
+ _screenCaptureRectRestartKey(sourceType, sourceId) {
1851
+ return `${sourceType}-${sourceId}`;
1852
+ }
1853
+ /**
1854
+ * @private
1855
+ * Record that one screen-capture restart has been requested for this source,
1856
+ * so the resulting `onMediaSourceAdded` echo can be recognized and skipped.
1857
+ */
1858
+ _markScreenCaptureRectRestart(sourceType, sourceId) {
1859
+ const key = this._screenCaptureRectRestartKey(sourceType, sourceId);
1860
+ this.screenCaptureRectRestartCounts.set(key, (this.screenCaptureRectRestartCounts.get(key) || 0) + 1);
1861
+ }
1862
+ /**
1863
+ * @private
1864
+ * Consume one pending restart marker. Returns true when the incoming
1865
+ * notification is an echo of a capture-region restart we triggered ourselves.
1866
+ */
1867
+ _consumeScreenCaptureRectRestart(sourceType, sourceId) {
1868
+ const key = this._screenCaptureRectRestartKey(sourceType, sourceId);
1869
+ const count = this.screenCaptureRectRestartCounts.get(key) || 0;
1870
+ if (count <= 0) {
1691
1871
  return false;
1692
1872
  }
1873
+ if (count === 1) {
1874
+ this.screenCaptureRectRestartCounts.delete(key);
1875
+ }
1876
+ else {
1877
+ this.screenCaptureRectRestartCounts.set(key, count - 1);
1878
+ }
1879
+ return true;
1880
+ }
1881
+ /**
1882
+ * @private
1883
+ * Drop any pending restart markers for this source.
1884
+ *
1885
+ * Called whenever a source is added or removed: a marker only makes sense for
1886
+ * the lifetime of one particular capture session. Should the native layer ever
1887
+ * fail to echo a restart, a stale marker left behind would otherwise swallow
1888
+ * the genuine insertion notification of a later re-add.
1889
+ */
1890
+ _clearScreenCaptureRectRestart(sourceType, sourceId) {
1891
+ this.screenCaptureRectRestartCounts.delete(this._screenCaptureRectRestartKey(sourceType, sourceId));
1892
+ }
1893
+ /**
1894
+ * @private
1895
+ * Validate and normalize `screen.captureRect` in place.
1896
+ *
1897
+ * A rect is accepted when it is either all-zero (meaning "capture the whole
1898
+ * target", matching the native default) or a well-formed region with a
1899
+ * positive width and height. Anything else is dropped with a warning so that
1900
+ * a malformed value never reaches the native layer and never disturbs the
1901
+ * currently applied capture region.
1902
+ *
1903
+ * Only applies to kScreen sources; `captureRect` on any other source type is
1904
+ * meaningless and is removed as well.
1905
+ */
1906
+ _normalizeScreenCaptureRect(mediaSource) {
1907
+ const screen = mediaSource.screen;
1908
+ if (!screen || screen.captureRect === undefined || screen.captureRect === null) {
1909
+ return;
1910
+ }
1911
+ if (mediaSource.sourceType !== types_1.TRTCMediaSourceType.kScreen) {
1912
+ logger_1.default.warn(`${this.logPrefix}screen.captureRect is only supported for kScreen source, ignored. sourceType:${mediaSource.sourceType}`);
1913
+ delete screen.captureRect;
1914
+ return;
1915
+ }
1916
+ const { left, top, right, bottom } = screen.captureRect;
1917
+ const isValidNumber = [left, top, right, bottom].every(item => typeof item === 'number' && Number.isInteger(item) && item >= -2147483648 && item <= 2147483647);
1918
+ if (!isValidNumber) {
1919
+ logger_1.default.warn(`${this.logPrefix}screen.captureRect must contain int32 integers, ignored:`, screen.captureRect);
1920
+ delete screen.captureRect;
1921
+ return;
1922
+ }
1923
+ const isFullTarget = left === 0 && top === 0 && right === 0 && bottom === 0;
1924
+ if (isFullTarget) {
1925
+ return;
1926
+ }
1927
+ if (left < 0 || top < 0 || right <= left || bottom <= top) {
1928
+ logger_1.default.warn(`${this.logPrefix}screen.captureRect is invalid, ignored:`, screen.captureRect);
1929
+ delete screen.captureRect;
1930
+ }
1931
+ }
1932
+ _setVideoFilePaused(sourceId, isPaused) {
1933
+ if (isPaused) {
1934
+ this.nodeMediaMixingPlugin.pauseVideoFileSource(sourceId);
1935
+ }
1936
+ else {
1937
+ this.nodeMediaMixingPlugin.resumeVideoFileSource(sourceId);
1938
+ }
1693
1939
  }
1694
1940
  previewInNativeWindow(viewOrRegion) {
1695
1941
  var _a;
@@ -46,6 +46,12 @@ export declare type TRTCOnlineVideoParam = {
46
46
  export declare type TRTCVideoFileParam = {
47
47
  playoutVolume: number;
48
48
  };
49
+ export declare type TRTCMediaMixingLocalVideoParam = TRTCVideoFileParam & {
50
+ isPaused?: boolean;
51
+ };
52
+ export declare type TRTCMediaMixingScreenParam = TRTCScreenCaptureProperty & {
53
+ captureRect?: Rect;
54
+ };
49
55
  export declare type TRTCMediaSource = {
50
56
  sourceType: TRTCMediaSourceType;
51
57
  sourceId: string;
@@ -53,12 +59,13 @@ export declare type TRTCMediaSource = {
53
59
  enableGreenScreen?: boolean;
54
60
  rect: Rect;
55
61
  isSelected?: boolean;
62
+ isLocked?: boolean;
56
63
  rotation?: TRTCVideoRotation;
57
64
  fillMode?: TRTCVideoFillMode;
58
65
  mirrorType?: TRTCVideoMirrorType;
59
66
  camera?: TRTCCameraCaptureParams;
60
- screen?: TRTCScreenCaptureProperty;
61
- localVideo?: TRTCVideoFileParam;
67
+ screen?: TRTCMediaMixingScreenParam;
68
+ localVideo?: TRTCMediaMixingLocalVideoParam;
62
69
  onlineVideo?: TRTCOnlineVideoParam;
63
70
  };
64
71
  export declare type TRTCMediaMixingEncParam = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trtc-electron-sdk",
3
- "version": "13.5.802-beta.0",
3
+ "version": "13.5.802-beta.1",
4
4
  "description": "trtc electron sdk",
5
5
  "main": "./liteav/index.js",
6
6
  "types": "./liteav/index.d.ts",