trtc-electron-sdk 11.3.502-beta.4 → 11.3.502-beta.5

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.
@@ -402,9 +402,9 @@ declare class TRTCLocalMediaTranscoder extends EventEmitter {
402
402
  removeImageSource(path: string): void;
403
403
  /**
404
404
  * 设置本地混流转码视频预览节点
405
- * @param el {HTMLElement | null} - 如果传入的是 HTML 元素,必须是块元素;传入 null 时,会停止视频预览
405
+ * @param view {HTMLElement | null} - 如果传入的是 HTML 元素,必须是块元素;传入 null 时,会停止视频预览
406
406
  */
407
- setMixedVideoRenderView(el: HTMLElement | null): void;
407
+ setMixedVideoRenderView(view: HTMLElement | null): void;
408
408
  private setMixedVideoFrameRenderCallback;
409
409
  private unsetMixedVideoFrameRenderCallback;
410
410
  private setEventCallback;
@@ -516,11 +516,11 @@ class TRTCLocalMediaTranscoder extends events_1.EventEmitter {
516
516
  }
517
517
  /**
518
518
  * 设置本地混流转码视频预览节点
519
- * @param el {HTMLElement | null} - 如果传入的是 HTML 元素,必须是块元素;传入 null 时,会停止视频预览
519
+ * @param view {HTMLElement | null} - 如果传入的是 HTML 元素,必须是块元素;传入 null 时,会停止视频预览
520
520
  */
521
- setMixedVideoRenderView(el) {
522
- if (el && el instanceof HTMLElement) {
523
- if (this.container === el) {
521
+ setMixedVideoRenderView(view) {
522
+ if (view && view instanceof HTMLElement) {
523
+ if (this.container === view) {
524
524
  return; // 重复在同一个 HTML 节点内渲染,不用处理,直接退出
525
525
  }
526
526
  else if (this.renderer) {
@@ -528,13 +528,25 @@ class TRTCLocalMediaTranscoder extends events_1.EventEmitter {
528
528
  this.renderer.destroy();
529
529
  this.renderer = null;
530
530
  // 重新记录渲染的 HTML 节点并创建渲染器
531
- this.container = el;
532
- this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container);
531
+ this.container = view;
532
+ this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container, {
533
+ type: Renderer_1.RenderType.WebGL,
534
+ onContextLost: () => {
535
+ this.container = view;
536
+ this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container, { type: Renderer_1.RenderType.Video });
537
+ },
538
+ });
533
539
  }
534
540
  else {
535
541
  // 第一次设置渲染的 HTML 节点,并创建渲染器,设置渲染回调
536
- this.container = el;
537
- this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container);
542
+ this.container = view;
543
+ this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container, {
544
+ type: Renderer_1.RenderType.WebGL,
545
+ onContextLost: () => {
546
+ this.container = view;
547
+ this.renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, this.container, { type: Renderer_1.RenderType.Video });
548
+ },
549
+ });
538
550
  this.setMixedVideoFrameRenderCallback();
539
551
  }
540
552
  }
@@ -12,7 +12,11 @@ declare class Canvas3dRenderer implements IRenderer {
12
12
  private i420Width;
13
13
  private i420Height;
14
14
  private i420Rotation;
15
- constructor(pixelFormat: TRTCVideoPixelFormat, view: HTMLElement);
15
+ private onContextLost;
16
+ constructor(pixelFormat: TRTCVideoPixelFormat, view: HTMLElement, options: {
17
+ onContextLost: (() => void) | null;
18
+ });
19
+ private _handleContextLost;
16
20
  private _createCanvas3DRenderer;
17
21
  setContentMode(mode: TRTCVideoFillMode): void;
18
22
  private bind;
@@ -11,9 +11,9 @@ const I420Canvas3DRenderer_1 = __importDefault(require("./I420Canvas3DRenderer")
11
11
  const UP_LIMIT_COUNT = 16;
12
12
  let currentCreatedCount = 0;
13
13
  class Canvas3dRenderer {
14
- constructor(pixelFormat, view) {
15
- this.i420Width = 0;
16
- this.i420Height = 0;
14
+ constructor(pixelFormat, view, options) {
15
+ this.i420Width = 640;
16
+ this.i420Height = 360;
17
17
  this.i420Rotation = 0;
18
18
  if (currentCreatedCount < UP_LIMIT_COUNT) {
19
19
  currentCreatedCount = currentCreatedCount + 1;
@@ -38,8 +38,15 @@ class Canvas3dRenderer {
38
38
  this.canvas = null;
39
39
  this.cacheCanvasOptions = {};
40
40
  this.canvas3DRenderer = null;
41
+ this.onContextLost = options.onContextLost || null;
42
+ this._handleContextLost = this._handleContextLost.bind(this);
41
43
  this.bind(view);
42
44
  }
45
+ _handleContextLost(e) {
46
+ console.warn("trtc: _handleContextLost:", e);
47
+ this.onContextLost && this.onContextLost();
48
+ this.destroy();
49
+ }
43
50
  _createCanvas3DRenderer() {
44
51
  if (this.canvas) {
45
52
  try {
@@ -69,22 +76,28 @@ class Canvas3dRenderer {
69
76
  this.canvas = document.createElement('canvas');
70
77
  this.viewWrapper.appendChild(this.canvas);
71
78
  this.viewContainer.appendChild(this.viewWrapper);
72
- // I420 WebGL 渲染有些特殊,视频宽高发生变化时,需要重新创建 canvas
73
- if (this.pixelFormat === trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420) {
74
- // 初始化时,i420Width i420Height 为 0,所以不会创建渲染器
75
- if (this.i420Width || this.i420Height) {
76
- this.canvas.width = this.i420Width;
77
- this.canvas.height = this.i420Height;
79
+ this.canvas.addEventListener("webglcontextlost", this._handleContextLost);
80
+ try {
81
+ // I420 WebGL 渲染有些特殊,视频宽高发生变化时,需要重新创建 canvas
82
+ if (this.pixelFormat === trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420) {
83
+ if (this.i420Width || this.i420Height) {
84
+ this.canvas.width = this.i420Width;
85
+ this.canvas.height = this.i420Height;
86
+ this.canvas3DRenderer = this._createCanvas3DRenderer();
87
+ }
88
+ }
89
+ else {
78
90
  this.canvas3DRenderer = this._createCanvas3DRenderer();
79
91
  }
80
92
  }
81
- else {
82
- this.canvas3DRenderer = this._createCanvas3DRenderer();
93
+ catch (e) {
94
+ this.canvas.removeEventListener("webglcontextlost", this._handleContextLost);
95
+ throw e;
83
96
  }
84
97
  }
85
98
  }
86
99
  unbind() {
87
- var _a, _b;
100
+ var _a, _b, _c;
88
101
  (_a = this.canvas3DRenderer) === null || _a === void 0 ? void 0 : _a.destroy();
89
102
  this.canvas3DRenderer = null;
90
103
  if (this.canvas && this.viewWrapper && this.canvas.parentElement === this.viewWrapper) {
@@ -93,12 +106,13 @@ class Canvas3dRenderer {
93
106
  else {
94
107
  console.warn("trtc: Canvas3DRenderer unbind error: remove canvas error", this.canvas, this.viewWrapper);
95
108
  }
109
+ (_b = this.canvas) === null || _b === void 0 ? void 0 : _b.removeEventListener("webglcontextlost", this._handleContextLost);
96
110
  this.canvas = null;
97
111
  if (this.viewWrapper && this.viewContainer && this.viewWrapper.parentElement === this.viewContainer) {
98
112
  this.viewContainer.removeChild(this.viewWrapper);
99
113
  }
100
114
  else {
101
- console.warn("trtc: Canvas3DRenderer unbind error: remove viewWrapper error", this.viewWrapper, this.viewContainer, (_b = this.viewContainer) === null || _b === void 0 ? void 0 : _b.parentElement);
115
+ console.warn("trtc: Canvas3DRenderer unbind error: remove viewWrapper error", this.viewWrapper, this.viewContainer, (_c = this.viewContainer) === null || _c === void 0 ? void 0 : _c.parentElement);
102
116
  }
103
117
  this.viewContainer = null;
104
118
  }
@@ -124,14 +138,21 @@ class Canvas3dRenderer {
124
138
  if (width <= 0 || height <= 0) {
125
139
  throw new Error(`wrong video parameter width:${width} or height:${height}`);
126
140
  }
127
- // I420 WebGL 渲染有些特殊,视频宽高发生变化时,需要重新创建 canvas
128
- if (width !== this.i420Width || height !== this.i420Height || rotation !== this.i420Rotation) {
129
- const tempViewContainer = this.viewContainer;
130
- this.unbind();
131
- this.i420Width = width;
132
- this.i420Height = height;
133
- this.i420Rotation = rotation;
134
- this.bind(tempViewContainer);
141
+ try {
142
+ // I420 WebGL 渲染有些特殊,视频宽高发生变化时,需要重新创建 canvas
143
+ if (width !== this.i420Width || height !== this.i420Height || rotation !== this.i420Rotation) {
144
+ const tempViewContainer = this.viewContainer;
145
+ this.unbind();
146
+ this.i420Width = width;
147
+ this.i420Height = height;
148
+ this.i420Rotation = rotation;
149
+ this.bind(tempViewContainer);
150
+ }
151
+ }
152
+ catch (e) {
153
+ this.onContextLost && this.onContextLost();
154
+ this.destroy();
155
+ throw new Error("re-create WebGL context failed");
135
156
  }
136
157
  if (this.viewWrapper && this.canvas3DRenderer) {
137
158
  this._updateCanvasStyle({
@@ -213,6 +234,7 @@ class Canvas3dRenderer {
213
234
  this.unbind();
214
235
  this.viewWrapper = null;
215
236
  currentCreatedCount--;
237
+ this.onContextLost = null;
216
238
  }
217
239
  }
218
240
  }
@@ -1,5 +1,14 @@
1
1
  import { TRTCVideoPixelFormat } from '../trtc_define';
2
2
  import IRenderer from './IRenderer';
3
- export declare function createRenderer(pixelFormat: TRTCVideoPixelFormat, view: HTMLElement): IRenderer;
3
+ export declare enum RenderType {
4
+ WebGL = "WebGL",
5
+ Canvas2D = "Canvas2D",
6
+ Video = "Video"
7
+ }
8
+ export interface RendererOptions {
9
+ onContextLost?: () => void;
10
+ type?: RenderType;
11
+ }
12
+ export declare function createRenderer(pixelFormat: TRTCVideoPixelFormat, view: HTMLElement, options: RendererOptions): IRenderer;
4
13
  export * from './IRenderer';
5
14
  export * from './types';
@@ -17,17 +17,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.createRenderer = void 0;
20
+ exports.createRenderer = exports.RenderType = void 0;
21
21
  const Canvas3DRenderer_1 = __importDefault(require("./Canvas3DRenderer"));
22
22
  const Canvas2DRenderer_1 = __importDefault(require("./Canvas2DRenderer"));
23
23
  const VideoRenderer_1 = __importDefault(require("./VideoRenderer"));
24
24
  const util_1 = require("./util");
25
25
  const isWebGLSupported = (0, util_1.isSupportWebGL)();
26
- function createRenderer(pixelFormat, view) {
26
+ var RenderType;
27
+ (function (RenderType) {
28
+ RenderType["WebGL"] = "WebGL";
29
+ RenderType["Canvas2D"] = "Canvas2D";
30
+ RenderType["Video"] = "Video";
31
+ })(RenderType = exports.RenderType || (exports.RenderType = {}));
32
+ function createRenderer(pixelFormat, view, options) {
33
+ if (options && !options.type) {
34
+ options.type = RenderType.WebGL;
35
+ }
27
36
  let renderer = null;
28
- if (isWebGLSupported) {
37
+ if (isWebGLSupported && options.type === RenderType.WebGL) {
29
38
  try {
30
- renderer = new Canvas3DRenderer_1.default(pixelFormat, view);
39
+ renderer = new Canvas3DRenderer_1.default(pixelFormat, view, {
40
+ onContextLost: options.onContextLost || null,
41
+ });
31
42
  console.log('trtc: created WebGL render');
32
43
  }
33
44
  catch (err) {
@@ -37,7 +48,8 @@ function createRenderer(pixelFormat, view) {
37
48
  }
38
49
  if (!renderer) {
39
50
  // @ts-ignore
40
- if (window.VideoFrame && window.VideoDecoder) {
51
+ if (window.VideoFrame && window.VideoDecoder
52
+ && (options.type === RenderType.WebGL || options.type === RenderType.Video)) {
41
53
  // Electron 15+ 版本支持 WebCodec API
42
54
  renderer = new VideoRenderer_1.default(pixelFormat, view);
43
55
  console.log('trtc: created Video render');
package/liteav/trtc.d.ts CHANGED
@@ -2271,6 +2271,7 @@ declare class TRTCCloud extends EventEmitter {
2271
2271
  private _getRendererMap;
2272
2272
  private _onRenderFrame;
2273
2273
  private _onRealRender;
2274
+ private _checkAndDeleteExistingRenderer;
2274
2275
  private _createVideoRenderer;
2275
2276
  private _initRenderer;
2276
2277
  private _destroyRenderer;
package/liteav/trtc.js CHANGED
@@ -4152,12 +4152,30 @@ class TRTCCloud extends events_1.EventEmitter {
4152
4152
  // 创建渲染器时 view 参数传了 null,只推流或者拉流,本地不渲染
4153
4153
  }
4154
4154
  }
4155
- _createVideoRenderer(view, key) {
4155
+ _checkAndDeleteExistingRenderer(view, key) {
4156
+ this.videoRendererMap.forEach((rendererMap, existingKey) => {
4157
+ rendererMap.forEach((renderer, node, map) => {
4158
+ if (node === view && existingKey !== key) {
4159
+ try {
4160
+ console.warn(`trtc: existing video renderer for ${existingKey}, destroy and create for ${key}.`, view);
4161
+ renderer.destroy();
4162
+ map.delete(node);
4163
+ }
4164
+ catch (err) {
4165
+ console.error("trtc: _checkAndDeleteExistingRenderer destroy render error:", err);
4166
+ }
4167
+ }
4168
+ });
4169
+ });
4170
+ }
4171
+ _createVideoRenderer(view, key, options) {
4172
+ // 事先清空一下,避免画面叠加
4156
4173
  if (view.childElementCount > 0) {
4157
4174
  console.warn("trtc: clear HTML element content:", view);
4158
4175
  }
4159
- view.innerHTML = ''; // 事先清空一下,避免画面叠加
4160
- const renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, view);
4176
+ this._checkAndDeleteExistingRenderer(view, key);
4177
+ view.innerHTML = '';
4178
+ const renderer = (0, Renderer_1.createRenderer)(this.pixelFormat, view, options);
4161
4179
  if (key === this.getKey(LOCAL_USER_VIDEO_ID, trtc_define_1.TRTCVideoStreamType.TRTCVideoStreamTypeBig)) {
4162
4180
  renderer.setContentMode(this.localFillMode);
4163
4181
  }
@@ -4170,10 +4188,25 @@ class TRTCCloud extends events_1.EventEmitter {
4170
4188
  return renderer;
4171
4189
  }
4172
4190
  _initRenderer(key, views) {
4191
+ const onContextLost = (key, view) => {
4192
+ const rendererMap = this.videoRendererMap.get(key);
4193
+ if (rendererMap) {
4194
+ const render = this._createVideoRenderer(view, key, { type: Renderer_1.RenderType.Video });
4195
+ rendererMap === null || rendererMap === void 0 ? void 0 : rendererMap.set(view, render);
4196
+ this.videoRendererMap.set(key, rendererMap);
4197
+ }
4198
+ };
4199
+ const validViews = views.filter(view => {
4200
+ const isValid = view && view instanceof HTMLElement;
4201
+ if (!isValid) {
4202
+ console.warn("trtc: create renderer failed due to invalid HTMLElement", view);
4203
+ }
4204
+ return isValid;
4205
+ });
4173
4206
  let rendererMap = this.videoRendererMap.get(key);
4174
4207
  if (rendererMap) {
4175
4208
  rendererMap.forEach((value, innerKey, map) => {
4176
- if (views.indexOf(innerKey) === -1 || !value.isValid(innerKey)) {
4209
+ if (validViews.indexOf(innerKey) === -1 || !value.isValid(innerKey)) {
4177
4210
  try {
4178
4211
  value.destroy();
4179
4212
  map.delete(innerKey);
@@ -4183,17 +4216,27 @@ class TRTCCloud extends events_1.EventEmitter {
4183
4216
  }
4184
4217
  }
4185
4218
  });
4186
- views.forEach((view) => {
4219
+ validViews.forEach((view) => {
4187
4220
  if (!(rendererMap === null || rendererMap === void 0 ? void 0 : rendererMap.has(view))) {
4188
- const renderer = this._createVideoRenderer(view, key);
4221
+ const renderer = this._createVideoRenderer(view, key, {
4222
+ type: Renderer_1.RenderType.WebGL,
4223
+ onContextLost: () => {
4224
+ onContextLost(key, view);
4225
+ },
4226
+ });
4189
4227
  rendererMap === null || rendererMap === void 0 ? void 0 : rendererMap.set(view, renderer);
4190
4228
  }
4191
4229
  });
4192
4230
  }
4193
4231
  else {
4194
4232
  rendererMap = new Map();
4195
- views.forEach((view) => {
4196
- const renderer = this._createVideoRenderer(view, key);
4233
+ validViews.forEach((view) => {
4234
+ const renderer = this._createVideoRenderer(view, key, {
4235
+ type: Renderer_1.RenderType.WebGL,
4236
+ onContextLost: () => {
4237
+ onContextLost(key, view);
4238
+ },
4239
+ });
4197
4240
  rendererMap === null || rendererMap === void 0 ? void 0 : rendererMap.set(view, renderer);
4198
4241
  });
4199
4242
  }
@@ -143,7 +143,12 @@ class VodPlayer extends events_1.EventEmitter {
143
143
  this.destroyRender();
144
144
  }
145
145
  view.innerHTML = ''; // 事先清空一下,避免画面叠加
146
- this.renderer = (0, Renderer_1.createRenderer)(trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420, view);
146
+ this.renderer = (0, Renderer_1.createRenderer)(trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420, view, {
147
+ type: Renderer_1.RenderType.WebGL,
148
+ onContextLost: () => {
149
+ this.renderer = (0, Renderer_1.createRenderer)(trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420, view, { type: Renderer_1.RenderType.Video });
150
+ },
151
+ });
147
152
  }
148
153
  destroyRender() {
149
154
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trtc-electron-sdk",
3
- "version": "11.3.502-beta.4",
3
+ "version": "11.3.502-beta.5",
4
4
  "description": "trtc electron sdk",
5
5
  "main": "./liteav/trtc.js",
6
6
  "types": "./liteav/trtc.d.ts",