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,110 +1,400 @@
|
|
|
1
|
+
import createAgoraRtcEngine from '../AgoraSdk';
|
|
2
|
+
import {
|
|
3
|
+
VideoMirrorModeType,
|
|
4
|
+
VideoStreamType,
|
|
5
|
+
VideoViewSetupMode,
|
|
6
|
+
} from '../Private/AgoraBase';
|
|
7
|
+
import {
|
|
8
|
+
RenderModeType,
|
|
9
|
+
VideoModulePosition,
|
|
10
|
+
VideoSourceType,
|
|
11
|
+
} from '../Private/AgoraMediaBase';
|
|
1
12
|
import {
|
|
2
|
-
RENDER_MODE,
|
|
3
13
|
RendererCacheContext,
|
|
14
|
+
RendererCacheType,
|
|
4
15
|
RendererContext,
|
|
5
16
|
RendererType,
|
|
6
17
|
} from '../Types';
|
|
7
|
-
import { isSupportWebGL } from '../Utils';
|
|
18
|
+
import { AgoraEnv, isSupportWebGL, logDebug } from '../Utils';
|
|
8
19
|
|
|
9
20
|
import { IRenderer } from './IRenderer';
|
|
10
|
-
import {
|
|
21
|
+
import { generateRendererCacheKey, isUseConnection } from './IRendererCache';
|
|
11
22
|
import { RendererCache } from './RendererCache';
|
|
23
|
+
import { WebCodecsRenderer } from './WebCodecsRenderer';
|
|
24
|
+
import { WebCodecsRendererCache } from './WebCodecsRendererCache';
|
|
12
25
|
import { WebGLFallback, WebGLRenderer } from './WebGLRenderer';
|
|
13
26
|
import { YUVCanvasRenderer } from './YUVCanvasRenderer';
|
|
14
27
|
|
|
15
28
|
/**
|
|
16
29
|
* @ignore
|
|
17
30
|
*/
|
|
18
|
-
export class RendererManager
|
|
31
|
+
export class RendererManager {
|
|
32
|
+
/**
|
|
33
|
+
* @ignore
|
|
34
|
+
*/
|
|
35
|
+
private renderingFps: number;
|
|
36
|
+
/**
|
|
37
|
+
* @ignore
|
|
38
|
+
*/
|
|
39
|
+
private _currentFrameCount: number;
|
|
40
|
+
/**
|
|
41
|
+
* @ignore
|
|
42
|
+
*/
|
|
43
|
+
private _previousFirstFrameTime: number;
|
|
44
|
+
/**
|
|
45
|
+
* @ignore
|
|
46
|
+
*/
|
|
47
|
+
private _renderingTimer?: number;
|
|
19
48
|
/**
|
|
20
49
|
* @ignore
|
|
21
50
|
*/
|
|
22
|
-
private
|
|
51
|
+
private _rendererCaches: RendererCacheType[];
|
|
52
|
+
/**
|
|
53
|
+
* @ignore
|
|
54
|
+
*/
|
|
55
|
+
private _context: RendererContext;
|
|
23
56
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
57
|
+
/**
|
|
58
|
+
* @ignore
|
|
59
|
+
*/
|
|
60
|
+
private rendererType: RendererType;
|
|
29
61
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Currently, the remote video frame is observed in the pre-renderer position and you can not change it.
|
|
64
|
+
* the local video frame is observed in the pre-encoder position by default, and you can change it.
|
|
65
|
+
* @ignore
|
|
66
|
+
*/
|
|
67
|
+
private defaultObservedFramePosition: number =
|
|
68
|
+
VideoModulePosition.PositionPreRenderer |
|
|
69
|
+
VideoModulePosition.PositionPreEncoder;
|
|
33
70
|
|
|
34
71
|
constructor() {
|
|
35
|
-
|
|
36
|
-
this.
|
|
72
|
+
this.renderingFps = 15;
|
|
73
|
+
this._currentFrameCount = 0;
|
|
74
|
+
this._previousFirstFrameTime = 0;
|
|
75
|
+
this._rendererCaches = [];
|
|
76
|
+
this._context = {
|
|
77
|
+
renderMode: RenderModeType.RenderModeHidden,
|
|
78
|
+
mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled,
|
|
79
|
+
};
|
|
80
|
+
this.rendererType = isSupportWebGL()
|
|
37
81
|
? RendererType.WEBGL
|
|
38
82
|
: RendererType.SOFTWARE;
|
|
39
83
|
}
|
|
40
84
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
public setRenderingFps(fps: number) {
|
|
86
|
+
this.renderingFps = fps;
|
|
87
|
+
if (this._renderingTimer) {
|
|
88
|
+
this.stopRendering();
|
|
89
|
+
this.startRendering();
|
|
90
|
+
}
|
|
46
91
|
}
|
|
47
92
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*/
|
|
51
|
-
public setFPS(fps: number) {
|
|
52
|
-
this.renderingFps = fps;
|
|
93
|
+
public set defaultChannelId(channelId: string) {
|
|
94
|
+
this._context.channelId = channelId;
|
|
53
95
|
}
|
|
54
96
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*/
|
|
58
|
-
public getRender(context: RendererCacheContext): RendererCache | undefined {
|
|
59
|
-
return this.getRendererCache(context);
|
|
97
|
+
public get defaultChannelId(): string {
|
|
98
|
+
return this._context.channelId ?? '';
|
|
60
99
|
}
|
|
61
100
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
public get defaultRenderMode(): RenderModeType {
|
|
102
|
+
return this._context.renderMode!;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public get defaultMirrorMode(): VideoMirrorModeType {
|
|
106
|
+
return this._context.mirrorMode!;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public release(): void {
|
|
110
|
+
this.stopRendering();
|
|
111
|
+
this.clearRendererCache();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private presetRendererContext(context: RendererContext): RendererContext {
|
|
115
|
+
//this is for preset default value
|
|
116
|
+
context.renderMode = context.renderMode || this.defaultRenderMode;
|
|
117
|
+
context.mirrorMode = context.mirrorMode || this.defaultMirrorMode;
|
|
118
|
+
context.useWebCodecsDecoder = context.useWebCodecsDecoder || false;
|
|
119
|
+
context.enableFps = context.enableFps || false;
|
|
120
|
+
context.position = context.position || this.defaultObservedFramePosition;
|
|
121
|
+
|
|
122
|
+
if (!AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) {
|
|
123
|
+
context.useWebCodecsDecoder = false;
|
|
68
124
|
}
|
|
69
125
|
|
|
126
|
+
switch (context.sourceType) {
|
|
127
|
+
case VideoSourceType.VideoSourceRemote:
|
|
128
|
+
if (context.uid === undefined) {
|
|
129
|
+
throw new Error('uid is required');
|
|
130
|
+
}
|
|
131
|
+
context.channelId = context.channelId ?? this.defaultChannelId;
|
|
132
|
+
break;
|
|
133
|
+
case VideoSourceType.VideoSourceMediaPlayer:
|
|
134
|
+
if (context.mediaPlayerId === undefined) {
|
|
135
|
+
throw new Error('mediaPlayerId is required');
|
|
136
|
+
}
|
|
137
|
+
context.channelId = '';
|
|
138
|
+
context.uid = context.mediaPlayerId;
|
|
139
|
+
break;
|
|
140
|
+
case undefined:
|
|
141
|
+
if (context.uid) {
|
|
142
|
+
context.sourceType = VideoSourceType.VideoSourceRemote;
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
context.channelId = '';
|
|
147
|
+
context.uid = 0;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
return context;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public addOrRemoveRenderer(
|
|
154
|
+
context: RendererContext
|
|
155
|
+
): RendererCacheType | undefined {
|
|
156
|
+
// To be compatible with the old API
|
|
157
|
+
let { setupMode = VideoViewSetupMode.VideoViewSetupAdd } = context;
|
|
158
|
+
if (!context.view) setupMode = VideoViewSetupMode.VideoViewSetupRemove;
|
|
159
|
+
switch (setupMode) {
|
|
160
|
+
case VideoViewSetupMode.VideoViewSetupAdd:
|
|
161
|
+
return this.addRendererToCache(context);
|
|
162
|
+
case VideoViewSetupMode.VideoViewSetupRemove:
|
|
163
|
+
this.removeRendererFromCache(context);
|
|
164
|
+
return undefined;
|
|
165
|
+
case VideoViewSetupMode.VideoViewSetupReplace:
|
|
166
|
+
this.removeRendererFromCache(context);
|
|
167
|
+
return this.addRendererToCache(context);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private addRendererToCache(
|
|
172
|
+
context: RendererContext
|
|
173
|
+
): RendererCacheType | undefined {
|
|
174
|
+
const checkedContext = this.presetRendererContext(context);
|
|
175
|
+
|
|
176
|
+
if (!checkedContext.view) return undefined;
|
|
177
|
+
|
|
178
|
+
if (this.findRenderer(checkedContext.view)) {
|
|
179
|
+
throw new Error('You have already added this view to the renderer');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let rendererCache = this.getRendererCache(checkedContext);
|
|
183
|
+
if (!rendererCache) {
|
|
184
|
+
if (context.useWebCodecsDecoder) {
|
|
185
|
+
rendererCache = new WebCodecsRendererCache(checkedContext);
|
|
186
|
+
} else {
|
|
187
|
+
rendererCache = new RendererCache(checkedContext);
|
|
188
|
+
}
|
|
189
|
+
this._rendererCaches.push(rendererCache);
|
|
190
|
+
}
|
|
191
|
+
rendererCache.addRenderer(this.createRenderer(checkedContext));
|
|
192
|
+
if (!context.useWebCodecsDecoder) {
|
|
193
|
+
this.startRendering();
|
|
194
|
+
}
|
|
195
|
+
return rendererCache;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public removeRendererFromCache(context: RendererContext): void {
|
|
199
|
+
const checkedContext = this.presetRendererContext(context);
|
|
200
|
+
|
|
201
|
+
const rendererCache = this.getRendererCache(checkedContext);
|
|
202
|
+
if (!rendererCache) return;
|
|
203
|
+
if (checkedContext.view) {
|
|
204
|
+
const renderer = rendererCache.findRenderer(checkedContext.view);
|
|
205
|
+
if (!renderer) return;
|
|
206
|
+
rendererCache.removeRenderer(renderer);
|
|
207
|
+
} else {
|
|
208
|
+
rendererCache.removeRenderer();
|
|
209
|
+
}
|
|
210
|
+
if (rendererCache.renderers.length === 0) {
|
|
211
|
+
rendererCache.release();
|
|
212
|
+
this._rendererCaches.splice(
|
|
213
|
+
this._rendererCaches.indexOf(rendererCache),
|
|
214
|
+
1
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public clearRendererCache(): void {
|
|
220
|
+
for (const rendererCache of this._rendererCaches) {
|
|
221
|
+
rendererCache.release();
|
|
222
|
+
}
|
|
223
|
+
this._rendererCaches.splice(0);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public getRendererCache(
|
|
227
|
+
context: RendererContext
|
|
228
|
+
): RendererCacheType | undefined {
|
|
229
|
+
return this._rendererCaches.find(
|
|
230
|
+
(cache) => cache.key === generateRendererCacheKey(context)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
public getRenderers(context: RendererContext): IRenderer[] {
|
|
235
|
+
return this.getRendererCache(context)?.renderers || [];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public findRenderer(view: Element): IRenderer | undefined {
|
|
239
|
+
for (const rendererCache of this._rendererCaches) {
|
|
240
|
+
const renderer = rendererCache.findRenderer(view);
|
|
241
|
+
if (renderer) return renderer;
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
protected createRenderer(
|
|
247
|
+
context: RendererContext,
|
|
248
|
+
rendererType: RendererType = this.rendererType
|
|
249
|
+
): IRenderer {
|
|
70
250
|
let renderer: IRenderer;
|
|
71
251
|
switch (rendererType) {
|
|
72
252
|
case RendererType.WEBGL:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
253
|
+
if (context.useWebCodecsDecoder) {
|
|
254
|
+
renderer = new WebCodecsRenderer();
|
|
255
|
+
} else {
|
|
256
|
+
renderer = new WebGLRenderer(
|
|
257
|
+
this.handleWebGLFallback(context).bind(this)
|
|
258
|
+
);
|
|
259
|
+
renderer.bind(context.view);
|
|
260
|
+
}
|
|
76
261
|
break;
|
|
77
262
|
case RendererType.SOFTWARE:
|
|
78
263
|
renderer = new YUVCanvasRenderer();
|
|
264
|
+
renderer.bind(context.view);
|
|
79
265
|
break;
|
|
80
266
|
default:
|
|
81
267
|
throw new Error('Unknown renderer type');
|
|
82
268
|
}
|
|
83
269
|
|
|
84
|
-
renderer.
|
|
85
|
-
renderer.context = {
|
|
86
|
-
renderMode: context.renderMode,
|
|
87
|
-
mirrorMode: context.mirrorMode,
|
|
88
|
-
};
|
|
270
|
+
renderer.setContext(context);
|
|
89
271
|
return renderer;
|
|
90
272
|
}
|
|
91
273
|
|
|
92
|
-
public
|
|
274
|
+
public startRendering(): void {
|
|
275
|
+
if (this._renderingTimer) return;
|
|
276
|
+
|
|
277
|
+
const renderingLooper = () => {
|
|
278
|
+
if (this._previousFirstFrameTime === 0) {
|
|
279
|
+
// Get the current time as the time of the first frame of per second
|
|
280
|
+
this._previousFirstFrameTime = performance.now();
|
|
281
|
+
// Reset the frame count
|
|
282
|
+
this._currentFrameCount = 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Increase the frame count
|
|
286
|
+
++this._currentFrameCount;
|
|
287
|
+
|
|
288
|
+
// Get the current time
|
|
289
|
+
const currentFrameTime = performance.now();
|
|
290
|
+
// Calculate the time difference between the current frame and the previous frame
|
|
291
|
+
const deltaTime = currentFrameTime - this._previousFirstFrameTime;
|
|
292
|
+
// Calculate the expected time of the current frame
|
|
293
|
+
const expectedTime = (this._currentFrameCount * 1000) / this.renderingFps;
|
|
294
|
+
logDebug(
|
|
295
|
+
new Date().toLocaleTimeString(),
|
|
296
|
+
'currentFrameCount',
|
|
297
|
+
this._currentFrameCount,
|
|
298
|
+
'expectedTime',
|
|
299
|
+
expectedTime,
|
|
300
|
+
'deltaTime',
|
|
301
|
+
deltaTime
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
if (this._rendererCaches.length === 0) {
|
|
305
|
+
// If there is no renderer, stop rendering
|
|
306
|
+
this.stopRendering();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Render all renderers that do not use WebCodecs
|
|
311
|
+
for (const rendererCache of this._rendererCaches.filter(
|
|
312
|
+
(cache) => cache instanceof RendererCache
|
|
313
|
+
)) {
|
|
314
|
+
this.doRendering(rendererCache);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (this._currentFrameCount >= this.renderingFps) {
|
|
318
|
+
this._previousFirstFrameTime = 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (deltaTime < expectedTime) {
|
|
322
|
+
// If the time difference between the current frame and the previous frame is less than the expected time, then wait for the difference
|
|
323
|
+
this._renderingTimer = window.setTimeout(
|
|
324
|
+
renderingLooper,
|
|
325
|
+
expectedTime - deltaTime
|
|
326
|
+
);
|
|
327
|
+
} else {
|
|
328
|
+
// If the time difference between the current frame and the previous frame is greater than the expected time, then render immediately
|
|
329
|
+
renderingLooper();
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
renderingLooper();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
public doRendering(rendererCache: RendererCacheType): void {
|
|
93
336
|
rendererCache.draw();
|
|
94
337
|
}
|
|
95
338
|
|
|
96
339
|
private handleWebGLFallback(context: RendererContext): WebGLFallback {
|
|
97
340
|
return (renderer: WebGLRenderer) => {
|
|
98
|
-
const {
|
|
99
|
-
context: { renderMode, mirrorMode },
|
|
100
|
-
} = renderer;
|
|
101
341
|
const renderers = this.getRenderers(context);
|
|
102
342
|
renderer.unbind();
|
|
103
|
-
const newRenderer = this.createRenderer(
|
|
104
|
-
{ ...context, renderMode, mirrorMode },
|
|
105
|
-
RendererType.SOFTWARE
|
|
106
|
-
);
|
|
343
|
+
const newRenderer = this.createRenderer(context, RendererType.SOFTWARE);
|
|
107
344
|
renderers.splice(renderers.indexOf(renderer), 1, newRenderer);
|
|
108
345
|
};
|
|
109
346
|
}
|
|
347
|
+
|
|
348
|
+
public handleWebCodecsFallback(context: RendererCacheContext): void {
|
|
349
|
+
let engine = createAgoraRtcEngine();
|
|
350
|
+
engine.getMediaEngine().unregisterVideoEncodedFrameObserver({});
|
|
351
|
+
if (context.uid) {
|
|
352
|
+
if (isUseConnection(context)) {
|
|
353
|
+
engine.setRemoteVideoSubscriptionOptionsEx(
|
|
354
|
+
context.uid,
|
|
355
|
+
{
|
|
356
|
+
type: VideoStreamType.VideoStreamHigh,
|
|
357
|
+
encodedFrameOnly: false,
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
channelId: context.channelId,
|
|
361
|
+
localUid: context.localUid,
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
} else {
|
|
365
|
+
engine.setRemoteVideoSubscriptionOptions(context.uid, {
|
|
366
|
+
type: VideoStreamType.VideoStreamHigh,
|
|
367
|
+
encodedFrameOnly: false,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
AgoraEnv.enableWebCodecsDecoder = false;
|
|
372
|
+
AgoraEnv.CapabilityManager?.setWebCodecsDecoderEnabled(false);
|
|
373
|
+
let renderers = this.getRenderers(context);
|
|
374
|
+
for (let renderer of renderers) {
|
|
375
|
+
this.addOrRemoveRenderer({
|
|
376
|
+
...renderer.context,
|
|
377
|
+
setupMode: VideoViewSetupMode.VideoViewSetupReplace,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public stopRendering(): void {
|
|
383
|
+
if (this._renderingTimer) {
|
|
384
|
+
window.clearTimeout(this._renderingTimer);
|
|
385
|
+
this._renderingTimer = undefined;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public setRendererContext(context: RendererContext): boolean {
|
|
390
|
+
const checkedContext = this.presetRendererContext(context);
|
|
391
|
+
|
|
392
|
+
for (const rendererCache of this._rendererCaches) {
|
|
393
|
+
const result = rendererCache.setRendererContext(checkedContext);
|
|
394
|
+
if (result) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
110
400
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { VideoFrame } from '../../Private/AgoraMediaBase';
|
|
2
|
+
import { CodecConfigInfo, RendererType } from '../../Types';
|
|
3
|
+
import { getContextByCanvas } from '../../Utils';
|
|
4
|
+
import { IRenderer } from '../IRenderer';
|
|
5
|
+
|
|
6
|
+
export class WebCodecsRenderer extends IRenderer {
|
|
7
|
+
gl?: WebGLRenderingContext | WebGL2RenderingContext | null;
|
|
8
|
+
// eslint-disable-next-line auto-import/auto-import
|
|
9
|
+
offscreenCanvas: OffscreenCanvas | undefined;
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this.rendererType = RendererType.WEBCODECSRENDERER;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static vertexShaderSource = `
|
|
17
|
+
attribute vec2 xy;
|
|
18
|
+
varying highp vec2 uv;
|
|
19
|
+
void main(void) {
|
|
20
|
+
gl_Position = vec4(xy, 0.0, 1.0);
|
|
21
|
+
// Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1).
|
|
22
|
+
// UV coordinates are Y-flipped relative to vertex coordinates.
|
|
23
|
+
uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0);
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
static fragmentShaderSource = `
|
|
27
|
+
varying highp vec2 uv;
|
|
28
|
+
uniform sampler2D texture;
|
|
29
|
+
void main(void) {
|
|
30
|
+
gl_FragColor = texture2D(texture, uv);
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
bind(element: HTMLElement) {
|
|
35
|
+
super.bind(element);
|
|
36
|
+
if (!this.canvas) return;
|
|
37
|
+
this.offscreenCanvas = this.canvas.transferControlToOffscreen();
|
|
38
|
+
this.gl = getContextByCanvas(this.offscreenCanvas);
|
|
39
|
+
if (!this.gl) return;
|
|
40
|
+
const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER);
|
|
41
|
+
if (!vertexShader) return;
|
|
42
|
+
this.gl.shaderSource(vertexShader, WebCodecsRenderer.vertexShaderSource);
|
|
43
|
+
this.gl.compileShader(vertexShader);
|
|
44
|
+
if (!this.gl.getShaderParameter(vertexShader, this.gl.COMPILE_STATUS)) {
|
|
45
|
+
throw this.gl.getShaderInfoLog(vertexShader);
|
|
46
|
+
}
|
|
47
|
+
const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
|
|
48
|
+
if (!fragmentShader) return;
|
|
49
|
+
this.gl.shaderSource(
|
|
50
|
+
fragmentShader,
|
|
51
|
+
WebCodecsRenderer.fragmentShaderSource
|
|
52
|
+
);
|
|
53
|
+
this.gl.compileShader(fragmentShader);
|
|
54
|
+
if (!this.gl.getShaderParameter(fragmentShader, this.gl.COMPILE_STATUS)) {
|
|
55
|
+
throw this.gl.getShaderInfoLog(fragmentShader);
|
|
56
|
+
}
|
|
57
|
+
const shaderProgram = this.gl.createProgram();
|
|
58
|
+
if (!shaderProgram) return;
|
|
59
|
+
this.gl.attachShader(shaderProgram, vertexShader);
|
|
60
|
+
this.gl.attachShader(shaderProgram, fragmentShader);
|
|
61
|
+
this.gl.linkProgram(shaderProgram);
|
|
62
|
+
if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) {
|
|
63
|
+
throw this.gl.getProgramInfoLog(shaderProgram);
|
|
64
|
+
}
|
|
65
|
+
this.gl.useProgram(shaderProgram);
|
|
66
|
+
// Vertex coordinates, clockwise from bottom-left.
|
|
67
|
+
const vertexBuffer = this.gl.createBuffer();
|
|
68
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer);
|
|
69
|
+
this.gl.bufferData(
|
|
70
|
+
this.gl.ARRAY_BUFFER,
|
|
71
|
+
new Float32Array([-1.0, -1.0, -1.0, +1.0, +1.0, +1.0, +1.0, -1.0]),
|
|
72
|
+
this.gl.STATIC_DRAW
|
|
73
|
+
);
|
|
74
|
+
const xyLocation = this.gl.getAttribLocation(shaderProgram, 'xy');
|
|
75
|
+
this.gl.vertexAttribPointer(xyLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
76
|
+
this.gl.enableVertexAttribArray(xyLocation);
|
|
77
|
+
// Create one texture to upload frames to.
|
|
78
|
+
const texture = this.gl.createTexture();
|
|
79
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
80
|
+
this.gl.texParameteri(
|
|
81
|
+
this.gl.TEXTURE_2D,
|
|
82
|
+
this.gl.TEXTURE_MAG_FILTER,
|
|
83
|
+
this.gl.NEAREST
|
|
84
|
+
);
|
|
85
|
+
this.gl.texParameteri(
|
|
86
|
+
this.gl.TEXTURE_2D,
|
|
87
|
+
this.gl.TEXTURE_MIN_FILTER,
|
|
88
|
+
this.gl.NEAREST
|
|
89
|
+
);
|
|
90
|
+
this.gl.texParameteri(
|
|
91
|
+
this.gl.TEXTURE_2D,
|
|
92
|
+
this.gl.TEXTURE_WRAP_S,
|
|
93
|
+
this.gl.CLAMP_TO_EDGE
|
|
94
|
+
);
|
|
95
|
+
this.gl.texParameteri(
|
|
96
|
+
this.gl.TEXTURE_2D,
|
|
97
|
+
this.gl.TEXTURE_WRAP_T,
|
|
98
|
+
this.gl.CLAMP_TO_EDGE
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
drawFrame(frame: any, _codecConfig: CodecConfigInfo) {
|
|
103
|
+
if (!this.offscreenCanvas || !frame) return;
|
|
104
|
+
|
|
105
|
+
this.offscreenCanvas.width = _codecConfig.codedWidth!;
|
|
106
|
+
this.offscreenCanvas.height = _codecConfig.codedHeight!;
|
|
107
|
+
|
|
108
|
+
this.updateRenderMode();
|
|
109
|
+
this.rotateCanvas({
|
|
110
|
+
rotation: _codecConfig.rotation,
|
|
111
|
+
});
|
|
112
|
+
if (!this.gl) return;
|
|
113
|
+
|
|
114
|
+
if (this.gl) {
|
|
115
|
+
// Upload the frame.
|
|
116
|
+
this.gl.texImage2D(
|
|
117
|
+
this.gl.TEXTURE_2D,
|
|
118
|
+
0,
|
|
119
|
+
this.gl.RGBA,
|
|
120
|
+
this.gl.RGBA,
|
|
121
|
+
this.gl.UNSIGNED_BYTE,
|
|
122
|
+
frame
|
|
123
|
+
);
|
|
124
|
+
frame.close();
|
|
125
|
+
// Configure and clear the drawing area.
|
|
126
|
+
this.gl.viewport(
|
|
127
|
+
0,
|
|
128
|
+
0,
|
|
129
|
+
this.gl.drawingBufferWidth,
|
|
130
|
+
this.gl.drawingBufferHeight
|
|
131
|
+
);
|
|
132
|
+
this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
|
133
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
134
|
+
// Draw the frame.
|
|
135
|
+
this.gl.drawArrays(this.gl.TRIANGLE_FAN, 0, 4);
|
|
136
|
+
}
|
|
137
|
+
super.drawFrame();
|
|
138
|
+
this.getFps();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected override rotateCanvas({ rotation }: VideoFrame) {
|
|
142
|
+
if (!this.offscreenCanvas || !this.canvas) return;
|
|
143
|
+
this.canvas.style.transform += ` rotateZ(${rotation}deg)`;
|
|
144
|
+
}
|
|
145
|
+
}
|