agora-electron-sdk 4.5.1 → 4.5.2-dev.2
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.
- package/CHANGELOG.md +23 -0
- package/js/Decoder/gpu-utils.js +74 -0
- package/js/Decoder/index.js +172 -0
- package/js/Private/AgoraBase.js +15 -3
- package/js/Private/extension/AgoraBaseExtension.js +1 -0
- package/js/Private/internal/IrisApiEngine.js +20 -7
- package/js/Private/internal/RtcEngineExInternal.js +31 -16
- package/js/Private/ipc/main.js +21 -0
- package/js/Private/ipc/renderer.js +21 -0
- package/js/Renderer/CapabilityManager.js +99 -0
- package/js/Renderer/IRenderer.js +40 -11
- package/js/Renderer/IRendererCache.js +75 -0
- package/js/Renderer/RendererCache.js +26 -63
- package/js/Renderer/RendererManager.js +259 -38
- package/js/Renderer/WebCodecsRenderer/index.js +109 -0
- package/js/Renderer/WebCodecsRendererCache.js +115 -0
- package/js/Renderer/WebGLRenderer/index.js +115 -67
- package/js/Renderer/YUVCanvasRenderer/index.js +5 -3
- package/js/Renderer/index.js +0 -1
- package/js/Types.js +51 -1
- package/js/Utils.js +47 -7
- package/package.json +28 -11
- package/scripts/checkElectron.js +4 -2
- package/scripts/download.js +102 -0
- package/scripts/downloadPrebuild.js +2 -1
- package/scripts/synclib.js +2 -2
- package/ts/Decoder/gpu-utils.ts +92 -0
- package/ts/Decoder/index.ts +206 -0
- package/ts/Private/AgoraBase.ts +18 -4
- package/ts/Private/IAgoraRtcEngine.ts +6 -7
- package/ts/Private/IAgoraRtcEngineEx.ts +2 -1
- package/ts/Private/extension/AgoraBaseExtension.ts +14 -1
- package/ts/Private/internal/IrisApiEngine.ts +21 -7
- package/ts/Private/internal/RtcEngineExInternal.ts +27 -8
- package/ts/Private/ipc/main.ts +22 -0
- package/ts/Private/ipc/renderer.ts +21 -0
- package/ts/Renderer/CapabilityManager.ts +126 -0
- package/ts/Renderer/IRenderer.ts +52 -17
- package/ts/Renderer/IRendererCache.ts +96 -0
- package/ts/Renderer/RendererCache.ts +42 -85
- package/ts/Renderer/RendererManager.ts +342 -52
- package/ts/Renderer/WebCodecsRenderer/index.ts +145 -0
- package/ts/Renderer/WebCodecsRendererCache.ts +137 -0
- package/ts/Renderer/WebGLRenderer/index.ts +153 -107
- package/ts/Renderer/YUVCanvasRenderer/index.ts +24 -22
- package/ts/Renderer/index.ts +0 -1
- package/ts/Types.ts +130 -7
- package/ts/Utils.ts +53 -7
- package/types/Decoder/gpu-utils.d.ts +21 -0
- package/types/Decoder/gpu-utils.d.ts.map +1 -0
- package/types/Decoder/index.d.ts +26 -0
- package/types/Decoder/index.d.ts.map +1 -0
- package/types/Private/AgoraBase.d.ts +18 -4
- package/types/Private/AgoraBase.d.ts.map +1 -1
- package/types/Private/IAgoraRtcEngine.d.ts +6 -7
- package/types/Private/IAgoraRtcEngine.d.ts.map +1 -1
- package/types/Private/IAgoraRtcEngineEx.d.ts +2 -1
- package/types/Private/IAgoraRtcEngineEx.d.ts.map +1 -1
- package/types/Private/extension/AgoraBaseExtension.d.ts +13 -1
- package/types/Private/extension/AgoraBaseExtension.d.ts.map +1 -1
- package/types/Private/internal/IrisApiEngine.d.ts +2 -0
- package/types/Private/internal/IrisApiEngine.d.ts.map +1 -1
- package/types/Private/internal/RtcEngineExInternal.d.ts +2 -0
- package/types/Private/internal/RtcEngineExInternal.d.ts.map +1 -1
- package/types/Private/ipc/main.d.ts +2 -0
- package/types/Private/ipc/main.d.ts.map +1 -0
- package/types/Private/ipc/renderer.d.ts +3 -0
- package/types/Private/ipc/renderer.d.ts.map +1 -0
- package/types/Renderer/CapabilityManager.d.ts +20 -0
- package/types/Renderer/CapabilityManager.d.ts.map +1 -0
- package/types/Renderer/IRenderer.d.ts +8 -7
- package/types/Renderer/IRenderer.d.ts.map +1 -1
- package/types/Renderer/IRendererCache.d.ts +26 -0
- package/types/Renderer/IRendererCache.d.ts.map +1 -0
- package/types/Renderer/RendererCache.d.ts +6 -18
- package/types/Renderer/RendererCache.d.ts.map +1 -1
- package/types/Renderer/RendererManager.d.ts +49 -15
- package/types/Renderer/RendererManager.d.ts.map +1 -1
- package/types/Renderer/WebCodecsRenderer/index.d.ts +14 -0
- package/types/Renderer/WebCodecsRenderer/index.d.ts.map +1 -0
- package/types/Renderer/WebCodecsRendererCache.d.ts +15 -0
- package/types/Renderer/WebCodecsRendererCache.d.ts.map +1 -0
- package/types/Renderer/WebGLRenderer/index.d.ts +5 -3
- package/types/Renderer/WebGLRenderer/index.d.ts.map +1 -1
- package/types/Renderer/YUVCanvasRenderer/index.d.ts +1 -1
- package/types/Renderer/YUVCanvasRenderer/index.d.ts.map +1 -1
- package/types/Renderer/index.d.ts +0 -1
- package/types/Renderer/index.d.ts.map +1 -1
- package/types/Types.d.ts +99 -8
- package/types/Types.d.ts.map +1 -1
- package/types/Utils.d.ts +4 -0
- package/types/Utils.d.ts.map +1 -1
- package/js/Renderer/IRendererManager.js +0 -229
- package/scripts/publishCN/common.sh +0 -19
- package/scripts/publishCN/rewrite-dep.sh +0 -22
- package/scripts/publishCN/rewrite-example.sh +0 -22
- package/ts/Renderer/IRendererManager.ts +0 -316
- package/types/Renderer/IRendererManager.d.ts +0 -56
- package/types/Renderer/IRendererManager.d.ts.map +0 -1
|
@@ -1,80 +1,301 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.RendererManager = void 0;
|
|
7
|
+
const AgoraSdk_1 = __importDefault(require("../AgoraSdk"));
|
|
8
|
+
const AgoraBase_1 = require("../Private/AgoraBase");
|
|
9
|
+
const AgoraMediaBase_1 = require("../Private/AgoraMediaBase");
|
|
4
10
|
const Types_1 = require("../Types");
|
|
5
11
|
const Utils_1 = require("../Utils");
|
|
6
|
-
const
|
|
12
|
+
const IRendererCache_1 = require("./IRendererCache");
|
|
13
|
+
const RendererCache_1 = require("./RendererCache");
|
|
14
|
+
const WebCodecsRenderer_1 = require("./WebCodecsRenderer");
|
|
15
|
+
const WebCodecsRendererCache_1 = require("./WebCodecsRendererCache");
|
|
7
16
|
const WebGLRenderer_1 = require("./WebGLRenderer");
|
|
8
17
|
const YUVCanvasRenderer_1 = require("./YUVCanvasRenderer");
|
|
9
18
|
/**
|
|
10
19
|
* @ignore
|
|
11
20
|
*/
|
|
12
|
-
class RendererManager
|
|
13
|
-
set rendererType(rendererType) {
|
|
14
|
-
if (this._rendererType !== rendererType) {
|
|
15
|
-
this._rendererType = rendererType;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
get rendererType() {
|
|
19
|
-
return this._rendererType;
|
|
20
|
-
}
|
|
21
|
+
class RendererManager {
|
|
21
22
|
constructor() {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Currently, the remote video frame is observed in the pre-renderer position and you can not change it.
|
|
25
|
+
* the local video frame is observed in the pre-encoder position by default, and you can change it.
|
|
26
|
+
* @ignore
|
|
27
|
+
*/
|
|
28
|
+
this.defaultObservedFramePosition = AgoraMediaBase_1.VideoModulePosition.PositionPreRenderer |
|
|
29
|
+
AgoraMediaBase_1.VideoModulePosition.PositionPreEncoder;
|
|
30
|
+
this.renderingFps = 15;
|
|
31
|
+
this._currentFrameCount = 0;
|
|
32
|
+
this._previousFirstFrameTime = 0;
|
|
33
|
+
this._rendererCaches = [];
|
|
34
|
+
this._context = {
|
|
35
|
+
renderMode: AgoraMediaBase_1.RenderModeType.RenderModeHidden,
|
|
36
|
+
mirrorMode: AgoraBase_1.VideoMirrorModeType.VideoMirrorModeDisabled,
|
|
37
|
+
};
|
|
38
|
+
this.rendererType = (0, Utils_1.isSupportWebGL)()
|
|
24
39
|
? Types_1.RendererType.WEBGL
|
|
25
40
|
: Types_1.RendererType.SOFTWARE;
|
|
26
41
|
}
|
|
27
|
-
|
|
28
|
-
* @deprecated Use rendererType instead
|
|
29
|
-
*/
|
|
30
|
-
setRenderMode(mode) {
|
|
31
|
-
this.rendererType = mode;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* @deprecated Use renderingFps instead
|
|
35
|
-
*/
|
|
36
|
-
setFPS(fps) {
|
|
42
|
+
setRenderingFps(fps) {
|
|
37
43
|
this.renderingFps = fps;
|
|
44
|
+
if (this._renderingTimer) {
|
|
45
|
+
this.stopRendering();
|
|
46
|
+
this.startRendering();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
set defaultChannelId(channelId) {
|
|
50
|
+
this._context.channelId = channelId;
|
|
51
|
+
}
|
|
52
|
+
get defaultChannelId() {
|
|
53
|
+
return this._context.channelId ?? '';
|
|
54
|
+
}
|
|
55
|
+
get defaultRenderMode() {
|
|
56
|
+
return this._context.renderMode;
|
|
57
|
+
}
|
|
58
|
+
get defaultMirrorMode() {
|
|
59
|
+
return this._context.mirrorMode;
|
|
60
|
+
}
|
|
61
|
+
release() {
|
|
62
|
+
this.stopRendering();
|
|
63
|
+
this.clearRendererCache();
|
|
38
64
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
presetRendererContext(context) {
|
|
66
|
+
//this is for preset default value
|
|
67
|
+
context.renderMode = context.renderMode || this.defaultRenderMode;
|
|
68
|
+
context.mirrorMode = context.mirrorMode || this.defaultMirrorMode;
|
|
69
|
+
context.useWebCodecsDecoder = context.useWebCodecsDecoder || false;
|
|
70
|
+
context.enableFps = context.enableFps || false;
|
|
71
|
+
context.position = context.position || this.defaultObservedFramePosition;
|
|
72
|
+
if (!Utils_1.AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) {
|
|
73
|
+
context.useWebCodecsDecoder = false;
|
|
74
|
+
}
|
|
75
|
+
switch (context.sourceType) {
|
|
76
|
+
case AgoraMediaBase_1.VideoSourceType.VideoSourceRemote:
|
|
77
|
+
if (context.uid === undefined) {
|
|
78
|
+
throw new Error('uid is required');
|
|
79
|
+
}
|
|
80
|
+
context.channelId = context.channelId ?? this.defaultChannelId;
|
|
81
|
+
break;
|
|
82
|
+
case AgoraMediaBase_1.VideoSourceType.VideoSourceMediaPlayer:
|
|
83
|
+
if (context.mediaPlayerId === undefined) {
|
|
84
|
+
throw new Error('mediaPlayerId is required');
|
|
85
|
+
}
|
|
86
|
+
context.channelId = '';
|
|
87
|
+
context.uid = context.mediaPlayerId;
|
|
88
|
+
break;
|
|
89
|
+
case undefined:
|
|
90
|
+
if (context.uid) {
|
|
91
|
+
context.sourceType = AgoraMediaBase_1.VideoSourceType.VideoSourceRemote;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
context.channelId = '';
|
|
96
|
+
context.uid = 0;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
return context;
|
|
100
|
+
}
|
|
101
|
+
addOrRemoveRenderer(context) {
|
|
102
|
+
// To be compatible with the old API
|
|
103
|
+
let { setupMode = AgoraBase_1.VideoViewSetupMode.VideoViewSetupAdd } = context;
|
|
104
|
+
if (!context.view)
|
|
105
|
+
setupMode = AgoraBase_1.VideoViewSetupMode.VideoViewSetupRemove;
|
|
106
|
+
switch (setupMode) {
|
|
107
|
+
case AgoraBase_1.VideoViewSetupMode.VideoViewSetupAdd:
|
|
108
|
+
return this.addRendererToCache(context);
|
|
109
|
+
case AgoraBase_1.VideoViewSetupMode.VideoViewSetupRemove:
|
|
110
|
+
this.removeRendererFromCache(context);
|
|
111
|
+
return undefined;
|
|
112
|
+
case AgoraBase_1.VideoViewSetupMode.VideoViewSetupReplace:
|
|
113
|
+
this.removeRendererFromCache(context);
|
|
114
|
+
return this.addRendererToCache(context);
|
|
115
|
+
}
|
|
44
116
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
117
|
+
addRendererToCache(context) {
|
|
118
|
+
const checkedContext = this.presetRendererContext(context);
|
|
119
|
+
if (!checkedContext.view)
|
|
120
|
+
return undefined;
|
|
121
|
+
if (this.findRenderer(checkedContext.view)) {
|
|
122
|
+
throw new Error('You have already added this view to the renderer');
|
|
123
|
+
}
|
|
124
|
+
let rendererCache = this.getRendererCache(checkedContext);
|
|
125
|
+
if (!rendererCache) {
|
|
126
|
+
if (context.useWebCodecsDecoder) {
|
|
127
|
+
rendererCache = new WebCodecsRendererCache_1.WebCodecsRendererCache(checkedContext);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
rendererCache = new RendererCache_1.RendererCache(checkedContext);
|
|
131
|
+
}
|
|
132
|
+
this._rendererCaches.push(rendererCache);
|
|
133
|
+
}
|
|
134
|
+
rendererCache.addRenderer(this.createRenderer(checkedContext));
|
|
135
|
+
if (!context.useWebCodecsDecoder) {
|
|
136
|
+
this.startRendering();
|
|
48
137
|
}
|
|
138
|
+
return rendererCache;
|
|
139
|
+
}
|
|
140
|
+
removeRendererFromCache(context) {
|
|
141
|
+
const checkedContext = this.presetRendererContext(context);
|
|
142
|
+
const rendererCache = this.getRendererCache(checkedContext);
|
|
143
|
+
if (!rendererCache)
|
|
144
|
+
return;
|
|
145
|
+
if (checkedContext.view) {
|
|
146
|
+
const renderer = rendererCache.findRenderer(checkedContext.view);
|
|
147
|
+
if (!renderer)
|
|
148
|
+
return;
|
|
149
|
+
rendererCache.removeRenderer(renderer);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
rendererCache.removeRenderer();
|
|
153
|
+
}
|
|
154
|
+
if (rendererCache.renderers.length === 0) {
|
|
155
|
+
rendererCache.release();
|
|
156
|
+
this._rendererCaches.splice(this._rendererCaches.indexOf(rendererCache), 1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
clearRendererCache() {
|
|
160
|
+
for (const rendererCache of this._rendererCaches) {
|
|
161
|
+
rendererCache.release();
|
|
162
|
+
}
|
|
163
|
+
this._rendererCaches.splice(0);
|
|
164
|
+
}
|
|
165
|
+
getRendererCache(context) {
|
|
166
|
+
return this._rendererCaches.find((cache) => cache.key === (0, IRendererCache_1.generateRendererCacheKey)(context));
|
|
167
|
+
}
|
|
168
|
+
getRenderers(context) {
|
|
169
|
+
return this.getRendererCache(context)?.renderers || [];
|
|
170
|
+
}
|
|
171
|
+
findRenderer(view) {
|
|
172
|
+
for (const rendererCache of this._rendererCaches) {
|
|
173
|
+
const renderer = rendererCache.findRenderer(view);
|
|
174
|
+
if (renderer)
|
|
175
|
+
return renderer;
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
createRenderer(context, rendererType = this.rendererType) {
|
|
49
180
|
let renderer;
|
|
50
181
|
switch (rendererType) {
|
|
51
182
|
case Types_1.RendererType.WEBGL:
|
|
52
|
-
|
|
183
|
+
if (context.useWebCodecsDecoder) {
|
|
184
|
+
renderer = new WebCodecsRenderer_1.WebCodecsRenderer();
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
renderer = new WebGLRenderer_1.WebGLRenderer(this.handleWebGLFallback(context).bind(this));
|
|
188
|
+
renderer.bind(context.view);
|
|
189
|
+
}
|
|
53
190
|
break;
|
|
54
191
|
case Types_1.RendererType.SOFTWARE:
|
|
55
192
|
renderer = new YUVCanvasRenderer_1.YUVCanvasRenderer();
|
|
193
|
+
renderer.bind(context.view);
|
|
56
194
|
break;
|
|
57
195
|
default:
|
|
58
196
|
throw new Error('Unknown renderer type');
|
|
59
197
|
}
|
|
60
|
-
renderer.
|
|
61
|
-
renderer.context = {
|
|
62
|
-
renderMode: context.renderMode,
|
|
63
|
-
mirrorMode: context.mirrorMode,
|
|
64
|
-
};
|
|
198
|
+
renderer.setContext(context);
|
|
65
199
|
return renderer;
|
|
66
200
|
}
|
|
201
|
+
startRendering() {
|
|
202
|
+
if (this._renderingTimer)
|
|
203
|
+
return;
|
|
204
|
+
const renderingLooper = () => {
|
|
205
|
+
if (this._previousFirstFrameTime === 0) {
|
|
206
|
+
// Get the current time as the time of the first frame of per second
|
|
207
|
+
this._previousFirstFrameTime = performance.now();
|
|
208
|
+
// Reset the frame count
|
|
209
|
+
this._currentFrameCount = 0;
|
|
210
|
+
}
|
|
211
|
+
// Increase the frame count
|
|
212
|
+
++this._currentFrameCount;
|
|
213
|
+
// Get the current time
|
|
214
|
+
const currentFrameTime = performance.now();
|
|
215
|
+
// Calculate the time difference between the current frame and the previous frame
|
|
216
|
+
const deltaTime = currentFrameTime - this._previousFirstFrameTime;
|
|
217
|
+
// Calculate the expected time of the current frame
|
|
218
|
+
const expectedTime = (this._currentFrameCount * 1000) / this.renderingFps;
|
|
219
|
+
(0, Utils_1.logDebug)(new Date().toLocaleTimeString(), 'currentFrameCount', this._currentFrameCount, 'expectedTime', expectedTime, 'deltaTime', deltaTime);
|
|
220
|
+
if (this._rendererCaches.length === 0) {
|
|
221
|
+
// If there is no renderer, stop rendering
|
|
222
|
+
this.stopRendering();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
// Render all renderers that do not use WebCodecs
|
|
226
|
+
for (const rendererCache of this._rendererCaches.filter((cache) => cache instanceof RendererCache_1.RendererCache)) {
|
|
227
|
+
this.doRendering(rendererCache);
|
|
228
|
+
}
|
|
229
|
+
if (this._currentFrameCount >= this.renderingFps) {
|
|
230
|
+
this._previousFirstFrameTime = 0;
|
|
231
|
+
}
|
|
232
|
+
if (deltaTime < expectedTime) {
|
|
233
|
+
// If the time difference between the current frame and the previous frame is less than the expected time, then wait for the difference
|
|
234
|
+
this._renderingTimer = window.setTimeout(renderingLooper, expectedTime - deltaTime);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// If the time difference between the current frame and the previous frame is greater than the expected time, then render immediately
|
|
238
|
+
renderingLooper();
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
renderingLooper();
|
|
242
|
+
}
|
|
67
243
|
doRendering(rendererCache) {
|
|
68
244
|
rendererCache.draw();
|
|
69
245
|
}
|
|
70
246
|
handleWebGLFallback(context) {
|
|
71
247
|
return (renderer) => {
|
|
72
|
-
const { context: { renderMode, mirrorMode }, } = renderer;
|
|
73
248
|
const renderers = this.getRenderers(context);
|
|
74
249
|
renderer.unbind();
|
|
75
|
-
const newRenderer = this.createRenderer(
|
|
250
|
+
const newRenderer = this.createRenderer(context, Types_1.RendererType.SOFTWARE);
|
|
76
251
|
renderers.splice(renderers.indexOf(renderer), 1, newRenderer);
|
|
77
252
|
};
|
|
78
253
|
}
|
|
254
|
+
handleWebCodecsFallback(context) {
|
|
255
|
+
let engine = (0, AgoraSdk_1.default)();
|
|
256
|
+
engine.getMediaEngine().unregisterVideoEncodedFrameObserver({});
|
|
257
|
+
if (context.uid) {
|
|
258
|
+
if ((0, IRendererCache_1.isUseConnection)(context)) {
|
|
259
|
+
engine.setRemoteVideoSubscriptionOptionsEx(context.uid, {
|
|
260
|
+
type: AgoraBase_1.VideoStreamType.VideoStreamHigh,
|
|
261
|
+
encodedFrameOnly: false,
|
|
262
|
+
}, {
|
|
263
|
+
channelId: context.channelId,
|
|
264
|
+
localUid: context.localUid,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
engine.setRemoteVideoSubscriptionOptions(context.uid, {
|
|
269
|
+
type: AgoraBase_1.VideoStreamType.VideoStreamHigh,
|
|
270
|
+
encodedFrameOnly: false,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
Utils_1.AgoraEnv.enableWebCodecsDecoder = false;
|
|
275
|
+
Utils_1.AgoraEnv.CapabilityManager?.setWebCodecsDecoderEnabled(false);
|
|
276
|
+
let renderers = this.getRenderers(context);
|
|
277
|
+
for (let renderer of renderers) {
|
|
278
|
+
this.addOrRemoveRenderer({
|
|
279
|
+
...renderer.context,
|
|
280
|
+
setupMode: AgoraBase_1.VideoViewSetupMode.VideoViewSetupReplace,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
stopRendering() {
|
|
285
|
+
if (this._renderingTimer) {
|
|
286
|
+
window.clearTimeout(this._renderingTimer);
|
|
287
|
+
this._renderingTimer = undefined;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
setRendererContext(context) {
|
|
291
|
+
const checkedContext = this.presetRendererContext(context);
|
|
292
|
+
for (const rendererCache of this._rendererCaches) {
|
|
293
|
+
const result = rendererCache.setRendererContext(checkedContext);
|
|
294
|
+
if (result) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
79
300
|
}
|
|
80
301
|
exports.RendererManager = RendererManager;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebCodecsRenderer = void 0;
|
|
4
|
+
const Types_1 = require("../../Types");
|
|
5
|
+
const Utils_1 = require("../../Utils");
|
|
6
|
+
const IRenderer_1 = require("../IRenderer");
|
|
7
|
+
class WebCodecsRenderer extends IRenderer_1.IRenderer {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.rendererType = Types_1.RendererType.WEBCODECSRENDERER;
|
|
11
|
+
}
|
|
12
|
+
bind(element) {
|
|
13
|
+
super.bind(element);
|
|
14
|
+
if (!this.canvas)
|
|
15
|
+
return;
|
|
16
|
+
this.offscreenCanvas = this.canvas.transferControlToOffscreen();
|
|
17
|
+
this.gl = (0, Utils_1.getContextByCanvas)(this.offscreenCanvas);
|
|
18
|
+
if (!this.gl)
|
|
19
|
+
return;
|
|
20
|
+
const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER);
|
|
21
|
+
if (!vertexShader)
|
|
22
|
+
return;
|
|
23
|
+
this.gl.shaderSource(vertexShader, WebCodecsRenderer.vertexShaderSource);
|
|
24
|
+
this.gl.compileShader(vertexShader);
|
|
25
|
+
if (!this.gl.getShaderParameter(vertexShader, this.gl.COMPILE_STATUS)) {
|
|
26
|
+
throw this.gl.getShaderInfoLog(vertexShader);
|
|
27
|
+
}
|
|
28
|
+
const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
|
|
29
|
+
if (!fragmentShader)
|
|
30
|
+
return;
|
|
31
|
+
this.gl.shaderSource(fragmentShader, WebCodecsRenderer.fragmentShaderSource);
|
|
32
|
+
this.gl.compileShader(fragmentShader);
|
|
33
|
+
if (!this.gl.getShaderParameter(fragmentShader, this.gl.COMPILE_STATUS)) {
|
|
34
|
+
throw this.gl.getShaderInfoLog(fragmentShader);
|
|
35
|
+
}
|
|
36
|
+
const shaderProgram = this.gl.createProgram();
|
|
37
|
+
if (!shaderProgram)
|
|
38
|
+
return;
|
|
39
|
+
this.gl.attachShader(shaderProgram, vertexShader);
|
|
40
|
+
this.gl.attachShader(shaderProgram, fragmentShader);
|
|
41
|
+
this.gl.linkProgram(shaderProgram);
|
|
42
|
+
if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) {
|
|
43
|
+
throw this.gl.getProgramInfoLog(shaderProgram);
|
|
44
|
+
}
|
|
45
|
+
this.gl.useProgram(shaderProgram);
|
|
46
|
+
// Vertex coordinates, clockwise from bottom-left.
|
|
47
|
+
const vertexBuffer = this.gl.createBuffer();
|
|
48
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer);
|
|
49
|
+
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, -1.0, +1.0, +1.0, +1.0, +1.0, -1.0]), this.gl.STATIC_DRAW);
|
|
50
|
+
const xyLocation = this.gl.getAttribLocation(shaderProgram, 'xy');
|
|
51
|
+
this.gl.vertexAttribPointer(xyLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
52
|
+
this.gl.enableVertexAttribArray(xyLocation);
|
|
53
|
+
// Create one texture to upload frames to.
|
|
54
|
+
const texture = this.gl.createTexture();
|
|
55
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
56
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
57
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
58
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
59
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
60
|
+
}
|
|
61
|
+
drawFrame(frame, _codecConfig) {
|
|
62
|
+
if (!this.offscreenCanvas || !frame)
|
|
63
|
+
return;
|
|
64
|
+
this.offscreenCanvas.width = _codecConfig.codedWidth;
|
|
65
|
+
this.offscreenCanvas.height = _codecConfig.codedHeight;
|
|
66
|
+
this.updateRenderMode();
|
|
67
|
+
this.rotateCanvas({
|
|
68
|
+
rotation: _codecConfig.rotation,
|
|
69
|
+
});
|
|
70
|
+
if (!this.gl)
|
|
71
|
+
return;
|
|
72
|
+
if (this.gl) {
|
|
73
|
+
// Upload the frame.
|
|
74
|
+
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, frame);
|
|
75
|
+
frame.close();
|
|
76
|
+
// Configure and clear the drawing area.
|
|
77
|
+
this.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);
|
|
78
|
+
this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
|
79
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
80
|
+
// Draw the frame.
|
|
81
|
+
this.gl.drawArrays(this.gl.TRIANGLE_FAN, 0, 4);
|
|
82
|
+
}
|
|
83
|
+
super.drawFrame();
|
|
84
|
+
this.getFps();
|
|
85
|
+
}
|
|
86
|
+
rotateCanvas({ rotation }) {
|
|
87
|
+
if (!this.offscreenCanvas || !this.canvas)
|
|
88
|
+
return;
|
|
89
|
+
this.canvas.style.transform += ` rotateZ(${rotation}deg)`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.WebCodecsRenderer = WebCodecsRenderer;
|
|
93
|
+
WebCodecsRenderer.vertexShaderSource = `
|
|
94
|
+
attribute vec2 xy;
|
|
95
|
+
varying highp vec2 uv;
|
|
96
|
+
void main(void) {
|
|
97
|
+
gl_Position = vec4(xy, 0.0, 1.0);
|
|
98
|
+
// Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1).
|
|
99
|
+
// UV coordinates are Y-flipped relative to vertex coordinates.
|
|
100
|
+
uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0);
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
WebCodecsRenderer.fragmentShaderSource = `
|
|
104
|
+
varying highp vec2 uv;
|
|
105
|
+
uniform sampler2D texture;
|
|
106
|
+
void main(void) {
|
|
107
|
+
gl_FragColor = texture2D(texture, uv);
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
exports.WebCodecsRendererCache = void 0;
|
|
7
|
+
const AgoraSdk_1 = __importDefault(require("../AgoraSdk"));
|
|
8
|
+
const index_1 = require("../Decoder/index");
|
|
9
|
+
const AgoraBase_1 = require("../Private/AgoraBase");
|
|
10
|
+
const IrisApiEngine_1 = require("../Private/internal/IrisApiEngine");
|
|
11
|
+
const Types_1 = require("../Types");
|
|
12
|
+
const Utils_1 = require("../Utils");
|
|
13
|
+
const IRendererCache_1 = require("./IRendererCache");
|
|
14
|
+
class WebCodecsRendererCache extends IRendererCache_1.IRendererCache {
|
|
15
|
+
constructor(context) {
|
|
16
|
+
super(context);
|
|
17
|
+
this._firstFrame = true;
|
|
18
|
+
this._engine = (0, AgoraSdk_1.default)();
|
|
19
|
+
this._decoder = new index_1.WebCodecsDecoder(this.renderers, this.onDecoderError.bind(this), context);
|
|
20
|
+
this.draw();
|
|
21
|
+
}
|
|
22
|
+
onDecoderError(e) {
|
|
23
|
+
(0, Utils_1.logInfo)('webCodecsDecoder decode failed, fallback to native decoder', e);
|
|
24
|
+
Utils_1.AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext);
|
|
25
|
+
}
|
|
26
|
+
onEncodedVideoFrameReceived(...[data, buffer]) {
|
|
27
|
+
let _data;
|
|
28
|
+
try {
|
|
29
|
+
_data = JSON.parse(data) ?? {};
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
_data = {};
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(_data).length === 0 ||
|
|
35
|
+
!this._decoder ||
|
|
36
|
+
this.cacheContext.uid !== _data.uid)
|
|
37
|
+
return;
|
|
38
|
+
if (this._firstFrame) {
|
|
39
|
+
for (let renderer of this.renderers) {
|
|
40
|
+
if (renderer.rendererType !== Types_1.RendererType.WEBCODECSRENDERER) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
renderer.bind(renderer.context.view);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
this._decoder.decoderConfigure(_data.videoEncodedFrameInfo);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
(0, Utils_1.logInfo)(error);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this._firstFrame = false;
|
|
53
|
+
}
|
|
54
|
+
if (this.shouldFallback(_data.videoEncodedFrameInfo)) {
|
|
55
|
+
Utils_1.AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this._decoder.decodeFrame(buffer, _data.videoEncodedFrameInfo, new Date().getTime());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
draw() {
|
|
62
|
+
if ((0, IRendererCache_1.isUseConnection)(this.cacheContext)) {
|
|
63
|
+
this._engine?.setRemoteVideoSubscriptionOptionsEx(this.cacheContext.uid, {
|
|
64
|
+
type: AgoraBase_1.VideoStreamType.VideoStreamHigh,
|
|
65
|
+
encodedFrameOnly: true,
|
|
66
|
+
}, {
|
|
67
|
+
channelId: this.cacheContext.channelId,
|
|
68
|
+
localUid: this.cacheContext.localUid,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this._engine?.setRemoteVideoSubscriptionOptions(this.cacheContext.uid, {
|
|
73
|
+
type: AgoraBase_1.VideoStreamType.VideoStreamHigh,
|
|
74
|
+
encodedFrameOnly: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
IrisApiEngine_1.AgoraElectronBridge.OnEvent(`call_back_with_encoded_video_frame_${this.cacheContext.uid}`, (...params) => {
|
|
78
|
+
try {
|
|
79
|
+
this.onEncodedVideoFrameReceived(...params);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
console.error(e);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
shouldFallback(frameInfo) {
|
|
87
|
+
let shouldFallback = false;
|
|
88
|
+
if (!frameInfo.codecType) {
|
|
89
|
+
shouldFallback = true;
|
|
90
|
+
(0, Utils_1.logInfo)('codecType is not supported, fallback to native decoder');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const mapping = Utils_1.AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType];
|
|
94
|
+
if (mapping === undefined) {
|
|
95
|
+
shouldFallback = true;
|
|
96
|
+
(0, Utils_1.logInfo)('codecType is not supported, fallback to native decoder');
|
|
97
|
+
}
|
|
98
|
+
else if (mapping.minWidth >= frameInfo.width &&
|
|
99
|
+
mapping.minHeight >= frameInfo.height &&
|
|
100
|
+
mapping.maxWidth <= frameInfo.width &&
|
|
101
|
+
mapping.maxHeight <= frameInfo.height) {
|
|
102
|
+
shouldFallback = true;
|
|
103
|
+
(0, Utils_1.logInfo)('frame size is not supported, fallback to native decoder');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return shouldFallback;
|
|
107
|
+
}
|
|
108
|
+
release() {
|
|
109
|
+
IrisApiEngine_1.AgoraElectronBridge.UnEvent(`call_back_with_encoded_video_frame_${this.cacheContext.uid}`);
|
|
110
|
+
this._decoder?.release();
|
|
111
|
+
this._decoder = null;
|
|
112
|
+
super.release();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.WebCodecsRendererCache = WebCodecsRendererCache;
|