From 76b6703f670927600b0ac10a95e42b7850567f20 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 1 Apr 2024 17:42:03 +0800 Subject: [PATCH 001/101] chore: for electron22 --- .../ProcessVideoRawData.tsx | 74 +++++++++++-------- example/webpack.renderer.additions.js | 2 +- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/example/src/renderer/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx b/example/src/renderer/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx index 7e9d041e2..5124f92ae 100644 --- a/example/src/renderer/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx +++ b/example/src/renderer/examples/advanced/ProcessVideoRawData/ProcessVideoRawData.tsx @@ -9,10 +9,7 @@ import { createAgoraRtcEngine, } from 'agora-electron-sdk'; import download from 'download'; -import ffi, { - LibraryObject, - LibraryObjectDefinitionToLibraryDefinition, -} from 'ffi-napi'; +import ffi, { IKoffiLib } from 'koffi'; import React, { ReactElement } from 'react'; import { @@ -33,12 +30,21 @@ if (process.platform === 'darwin') { } pluginName += postfix; -type PluginType = { - EnablePlugin: ['bool', ['uint64']]; - DisablePlugin: ['bool', ['uint64']]; - CreateSamplePlugin: ['uint64', ['uint64']]; - DestroySamplePlugin: ['void', ['uint64']]; - CreateSampleAudioPlugin: ['uint64', ['uint64']]; +type FuncConfig = { + returnType: string; + paramTypes: string[]; +}; + +type PluginConfig = { + [funcName: string]: FuncConfig; +}; + +const pluginConfig: PluginConfig = { + CreateSampleAudioPlugin: { returnType: 'uint64', paramTypes: ['uint64'] }, + CreateSamplePlugin: { returnType: 'uint64', paramTypes: ['uint64'] }, + DestroySamplePlugin: { returnType: 'void', paramTypes: ['uint64'] }, + DisablePlugin: { returnType: 'bool', paramTypes: ['uint64'] }, + EnablePlugin: { returnType: 'bool', paramTypes: ['uint64'] }, }; interface State extends BaseVideoComponentState { @@ -49,9 +55,16 @@ export default class ProcessVideoRawData extends BaseComponent<{}, State> implements IRtcEngineEventHandler { - pluginLibrary?: LibraryObject< - LibraryObjectDefinitionToLibraryDefinition - >; + nativeLib?: IKoffiLib; + pluginLibrary: { + [funcName: string]: Function; + } = { + CreateSampleAudioPlugin: () => {}, + CreateSamplePlugin: () => {}, + DestroySamplePlugin: () => {}, + DisablePlugin: () => {}, + EnablePlugin: () => {}, + }; plugin?: string | number; pluginAudio?: string | number; @@ -137,21 +150,24 @@ export default class ProcessVideoRawData console.log(`download success`); } - const plugin: PluginType = { - CreateSampleAudioPlugin: ['uint64', ['uint64']], - CreateSamplePlugin: ['uint64', ['uint64']], - DestroySamplePlugin: ['void', ['uint64']], - DisablePlugin: ['bool', ['uint64']], - EnablePlugin: ['bool', ['uint64']], - }; - this.pluginLibrary ??= ffi.Library(dllPath, plugin); + this.nativeLib ??= ffi.load(dllPath); + + for (const [funcName, { returnType, paramTypes }] of Object.entries( + pluginConfig + )) { + this.pluginLibrary[funcName] = this.nativeLib.func( + funcName, + returnType, + paramTypes + ); + } const handle = this.engine?.getNativeHandle(); if (handle !== undefined) { - this.plugin = this.pluginLibrary.CreateSamplePlugin(handle); - this.pluginLibrary.EnablePlugin(this.plugin); - this.pluginAudio = this.pluginLibrary.CreateSampleAudioPlugin(handle); - this.pluginLibrary.EnablePlugin(this.pluginAudio); + this.plugin = this.pluginLibrary.CreateSamplePlugin?.(handle); + this.pluginLibrary.EnablePlugin?.(this.plugin); + this.pluginAudio = this.pluginLibrary.CreateSampleAudioPlugin?.(handle); + this.pluginLibrary.EnablePlugin?.(this.pluginAudio); } this.setState({ enablePlugin: true }); }; @@ -161,16 +177,16 @@ export default class ProcessVideoRawData */ disablePlugin = () => { if (this.plugin) { - this.pluginLibrary?.DisablePlugin(this.plugin); - this.pluginLibrary?.DestroySamplePlugin(this.plugin); + this.pluginLibrary.DisablePlugin?.(this.plugin); + this.pluginLibrary.DestroySamplePlugin?.(this.plugin); this.plugin = undefined; } else { this.error('plugin is invalid'); } if (this.pluginAudio) { - this.pluginLibrary?.DisablePlugin(this.pluginAudio); - this.pluginLibrary?.DestroySamplePlugin(this.pluginAudio); + this.pluginLibrary.DisablePlugin?.(this.pluginAudio); + this.pluginLibrary.DestroySamplePlugin?.(this.pluginAudio); this.pluginAudio = undefined; } else { this.error('pluginAudio is invalid'); diff --git a/example/webpack.renderer.additions.js b/example/webpack.renderer.additions.js index 8777458fd..558c0ccf1 100644 --- a/example/webpack.renderer.additions.js +++ b/example/webpack.renderer.additions.js @@ -81,7 +81,7 @@ module.exports = function (config) { // ...config.externals, 'webpack', 'agora-electron-sdk', - 'ffi-napi', + 'koffi', 'ref-napi', ]; console.log('config', config.module.rules); From d7bd5a97025ff0955fc9710844b652b2baa2d1c8 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 1 Apr 2024 17:45:21 +0800 Subject: [PATCH 002/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 171 ++++++++++++++++++ example/src/renderer/examples/basic/index.ts | 5 + ts/AgoraSdk.ts | 1 + ts/Decoder/WebCodecsDecoder.ts | 151 ++++++++++++++++ ts/Decoder/index.ts | 1 + ts/Decoder/renderer_webgl.ts | 86 +++++++++ 6 files changed, 415 insertions(+) create mode 100644 example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx create mode 100644 ts/Decoder/WebCodecsDecoder.ts create mode 100644 ts/Decoder/index.ts create mode 100755 ts/Decoder/renderer_webgl.ts diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx new file mode 100644 index 000000000..9596d084e --- /dev/null +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -0,0 +1,171 @@ +import { + ChannelProfileType, + ClientRoleType, + EncodedVideoFrameInfo, + IRtcEngineEventHandler, + IRtcEngineEx, + IVideoEncodedFrameObserver, + RtcConnection, + UserOfflineReasonType, + VideoStreamType, + WebCodecsDecoder, + createAgoraRtcEngine, +} from 'agora-electron-sdk'; +import React, { ReactElement } from 'react'; + +import { + BaseAudioComponentState, + BaseComponent, +} from '../../../components/BaseComponent'; +import Config from '../../../config/agora.config'; +import { askMediaAccess } from '../../../utils/permissions'; + +interface State extends BaseAudioComponentState { + fps: number; +} + +const SCREEN_UID = 7; + +export default class VideoDecoder + extends BaseComponent<{}, State> + implements IRtcEngineEventHandler, IVideoEncodedFrameObserver +{ + // @ts-ignore + protected engine?: IRtcEngineEx; + private decoder?: WebCodecsDecoder; + + protected createState(): State { + return { + appId: Config.appId, + fps: 0, + enableVideo: true, + channelId: Config.channelId, + token: Config.token, + uid: Config.uid, + joinChannelSuccess: false, + remoteUsers: [], + startPreview: false, + }; + } + + /** + * Step 1: initRtcEngine + */ + protected async initRtcEngine() { + const { appId } = this.state; + if (!appId) { + this.error(`appId is invalid`); + } + + this.engine = createAgoraRtcEngine() as IRtcEngineEx; + this.engine.initialize({ + appId, + logConfig: { filePath: Config.logFilePath }, + // Should use ChannelProfileLiveBroadcasting on most of cases + channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, + }); + this.engine.registerEventHandler(this); + this.engine.getMediaEngine().registerVideoEncodedFrameObserver(this); + + // Need granted the microphone and camera permission + await askMediaAccess(['microphone', 'camera', 'screen']); + + // Need to enable video on this case + // If you only call `enableAudio`, only relay the audio stream to the target channel + this.engine.enableVideo(); + // Start preview before joinChannel + // this.engine.startPreview(); + this.setState({ startPreview: true }); + } + + /** + * Step 2: joinChannel + */ + protected joinChannel() { + const { channelId, token, uid } = this.state; + if (!channelId) { + this.error('channelId is invalid'); + return; + } + if (uid < 0) { + this.error('uid is invalid'); + return; + } + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + this.engine?.joinChannel(token, channelId, uid, { + // Make myself as the broadcaster to send stream to remote + clientRoleType: ClientRoleType.ClientRoleBroadcaster, + }); + this.decoder = new WebCodecsDecoder(); + this.decoder.enableFps = true; + } + + /** + * Step 4: leaveChannel + */ + protected leaveChannel() { + this.engine?.leaveChannel(); + } + + /** + * Step 5: releaseRtcEngine + */ + protected releaseRtcEngine() { + this.engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); + this.engine?.unregisterEventHandler(this); + this.engine?.release(); + } + + onEncodedVideoFrameReceived( + uid: number, + imageBuffer: Uint8Array, + length: number, + videoEncodedFrameInfo: EncodedVideoFrameInfo + ) { + if (uid == SCREEN_UID) { + // start decode + this.decoder?.decodeFrame( + imageBuffer, + videoEncodedFrameInfo, + new Date().getTime() + ); + this.setState({ fps: this.decoder?.getFps() || 0 }); + } + } + + onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { + this.engine?.setRemoteVideoSubscriptionOptions(remoteUid, { + type: VideoStreamType.VideoStreamHigh, + encodedFrameOnly: true, + }); + super.onUserJoined(connection, remoteUid, elapsed); + } + + onUserOffline( + connection: RtcConnection, + remoteUid: number, + reason: UserOfflineReasonType + ) { + if (remoteUid == SCREEN_UID) { + // stop decode + this.decoder?.release(); + } + super.onUserOffline(connection, remoteUid, reason); + } + + protected renderUsers(): ReactElement | undefined { + let { fps } = this.state; + return ( + <> +

Current Fps: {fps}

+ + + ); + } +} diff --git a/example/src/renderer/examples/basic/index.ts b/example/src/renderer/examples/basic/index.ts index 255daface..db9285a32 100644 --- a/example/src/renderer/examples/basic/index.ts +++ b/example/src/renderer/examples/basic/index.ts @@ -1,6 +1,7 @@ import JoinChannelAudio from './JoinChannelAudio/JoinChannelAudio'; import JoinChannelVideo from './JoinChannelVideo/JoinChannelVideo'; import StringUid from './StringUid/StringUid'; +import VideoDecoder from './VideoDecoder/VideoDecoder'; const Basic = { title: 'Basic', @@ -17,6 +18,10 @@ const Basic = { name: 'StringUid', component: StringUid, }, + { + name: 'VideoDecoder', + component: VideoDecoder, + }, ], }; diff --git a/ts/AgoraSdk.ts b/ts/AgoraSdk.ts index 071f575e8..a59017846 100644 --- a/ts/AgoraSdk.ts +++ b/ts/AgoraSdk.ts @@ -19,6 +19,7 @@ export * from './Private/IAgoraRtcEngineEx'; export * from './Private/IAgoraSpatialAudio'; export * from './Private/IAudioDeviceManager'; export * from './Renderer'; +export * from './Decoder'; export * from './Types'; export * from './Utils'; diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts new file mode 100644 index 000000000..6cf27abe5 --- /dev/null +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -0,0 +1,151 @@ +import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; + +import { logDebug, logError } from '../Utils'; + +import { WebGLRenderer } from './renderer_webgl'; + +const frameTypeMapping = { + [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', + [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', +}; + +export class WebCodecsDecoder { + public enableFps = false; + + // eslint-disable-next-line auto-import/auto-import + private _decoder: VideoDecoder; + private _startTime: number | null = null; + private renderer: any; + // eslint-disable-next-line auto-import/auto-import + private pendingFrame: VideoFrame | null = null; + private _frameCount = 0; + + private _frame_ts: number[] = []; + private _base_ts = 0; + private _base_ts_ntp = 1; + private _last_ts_ntp = 1; + + constructor() { + this.renderer = new WebGLRenderer( + 'webgl2', + document.querySelector('canvas')!.transferControlToOffscreen() + ); + // eslint-disable-next-line auto-import/auto-import + this._decoder = new VideoDecoder({ + // @ts-ignore + output: this._output.bind(this), + error: this._error.bind(this), + }); + this.decoder!.configure({ + codec: 'hvc1.1.2.H153.90', + codedWidth: 3840, + codedHeight: 2160, + }); + } + + // eslint-disable-next-line auto-import/auto-import + getDecoder(): VideoDecoder { + return this._decoder; + } + + // eslint-disable-next-line auto-import/auto-import + _output(frame: VideoFrame) { + this.getFps(); + // Schedule the frame to be rendered. + this._renderFrame(frame); + } + + _error(e: any) { + console.error('Decoder error:', e); + } + + get decoder() { + return this._decoder; + } + + getFps(): number { + let fps = 0; + if (!this.enableFps) { + return fps; + } + // Update statistics. + if (this._startTime == null) { + this._startTime = performance.now(); + } else { + const elapsed = (performance.now() - this._startTime) / 1000; + fps = ++this._frameCount / elapsed; + logDebug('render', `${fps.toFixed(0)} fps`); + } + return fps; + } + + // eslint-disable-next-line auto-import/auto-import + _renderFrame(frame: VideoFrame) { + if (!this.pendingFrame) { + // Schedule rendering in the next animation frame. + // eslint-disable-next-line auto-import/auto-import + requestAnimationFrame(this.renderAnimationFrame.bind(this)); + } else { + // Close the current pending frame before replacing it. + this.pendingFrame.close(); + } + // Set or replace the pending frame. + this.pendingFrame = frame; + } + + renderAnimationFrame() { + this.renderer.draw(this.pendingFrame); + this.pendingFrame = null; + } + + // @ts-ignore + decodeFrame( + imageBuffer: Uint8Array, + frameInfo: EncodedVideoFrameInfo, + ts: number + ) { + if (!imageBuffer) { + logError('imageBuffer is empty, cannot decode frame'); + return; + } + this._frame_ts.push(ts); + if (this._base_ts !== 0) { + if (ts > this._base_ts) { + this._last_ts_ntp = + this._base_ts_ntp + Math.floor(((ts - this._base_ts) * 1000) / 90); + } else { + this._base_ts = ts; + this._last_ts_ntp++; + this._base_ts_ntp = this._last_ts_ntp; + } + } else { + this._base_ts = ts; + this._last_ts_ntp = 1; + } + let frameType: string | undefined; + if (frameInfo.frameType !== undefined) { + // @ts-ignore + frameType = frameTypeMapping[frameInfo.frameType]; + } + if (!frameType) { + logError('frameType is incorrect, cannot decode frame'); + return; + } + this._decoder.decode( + // eslint-disable-next-line auto-import/auto-import + new EncodedVideoChunk({ + data: imageBuffer, + timestamp: this._last_ts_ntp, + // @ts-ignore + type: frameType, + // @ts-ignore + transfer: [imageBuffer.buffer], + }) + ); + } + + release() { + this._decoder.reset(); + this._decoder.close(); + } +} diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts new file mode 100644 index 000000000..da3150b87 --- /dev/null +++ b/ts/Decoder/index.ts @@ -0,0 +1 @@ +export * from './WebCodecsDecoder'; diff --git a/ts/Decoder/renderer_webgl.ts b/ts/Decoder/renderer_webgl.ts new file mode 100755 index 000000000..5a74df4e1 --- /dev/null +++ b/ts/Decoder/renderer_webgl.ts @@ -0,0 +1,86 @@ +export class WebGLRenderer { + private _canvas: any = null; + private _ctx: any = null; + static vertexShaderSource = ` + attribute vec2 xy; + varying highp vec2 uv; + void main(void) { + gl_Position = vec4(xy, 0.0, 1.0); + // Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1). + // UV coordinates are Y-flipped relative to vertex coordinates. + uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0); + } + `; + static fragmentShaderSource = ` + varying highp vec2 uv; + uniform sampler2D texture; + void main(void) { + gl_FragColor = texture2D(texture, uv); + } + `; + constructor(type: any, canvas: any) { + this._canvas = canvas; + const gl = (this._ctx = canvas.getContext(type)); + const vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, WebGLRenderer.vertexShaderSource); + gl.compileShader(vertexShader); + if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(vertexShader); + } + const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, WebGLRenderer.fragmentShaderSource); + gl.compileShader(fragmentShader); + if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(fragmentShader); + } + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + throw gl.getProgramInfoLog(shaderProgram); + } + gl.useProgram(shaderProgram); + // Vertex coordinates, clockwise from bottom-left. + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([-1.0, -1.0, -1.0, +1.0, +1.0, +1.0, +1.0, -1.0]), + gl.STATIC_DRAW + ); + const xyLocation = gl.getAttribLocation(shaderProgram, 'xy'); + gl.vertexAttribPointer(xyLocation, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(xyLocation); + // Create one texture to upload frames to. + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + draw(frame: any) { + this._canvas.width = frame.displayWidth; + this._canvas.height = frame.displayHeight; + const gl = this._ctx; + if (gl) { + // Upload the frame. + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + gl.RGBA, + gl.UNSIGNED_BYTE, + frame + ); + frame.close(); + // Configure and clear the drawing area. + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + gl.clearColor(1.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + // Draw the frame. + gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); + } + } +} From 4f5282ad16c8aaaa3c087a5a27ac0e29b0f2dde1 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 1 Apr 2024 18:16:53 +0800 Subject: [PATCH 003/101] chore: optimize --- .eslintignore | 1 + .eslintrc | 4 + .gitignore | 1 + example/package.json | 4 +- .../src/renderer/components/BaseComponent.tsx | 1 - .../components/RtcSurfaceView/index.tsx | 87 +- .../LocalVideoTranscoder.tsx | 2 +- .../advanced/MediaPlayer/MediaPlayer.tsx | 2 + .../advanced/ScreenShare/ScreenShare.tsx | 1 - .../SendMultiVideoStream.tsx | 2 + .../VideoEncoderConfiguration.tsx | 38 +- .../examples/hook/ScreenShare/ScreenShare.tsx | 1 - .../hook/components/BaseRenderUsers.tsx | 1 - example/yarn.lock | 205 +---- package.json | 1 + .../agora_node_ext/agora_electron_bridge.cpp | 76 +- ts/Private/internal/IrisApiEngine.ts | 21 +- ts/Private/internal/MediaPlayerInternal.ts | 44 +- ts/Private/internal/RtcEngineExInternal.ts | 191 ++--- ts/Renderer/AgoraView.ts | 48 +- ts/Renderer/IRenderer.ts | 130 ++- ts/Renderer/IRendererManager.ts | 306 ++++++- ts/Renderer/RendererCache.ts | 167 ++++ ts/Renderer/RendererManager.ts | 648 ++------------- ts/Renderer/WebGLRenderer/index.ts | 781 +++++++----------- ts/Renderer/YUVCanvasRenderer/index.ts | 273 ++---- ts/Types.ts | 211 +---- ts/Utils.ts | 136 +-- yarn.lock | 5 + 29 files changed, 1310 insertions(+), 2078 deletions(-) create mode 100644 ts/Renderer/RendererCache.ts diff --git a/.eslintignore b/.eslintignore index 3acd846b5..c972a6245 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ build/ js/ types/ ts/Private/ti/ +native/ diff --git a/.eslintrc b/.eslintrc index 746601a68..077ae39da 100644 --- a/.eslintrc +++ b/.eslintrc @@ -84,8 +84,12 @@ "document": false, "HTMLElement": false, "HTMLDivElement": false, + "RenderingContext": false, + "WebGLRenderingContext": false, "WebGL2RenderingContext": false, "WebGLTexture": false, + "WebGLBuffer": false, + "WebGLProgram": false, "HTMLCanvasElement": false, "ResizeObserver": false, "name": false, diff --git a/.gitignore b/.gitignore index dcc4de47a..7ecb89fd3 100644 --- a/.gitignore +++ b/.gitignore @@ -242,3 +242,4 @@ docs/ types/ iris/ appId.* +native/ diff --git a/example/package.json b/example/package.json index 3f1faa32a..3629877e0 100644 --- a/example/package.json +++ b/example/package.json @@ -73,7 +73,7 @@ "agora-electron-sdk": "4.2.2-build.142-rc.1", "antd": "^4.20.3", "download": "^8.0.0", - "ffi-napi": "^4.0.3", + "koffi": "^2.8.0", "react": "^18.1.0", "react-color": "^2.19.3", "react-dom": "^18.1.0", @@ -94,7 +94,7 @@ "@types/react-dom": "^18.0.3", "@types/react-router-dom": "^5.1.6", "@types/ref-napi": "^3.0.7", - "electron": "18.2.3", + "electron": "22.0.0", "electron-builder": "^23.1.0", "electron-webpack": "^2.8.2", "fork-ts-checker-webpack-plugin": "^4.1.2", diff --git a/example/src/renderer/components/BaseComponent.tsx b/example/src/renderer/components/BaseComponent.tsx index 1e2ab914f..d8b52a8b7 100644 --- a/example/src/renderer/components/BaseComponent.tsx +++ b/example/src/renderer/components/BaseComponent.tsx @@ -190,7 +190,6 @@ export abstract class BaseComponent< <> {!!startPreview || joinChannelSuccess ? this.renderUser({ - uid: 0, sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} diff --git a/example/src/renderer/components/RtcSurfaceView/index.tsx b/example/src/renderer/components/RtcSurfaceView/index.tsx index 783b2e873..0476ce209 100644 --- a/example/src/renderer/components/RtcSurfaceView/index.tsx +++ b/example/src/renderer/components/RtcSurfaceView/index.tsx @@ -1,10 +1,12 @@ import { + AgoraEnv, IMediaPlayer, IRtcEngineEx, RtcConnection, VideoCanvas, VideoMirrorModeType, VideoSourceType, + VideoViewSetupMode, createAgoraRtcEngine, } from 'agora-electron-sdk'; import React, { Component } from 'react'; @@ -23,6 +25,12 @@ interface State { uniqueId: number; } +type SetupVideoFunc = + | typeof IRtcEngineEx.prototype.setupRemoteVideoEx + | typeof IRtcEngineEx.prototype.setupRemoteVideo + | typeof IRtcEngineEx.prototype.setupLocalVideo + | typeof IMediaPlayer.prototype.setView; + export class RtcSurfaceView extends Component { constructor(props: Props) { super(props); @@ -43,7 +51,16 @@ export class RtcSurfaceView extends Component { }; componentDidMount() { - this.updateRender(); + const { canvas, connection } = this.props; + this.getSetupVideoFunc().call( + this, + { + ...canvas, + setupMode: VideoViewSetupMode.VideoViewSetupAdd, + view: this.getHTMLElement(), + }, + connection! + ); } shouldComponentUpdate( @@ -59,59 +76,59 @@ export class RtcSurfaceView extends Component { } componentDidUpdate() { - this.updateRender(); + this.updateRenderer(); } componentWillUnmount() { - const dom = this.getHTMLElement(); + const { canvas, connection } = this.props; - createAgoraRtcEngine().destroyRendererByView(dom); + this.getSetupVideoFunc().call( + this, + { + ...canvas, + setupMode: VideoViewSetupMode.VideoViewSetupRemove, + view: this.getHTMLElement(), + }, + connection! + ); } - updateRender = () => { + getSetupVideoFunc = (): SetupVideoFunc => { const { canvas, connection } = this.props; - const { isMirror } = this.state; - const dom = this.getHTMLElement(); const engine = createAgoraRtcEngine(); - let funcName: - | typeof IRtcEngineEx.prototype.setupRemoteVideoEx - | typeof IRtcEngineEx.prototype.setupRemoteVideo - | typeof IRtcEngineEx.prototype.setupLocalVideo - | typeof IMediaPlayer.prototype.setView; + let func: SetupVideoFunc; if (canvas.sourceType === undefined) { if (canvas.uid) { - funcName = engine.setupRemoteVideo; + func = engine.setupRemoteVideo; } else { - funcName = engine.setupLocalVideo; + func = engine.setupLocalVideo; } } else if (canvas.sourceType === VideoSourceType.VideoSourceRemote) { - funcName = engine.setupRemoteVideo; + func = engine.setupRemoteVideo; } else { - funcName = engine.setupLocalVideo; + func = engine.setupLocalVideo; } - if (funcName === engine.setupRemoteVideo && connection) { - funcName = engine.setupRemoteVideoEx; + if (func === engine.setupRemoteVideo && connection) { + func = engine.setupRemoteVideoEx; } - try { - engine.destroyRendererByView(dom); - } catch (e) { - console.warn(e); - } - funcName.call( - this, - { - ...canvas, - mirrorMode: isMirror - ? VideoMirrorModeType.VideoMirrorModeEnabled - : VideoMirrorModeType.VideoMirrorModeDisabled, - view: dom, - }, - connection! - ); + return func; + }; + + updateRenderer = () => { + const { canvas, connection } = this.props; + const { isMirror } = this.state; + AgoraEnv.AgoraRendererManager?.setRendererContext({ + ...canvas, + ...connection, + mirrorMode: isMirror + ? VideoMirrorModeType.VideoMirrorModeEnabled + : VideoMirrorModeType.VideoMirrorModeDisabled, + view: this.getHTMLElement(), + }); }; render() { @@ -124,7 +141,7 @@ export class RtcSurfaceView extends Component { onClick={() => { this.setState((preState) => { return { isMirror: !preState.isMirror }; - }, this.updateRender); + }, this.updateRenderer); }} >
) : undefined} diff --git a/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx b/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx index e4b2fdb13..532d39163 100644 --- a/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx +++ b/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx @@ -5,6 +5,7 @@ import { MediaPlayerError, MediaPlayerEvent, MediaPlayerState, + RenderModeType, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -353,6 +354,7 @@ export default class MediaPlayer canvas={{ mediaPlayerId: this.player?.getMediaPlayerId(), sourceType: VideoSourceType.VideoSourceMediaPlayer, + renderMode: RenderModeType.RenderModeFit, }} /> ) : undefined} diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 7b3a9feb8..57b628158 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -399,7 +399,6 @@ export default class ScreenShare {startScreenCapture ? ( ) : undefined} diff --git a/example/src/renderer/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx b/example/src/renderer/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx index 47b2f9885..893435925 100644 --- a/example/src/renderer/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx +++ b/example/src/renderer/examples/advanced/VideoEncoderConfiguration/VideoEncoderConfiguration.tsx @@ -1,11 +1,9 @@ import { - AgoraEnv, ChannelProfileType, ClientRoleType, DegradationPreference, IRtcEngineEventHandler, OrientationMode, - RENDER_MODE, RenderModeType, VideoCodecType, VideoMirrorModeType, @@ -37,8 +35,7 @@ interface State extends BaseVideoComponentState { bitrate: number; minBitrate: number; orientationMode: OrientationMode; - renderMode: RENDER_MODE; - renderModeType: RenderModeType; + renderMode: RenderModeType; degradationPreference: DegradationPreference; mirrorMode: VideoMirrorModeType; } @@ -64,8 +61,7 @@ export default class VideoEncoderConfiguration bitrate: 0, minBitrate: -1, orientationMode: OrientationMode.OrientationModeAdaptive, - renderMode: RENDER_MODE.WEBGL, - renderModeType: RenderModeType.RenderModeFit, + renderMode: RenderModeType.RenderModeHidden, degradationPreference: DegradationPreference.MaintainQuality, mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, }; @@ -130,18 +126,9 @@ export default class VideoEncoderConfiguration /** * Step 3-1: setRenderMode,need leave and join channel again */ - setRenderMode = () => { - const { renderMode } = this.state; - // @ts-ignore - AgoraEnv?.AgoraRendererManager?.['setRenderMode'](renderMode); - }; - - /** - * Step 3-2: setVideoRenderMode - */ setVideoRenderMode = () => { - const { renderModeType, mirrorMode } = this.state; - this.engine?.setLocalRenderMode(renderModeType, mirrorMode); + const { renderMode, mirrorMode } = this.state; + this.engine?.setLocalRenderMode(renderMode, mirrorMode); }; /** @@ -194,7 +181,6 @@ export default class VideoEncoderConfiguration codecType, orientationMode, renderMode, - renderModeType, degradationPreference, mirrorMode, } = this.state; @@ -283,16 +269,6 @@ export default class VideoEncoderConfiguration }} /> - { - this.setState({ renderMode: value }); - }} - /> - - { - this.setState({ renderModeType: value }); + this.setState({ renderMode: value }); }} /> {!!startPreview || joinChannelSuccess ? renderUser({ - uid: 0, sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} diff --git a/example/yarn.lock b/example/yarn.lock index d4eb58293..8676324d5 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1052,21 +1052,20 @@ ajv "^6.12.0" ajv-keywords "^3.4.1" -"@electron/get@^1.13.0": - version "1.14.1" - resolved "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz#16ba75f02dffb74c23965e72d617adc721d27f40" - integrity sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw== +"@electron/get@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz#fba552683d387aebd9f3fcadbcafc8e12ee4f960" + integrity sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ== dependencies: debug "^4.1.1" env-paths "^2.2.0" fs-extra "^8.1.0" - got "^9.6.0" + got "^11.8.5" progress "^2.0.3" semver "^6.2.0" sumchecker "^3.0.1" optionalDependencies: global-agent "^3.0.0" - global-tunnel-ng "^2.7.1" "@electron/rebuild@^3.2.10": version "3.2.13" @@ -1211,11 +1210,6 @@ classnames "^2.3.2" rc-util "^5.24.4" -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" @@ -1226,13 +1220,6 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -1586,6 +1573,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yauzl@^2.9.1": + version "2.10.3" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" + integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== + dependencies: + "@types/node" "*" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2786,19 +2780,6 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - cacheable-request@^7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" @@ -3212,7 +3193,7 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.2: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -3222,14 +3203,6 @@ concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" -config-chain@^1.1.11: - version "1.1.13" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -3580,7 +3553,7 @@ dayjs@1.x: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -3594,7 +3567,7 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: dependencies: ms "2.1.2" -debug@^3.1.0, debug@^3.2.7: +debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -3722,11 +3695,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - defer-to-connect@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" @@ -4130,14 +4098,14 @@ electron-webpack@^2.8.2: webpack-merge "^4.2.2" yargs "^15.3.1" -electron@18.2.3: - version "18.2.3" - resolved "https://registry.npmjs.org/electron/-/electron-18.2.3.tgz#36bcb8f71e41631e6b11179eeff291c8228bfd6a" - integrity sha512-DJWX03hCRKTscsfXxmW4gmgFuseop+g+m4ml7NfOMfankD8uYyr2Xyi3Ui02inL9qZOlbLMeLVCu6jKCKs8p/w== +electron@22.0.0: + version "22.0.0" + resolved "https://registry.npmjs.org/electron/-/electron-22.0.0.tgz#ef84ab9cf23aa3f8c2f42a1e8e000ad7fd941058" + integrity sha512-cgRc4wjyM+81A0E8UGv1HNJjL1HBI5cWNh/DUIjzYvoUuiEM0SS0hAH/zaFQ18xOz2ced6Yih8SybpOiOYJhdg== dependencies: - "@electron/get" "^1.13.0" + "@electron/get" "^2.0.0" "@types/node" "^16.11.26" - extract-zip "^1.0.3" + extract-zip "^2.0.1" elliptic@^6.5.3: version "6.5.4" @@ -4172,7 +4140,7 @@ enabled@2.0.x: resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@^1.0.2, encodeurl@~1.0.2: +encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== @@ -4554,15 +4522,16 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.0.3: - version "1.7.0" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" - integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== +extract-zip@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== dependencies: - concat-stream "^1.6.2" - debug "^2.6.9" - mkdirp "^0.5.4" + debug "^4.1.1" + get-stream "^5.1.0" yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" extsprintf@^1.2.0: version "1.4.1" @@ -4618,18 +4587,6 @@ fecha@^4.2.0: resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -ffi-napi@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/ffi-napi/-/ffi-napi-4.0.3.tgz#27a8d42a8ea938457154895c59761fbf1a10f441" - integrity sha512-PMdLCIvDY9mS32RxZ0XGb95sonPRal8aqRhLbeEtWKZTe2A87qRFG9HjOhvG8EX2UmQw5XNRMIOT+1MYlWmdeg== - dependencies: - debug "^4.1.1" - get-uv-event-loop-napi-h "^1.0.5" - node-addon-api "^3.0.0" - node-gyp-build "^4.2.1" - ref-napi "^2.0.1 || ^3.0.2" - ref-struct-di "^1.1.0" - figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -5080,18 +5037,11 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-symbol-from-current-process-h@^1.0.1, get-symbol-from-current-process-h@^1.0.2: +get-symbol-from-current-process-h@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-symbol-from-current-process-h/-/get-symbol-from-current-process-h-1.0.2.tgz#510af52eaef873f7028854c3377f47f7bb200265" integrity sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw== -get-uv-event-loop-napi-h@^1.0.5: - version "1.0.6" - resolved "https://registry.npmjs.org/get-uv-event-loop-napi-h/-/get-uv-event-loop-napi-h-1.0.6.tgz#42b0b06b74c3ed21fbac8e7c72845fdb7a200208" - integrity sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg== - dependencies: - get-symbol-from-current-process-h "^1.0.1" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -5212,16 +5162,6 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global-tunnel-ng@^2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f" - integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg== - dependencies: - encodeurl "^1.0.2" - lodash "^4.17.10" - npm-conf "^1.1.3" - tunnel "^0.0.6" - globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -5259,7 +5199,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@^11.7.0: +got@^11.7.0, got@^11.8.5: version "11.8.6" resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== @@ -5299,23 +5239,6 @@ got@^8.3.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -got@^9.6.0: - version "9.6.0" - resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -6434,13 +6357,6 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - keyv@^4.0.0: version "4.5.2" resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" @@ -6482,6 +6398,11 @@ klona@^2.0.4: resolved "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +koffi@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/koffi/-/koffi-2.8.0.tgz#26cb3a608ef8ce4684ff6ed7096fffeec21da7cb" + integrity sha512-EXhiH9Ya4f+o4+24+uV4vFAMyPEskARVUaY8VHbIYWqkQVPTDyYJCBNfxp0Kxw6WdhaMwXeR8xIUyz8R2H8Rew== + kuler@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" @@ -6606,7 +6527,7 @@ lodash.isequal@^4.5.0: resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== -lodash@^4.0.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.2.0: +lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.2.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6655,7 +6576,7 @@ lowercase-keys@1.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: +lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== @@ -6881,7 +6802,7 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -7020,7 +6941,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.6: +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -7269,11 +7190,6 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -7286,14 +7202,6 @@ now-and-later@^2.0.0: dependencies: once "^1.3.2" -npm-conf@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -7500,11 +7408,6 @@ p-cancelable@^0.4.0: resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" @@ -7980,11 +7883,6 @@ prop-types@^15.5.10, prop-types@^15.6.2: object-assign "^4.1.1" react-is "^16.13.1" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== - proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -8716,7 +8614,7 @@ reduce-css-calc@^2.1.8: css-unit-converter "^1.1.1" postcss-value-parser "^3.3.0" -"ref-napi@^2.0.1 || ^3.0.2", ref-napi@^3.0.3: +ref-napi@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/ref-napi/-/ref-napi-3.0.3.tgz#e259bfc2bbafb3e169e8cd9ba49037dd00396b22" integrity sha512-LiMq/XDGcgodTYOMppikEtJelWsKQERbLQsYm0IOOnzhwE9xYZC7x8txNnFC9wJNOkPferQI4vD4ZkC0mDyrOA== @@ -8726,13 +8624,6 @@ reduce-css-calc@^2.1.8: node-addon-api "^3.0.0" node-gyp-build "^4.2.1" -ref-struct-di@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/ref-struct-di/-/ref-struct-di-1.1.1.tgz#5827b1d3b32372058f177547093db1fe1602dc10" - integrity sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g== - dependencies: - debug "^3.1.0" - regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -8931,7 +8822,7 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.4.0 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -responselike@1.0.2, responselike@^1.0.2: +responselike@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== @@ -10016,11 +9907,6 @@ to-object-path@^0.3.0: dependencies: kind-of "^3.0.2" -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" @@ -10108,11 +9994,6 @@ tty-browserify@0.0.0: resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw== -tunnel@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== - type-fest@^0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" diff --git a/package.json b/package.json index d6b35856c..9d0368ed6 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@commitlint/config-conventional": "^17.0.2", "@evilmartians/lefthook": "^1.2.2", "@release-it/conventional-changelog": "^5.0.0", + "@types/dom-webcodecs": "^0.1.11", "@types/jest": "^28.1.2", "@types/json-bigint": "^1.0.1", "@types/lodash.isequal": "^4.5.6", diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index 1030bf187..82549f026 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -163,8 +163,10 @@ napi_value AgoraElectronBridge::CallApi(napi_env env, napi_callback_info info) { } } else { std::smatch output; - std::regex pattern = std::regex( - "^.*(Observer|Handler|Callback|Receiver|DirectCdnStreaming)$"); + std::regex pattern = + std::regex("^.*_.*((EventHandler|Observer|startDirectCdnStreaming|" + "Source|VideoFrameRenderer)(_[a-zA-Z0-9]*)?)$"); + if (std::regex_match(funcName, output, pattern)) { bufferCount = 1; buffer.resize(bufferCount); @@ -295,7 +297,7 @@ napi_value AgoraElectronBridge::EnableVideoFrameCache(napi_env env, unsigned int height = 0; napi_obj_get_property(env, obj, "uid", config.uid); - napi_obj_get_property(env, obj, "videoSourceType", config.video_source_type); + napi_obj_get_property(env, obj, "sourceType", config.video_source_type); napi_obj_get_property(env, obj, "channelId", channelId); strcpy(config.channelId, channelId.c_str()); napi_obj_get_property(env, obj, "width", width); @@ -340,7 +342,7 @@ AgoraElectronBridge::DisableVideoFrameCache(napi_env env, std::string channelId = ""; napi_obj_get_property(env, obj, "uid", config.uid); - napi_obj_get_property(env, obj, "videoSourceType", config.video_source_type); + napi_obj_get_property(env, obj, "sourceType", config.video_source_type); napi_obj_get_property(env, obj, "channelId", channelId); strcpy(config.channelId, channelId.c_str()); @@ -368,8 +370,8 @@ napi_value AgoraElectronBridge::GetVideoFrame(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; - size_t argc = 1; - napi_value args[1]; + size_t argc = 2; + napi_value args[2]; status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); AgoraElectronBridge *agoraElectronBridge; @@ -377,9 +379,15 @@ napi_value AgoraElectronBridge::GetVideoFrame(napi_env env, napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); IrisRtcVideoFrameConfig config = EmptyIrisRtcVideoFrameConfig; - napi_value obj = args[0]; - int videoSourceType; + napi_value obj0 = args[0]; std::string channel_id; + + napi_obj_get_property(env, obj0, "uid", config.uid); + napi_obj_get_property(env, obj0, "sourceType", config.video_source_type); + napi_obj_get_property(env, obj0, "channelId", channel_id); + strcpy(config.channelId, channel_id.c_str()); + + napi_value obj1 = args[1]; napi_value y_buffer_obj; void *y_buffer; size_t y_length; @@ -389,40 +397,41 @@ napi_value AgoraElectronBridge::GetVideoFrame(napi_env env, napi_value v_buffer_obj; void *v_buffer; size_t v_length; - int height; int width; + int height; int yStride; + int uStride; + int vStride; - napi_obj_get_property(env, obj, "uid", config.uid); - napi_obj_get_property(env, obj, "videoSourceType", config.video_source_type); - napi_obj_get_property(env, obj, "channelId", channel_id); - strcpy(config.channelId, channel_id.c_str()); - - napi_obj_get_property(env, obj, "yBuffer", y_buffer_obj); + napi_obj_get_property(env, obj1, "yBuffer", y_buffer_obj); napi_get_buffer_info(env, y_buffer_obj, &y_buffer, &y_length); - napi_obj_get_property(env, obj, "uBuffer", u_buffer_obj); + napi_obj_get_property(env, obj1, "uBuffer", u_buffer_obj); napi_get_buffer_info(env, u_buffer_obj, &u_buffer, &u_length); - napi_obj_get_property(env, obj, "vBuffer", v_buffer_obj); + napi_obj_get_property(env, obj1, "vBuffer", v_buffer_obj); napi_get_buffer_info(env, v_buffer_obj, &v_buffer, &v_length); - napi_obj_get_property(env, obj, "height", height); - napi_obj_get_property(env, obj, "width", width); - napi_obj_get_property(env, obj, "yStride", yStride); + napi_obj_get_property(env, obj1, "width", width); + napi_obj_get_property(env, obj1, "height", height); + napi_obj_get_property(env, obj1, "yStride", yStride); + napi_obj_get_property(env, obj1, "uStride", uStride); + napi_obj_get_property(env, obj1, "vStride", vStride); IrisCVideoFrame videoFrame; videoFrame.yBuffer = (uint8_t *) y_buffer; videoFrame.uBuffer = (uint8_t *) u_buffer; videoFrame.vBuffer = (uint8_t *) v_buffer; - videoFrame.height = height; videoFrame.width = width; + videoFrame.height = height; videoFrame.yStride = yStride; + videoFrame.uStride = uStride; + videoFrame.vStride = vStride; videoFrame.metadata_buffer = nullptr; videoFrame.metadata_size = 0; videoFrame.alphaBuffer = nullptr; - bool isFresh = false; + bool isNewFrame = false; napi_value retObj; int32_t ret = ERR_NOT_INITIALIZED; status = napi_create_object(env, &retObj); @@ -434,16 +443,23 @@ napi_value AgoraElectronBridge::GetVideoFrame(napi_env env, } ret = agoraElectronBridge->_iris_rendering->GetVideoFrameCache( - config, &videoFrame, isFresh); + config, &videoFrame, isNewFrame); - unsigned int rotation = 0; napi_obj_set_property(env, retObj, "ret", ret); - napi_obj_set_property(env, retObj, "isNewFrame", isFresh); - napi_obj_set_property(env, retObj, "width", videoFrame.width); - napi_obj_set_property(env, retObj, "height", videoFrame.height); - napi_obj_set_property(env, retObj, "yStride", videoFrame.yStride); - napi_obj_set_property(env, retObj, "rotation", rotation); - napi_obj_set_property(env, retObj, "timestamp", videoFrame.renderTimeMs); + napi_obj_set_property(env, retObj, "isNewFrame", isNewFrame); + + napi_obj_set_property(env, obj1, "type", videoFrame.type); + napi_obj_set_property(env, obj1, "width", videoFrame.width); + napi_obj_set_property(env, obj1, "height", videoFrame.height); + napi_obj_set_property(env, obj1, "yStride", videoFrame.yStride); + napi_obj_set_property(env, obj1, "uStride", videoFrame.uStride); + napi_obj_set_property(env, obj1, "vStride", videoFrame.vStride); + napi_obj_set_property(env, obj1, "rotation", videoFrame.rotation); + napi_obj_set_property(env, obj1, "renderTimeMs", videoFrame.renderTimeMs); + napi_obj_set_property(env, obj1, "avsync_type", videoFrame.avsync_type); + napi_obj_set_property(env, obj1, "metadata_size", videoFrame.metadata_size); + // napi_obj_set_property(env, obj1, "textureId", videoFrame.textureId); + return retObj; } diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 429540576..5b66ee449 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -1,7 +1,7 @@ import EventEmitter from 'eventemitter3'; import JSON from 'json-bigint'; -import { AgoraEnv } from '../../Utils'; +import { AgoraEnv, logDebug, logError, logInfo, logWarn } from '../../Utils'; import { IAudioEncodedFrameObserver } from '../AgoraBase'; import { AudioFrame, @@ -355,7 +355,7 @@ export const EVENT_PROCESSORS: EventProcessors = { function handleEvent(...[event, data, buffers]: any) { if (isDebuggable()) { - console.info('onEvent', event, data, buffers); + logInfo('onEvent', event, data, buffers); } let _event: string = event; @@ -506,35 +506,30 @@ export function callIrisApi(funcName: string, params: any): any { const retObj = JSON.parse(ret); if (isDebuggable()) { if (typeof retObj.result === 'number' && retObj.result < 0) { - console.error('callApi', funcName, JSON.stringify(params), ret); + logError('callApi', funcName, JSON.stringify(params), ret); } else { - console.debug('callApi', funcName, JSON.stringify(params), ret); + logDebug('callApi', funcName, JSON.stringify(params), ret); } } return retObj; } else { if (isDebuggable()) { - console.error( + logError( 'callApi', funcName, JSON.stringify(params), callApiReturnCode ); } else { - console.warn( - 'callApi', - funcName, - JSON.stringify(params), - callApiReturnCode - ); + logWarn('callApi', funcName, JSON.stringify(params), callApiReturnCode); } return { result: callApiReturnCode }; } } catch (e) { if (isDebuggable()) { - console.error('callApi', funcName, JSON.stringify(params), e); + logError('callApi', funcName, JSON.stringify(params), e); } else { - console.warn('callApi', funcName, JSON.stringify(params), e); + logWarn('callApi', funcName, JSON.stringify(params), e); } } return {}; diff --git a/ts/Private/internal/MediaPlayerInternal.ts b/ts/Private/internal/MediaPlayerInternal.ts index 888a513e7..140ad74ef 100644 --- a/ts/Private/internal/MediaPlayerInternal.ts +++ b/ts/Private/internal/MediaPlayerInternal.ts @@ -1,6 +1,6 @@ import { createCheckers } from 'ts-interface-checker'; -import { AgoraEnv, logWarn } from '../../Utils'; +import { AgoraEnv, logError } from '../../Utils'; import { ErrorCodeType } from '../AgoraBase'; import { @@ -105,7 +105,7 @@ export class MediaPlayerInternal extends IMediaPlayerImpl { MediaPlayerInternal._audio_spectrum_observers.get(this._mediaPlayerId) ?.length === 0 ) { - console.error( + logError( 'Please call `registerMediaPlayerAudioSpectrumObserver` before you want to receive event by `addListener`' ); return false; @@ -303,32 +303,24 @@ export class MediaPlayerInternal extends IMediaPlayerImpl { } override setView(view: HTMLElement): number { - logWarn('Also can use other api setupLocalVideo'); - return ( - AgoraEnv.AgoraRendererManager?.setupVideo({ - videoSourceType: VideoSourceType.VideoSourceMediaPlayer, - uid: this._mediaPlayerId, - view, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const renderer = AgoraEnv.AgoraRendererManager.addOrRemoveRenderer({ + sourceType: VideoSourceType.VideoSourceMediaPlayer, + mediaPlayerId: this._mediaPlayerId, + view, + }); + if (!renderer) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setRenderMode(renderMode: RenderModeType): number { - logWarn( - 'Also can use other api setRenderOption or setRenderOptionByConfig' - ); - return ( - AgoraEnv.AgoraRendererManager?.setRenderOptionByConfig({ - videoSourceType: VideoSourceType.VideoSourceMediaPlayer, - uid: this._mediaPlayerId, - rendererOptions: { - contentMode: - renderMode === RenderModeType.RenderModeFit - ? RenderModeType.RenderModeFit - : RenderModeType.RenderModeHidden, - mirror: true, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const renderer = AgoraEnv.AgoraRendererManager.setRendererContext({ + sourceType: VideoSourceType.VideoSourceMediaPlayer, + mediaPlayerId: this._mediaPlayerId, + renderMode, + }); + if (!renderer) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } } diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index 4598255ca..a2b917f4c 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -1,7 +1,6 @@ import { createCheckers } from 'ts-interface-checker'; -import { Channel } from '../../Types'; -import { AgoraEnv } from '../../Utils'; +import { AgoraEnv, logError } from '../../Utils'; import { AudioEncodedFrameObserverConfig, AudioRecordingConfiguration, @@ -97,7 +96,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { AgoraEnv.AgoraRendererManager = new RendererManager(); } } - AgoraEnv.AgoraRendererManager?.enableRender(); const ret = super.initialize(context); callIrisApi.call(this, 'RtcEngine_setAppType', { appType: 3, @@ -107,7 +105,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { override release(sync: boolean = false) { AgoraEnv.AgoraElectronBridge.ReleaseRenderer(); - AgoraEnv.AgoraRendererManager?.clear(); + AgoraEnv.AgoraRendererManager?.release(); AgoraEnv.AgoraRendererManager = undefined; this._audio_device_manager.release(); this._video_device_manager.release(); @@ -145,7 +143,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { if ( RtcEngineExInternal._direct_cdn_streaming_event_handler.length === 0 ) { - console.error( + logError( 'Please call `startDirectCdnStreaming` before you want to receive event by `addListener`' ); return false; @@ -157,7 +155,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { }) ) { if (RtcEngineExInternal._metadata_observer.length === 0) { - console.error( + logError( 'Please call `registerMediaMetadataObserver` before you want to receive event by `addListener`' ); return false; @@ -169,7 +167,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { }) ) { if (RtcEngineExInternal._audio_encoded_frame_observers.length === 0) { - console.error( + logError( 'Please call `registerAudioEncodedFrameObserver` before you want to receive event by `addListener`' ); return false; @@ -190,7 +188,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { addListener( eventType: EventType, listener: IRtcEngineEvent[EventType] - ): void { + ) { this._addListenerPreCheck(eventType); const callback = (eventProcessor: EventProcessor, data: any) => { if (eventProcessor.type(data) !== EVENT_TYPE.IRtcEngine) { @@ -326,7 +324,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { options: ChannelMediaOptions ): string { if (AgoraEnv.AgoraRendererManager) { - AgoraEnv.AgoraRendererManager.defaultRenderConfig.channelId = channelId; + AgoraEnv.AgoraRendererManager.defaultChannelId = channelId; } return 'RtcEngine_joinChannel2'; } @@ -426,7 +424,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { options?: ChannelMediaOptions ): string { if (AgoraEnv.AgoraRendererManager) { - AgoraEnv.AgoraRendererManager.defaultRenderConfig.channelId = channelId; + AgoraEnv.AgoraRendererManager.defaultChannelId = channelId; } return options === undefined ? 'RtcEngine_joinChannelWithUserAccount' @@ -579,98 +577,44 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { } override setupLocalVideo(canvas: VideoCanvas): number { - let { - sourceType = VideoSourceType.VideoSourceCamera, - uid, - mediaPlayerId, - view, - renderMode, - mirrorMode, - } = canvas; - if ( - sourceType === VideoSourceType.VideoSourceMediaPlayer && - mediaPlayerId !== undefined - ) { - uid = mediaPlayerId; - } - return ( - AgoraEnv.AgoraRendererManager?.setupLocalVideo({ - videoSourceType: sourceType, - channelId: '', - uid, - view, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const renderer = AgoraEnv.AgoraRendererManager.addOrRemoveRenderer(canvas); + if (!renderer) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setupRemoteVideo(canvas: VideoCanvas): number { - const { - sourceType = VideoSourceType.VideoSourceRemote, - uid, - view, - renderMode, - mirrorMode, - } = canvas; - return ( - AgoraEnv.AgoraRendererManager?.setupRemoteVideo({ - videoSourceType: sourceType, - channelId: - AgoraEnv.AgoraRendererManager?.defaultRenderConfig?.channelId, - uid, - view, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const renderer = AgoraEnv.AgoraRendererManager.addOrRemoveRenderer(canvas); + if (!renderer) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setupRemoteVideoEx( canvas: VideoCanvas, connection: RtcConnection ): number { - const { - sourceType = VideoSourceType.VideoSourceRemote, - uid, - view, - renderMode, - mirrorMode, - } = canvas; - const { channelId } = connection; - return ( - AgoraEnv.AgoraRendererManager?.setupRemoteVideo({ - videoSourceType: sourceType, - channelId, - uid, - view, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const renderer = AgoraEnv.AgoraRendererManager.addOrRemoveRenderer({ + ...canvas, + ...connection, + }); + if (!renderer) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setLocalRenderMode( renderMode: RenderModeType, mirrorMode: VideoMirrorModeType = VideoMirrorModeType.VideoMirrorModeAuto ): number { - return ( - AgoraEnv.AgoraRendererManager?.setRenderOptionByConfig({ - videoSourceType: VideoSourceType.VideoSourceCamera, - channelId: '', - uid: 0, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const result = AgoraEnv.AgoraRendererManager.setRendererContext({ + sourceType: VideoSourceType.VideoSourceCamera, + renderMode, + mirrorMode, + }); + if (!result) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setRemoteRenderMode( @@ -678,17 +622,15 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { renderMode: RenderModeType, mirrorMode: VideoMirrorModeType ): number { - return ( - AgoraEnv.AgoraRendererManager?.setRenderOptionByConfig({ - videoSourceType: VideoSourceType.VideoSourceRemote, - channelId: AgoraEnv.AgoraRendererManager?.defaultRenderConfig.channelId, - uid, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const result = AgoraEnv.AgoraRendererManager.setRendererContext({ + sourceType: VideoSourceType.VideoSourceRemote, + uid, + renderMode, + mirrorMode, + }); + if (!result) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setRemoteRenderModeEx( @@ -697,46 +639,41 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { mirrorMode: VideoMirrorModeType, connection: RtcConnection ): number { - const { channelId } = connection; - return ( - AgoraEnv.AgoraRendererManager?.setRenderOptionByConfig({ - videoSourceType: VideoSourceType.VideoSourceRemote, - channelId, - uid, - rendererOptions: { - contentMode: renderMode, - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const result = AgoraEnv.AgoraRendererManager.setRendererContext({ + sourceType: VideoSourceType.VideoSourceRemote, + ...connection, + uid, + renderMode, + mirrorMode, + }); + if (!result) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override setLocalVideoMirrorMode(mirrorMode: VideoMirrorModeType): number { - return ( - AgoraEnv.AgoraRendererManager?.setRenderOptionByConfig({ - videoSourceType: VideoSourceType.VideoSourceCamera, - channelId: '', - uid: 0, - rendererOptions: { - mirror: mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled, - }, - }) ?? -ErrorCodeType.ErrNotInitialized - ); + if (!AgoraEnv.AgoraRendererManager) return -ErrorCodeType.ErrNotInitialized; + const result = AgoraEnv.AgoraRendererManager.setRendererContext({ + sourceType: VideoSourceType.VideoSourceCamera, + mirrorMode, + }); + if (!result) return -ErrorCodeType.ErrFailed; + return ErrorCodeType.ErrOk; } override destroyRendererByView(view: any) { - AgoraEnv.AgoraRendererManager?.destroyRendererByView(view); + AgoraEnv.AgoraRendererManager?.removeRendererFromCache({ view }); } override destroyRendererByConfig( - videoSourceType: VideoSourceType, - channelId?: Channel, + sourceType: VideoSourceType, + channelId?: string, uid?: number ) { - AgoraEnv.AgoraRendererManager?.destroyRenderersByConfig( - videoSourceType, + AgoraEnv.AgoraRendererManager?.removeRendererFromCache({ + sourceType, channelId, - uid - ); + uid, + }); } } diff --git a/ts/Renderer/AgoraView.ts b/ts/Renderer/AgoraView.ts index 29f126474..b0ffae770 100644 --- a/ts/Renderer/AgoraView.ts +++ b/ts/Renderer/AgoraView.ts @@ -1,3 +1,4 @@ +import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { AgoraEnv } from '../Utils'; @@ -70,12 +71,12 @@ export default class AgoraView extends HTMLElement { return observedAttributes; } - get videoSourceType(): VideoSourceType { + get sourceType(): VideoSourceType { const number = Number(this.getAttribute(VIDEO_SOURCE_TYPE_STRING)); return isNaN(number) ? 0 : number; } - set videoSourceType(val) { + set sourceType(val) { if (val) { this.setAttribute(VIDEO_SOURCE_TYPE_STRING, String(val)); } else { @@ -108,7 +109,7 @@ export default class AgoraView extends HTMLElement { } } - get renderContentMode(): RenderModeType { + get renderMode(): RenderModeType { const number = Number( this.getAttribute(RENDERER_CONTENT_MODE_STRING) || RenderModeType.RenderModeFit @@ -116,7 +117,7 @@ export default class AgoraView extends HTMLElement { return isNaN(number) ? RenderModeType.RenderModeFit : number; } - set renderContentMode(val) { + set renderMode(val) { if (val) { this.setAttribute(RENDERER_CONTENT_MODE_STRING, String(val)); } else { @@ -141,21 +142,28 @@ export default class AgoraView extends HTMLElement { } initializeRender = () => { - AgoraEnv.AgoraRendererManager?.destroyRendererByView(this); - AgoraEnv.AgoraRendererManager?.setupVideo({ - videoSourceType: this.videoSourceType, + const { channelId, uid, sourceType, renderMode, renderMirror } = this; + AgoraEnv.AgoraRendererManager?.addOrRemoveRenderer({ + sourceType, view: this, - uid: this.uid, - channelId: this.channelId, - rendererOptions: { - mirror: this.renderMirror, - contentMode: this.renderContentMode, - }, + uid, + channelId, + renderMode, + mirrorMode: renderMirror + ? VideoMirrorModeType.VideoMirrorModeEnabled + : VideoMirrorModeType.VideoMirrorModeDisabled, + setupMode: VideoViewSetupMode.VideoViewSetupReplace, }); }; destroyRender = () => { - AgoraEnv.AgoraRendererManager?.destroyRendererByView(this); + const { channelId, uid, sourceType } = this; + AgoraEnv.AgoraRendererManager?.removeRendererFromCache({ + channelId, + uid, + sourceType, + view: this, + }); }; connectedCallback() { @@ -173,11 +181,13 @@ export default class AgoraView extends HTMLElement { ].includes(attrName); if (isSetRenderOption) { - AgoraEnv.AgoraRendererManager?.setRenderOption( - this, - this.renderContentMode, - this.renderMirror - ); + AgoraEnv.AgoraRendererManager?.setRendererContext({ + view: this, + renderMode: this.renderMode, + mirrorMode: this.renderMirror + ? VideoMirrorModeType.VideoMirrorModeEnabled + : VideoMirrorModeType.VideoMirrorModeDisabled, + }); return; } const isNeedReInitialize = observedAttributes.includes(attrName); diff --git a/ts/Renderer/IRenderer.ts b/ts/Renderer/IRenderer.ts index 1c0318964..d37016b21 100644 --- a/ts/Renderer/IRenderer.ts +++ b/ts/Renderer/IRenderer.ts @@ -1,55 +1,117 @@ -import { EventEmitter } from 'events'; +import { VideoMirrorModeType } from '../Private/AgoraBase'; +import { RenderModeType, VideoFrame } from '../Private/AgoraMediaBase'; +import { RendererContext } from '../Types'; -import { RenderModeType } from '../Private/AgoraMediaBase'; -import { RendererOptions, ShareVideoFrame } from '../Types'; - -export type RenderFailCallback = - | ((obj: { error: string }) => void) - | undefined - | null; +type Context = Pick; export abstract class IRenderer { parentElement?: HTMLElement; + container?: HTMLElement; canvas?: HTMLCanvasElement; - event?: EventEmitter; - contentMode = RenderModeType.RenderModeFit; - mirror?: boolean; + _context: Context = {}; - public snapshot(fileType = 'image/png') { - if (this.canvas && this.canvas.toDataURL) { - return this.canvas.toDataURL(fileType); - } - return null; + public bind(element: HTMLElement) { + this.parentElement = element; + this.container = document.createElement('div'); + Object.assign(this.container.style, { + width: '100%', + height: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + overflow: 'hidden', + }); + this.parentElement.appendChild(this.container); + this.canvas = document.createElement('canvas'); + this.container.appendChild(this.canvas); } - public bind(element: HTMLElement) { - if (!element) { - throw new Error('You have pass a element'); + public unbind() { + if (this.container && this.canvas?.parentNode === this.container) { + this.container.removeChild(this.canvas); } - this.parentElement = element; + if ( + this.parentElement && + this.container?.parentNode === this.parentElement + ) { + this.parentElement.removeChild(this.container); + } + + this.canvas = undefined; + this.container = undefined; + this.parentElement = undefined; } - abstract unbind(): void; + public abstract drawFrame(videoFrame: VideoFrame): void; + + public set context({ renderMode, mirrorMode }: Context) { + if (this.context.renderMode !== renderMode) { + this.context.renderMode = renderMode; + this.updateRenderMode(); + } - public equalsElement(element: Element): boolean { - if (!element) { - throw new Error('You have pass a element'); + if (this.context.mirrorMode !== mirrorMode) { + this.context.mirrorMode = mirrorMode; + this.updateMirrorMode(); } - if (!this.parentElement) { - throw new Error('parentElement is null'); + } + + public get context(): Context { + return this._context; + } + + protected updateRenderMode() { + if (!this.canvas || !this.container) return; + + const { clientWidth, clientHeight } = this.container; + const { width, height } = this.canvas; + + const containerAspectRatio = clientWidth / clientHeight; + const canvasAspectRatio = width / height; + const widthScale = clientWidth / width; + const heightScale = clientHeight / height; + + const isHidden = + this.context?.renderMode === RenderModeType.RenderModeHidden; + + let scale = 1; + // If container's aspect ratio is larger than canvas's aspect ratio + if (containerAspectRatio > canvasAspectRatio) { + // Scale canvas to fit container's width on hidden mode + // Scale canvas to fit container's height on fit mode + scale = isHidden ? widthScale : heightScale; + } else { + // Scale canvas to fit container's height on hidden mode + // Scale canvas to fit container's width on fit mode + scale = isHidden ? heightScale : widthScale; } - return element === this.parentElement; + this.canvas.style.transform = `scale(${scale})`; } - abstract drawFrame(imageData: ShareVideoFrame): void; + protected updateMirrorMode(): void { + if (!this.parentElement) return; - public setRenderOption({ contentMode, mirror }: RendererOptions) { - this.contentMode = contentMode ?? RenderModeType.RenderModeFit; - this.mirror = mirror; - Object.assign(this.parentElement!.style, { - transform: mirror ? 'rotateY(180deg)' : '', + Object.assign(this.parentElement.style, { + transform: + this.context.mirrorMode === VideoMirrorModeType.VideoMirrorModeEnabled + ? 'rotateY(180deg)' + : '', }); } - abstract refreshCanvas(): void; + protected rotateCanvas({ width, height, rotation }: VideoFrame): void { + if (!this.canvas) return; + + if (rotation === 0 || rotation === 180) { + this.canvas.width = width!; + this.canvas.height = height!; + } else if (rotation === 90 || rotation === 270) { + this.canvas.height = width!; + this.canvas.width = height!; + } else { + throw new Error( + `Invalid rotation: ${rotation}, only 0, 90, 180, 270 are supported` + ); + } + } } diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index cba695edc..f4cab0830 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -1,35 +1,303 @@ +import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { Channel, RendererVideoConfig } from '../Types'; +import { RendererContext, RendererType } from '../Types'; +import { logDebug } from '../Utils'; + +import { IRenderer } from './IRenderer'; +import { RendererCache, generateRendererCacheKey } from './RendererCache'; /** * @ignore */ export abstract class IRendererManager { - abstract get defaultRenderConfig(): RendererVideoConfig; + /** + * @ignore + */ + private _renderingFps: number; + /** + * @ignore + */ + private _currentFrameCount: number; + /** + * @ignore + */ + private _previousFirstFrameTime: number; + /** + * @ignore + */ + private _renderingTimer?: number; + /** + * @ignore + */ + private _rendererCaches: RendererCache[]; + /** + * @ignore + */ + private _context: RendererContext; + /** + * @ignore + */ + private _webCodecDecoderEnabled: boolean; + + constructor() { + this._renderingFps = 15; + //todo Enable the WebCodecDecoder by default temporarily + this._webCodecDecoderEnabled = true; + this._currentFrameCount = 0; + this._previousFirstFrameTime = 0; + this._rendererCaches = []; + this._context = { + renderMode: RenderModeType.RenderModeHidden, + mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, + }; + } + + public set webCodecDecoderEnabled(value: boolean) { + this._webCodecDecoderEnabled = value; + } + + public get webCodecDecoderEnabled(): boolean { + return this._webCodecDecoderEnabled; + } + + public set renderingFps(fps: number) { + if (this._renderingFps !== fps) { + this._renderingFps = fps; + if (this._renderingTimer) { + this.stopRendering(); + this.startRendering(); + } + } + } + + public get renderingFps(): number { + return this._renderingFps; + } + + public set defaultChannelId(channelId: string) { + this._context.channelId = channelId; + } + + public get defaultChannelId(): string { + return this._context.channelId ?? ''; + } + + public get defaultRenderMode(): RenderModeType { + return this._context.renderMode!; + } + + public get defaultMirrorMode(): VideoMirrorModeType { + return this._context.mirrorMode!; + } + + public release(): void { + this.stopRendering(); + this.clearRendererCache(); + } + + private precheckRendererContext(context: RendererContext): RendererContext { + let { + sourceType, + uid, + channelId, + mediaPlayerId, + renderMode = this.defaultRenderMode, + mirrorMode = this.defaultMirrorMode, + } = context; + switch (sourceType) { + case VideoSourceType.VideoSourceRemote: + if (uid === undefined) { + throw new Error('uid is required'); + } + channelId = channelId ?? this.defaultChannelId; + break; + case VideoSourceType.VideoSourceMediaPlayer: + if (mediaPlayerId === undefined) { + throw new Error('mediaPlayerId is required'); + } + channelId = ''; + uid = mediaPlayerId; + break; + case undefined: + if (uid) { + sourceType = VideoSourceType.VideoSourceRemote; + } + break; + default: + channelId = ''; + uid = 0; + break; + } + return { ...context, sourceType, uid, channelId, renderMode, mirrorMode }; + } + + public addOrRemoveRenderer( + context: RendererContext + ): RendererCache | undefined { + // To be compatible with the old API + let { setupMode = VideoViewSetupMode.VideoViewSetupAdd } = context; + if (!context.view) setupMode = VideoViewSetupMode.VideoViewSetupRemove; + switch (setupMode) { + case VideoViewSetupMode.VideoViewSetupAdd: + return this.addRendererToCache(context); + case VideoViewSetupMode.VideoViewSetupRemove: + this.removeRendererFromCache(context); + return undefined; + case VideoViewSetupMode.VideoViewSetupReplace: + this.removeRendererFromCache(context); + return this.addRendererToCache(context); + } + } + + private addRendererToCache( + context: RendererContext + ): RendererCache | undefined { + const checkedContext = this.precheckRendererContext(context); + + if (!checkedContext.view) return undefined; + + if (this.findRenderer(checkedContext.view)) { + throw new Error('You have already added this view to the renderer'); + } + + let rendererCache = this.getRendererCache(checkedContext); + if (!rendererCache) { + rendererCache = new RendererCache(checkedContext); + this._rendererCaches.push(rendererCache); + } + rendererCache.addRenderer(this.createRenderer(checkedContext)); + this.startRendering(); + return rendererCache; + } + + public removeRendererFromCache(context: RendererContext): void { + const checkedContext = this.precheckRendererContext(context); + + const rendererCache = this.getRendererCache(checkedContext); + if (!rendererCache) return; + if (checkedContext.view) { + const renderer = rendererCache.findRenderer(checkedContext.view); + if (!renderer) return; + rendererCache.removeRenderer(renderer); + } else { + rendererCache.removeRenderer(); + } + if (rendererCache.renderers.length === 0) { + this._rendererCaches.splice( + this._rendererCaches.indexOf(rendererCache), + 1 + ); + } + } + + public clearRendererCache(): void { + for (const rendererCache of this._rendererCaches) { + rendererCache.removeRenderer(); + } + this._rendererCaches.splice(0); + } + + public getRendererCache(context: RendererContext): RendererCache | undefined { + return this._rendererCaches.find( + (cache) => cache.key === generateRendererCacheKey(context) + ); + } + + public getRenderers(context: RendererContext): IRenderer[] { + return this.getRendererCache(context)?.renderers || []; + } + + public findRenderer(view: Element): IRenderer | undefined { + for (const rendererCache of this._rendererCaches) { + const renderer = rendererCache.findRenderer(view); + if (renderer) return renderer; + } + return undefined; + } + + protected abstract createRenderer( + context: RendererContext, + rendererType?: RendererType + ): IRenderer; + + public startRendering(): void { + if (this._renderingTimer) return; + + const renderingLooper = () => { + if (this._previousFirstFrameTime === 0) { + // Get the current time as the time of the first frame of per second + this._previousFirstFrameTime = performance.now(); + // Reset the frame count + this._currentFrameCount = 0; + } + + // Increase the frame count + ++this._currentFrameCount; - abstract enableRender(enabled?: boolean): void; + // Get the current time + const currentFrameTime = performance.now(); + // Calculate the time difference between the current frame and the previous frame + const deltaTime = currentFrameTime - this._previousFirstFrameTime; + // Calculate the expected time of the current frame + const expectedTime = + (this._currentFrameCount * 1000) / this._renderingFps; + logDebug( + new Date().toLocaleTimeString(), + 'currentFrameCount', + this._currentFrameCount, + 'expectedTime', + expectedTime, + 'deltaTime', + deltaTime + ); - abstract clear(): void; + if (this._rendererCaches.length === 0) { + // If there is no renderer, stop rendering + this.stopRendering(); + return; + } - abstract setupVideo(rendererVideoConfig: RendererVideoConfig): number; + // Render all renderers + for (const rendererCache of this._rendererCaches) { + this.doRendering(rendererCache); + } - abstract setupLocalVideo(rendererConfig: RendererVideoConfig): number; + if (this._currentFrameCount >= this.renderingFps) { + this._previousFirstFrameTime = 0; + } - abstract setupRemoteVideo(rendererConfig: RendererVideoConfig): number; + if (deltaTime < expectedTime) { + // If the time difference between the current frame and the previous frame is less than the expected time, then wait for the difference + this._renderingTimer = window.setTimeout( + renderingLooper, + expectedTime - deltaTime + ); + } else { + // If the time difference between the current frame and the previous frame is greater than the expected time, then render immediately + renderingLooper(); + } + }; + renderingLooper(); + } - abstract setRenderOptionByConfig(rendererConfig: RendererVideoConfig): number; + public abstract doRendering(rendererCache: RendererCache): void; - abstract destroyRendererByView(view: Element): void; + public stopRendering(): void { + if (this._renderingTimer) { + window.clearTimeout(this._renderingTimer); + this._renderingTimer = undefined; + } + } - abstract destroyRenderersByConfig( - videoSourceType: VideoSourceType, - channelId?: Channel, - uid?: number - ): void; + public setRendererContext(context: RendererContext): boolean { + const checkedContext = this.precheckRendererContext(context); - abstract setRenderOption( - view: HTMLElement, - contentMode?: RenderModeType, - mirror?: boolean - ): void; + for (const rendererCache of this._rendererCaches) { + const result = rendererCache.setRendererContext(checkedContext); + if (result) { + return true; + } + } + return false; + } } diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts new file mode 100644 index 000000000..782f2c4f4 --- /dev/null +++ b/ts/Renderer/RendererCache.ts @@ -0,0 +1,167 @@ +import { VideoFrame } from '../Private/AgoraMediaBase'; +import { RendererCacheContext, RendererContext } from '../Types'; +import { AgoraEnv, logDebug } from '../Utils'; + +import { IRenderer } from './IRenderer'; + +export function generateRendererCacheKey({ + channelId, + uid, + sourceType, +}: RendererContext): string { + return `${channelId}_${uid}_${sourceType}`; +} + +export class RendererCache { + private _renderers: IRenderer[]; + private _videoFrame: VideoFrame; + private _context: RendererCacheContext; + private _enabled: boolean; + + constructor({ channelId, uid, sourceType }: RendererContext) { + this._renderers = []; + this._videoFrame = { + yBuffer: Buffer.alloc(0), + uBuffer: Buffer.alloc(0), + vBuffer: Buffer.alloc(0), + width: 0, + height: 0, + yStride: 0, + uStride: 0, + vStride: 0, + rotation: 0, + }; + this._context = { channelId, uid, sourceType }; + this._enabled = false; + } + + public get key(): string { + return generateRendererCacheKey(this._context); + } + + public get renderers(): IRenderer[] { + return this._renderers; + } + + public get videoFrame(): VideoFrame { + return this._videoFrame; + } + + public get context(): RendererCacheContext { + return this._context; + } + + /** + * @deprecated Use renderers instead + */ + public get renders(): IRenderer[] { + return this.renderers; + } + + /** + * @deprecated Use videoFrame instead + */ + public get shareVideoFrame(): VideoFrame | undefined { + return this.videoFrame; + } + + private get bridge() { + return AgoraEnv.AgoraElectronBridge; + } + + private enable() { + if (this._enabled) return; + this.bridge.EnableVideoFrameCache(this._context); + this._enabled = true; + } + + private disable() { + if (!this._enabled) return; + this.bridge.DisableVideoFrameCache(this._context); + this._enabled = false; + } + + private shouldEnable() { + if (this.renderers.length > 0) { + this.enable(); + } else { + this.disable(); + } + } + + public draw() { + let { ret, isNewFrame } = this.bridge.GetVideoFrame( + this.context, + this.videoFrame + ); + + switch (ret) { + case 0: // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::OK = 0 + // + break; + case 1: // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::RESIZED = 1 + const { yStride, uStride, vStride, height } = this.videoFrame; + this.videoFrame.yBuffer = Buffer.alloc(yStride! * height!); + this.videoFrame.uBuffer = Buffer.alloc(uStride! * height!); + this.videoFrame.vBuffer = Buffer.alloc(vStride! * height!); + + const result = this.bridge.GetVideoFrame(this.context, this.videoFrame); + ret = result.ret; + isNewFrame = result.isNewFrame; + break; + case 2: // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::NO_CACHE = 2 + logDebug('No renderer cache, please enable cache first'); + return; + } + + if (isNewFrame) { + this.renderers.forEach((renderer) => { + renderer.drawFrame(this.videoFrame); + }); + } + } + + public findRenderer(view: Element): IRenderer | undefined { + return this._renderers.find((renderer) => renderer.parentElement === view); + } + + public addRenderer(renderer: IRenderer): void { + this._renderers.push(renderer); + this.shouldEnable(); + } + + /** + * Remove the specified renderer if it is specified, otherwise remove all renderers + */ + public removeRenderer(renderer?: IRenderer): void { + let start = 0; + let deleteCount = this._renderers.length; + if (renderer) { + start = this._renderers.indexOf(renderer); + if (start < 0) return; + deleteCount = 1; + } + this._renderers.splice(start, deleteCount).forEach((it) => it.unbind()); + this.shouldEnable(); + } + + public setRendererContext({ + view, + renderMode, + mirrorMode, + }: RendererContext): boolean { + if (view) { + const renderer = this.findRenderer(view); + if (renderer) { + renderer.context = { renderMode, mirrorMode }; + return true; + } + return false; + } else { + this._renderers.forEach((it) => { + it.context = { renderMode, mirrorMode }; + }); + return this._renderers.length > 0; + } + } +} diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index aea4635df..09ed6b3f0 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,31 +1,15 @@ -import { ErrorCodeType } from '../Private/AgoraBase'; -import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { - AgoraElectronBridge, - Channel, - ChannelIdMap, - FormatRendererVideoConfig, RENDER_MODE, - RenderConfig, - RenderMap, - RendererVideoConfig, - ShareVideoFrame, - UidMap, - VideoFrameCacheConfig, + RendererCacheContext, + RendererContext, + RendererType, } from '../Types'; -import { - AgoraEnv, - formatConfigByVideoSourceType, - getDefaultRendererVideoConfig, - logDebug, - logError, - logInfo, - logWarn, -} from '../Utils'; +import { isSupportWebGL } from '../Utils'; -import { IRenderer, RenderFailCallback } from './IRenderer'; +import { IRenderer } from './IRenderer'; import { IRendererManager } from './IRendererManager'; -import WebGLRenderer from './WebGLRenderer'; +import { RendererCache } from './RendererCache'; +import { WebGLFallback, WebGLRenderer } from './WebGLRenderer'; import { YUVCanvasRenderer } from './YUVCanvasRenderer'; /** @@ -35,596 +19,92 @@ export class RendererManager extends IRendererManager { /** * @ignore */ - isRendering = false; - renderFps: number; - /** - * @ignore - */ - videoFrameUpdateInterval?: NodeJS.Timer; - /** - * @ignore - */ - renderers: RenderMap; - /** - * @ignore - */ - renderMode?: RENDER_MODE; - /** - * @ignore - */ - msgBridge: AgoraElectronBridge; - /** - * @ignore - */ - defaultRenderConfig: RendererVideoConfig; - - constructor() { - super(); - this.renderFps = 15; - this.renderers = new Map(); - this.setRenderMode(); - this.msgBridge = AgoraEnv.AgoraElectronBridge; - this.defaultRenderConfig = { - rendererOptions: { - contentMode: RenderModeType.RenderModeFit, - mirror: false, - }, - }; - } - - /** - * Sets the channel mode of the current audio file. - * In a stereo music file, the left and right channels can store different audio data. According to your needs, you can set the channel mode to original mode, left channel mode, right channel mode, or mixed channel mode. For example, in the KTV scenario, the left channel of the music file stores the musical accompaniment, and the right channel stores the singing voice. If you only need to listen to the accompaniment, call this method to set the channel mode of the music file to left channel mode; if you need to listen to the accompaniment and the singing voice at the same time, call this method to set the channel mode to mixed channel mode.Call this method after calling open .This method only applies to stereo audio files. - * - * @param mode The channel mode. See AudioDualMonoMode . - * - * @returns - * 0: Success.< 0: Failure. - */ - public setRenderMode(mode?: RENDER_MODE) { - if (mode === undefined) { - this.renderMode = this.checkWebglEnv() - ? RENDER_MODE.WEBGL - : RENDER_MODE.SOFTWARE; - return; - } + private _rendererType: RendererType; - if (mode !== this.renderMode) { - this.renderMode = mode; - logInfo( - 'setRenderMode: new render mode will take effect only if new view bind to render' - ); + public set rendererType(rendererType: RendererType) { + if (this._rendererType !== rendererType) { + this._rendererType = rendererType; } } - /** - * @ignore - */ - public setFPS(fps: number) { - this.renderFps = fps; - this.restartRender(); + public get rendererType(): RendererType { + return this._rendererType; } - /** - * @ignore - */ - public setRenderOption( - view: HTMLElement, - contentMode = RenderModeType.RenderModeFit, - mirror: boolean = false - ): void { - if (!view) { - logError('setRenderOption: view not exist', view); - } - this.forEachStream(({ renders }) => { - renders?.forEach((render) => { - if (render.equalsElement(view)) { - render.setRenderOption({ contentMode, mirror }); - } - }); - }); - } - - /** - * @ignore - */ - public setRenderOptionByConfig(rendererConfig: RendererVideoConfig): number { - const { - uid, - channelId, - rendererOptions, - videoSourceType, - }: FormatRendererVideoConfig = - getDefaultRendererVideoConfig(rendererConfig); - - const renderList = this.getRenderers({ uid, channelId, videoSourceType }); - renderList - ? renderList - .filter((renderItem) => { - if (rendererConfig.view) { - return renderItem.equalsElement(rendererConfig.view); - } else { - return true; - } - }) - .forEach((renderItem) => renderItem.setRenderOption(rendererOptions)) - : logWarn( - `RenderStreamType: ${videoSourceType} channelId:${channelId} uid:${uid} have no render view, you need to call this api after setView` - ); - return ErrorCodeType.ErrOk; - } - - /** - * @ignore - */ - public checkWebglEnv(): boolean { - let gl; - let canvas: HTMLCanvasElement = document.createElement('canvas'); - - try { - gl = - canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - logInfo('Your browser support webGL'); - } catch (e) { - logWarn('Your browser may not support webGL'); - return false; - } - - return !!gl; - } - - /** - * @ignore - */ - public setupVideo(rendererVideoConfig: RendererVideoConfig): number { - const formatConfig = getDefaultRendererVideoConfig(rendererVideoConfig); - - const { uid, channelId, videoSourceType, rendererOptions, view } = - formatConfig; - - if (!formatConfig.view) { - logWarn('setupVideo->destroyRenderersByConfig, because of view is null'); - this.destroyRenderersByConfig(videoSourceType, channelId, uid); - return -ErrorCodeType.ErrInvalidArgument; - } - - // ensure a render to RenderMap - const render = this.bindHTMLElementToRender(formatConfig, view!); - - // render config - render?.setRenderOption(rendererOptions); - - // enable iris videoFrame - this.enableVideoFrameCache({ - uid, - channelId, - videoSourceType, - }); - - // enable render - this.enableRender(true); - return ErrorCodeType.ErrOk; - } - - /** - * @ignore - */ - public setupLocalVideo(rendererConfig: RendererVideoConfig): number { - const { videoSourceType } = rendererConfig; - if (videoSourceType === VideoSourceType.VideoSourceRemote) { - logError('setupLocalVideo videoSourceType error', videoSourceType); - return -ErrorCodeType.ErrInvalidArgument; - } - this.setupVideo({ ...rendererConfig }); - return ErrorCodeType.ErrOk; - } - - /** - * @ignore - */ - public setupRemoteVideo(rendererConfig: RendererVideoConfig): number { - const { videoSourceType } = rendererConfig; - if (videoSourceType !== VideoSourceType.VideoSourceRemote) { - logError('setupRemoteVideo videoSourceType error', videoSourceType); - return -ErrorCodeType.ErrInvalidArgument; - } - this.setupVideo({ ...rendererConfig }); - return ErrorCodeType.ErrOk; - } - - /** - * Destroys a video renderer object. - * - * @param view The HTMLElement object to be destroyed. - */ - public destroyRendererByView(view: Element): void { - const renders = this.renderers; - renders.forEach((channelMap, videoSourceType) => { - channelMap.forEach((uidMap, channelId) => { - uidMap.forEach((renderConfig, uid) => { - let hasRender = false; - const remainRenders = renderConfig.renders?.filter((render) => { - const isFilter = render.equalsElement(view); - - if (isFilter) { - hasRender = true; - render.unbind(); - } - return !isFilter; - }); - if (!hasRender) { - return; - } - - if (remainRenders?.length === 0 || !remainRenders) { - this.disableVideoFrameCache({ uid, channelId, videoSourceType }); - } - renderConfig.renders = remainRenders; - }); - }); - }); + constructor() { + super(); + this._rendererType = isSupportWebGL() + ? RendererType.WEBGL + : RendererType.SOFTWARE; } /** - * @ignore + * @deprecated Use rendererType instead */ - public destroyRenderersByConfig( - videoSourceType: VideoSourceType, - channelId?: Channel, - uid?: number - ): void { - const config = formatConfigByVideoSourceType( - videoSourceType, - channelId, - uid - ); - videoSourceType = config.videoSourceType; - channelId = config.channelId; - uid = config.uid; - - this.disableVideoFrameCache(config); - const uidMap = this.renderers.get(videoSourceType)?.get(channelId); - const renderMap = uidMap?.get(uid); - if (!renderMap) { - return; - } - renderMap.renders?.forEach((renderItem) => { - renderItem.unbind(); - }); - renderMap.renders = []; + public setRenderMode(mode: RENDER_MODE) { + this.rendererType = mode; } /** - * @ignore + * @deprecated Use renderingFps instead */ - public removeAllRenderer(): void { - const renderMap = this.forEachStream( - (renderConfig, videoFrameCacheConfig) => { - this.disableVideoFrameCache(videoFrameCacheConfig); - renderConfig.renders?.forEach((renderItem) => { - renderItem.unbind(); - }); - renderConfig.renders = []; - } - ); - renderMap.clear(); + public setFPS(fps: number) { + this.renderingFps = fps; } /** - * @ignore + * @deprecated Use getRendererCache instead */ - public clear(): void { - this.stopRender(); - this.removeAllRenderer(); + public getRender(context: RendererCacheContext): RendererCache | undefined { + return this.getRendererCache(context); } - /** - * Enables/Disables the local video capture. - * This method disables or re-enables the local video capture, and does not affect receiving the remote video stream.After calling enableVideo , the local video capture is enabled by default. You can call enableLocalVideo (false) to disable the local video capture. If you want to re-enable the local video capture, call enableLocalVideo(true).After the local video capturer is successfully disabled or re-enabled, the SDK triggers the onRemoteVideoStateChanged callback on the remote client.You can call this method either before or after joining a channel.This method enables the internal engine and is valid after leaving the channel. - * - * @param enabled Whether to enable the local video capture.true: (Default) Enable the local video capture.false: Disable the local video capture. Once the local video is disabled, the remote users cannot receive the video stream of the local user, while the local user can still receive the video streams of remote users. When set to false, this method does not require a local camera. - * - * @returns - * 0: Success.< 0: Failure. - */ - public enableRender(enabled = true): void { - if (enabled && this.isRendering) { - //is already _isRendering - } else if (enabled && !this.isRendering) { - this.startRenderer(); - } else { - this.stopRender(); + protected override createRenderer( + context: RendererContext, + rendererType?: RendererType + ): IRenderer { + if (rendererType === undefined) { + rendererType = this.rendererType; } - } - /** - * @ignore - */ - public startRenderer(): void { - this.isRendering = true; - const renderFunc = ( - rendererItem: RenderConfig, - { videoSourceType, channelId, uid }: VideoFrameCacheConfig - ) => { - const { renders } = rendererItem; - if (!renders || renders?.length === 0) { - return; - } - let finalResult = this.msgBridge.GetVideoFrame( - rendererItem.shareVideoFrame - ); - - switch (finalResult.ret) { - case 0: - // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::OK = 0, - // everything is ok - break; - case 1: { - // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::RESIZED - const { width, height, yStride } = finalResult; - const newShareVideoFrame = this.resizeShareVideoFrame( - videoSourceType, - channelId, - uid, - width, - height, - yStride - ); - rendererItem.shareVideoFrame = newShareVideoFrame; - finalResult = this.msgBridge.GetVideoFrame(newShareVideoFrame); - break; - } - case 2: - // GET_VIDEO_FRAME_CACHE_RETURN_TYPE::NO_CACHE - // setupVideo/AgoraView render before initialize - // this.enableVideoFrameCache({ videoSourceType, channelId, uid }); - break; - default: - break; - } - if (finalResult.ret !== 0) { - logDebug('GetVideoFrame ret is', finalResult.ret, rendererItem); - return; - } - if (!finalResult.isNewFrame) { - logDebug('GetVideoFrame isNewFrame is false', rendererItem); - return; - } - const renderVideoFrame = rendererItem.shareVideoFrame; - if (renderVideoFrame.width > 0 && renderVideoFrame.height > 0) { - renders.forEach((renderItem) => { - renderItem.drawFrame(rendererItem.shareVideoFrame); - }); - } - }; - const render = () => { - this.forEachStream(renderFunc); - this.videoFrameUpdateInterval = setTimeout(render, 1000 / this.renderFps); + let renderer: IRenderer; + switch (rendererType) { + case RendererType.WEBGL: + renderer = new WebGLRenderer( + this.handleWebGLFallback(context).bind(this) + ); + break; + case RendererType.SOFTWARE: + renderer = new YUVCanvasRenderer(); + break; + default: + throw new Error('Unknown renderer type'); + } + + renderer.bind(context.view); + renderer.context = { + renderMode: context.renderMode, + mirrorMode: context.mirrorMode, }; - render(); - } - - /** - * @ignore - */ - public stopRender(): void { - this.isRendering = false; - if (this.videoFrameUpdateInterval) { - clearTimeout(this.videoFrameUpdateInterval); - this.videoFrameUpdateInterval = undefined; - } - } - - /** - * @ignore - */ - public restartRender(): void { - if (this.videoFrameUpdateInterval) { - this.stopRender(); - this.startRenderer(); - logInfo(`restartRender: Fps: ${this.renderFps} restartInterval`); - } - } - - /** - * @ignore - */ - private createRenderer(failCallback?: RenderFailCallback): IRenderer { - if (this.renderMode === RENDER_MODE.SOFTWARE) { - return new YUVCanvasRenderer(); - } else { - return new WebGLRenderer(failCallback); - } - } - - /** - * @ignore - */ - private getRender({ - videoSourceType, - channelId, - uid, - }: VideoFrameCacheConfig) { - return this.renderers.get(videoSourceType)?.get(channelId)?.get(uid); - } - - /** - * @ignore - */ - private getRenderers({ - videoSourceType, - channelId, - uid, - }: VideoFrameCacheConfig): IRenderer[] { - return this.getRender({ videoSourceType, channelId, uid })?.renders || []; - } - - /** - * @ignore - */ - private bindHTMLElementToRender( - config: FormatRendererVideoConfig, - view: HTMLElement - ): IRenderer | undefined { - this.ensureRendererConfig(config); - const renders = this.getRenderers(config); - const filterRenders = - renders?.filter((render) => render.equalsElement(view)) || []; - const hasBeenAdd = filterRenders.length > 0; - if (hasBeenAdd) { - logWarn( - 'bindHTMLElementToRender: this view has bind to render', - filterRenders - ); - return filterRenders[0]; - } - const renderer = this.createRenderer(() => { - const { contentMode, mirror } = renderer; - renderer.unbind(); - renders.splice(renders.indexOf(renderer), 1); - this.setRenderMode(); - const newRender = this.createRenderer(); - newRender.bind(view); - newRender.setRenderOption({ contentMode, mirror }); - renders.push(newRender); - }); - renderer.bind(view); - renders.push(renderer); return renderer; } - /** - * @ignore - */ - private forEachStream( - callbackfn: ( - renderConfig: RenderConfig, - videoFrameCacheConfig: VideoFrameCacheConfig, - maps: { - channelMap: ChannelIdMap; - uidMap: UidMap; - } - ) => void - ): RenderMap { - const renders = this.renderers; - renders.forEach((channelMap, videoSourceType) => { - channelMap.forEach((uidMap, channelId) => { - uidMap.forEach((renderConfig, uid) => { - callbackfn( - renderConfig, - { videoSourceType, channelId, uid }, - { channelMap, uidMap } - ); - }); - }); - }); - return renders; - } - - /** - * @ignore - */ - private enableVideoFrameCache( - videoFrameCacheConfig: VideoFrameCacheConfig - ): void { - logDebug(`enableVideoFrameCache ${JSON.stringify(videoFrameCacheConfig)}`); - this.msgBridge.EnableVideoFrameCache(videoFrameCacheConfig); - } - - /** - * @ignore - */ - private disableVideoFrameCache( - videoFrameCacheConfig: VideoFrameCacheConfig - ): void { - logDebug(`disableVideoFrameCache ${JSON.stringify(videoFrameCacheConfig)}`); - this.msgBridge.DisableVideoFrameCache(videoFrameCacheConfig); + public override doRendering(rendererCache: RendererCache): void { + rendererCache.draw(); } - /** - * @ignore - */ - private ensureRendererConfig(config: VideoFrameCacheConfig): - | Map< - number, - { - shareVideoFrame: ShareVideoFrame; - renders: IRenderer[]; - } - > - | undefined { - const { videoSourceType, uid, channelId } = config; - const emptyRenderConfig = { - renders: [], - shareVideoFrame: this.resizeShareVideoFrame( - videoSourceType, - channelId, - uid - ), - }; - const emptyUidMap = new Map([[uid, emptyRenderConfig]]); - const emptyChannelMap = new Map([[channelId, emptyUidMap]]); - - const renderers = this.renderers; - const videoSourceMap = renderers.get(videoSourceType); - if (!videoSourceMap) { - renderers.set(videoSourceType, emptyChannelMap); - return emptyUidMap; - } - const channelMap = videoSourceMap.get(channelId); - if (!channelMap) { - videoSourceMap.set(channelId, emptyUidMap); - return emptyUidMap; - } - const renderConfig = channelMap?.get(uid); - if (!renderConfig) { - channelMap?.set(uid, emptyRenderConfig); - logWarn( - `ensureRendererMap uid map for channelId:${channelId} uid:${uid}` + private handleWebGLFallback(context: RendererContext): WebGLFallback { + return (renderer: WebGLRenderer) => { + const { + context: { renderMode, mirrorMode }, + } = renderer; + const renderers = this.getRenderers(context); + renderer.unbind(); + const newRenderer = this.createRenderer( + { ...context, renderMode, mirrorMode }, + RendererType.SOFTWARE ); - return emptyUidMap; - } - return channelMap; - } - - /** - * @ignore - */ - private resizeShareVideoFrame( - videoSourceType: VideoSourceType, - channelId: string, - uid: number, - width = 0, - height = 0, - yStride = 0 - ): ShareVideoFrame { - return { - videoSourceType, - channelId, - uid, - yBuffer: Buffer.alloc(yStride * height), - uBuffer: Buffer.alloc((yStride * height) / 4), - vBuffer: Buffer.alloc((yStride * height) / 4), - width, - height, - yStride, + renderers.splice(renderers.indexOf(renderer), 1, newRenderer); }; } - - /** - * @ignore - */ - public updateVideoFrameCacheInMap( - config: VideoFrameCacheConfig, - shareVideoFrame: ShareVideoFrame - ): void { - let rendererConfigMap = this.ensureRendererConfig(config); - rendererConfigMap - ? Object.assign(rendererConfigMap.get(config.uid) ?? {}, { - shareVideoFrame, - }) - : logWarn( - `updateVideoFrameCacheInMap videoSourceType:${config.videoSourceType} channelId:${config.channelId} uid:${config.uid} rendererConfigMap is null` - ); - } } diff --git a/ts/Renderer/WebGLRenderer/index.ts b/ts/Renderer/WebGLRenderer/index.ts index 3e0552d0d..dea01c80d 100644 --- a/ts/Renderer/WebGLRenderer/index.ts +++ b/ts/Renderer/WebGLRenderer/index.ts @@ -1,10 +1,8 @@ -import { EventEmitter } from 'events'; +import { VideoFrame } from '../../Private/AgoraMediaBase'; +import { logWarn } from '../../Utils'; +import { IRenderer } from '../IRenderer'; -import { RenderModeType } from '../../Private/AgoraMediaBase'; - -import { ShareVideoFrame } from '../../Types'; -import { logError, logWarn } from '../../Utils'; -import { IRenderer, RenderFailCallback } from '../IRenderer'; +export type WebGLFallback = (renderer: WebGLRenderer, error: Error) => void; const createProgramFromSources = require('./webgl-utils').createProgramFromSources; @@ -44,181 +42,243 @@ const yuvShaderSource = ' gl_FragColor=vec4(r,g,b,1.0);' + '}'; -export class GlRenderer extends IRenderer { - gl: WebGL2RenderingContext | undefined | null; - program: any; - positionLocation: any; - texCoordLocation: any; - yTexture: WebGLTexture | undefined | null; - uTexture: WebGLTexture | undefined | null; - vTexture: WebGLTexture | undefined | null; - texCoordBuffer: any; - surfaceBuffer: any; - - // @ts-ignore - parentElement: HTMLElement | undefined; - container: HTMLElement | undefined; - // @ts-ignore - canvas: HTMLCanvasElement | undefined; - renderImageCount = 0; - initWidth = 0; - initHeight = 0; - initRotation = 0; - clientWidth = 0; - clientHeight = 0; - contentMode = 0; - event = new EventEmitter(); - firstFrameRender = false; - lastImageWidth = 0; - lastImageHeight = 0; - lastImageRotation = 0; - videoBuffer = {}; - - observer?: ResizeObserver; - - failInitRenderCB: RenderFailCallback; - - constructor(failCallback: RenderFailCallback) { +export class WebGLRenderer extends IRenderer { + gl?: WebGLRenderingContext | WebGL2RenderingContext | null; + program?: WebGLProgram; + positionLocation?: number; + texCoordLocation?: number; + yTexture: WebGLTexture | null; + uTexture: WebGLTexture | null; + vTexture: WebGLTexture | null; + texCoordBuffer: WebGLBuffer | null; + surfaceBuffer: WebGLBuffer | null; + fallback?: WebGLFallback; + + constructor(fallback?: WebGLFallback) { super(); - this.failInitRenderCB = failCallback; + this.gl = undefined; + this.yTexture = null; + this.uTexture = null; + this.vTexture = null; + this.texCoordBuffer = null; + this.surfaceBuffer = null; + this.fallback = fallback; } - public bind(view: HTMLElement) { + public override bind(view: HTMLElement) { super.bind(view); - } - public unbind() { - this.observer?.unobserve && this.observer.disconnect(); - this.program = undefined; - this.positionLocation = undefined; - this.texCoordLocation = undefined; + this.canvas?.addEventListener( + 'webglcontextlost', + this.handleContextLost, + false + ); + this.canvas?.addEventListener( + 'webglcontextrestored', + this.handleContextRestored, + false + ); - this.deleteTexture(this.yTexture); - this.deleteTexture(this.uTexture); - this.deleteTexture(this.vTexture); - this.yTexture = undefined; - this.uTexture = undefined; - this.vTexture = undefined; + const getContext = ( + contextNames = ['webgl2', 'webgl', 'experimental-webgl'] + ): WebGLRenderingContext | WebGLRenderingContext | null => { + for (let i = 0; i < contextNames.length; i++) { + const contextName = contextNames[i]!; + const context = this.canvas?.getContext(contextName, { + depth: true, + stencil: true, + alpha: false, + antialias: false, + premultipliedAlpha: true, + preserveDrawingBuffer: true, + powerPreference: 'default', + failIfMajorPerformanceCaveat: false, + }); + if (context) { + return context as WebGLRenderingContext | WebGLRenderingContext; + } + } + return null; + }; + this.gl ??= getContext(); - this.deleteBuffer(this.texCoordBuffer); - this.deleteBuffer(this.surfaceBuffer); - this.texCoordBuffer = undefined; - this.surfaceBuffer = undefined; + if (!this.gl) { + this.fallback?.call( + null, + this, + new Error('Browser not support! No WebGL detected.') + ); + return; + } - this.gl = undefined; + // Set clear color to black, fully opaque + this.gl.clearColor(0.0, 0.0, 0.0, 1.0); + // Enable depth testing + this.gl.enable(this.gl.DEPTH_TEST); + // Near things obscure far things + this.gl.depthFunc(this.gl.LEQUAL); + // Clear the color as well as the depth buffer. + this.gl.clear( + this.gl.COLOR_BUFFER_BIT | + this.gl.DEPTH_BUFFER_BIT | + this.gl.STENCIL_BUFFER_BIT + ); - try { - if ( - this.container && - this.canvas && - this.canvas.parentNode === this.container - ) { - this.container.removeChild(this.canvas); - } - if ( - this.parentElement && - this.container && - this.container.parentNode === this.parentElement - ) { - this.parentElement.removeChild(this.container); - } - } catch (e) { - logWarn('webgl renderer unbind happen some error', e); - } + // Setup GLSL program + this.program = createProgramFromSources(this.gl, [ + vertexShaderSource, + yuvShaderSource, + ]) as WebGLProgram; + this.gl.useProgram(this.program); - this.canvas && - this.canvas.removeEventListener( - 'webglcontextlost', - this.handleContextLost, - false - ); - this.canvas = undefined; - this.container = undefined; - this.parentElement = undefined; + this.initTextures(); } - private updateViewZoomLevel(rotation: number, width: number, height: number) { - if (!this.parentElement || !this.canvas) { - return; - } - this.clientWidth = this.parentElement.clientWidth; - this.clientHeight = this.parentElement.clientHeight; - - try { - if (this.contentMode === RenderModeType.RenderModeHidden) { - // Cover - if (rotation === 0 || rotation === 180) { - if (this.clientWidth / this.clientHeight > width / height) { - this.canvas.style.transform = `scale(${this.clientWidth / width})`; - } else { - this.canvas.style.transform = `scale(${ - this.clientHeight / height - })`; - } - } else { - // 90, 270 - if (this.clientHeight / this.clientWidth > width / height) { - this.canvas.style.transform = `scale(${this.clientHeight / width})`; - } else { - this.canvas.style.transform = `scale(${this.clientWidth / height})`; - } - } - // Contain - } else if (rotation === 0 || rotation === 180) { - if (this.clientWidth / this.clientHeight > width / height) { - this.canvas.style.transform = `scale(${this.clientHeight / height})`; - } else { - this.canvas.style.transform = `scale(${this.clientWidth / width})`; - } - } else { - // 90, 270 - if (this.clientHeight / this.clientWidth > width / height) { - this.canvas.style.transform = `scale(${this.clientWidth / height})`; - } else { - this.canvas.style.transform = `scale(${this.clientHeight / width})`; - } - } - } catch (e) { - logError('webgl updateViewZoomLevel', e); - return false; - } + public override unbind() { + this.canvas?.removeEventListener( + 'webglcontextlost', + this.handleContextLost, + false + ); + this.canvas?.removeEventListener( + 'webglcontextrestored', + this.handleContextRestored, + false + ); + + this.releaseTextures(); + this.gl = undefined; - return true; + super.unbind(); } - private updateCanvas(rotation: number, width: number, height: number) { - // if (this.canvasUpdated) { - // return; - // } - if (width || height) { - this.lastImageWidth = width; - this.lastImageHeight = height; - this.lastImageRotation = rotation; - } else { - width = this.lastImageWidth; - height = this.lastImageHeight; - rotation = this.lastImageRotation; - } - if (!this.updateViewZoomLevel(rotation, width, height)) { - return; - } - let gl = this.gl; - if (!gl) { - return; - } - gl.bindBuffer(gl.ARRAY_BUFFER, this.surfaceBuffer); - gl.enableVertexAttribArray(this.positionLocation); - gl.vertexAttribPointer(this.positionLocation, 2, gl.FLOAT, false, 0, 0); + public override drawFrame({ + width, + height, + yStride, + uStride, + vStride, + yBuffer, + uBuffer, + vBuffer, + rotation, + }: VideoFrame) { + this.rotateCanvas({ width, height, rotation }); + this.updateRenderMode(); + + if (!this.gl || !this.program) return; + + const left = 0, + top = 0, + right = yStride! - width!, + bottom = 0; + + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer); + const xWidth = width! + left + right; + const xHeight = height! + top + bottom; + this.gl.bufferData( + this.gl.ARRAY_BUFFER, + new Float32Array([ + left / xWidth, + bottom / xHeight, + 1 - right / xWidth, + bottom / xHeight, + left / xWidth, + 1 - top / xHeight, + left / xWidth, + 1 - top / xHeight, + 1 - right / xWidth, + bottom / xHeight, + 1 - right / xWidth, + 1 - top / xHeight, + ]), + this.gl.STATIC_DRAW + ); + this.gl.enableVertexAttribArray(this.texCoordLocation!); + this.gl.vertexAttribPointer( + this.texCoordLocation!, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); + + this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1); + + this.gl.activeTexture(this.gl.TEXTURE0); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.yTexture); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.LUMINANCE, + // Should use xWidth instead of width here (yStide) + xWidth, + height!, + 0, + this.gl.LUMINANCE, + this.gl.UNSIGNED_BYTE, + yBuffer! + ); + + this.gl.activeTexture(this.gl.TEXTURE1); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.uTexture); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.LUMINANCE, + uStride!, + height! / 2, + 0, + this.gl.LUMINANCE, + this.gl.UNSIGNED_BYTE, + uBuffer! + ); + + this.gl.activeTexture(this.gl.TEXTURE2); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.vTexture); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.LUMINANCE, + vStride!, + height! / 2, + 0, + this.gl.LUMINANCE, + this.gl.UNSIGNED_BYTE, + vBuffer! + ); + + this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); + } + + protected override rotateCanvas({ width, height, rotation }: VideoFrame) { + super.rotateCanvas({ width, height, rotation }); + + if (!this.gl) return; + + this.gl.viewport(0, 0, width!, height!); + + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.surfaceBuffer); + this.gl.enableVertexAttribArray(this.positionLocation!); + this.gl.vertexAttribPointer( + this.positionLocation!, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); // 4 vertex, 1(x1,y1), 2(x2,y1), 3(x2,y2), 4(x1,y2) - // 0: 1,2,4/4,2,3 + // 0: 1,2,4/4,2,3 // 90: 2,3,1/1,3,4 // 180: 3,4,2/2,4,1 // 270: 4,1,3/3,1,2 const p1 = { x: 0, y: 0 }; - const p2 = { x: width, y: 0 }; - const p3 = { x: width, y: height }; - const p4 = { x: 0, y: height }; + const p2 = { x: width!, y: 0 }; + const p3 = { x: width!, y: height! }; + const p4 = { x: 0, y: height! }; let pp1 = p1, pp2 = p2, pp3 = p3, @@ -247,8 +307,8 @@ export class GlRenderer extends IRenderer { break; default: } - gl.bufferData( - gl.ARRAY_BUFFER, + this.gl.bufferData( + this.gl.ARRAY_BUFFER, new Float32Array([ pp1.x, pp1.y, @@ -263,341 +323,120 @@ export class GlRenderer extends IRenderer { pp3.x, pp3.y, ]), - gl.STATIC_DRAW + this.gl.STATIC_DRAW ); - const resolutionLocation = gl.getUniformLocation( - this.program, + const resolutionLocation = this.gl.getUniformLocation( + this.program!, 'u_resolution' ); - gl.uniform2f(resolutionLocation, width, height); - } - - public drawFrame(videoFrame: ShareVideoFrame) { - let error; - try { - this.renderImage({ - width: videoFrame.width, - height: videoFrame.height, - left: 0, - top: 0, - right: videoFrame.yStride - videoFrame.width, - bottom: 0, - rotation: videoFrame.rotation || 0, - yplane: videoFrame.yBuffer, - uplane: videoFrame.uBuffer, - vplane: videoFrame.vBuffer, - }); - } catch (err) { - error = err; - } - if (!this.gl || error) { - this.failInitRenderCB && - this.failInitRenderCB({ - error: 'webgl lost or webgl initialize failed', - }); - this.failInitRenderCB = null; - return; - } - } - - public refreshCanvas() { - if (this.lastImageWidth) { - this.updateViewZoomLevel( - this.lastImageRotation, - this.lastImageWidth, - this.lastImageHeight - ); - } + this.gl.uniform2f(resolutionLocation, width!, height!); } - private renderImage(image: { - width: number; - height: number; - left: number; - top: number; - right: number; - bottom: number; - rotation: number; - yplane: Uint8Array; - uplane: Uint8Array; - vplane: Uint8Array; - }) { - // Rotation, width, height, left, top, right, bottom, yplane, uplane, vplane - - if ( - image.width != this.initWidth || - image.height != this.initHeight || - image.rotation != this.initRotation - ) { - const view = this.parentElement!; - this.unbind(); - - this.initCanvas(view, image.width, image.height, image.rotation); - const ResizeObserver = window.ResizeObserver; - if (ResizeObserver) { - this.observer = new ResizeObserver(() => { - this.refreshCanvas && this.refreshCanvas(); - }); - this.observer.observe(view); - } - } - let gl = this.gl; - if (!gl) { - return; - } + private initTextures() { + if (!this.gl) return; - gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer); - const xWidth = image.width + image.left + image.right; - const xHeight = image.height + image.top + image.bottom; - gl.bufferData( - gl.ARRAY_BUFFER, - new Float32Array([ - image.left / xWidth, - image.bottom / xHeight, - 1 - image.right / xWidth, - image.bottom / xHeight, - image.left / xWidth, - 1 - image.top / xHeight, - image.left / xWidth, - 1 - image.top / xHeight, - 1 - image.right / xWidth, - image.bottom / xHeight, - 1 - image.right / xWidth, - 1 - image.top / xHeight, - ]), - gl.STATIC_DRAW + this.positionLocation = this.gl.getAttribLocation( + this.program!, + 'a_position' + ); + this.texCoordLocation = this.gl.getAttribLocation( + this.program!, + 'a_texCoord' ); - gl.enableVertexAttribArray(this.texCoordLocation); - gl.vertexAttribPointer(this.texCoordLocation, 2, gl.FLOAT, false, 0, 0); - this.uploadYuv(xWidth, xHeight, image.yplane, image.uplane, image.vplane); + this.surfaceBuffer = this.gl.createBuffer(); + this.texCoordBuffer = this.gl.createBuffer(); + + const createTexture = (textureIndex: number) => { + if (!this.gl) return null; + + // Create a texture. + this.gl.activeTexture(textureIndex); + const texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + // Set the parameters so we can render any size + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_S, + this.gl.CLAMP_TO_EDGE + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_T, + this.gl.CLAMP_TO_EDGE + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MIN_FILTER, + this.gl.NEAREST + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MAG_FILTER, + this.gl.NEAREST + ); + return texture; + }; - this.updateCanvas(image.rotation, image.width, image.height); - gl.drawArrays(gl.TRIANGLES, 0, 6); - this.renderImageCount += 1; + this.yTexture = createTexture(this.gl.TEXTURE0); + this.uTexture = createTexture(this.gl.TEXTURE1); + this.vTexture = createTexture(this.gl.TEXTURE2); - if (!this.firstFrameRender) { - this.firstFrameRender = true; - this.event.emit('ready'); - } - } + const y = this.gl.getUniformLocation(this.program!, 'Ytex'); + this.gl.uniform1i(y, 0); /* Bind Ytex to texture unit 0 */ - private uploadYuv( - width: number, - height: number, - yplane: Uint8Array, - uplane: Uint8Array, - vplane: Uint8Array - ) { - let gl = this.gl; - if (!gl || !this.yTexture || !this.uTexture || !this.vTexture) { - return; - } + const u = this.gl.getUniformLocation(this.program!, 'Utex'); + this.gl.uniform1i(u, 1); /* Bind Utex to texture unit 1 */ - gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1); - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.yTexture); + const v = this.gl.getUniformLocation(this.program!, 'Vtex'); + this.gl.uniform1i(v, 2); /* Bind Vtex to texture unit 2 */ + } - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.LUMINANCE, - width, - height, - 0, - gl.LUMINANCE, - gl.UNSIGNED_BYTE, - yplane - ); + private releaseTextures() { + this.gl?.deleteProgram(this.program!); + this.program = undefined; - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, this.uTexture); - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.LUMINANCE, - width / 2, - height / 2, - 0, - gl.LUMINANCE, - gl.UNSIGNED_BYTE, - uplane - ); + this.positionLocation = undefined; + this.texCoordLocation = undefined; - gl.activeTexture(gl.TEXTURE2); - gl.bindTexture(gl.TEXTURE_2D, this.vTexture); - (''); - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.LUMINANCE, - width / 2, - height / 2, - 0, - gl.LUMINANCE, - gl.UNSIGNED_BYTE, - vplane - ); + this.gl?.deleteTexture(this.yTexture); + this.gl?.deleteTexture(this.uTexture); + this.gl?.deleteTexture(this.vTexture); + this.yTexture = null; + this.uTexture = null; + this.vTexture = null; + + this.gl?.deleteBuffer(this.texCoordBuffer); + this.gl?.deleteBuffer(this.surfaceBuffer); + this.texCoordBuffer = null; + this.surfaceBuffer = null; } - private deleteBuffer(buffer: any) { - if (buffer && this.gl) { - this.gl.deleteBuffer(buffer); - } - } + private handleContextLost = (event: Event) => { + event.preventDefault(); + logWarn('webglcontextlost', event); - private deleteTexture(texture: any) { - if (texture && this.gl) { - this.gl.deleteTexture(texture); - } - } + this.releaseTextures(); - private handleContextLost = (event: Event) => { - console.warn('webglcontextlost', event); - try { - this.canvas && - this.canvas.removeEventListener( - 'webglcontextlost', - this.handleContextLost, - false - ); - } catch (error) { - logWarn('webglcontextlost error', error); - } finally { - this.gl = undefined; - this.failInitRenderCB && - this.failInitRenderCB({ - error: 'Browser not support! No WebGL detected.', - }); - } + this.fallback?.call( + null, + this, + new Error('Browser not support! No WebGL detected.') + ); }; - private initCanvas( - view: HTMLElement, - width: number, - height: number, - rotation: number - ) { - this.clientWidth = view.clientWidth; - this.clientHeight = view.clientHeight; - - this.parentElement = view; - - this.container = document.createElement('div'); - this.container.style.width = '100%'; - this.container.style.height = '100%'; - this.container.style.display = 'flex'; - this.container.style.justifyContent = 'center'; - this.container.style.alignItems = 'center'; - this.container.style.overflow = 'hidden'; - this.parentElement.appendChild(this.container); - - this.canvas = document.createElement('canvas'); - if (rotation == 0 || rotation == 180) { - this.canvas.width = width; - this.canvas.height = height; - } else { - this.canvas.width = height; - this.canvas.height = width; - } - this.initWidth = width; - this.initHeight = height; - this.initRotation = rotation; - - this.container.appendChild(this.canvas); - try { - // Try to grab the standard context. If it fails, fallback to experimental. - this.gl = this.canvas.getContext('webgl2', { - preserveDrawingBuffer: true, - }); - // context list after toggle resolution on electron 12.0.6 - this.canvas.addEventListener( - 'webglcontextlost', - this.handleContextLost, - false - ); - } catch (e) { - logWarn('webgl create happen some warming', this.gl, this.canvas); - } - if (!this.gl) { - this.failInitRenderCB && - this.failInitRenderCB({ - error: 'Browser not support! No WebGL detected.', - }); - return; - } - const gl = this.gl as WebGL2RenderingContext; - - // Set clear color to black, fully opaque - gl.clearColor(0.0, 0.0, 0.0, 1.0); - // Enable depth testing - gl.enable(gl.DEPTH_TEST); - // Near things obscure far things - gl.depthFunc(gl.LEQUAL); - // Clear the color as well as the depth buffer. - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + private handleContextRestored = (event: Event) => { + event.preventDefault(); + logWarn('webglcontextrestored', event); // Setup GLSL program - this.program = createProgramFromSources(gl, [ + this.program = createProgramFromSources(this.gl, [ vertexShaderSource, yuvShaderSource, - ]); - this.gl.useProgram(this.program); + ]) as WebGLProgram; + this.gl?.useProgram(this.program); this.initTextures(); - } - - private initTextures() { - let gl = this.gl; - if (!gl) { - return; - } - let program = this.program; - - this.positionLocation = gl.getAttribLocation(program, 'a_position'); - this.texCoordLocation = gl.getAttribLocation(program, 'a_texCoord'); - - this.surfaceBuffer = gl.createBuffer(); - this.texCoordBuffer = gl.createBuffer(); - - // Create a texture. - gl.activeTexture(gl.TEXTURE0); - this.yTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.yTexture); - // Set the parameters so we can render any size image. - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - gl.activeTexture(gl.TEXTURE1); - this.uTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.uTexture); - // Set the parameters so we can render any size image. - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - gl.activeTexture(gl.TEXTURE2); - this.vTexture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.vTexture); - // Set the parameters so we can render any size image. - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - const y = gl.getUniformLocation(program, 'Ytex'); - gl.uniform1i(y, 0); /* Bind Ytex to texture unit 0 */ - - const u = gl.getUniformLocation(program, 'Utex'); - gl.uniform1i(u, 1); /* Bind Utex to texture unit 1 */ - - const v = gl.getUniformLocation(program, 'Vtex'); - gl.uniform1i(v, 2); /* Bind Vtex to texture unit 2 */ - } + }; } - -export default GlRenderer; diff --git a/ts/Renderer/YUVCanvasRenderer/index.ts b/ts/Renderer/YUVCanvasRenderer/index.ts index 8c4974559..30fea481a 100644 --- a/ts/Renderer/YUVCanvasRenderer/index.ts +++ b/ts/Renderer/YUVCanvasRenderer/index.ts @@ -1,243 +1,64 @@ -import isEqual from 'lodash.isequal'; - -import { RenderModeType } from '../../Private/AgoraMediaBase'; -import { CanvasOptions, ShareVideoFrame } from '../../Types'; +import { VideoFrame } from '../../Private/AgoraMediaBase'; import { IRenderer } from '../IRenderer'; const YUVBuffer = require('yuv-buffer'); const YUVCanvas = require('yuv-canvas'); export class YUVCanvasRenderer extends IRenderer { - private _cacheCanvasOptions?: CanvasOptions; - private _yuvCanvasSink?: any; - private _container?: HTMLElement; - private _videoFrame: ShareVideoFrame; - - constructor() { - super(); - this._videoFrame = { - rotation: 0, - width: 0, - height: 0, - yStride: 0, - yBuffer: new Uint8Array(0), - uBuffer: new Uint8Array(0), - vBuffer: new Uint8Array(0), - videoSourceType: -1, - }; - } + private frameSink?: any; - public bind(element: HTMLElement) { + public override bind(element: HTMLElement) { super.bind(element); - let container = document.createElement('div'); - Object.assign(container.style, { - width: '100%', - height: '100%', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - overflow: 'hidden', - }); - this._container = container; - this.parentElement!.appendChild(this._container); - this.canvas = document.createElement('canvas'); - this._container.appendChild(this.canvas); - - this._yuvCanvasSink = YUVCanvas.attach(this.canvas, { + this.frameSink = YUVCanvas.attach(this.canvas, { webGL: false, }); } - public unbind() { - if (this._container) { - this._container.replaceChildren(); - this._container = undefined; - } - if (this.parentElement) { - this.parentElement.replaceChildren(); - this.parentElement = undefined; - } - if (this.canvas) { - this.canvas = undefined; - } - if (this._yuvCanvasSink && this._yuvCanvasSink?.loseContext) { - this._yuvCanvasSink?.loseContext(); - } - } - - private zoom( - vertical: boolean, - contentMode: RenderModeType = RenderModeType.RenderModeFit, - width: number, - height: number, - clientWidth: number, - clientHeight: number - ): number { - let localRatio = clientWidth / clientHeight; - let tempRatio = width / height; - if (isNaN(localRatio) || isNaN(tempRatio)) { - return 1; - } - - if (contentMode === RenderModeType.RenderModeHidden) { - if (vertical) { - return clientHeight / clientWidth < width / height - ? clientWidth / height - : clientHeight / width; - } else { - return clientWidth / clientHeight > width / height - ? clientWidth / width - : clientHeight / height; - } - } else { - if (vertical) { - return clientHeight / clientWidth < width / height - ? clientHeight / width - : clientWidth / height; - } else { - return clientWidth / clientHeight > width / height - ? clientHeight / height - : clientWidth / width; - } - } - } - - private updateCanvas( - options: CanvasOptions = { - frameWidth: 0, - frameHeight: 0, - rotation: 0, - contentMode: 0, - clientWidth: 0, - clientHeight: 0, - } - ) { - if (this._cacheCanvasOptions) { - if (isEqual(this._cacheCanvasOptions, options)) { - return; - } - } - - this._cacheCanvasOptions = Object.assign({}, options); - - if (this.canvas) { - if (options.rotation === 0 || options.rotation === 180) { - this.canvas.width = options.frameWidth; - this.canvas.height = options.frameHeight; - Object.assign(this.canvas.style, { - 'width': options.frameWidth + 'px', - 'height': options.frameHeight + 'px', - 'object-fit': 'cover', - }); - } else if (options.rotation === 90 || options.rotation === 270) { - this.canvas.height = options.frameWidth; - this.canvas.width = options.frameHeight; - } else { - throw new Error( - 'Invalid value for rotation. Only support 0, 90, 180, 270' - ); - } - - let transformItems = []; - transformItems.push(`rotateZ(${options.rotation}deg)`); - - let scale = this.zoom( - options.rotation === 90 || options.rotation === 270, - options.contentMode, - options.frameWidth, - options.frameHeight, - options.clientWidth, - options.clientHeight - ); - - this.canvas.style.transform = `scale(${scale.toString()})`; - - if (transformItems.length > 0) { - this.canvas.style.transform += ` ${transformItems.join(' ')}`; - } - } - } - - public drawFrame(frame: ShareVideoFrame) { - if (!this._container || !this._yuvCanvasSink) { - return; - } - - let frameWidth = frame.width; - let frameHeight = frame.height; - - if ( - this._videoFrame.yStride === 0 || - this._videoFrame.height === 0 || - this._videoFrame.yStride != frame.yStride || - this._videoFrame.height != frame.height - ) { - this._videoFrame.yBuffer = new Uint8Array(frame.yStride * frameHeight); - this._videoFrame.uBuffer = new Uint8Array( - (frame.yStride * frameHeight) / 4 - ); - this._videoFrame.vBuffer = new Uint8Array( - (frame.yStride * frameHeight) / 4 - ); - } - - this._videoFrame.yBuffer.set(frame.yBuffer); - this._videoFrame.uBuffer.set(frame.uBuffer); - this._videoFrame.vBuffer.set(frame.vBuffer); - - this._videoFrame.width = frame.width; - this._videoFrame.height = frame.height; - this._videoFrame.yStride = frame.yStride; - this._videoFrame.rotation = frame.rotation; - - let options: CanvasOptions = { - frameWidth, - frameHeight, - rotation: frame.rotation ? frame.rotation : 0, - contentMode: this.contentMode, - clientWidth: this._container.clientWidth, - clientHeight: this._container.clientHeight, - }; - - this.updateCanvas(options); - - let format = YUVBuffer.format({ - width: frameWidth, - height: frameHeight, - chromaWidth: frameWidth / 2, - chromaHeight: frameHeight / 2, - cropLeft: frame.yStride - frameWidth, - }); - - let yuvBufferFrame = YUVBuffer.frame( - format, - { - bytes: this._videoFrame.yBuffer, - stride: frame.yStride, - }, - { - bytes: this._videoFrame.uBuffer, - stride: frame.yStride / 2, - }, - { - bytes: this._videoFrame.vBuffer, - stride: frame.yStride / 2, - } + public override drawFrame({ + width, + height, + yStride, + uStride, + vStride, + yBuffer, + uBuffer, + vBuffer, + rotation, + }: VideoFrame) { + this.rotateCanvas({ width, height, rotation }); + this.updateRenderMode(); + + if (!this.frameSink) return; + + this.frameSink.drawFrame( + YUVBuffer.frame( + YUVBuffer.format({ + width, + height, + chromaWidth: width! / 2, + chromaHeight: height! / 2, + cropLeft: yStride! - width!, + }), + { + bytes: yBuffer, + stride: yStride, + }, + { + bytes: uBuffer, + stride: uStride, + }, + { + bytes: vBuffer, + stride: vStride, + } + ) ); - this._yuvCanvasSink.drawFrame(yuvBufferFrame); } - public refreshCanvas() { - if (this._cacheCanvasOptions) { - this.zoom( - this._cacheCanvasOptions.rotation === 90 || - this._cacheCanvasOptions.rotation === 270, - this._cacheCanvasOptions.contentMode, - this._cacheCanvasOptions.frameWidth, - this._cacheCanvasOptions.frameHeight, - this._cacheCanvasOptions.clientWidth, - this._cacheCanvasOptions.clientHeight - ); - } + protected override rotateCanvas({ width, height, rotation }: VideoFrame) { + super.rotateCanvas({ width, height, rotation }); + + if (!this.canvas) return; + this.canvas.style.transform += ` rotateZ(${rotation}deg)`; } } diff --git a/ts/Types.ts b/ts/Types.ts index 5d018ca60..d75aa4cd5 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,5 +1,7 @@ -import { RenderModeType, VideoSourceType } from './Private/AgoraMediaBase'; -import { IRenderer, IRendererManager } from './Renderer'; +import { VideoCanvas } from './Private/AgoraBase'; +import { VideoFrame } from './Private/AgoraMediaBase'; +import { RtcConnection } from './Private/IAgoraRtcEngineEx'; +import { IRendererManager } from './Renderer'; /** * @ignore @@ -36,51 +38,7 @@ export interface AgoraEnvType extends AgoraEnvOptions { /** * @ignore */ -export interface CanvasOptions { - /** - * @ignore - */ - frameWidth: number; - /** - * @ignore - */ - frameHeight: number; - /** - * @ignore - */ - rotation: number; - /** - * @ignore - */ - contentMode: RenderModeType; - /** - * @ignore - */ - clientWidth: number; - /** - * @ignore - */ - clientHeight: number; -} - -/** - * @ignore - */ -export interface RendererOptions { - /** - * @ignore - */ - contentMode?: RenderModeType; - /** - * @ignore - */ - mirror?: boolean; -} - -/** - * @ignore - */ -export enum RENDER_MODE { +export enum RendererType { /** * @ignore */ @@ -91,129 +49,14 @@ export enum RENDER_MODE { SOFTWARE = 2, } -export type User = 'local' | 'videoSource' | number | string; +export type RENDER_MODE = RendererType; -export type Channel = '' | string; +export type RendererContext = VideoCanvas & RtcConnection; -/** - * @ignore - */ -export interface RendererVideoConfig { - /** - * @ignore - */ - videoSourceType?: VideoSourceType; - /** - * @ignore - */ - channelId?: Channel; - /** - * @ignore - */ - uid?: number; - /** - * @ignore - */ - view?: HTMLElement; - /** - * @ignore - */ - rendererOptions?: RendererOptions; -} - -/** - * @ignore - */ -export interface FormatRendererVideoConfig { - /** - * @ignore - */ - videoSourceType: VideoSourceType; - /** - * @ignore - */ - channelId: Channel; - /** - * @ignore - */ - uid: number; - /** - * @ignore - */ - view?: HTMLElement; - /** - * @ignore - */ - rendererOptions: RendererOptions; -} - -/** - * @ignore - */ -export interface VideoFrameCacheConfig { - /** - * @ignore - */ - uid: number; - /** - * @ignore - */ - channelId: string; - /** - * @ignore - */ - videoSourceType: VideoSourceType; -} - -/** - * @ignore - */ -export interface ShareVideoFrame { - /** - * @ignore - */ - width: number; - /** - * @ignore - */ - height: number; - /** - * @ignore - */ - yStride: number; - /** - * @ignore - */ - yBuffer: Buffer | Uint8Array; - /** - * @ignore - */ - uBuffer: Buffer | Uint8Array; - /** - * @ignore - */ - vBuffer: Buffer | Uint8Array; - /** - * @ignore - */ - mirror?: boolean; - /** - * @ignore - */ - rotation?: number; - /** - * @ignore - */ - uid?: number; - /** - * @ignore - */ - channelId?: string; - /** - * @ignore - */ - videoSourceType: VideoSourceType; -} +export type RendererCacheContext = Pick< + RendererContext, + 'channelId' | 'uid' | 'sourceType' +>; /** * @ignore @@ -260,20 +103,18 @@ export interface AgoraElectronBridge { ReleaseRenderer(): void; - EnableVideoFrameCache(config: VideoFrameCacheConfig): void; + EnableVideoFrameCache(context: RendererCacheContext): void; - DisableVideoFrameCache(config: VideoFrameCacheConfig): void; + DisableVideoFrameCache(context: RendererCacheContext): void; GetBuffer(ptr: number, length: number): Buffer; - GetVideoFrame(streamInfo: ShareVideoFrame): { + GetVideoFrame( + context: RendererCacheContext, + videoFrame: VideoFrame + ): { ret: number; isNewFrame: boolean; - yStride: number; - width: number; - height: number; - rotation: number; - timestamp: number; }; sendMsg: ( @@ -283,21 +124,3 @@ export interface AgoraElectronBridge { bufferCount?: number ) => Result; } - -/** - * @ignore - */ -export interface RenderConfig { - /** - * @ignore - */ - renders: IRenderer[]; - /** - * @ignore - */ - shareVideoFrame: ShareVideoFrame; -} - -export type UidMap = Map; -export type ChannelIdMap = Map; -export type RenderMap = Map; diff --git a/ts/Utils.ts b/ts/Utils.ts index f0b4adc7f..0933cccce 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -1,9 +1,4 @@ -import { VideoSourceType } from './Private/AgoraMediaBase'; -import { - AgoraEnvType, - FormatRendererVideoConfig, - RendererVideoConfig, -} from './Types'; +import { AgoraEnvType } from './Types'; /** * @ignore @@ -14,15 +9,6 @@ export const TAG = '[Agora]: '; */ export const DEBUG_TAG = '[Agora Debug]: '; -/** - * @ignore - */ -export const deprecate = (originApi?: string, replaceApi?: string) => - logError( - `${TAG} This method ${originApi} will be deprecated soon. `, - replaceApi ? `Please use ${replaceApi} instead` : '' - ); - /** * @ignore */ @@ -50,7 +36,7 @@ export const logInfo = (msg: string, ...optParams: any[]) => { if (!AgoraEnv.enableLogging) { return; } - console.log(`${TAG} ${msg}`, ...optParams); + console.info(`${TAG} ${msg}`, ...optParams); }; /** @@ -60,23 +46,7 @@ export const logDebug = (msg: string, ...optParams: any[]) => { if (!AgoraEnv.enableLogging || !AgoraEnv.enableDebugLogging) { return; } - console.warn(`${DEBUG_TAG} ${msg}`, ...optParams); -}; - -/** - * @ignore - */ -export const parseJSON = (jsonString: string) => { - if (jsonString === '') { - return jsonString; - } - let obj; - try { - obj = JSON.parse(jsonString); - } catch (error) { - logError('parseJSON', error); - } - return obj || jsonString; + console.debug(`${DEBUG_TAG} ${msg}`, ...optParams); }; /** @@ -93,71 +63,6 @@ export const objsKeysToLowerCase = (array: Array) => { }); }; -/** - * @ignore - */ -export const formatConfigByVideoSourceType = ( - videoSourceType?: VideoSourceType, - originChannelId = '', - originUid = 0 -): { - uid: number; - channelId: string; - videoSourceType: VideoSourceType; -} => { - if (videoSourceType === undefined || videoSourceType === null) { - throw new Error(`must set videoSourceType:${videoSourceType}`); - } - let uid = originUid; - let channelId = originChannelId; - - switch (videoSourceType) { - case VideoSourceType.VideoSourceCamera: - case VideoSourceType.VideoSourceCameraPrimary: - case VideoSourceType.VideoSourceScreen: - case VideoSourceType.VideoSourceScreenSecondary: - case VideoSourceType.VideoSourceTranscoded: - channelId = ''; - uid = 0; - break; - case VideoSourceType.VideoSourceRemote: - if (!uid || !channelId) { - throw new Error(`must set uid:${uid} and channelId:${channelId}`); - } - break; - case VideoSourceType.VideoSourceMediaPlayer: - channelId = ''; - if (!uid) { - throw new Error(`must set mediaPlayerId:${uid}`); - } - break; - default: - break; - } - return { uid, channelId, videoSourceType }; -}; - -/** - * @ignore - */ -export const getDefaultRendererVideoConfig = ( - config: RendererVideoConfig -): FormatRendererVideoConfig => { - const rendererOptions = Object.assign( - {}, - AgoraEnv.AgoraRendererManager?.defaultRenderConfig?.rendererOptions, - config.rendererOptions - ); - - const { uid, channelId, videoSourceType } = formatConfigByVideoSourceType( - config.videoSourceType, - config.channelId, - config.uid - ); - - return { ...config, uid, channelId, videoSourceType, rendererOptions }; -}; - /** * @ignore */ @@ -187,7 +92,38 @@ function copyProperties(target: T, source: any) { } } -const agora = require('../build/Release/agora_node_ext'); +/** + * @ignore + */ +export function isSupportWebGL(): boolean { + let flag = false; + const canvas: HTMLCanvasElement = document.createElement('canvas'); + try { + const getContext = ( + contextNames = ['webgl2', 'webgl', 'experimental-webgl'] + ): WebGLRenderingContext | WebGLRenderingContext | null => { + for (let i = 0; i < contextNames.length; i++) { + const contextName = contextNames[i]!; + const context = canvas?.getContext(contextName); + if (context) { + return context as WebGLRenderingContext | WebGLRenderingContext; + } + } + return null; + }; + let gl = getContext(); + flag = !!gl; + gl?.getExtension('WEBGL_lose_context')?.loseContext(); + gl = null; + logInfo('Your browser support webGL'); + } catch (e) { + logWarn('Your browser may not support webGL'); + flag = false; + } + return flag; +} + +const AgoraNode = require('../build/Release/agora_node_ext'); /** * @ignore @@ -196,5 +132,5 @@ export const AgoraEnv: AgoraEnvType = { enableLogging: true, enableDebugLogging: false, webEnvReady: true, - AgoraElectronBridge: new agora.AgoraElectronBridge(), + AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; diff --git a/yarn.lock b/yarn.lock index 1583ad924..c1fd6a061 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1733,6 +1733,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/dom-webcodecs@^0.1.11": + version "0.1.11" + resolved "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.11.tgz#2e36e5cc71789551f107e2fe15d956845fa19567" + integrity sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A== + "@types/graceful-fs@^4.1.3": version "4.1.6" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" From 6f5a52f1f443db93b6ea95b958c72989418b1016 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 1 Apr 2024 18:31:20 +0800 Subject: [PATCH 004/101] chore: optimize --- .eslintrc | 3 +++ ts/Decoder/WebCodecsDecoder.ts | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.eslintrc b/.eslintrc index 077ae39da..19d14f897 100644 --- a/.eslintrc +++ b/.eslintrc @@ -90,6 +90,9 @@ "WebGLTexture": false, "WebGLBuffer": false, "WebGLProgram": false, + "VideoDecoder": false, + "VideoFrame": false, + "EncodedVideoChunk":false, "HTMLCanvasElement": false, "ResizeObserver": false, "name": false, diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index 6cf27abe5..03e59483e 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -12,11 +12,9 @@ const frameTypeMapping = { export class WebCodecsDecoder { public enableFps = false; - // eslint-disable-next-line auto-import/auto-import private _decoder: VideoDecoder; private _startTime: number | null = null; private renderer: any; - // eslint-disable-next-line auto-import/auto-import private pendingFrame: VideoFrame | null = null; private _frameCount = 0; @@ -30,7 +28,6 @@ export class WebCodecsDecoder { 'webgl2', document.querySelector('canvas')!.transferControlToOffscreen() ); - // eslint-disable-next-line auto-import/auto-import this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), @@ -43,12 +40,10 @@ export class WebCodecsDecoder { }); } - // eslint-disable-next-line auto-import/auto-import getDecoder(): VideoDecoder { return this._decoder; } - // eslint-disable-next-line auto-import/auto-import _output(frame: VideoFrame) { this.getFps(); // Schedule the frame to be rendered. @@ -79,7 +74,6 @@ export class WebCodecsDecoder { return fps; } - // eslint-disable-next-line auto-import/auto-import _renderFrame(frame: VideoFrame) { if (!this.pendingFrame) { // Schedule rendering in the next animation frame. @@ -132,7 +126,6 @@ export class WebCodecsDecoder { return; } this._decoder.decode( - // eslint-disable-next-line auto-import/auto-import new EncodedVideoChunk({ data: imageBuffer, timestamp: this._last_ts_ntp, From b1dadacb2193259614d65c6f5f7a62c7bc28fafa Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 2 Apr 2024 13:03:14 +0800 Subject: [PATCH 005/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 75 +++++------ ts/Decoder/WebCodecsDecoder.ts | 53 +++----- ts/Decoder/WebCodecsRenderer.ts | 125 ++++++++++++++++++ ts/Decoder/WebCodecsRendererCache.ts | 58 ++++++++ ts/Decoder/renderer_webgl.ts | 86 ------------ ts/Renderer/IRenderer.ts | 3 +- ts/Renderer/IRendererCache.ts | 84 ++++++++++++ ts/Renderer/IRendererManager.ts | 41 +++--- ts/Renderer/RendererCache.ts | 78 ++--------- ts/Renderer/RendererManager.ts | 22 ++- ts/Types.ts | 7 + ts/Utils.ts | 31 +++++ 12 files changed, 409 insertions(+), 254 deletions(-) create mode 100755 ts/Decoder/WebCodecsRenderer.ts create mode 100644 ts/Decoder/WebCodecsRendererCache.ts delete mode 100755 ts/Decoder/renderer_webgl.ts create mode 100644 ts/Renderer/IRendererCache.ts diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 9596d084e..f9be35cec 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -1,14 +1,13 @@ import { + AgoraEnv, ChannelProfileType, ClientRoleType, - EncodedVideoFrameInfo, IRtcEngineEventHandler, IRtcEngineEx, - IVideoEncodedFrameObserver, RtcConnection, UserOfflineReasonType, + VideoSourceType, VideoStreamType, - WebCodecsDecoder, createAgoraRtcEngine, } from 'agora-electron-sdk'; import React, { ReactElement } from 'react'; @@ -17,6 +16,7 @@ import { BaseAudioComponentState, BaseComponent, } from '../../../components/BaseComponent'; +import { AgoraList } from '../../../components/ui'; import Config from '../../../config/agora.config'; import { askMediaAccess } from '../../../utils/permissions'; @@ -24,15 +24,13 @@ interface State extends BaseAudioComponentState { fps: number; } -const SCREEN_UID = 7; - export default class VideoDecoder extends BaseComponent<{}, State> - implements IRtcEngineEventHandler, IVideoEncodedFrameObserver + implements IRtcEngineEventHandler { // @ts-ignore protected engine?: IRtcEngineEx; - private decoder?: WebCodecsDecoder; + // private decoder?: WebCodecsDecoder; protected createState(): State { return { @@ -56,7 +54,7 @@ export default class VideoDecoder if (!appId) { this.error(`appId is invalid`); } - + AgoraEnv.enableWebCodecDecode = true; this.engine = createAgoraRtcEngine() as IRtcEngineEx; this.engine.initialize({ appId, @@ -65,7 +63,6 @@ export default class VideoDecoder channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, }); this.engine.registerEventHandler(this); - this.engine.getMediaEngine().registerVideoEncodedFrameObserver(this); // Need granted the microphone and camera permission await askMediaAccess(['microphone', 'camera', 'screen']); @@ -74,7 +71,6 @@ export default class VideoDecoder // If you only call `enableAudio`, only relay the audio stream to the target channel this.engine.enableVideo(); // Start preview before joinChannel - // this.engine.startPreview(); this.setState({ startPreview: true }); } @@ -102,8 +98,6 @@ export default class VideoDecoder // Make myself as the broadcaster to send stream to remote clientRoleType: ClientRoleType.ClientRoleBroadcaster, }); - this.decoder = new WebCodecsDecoder(); - this.decoder.enableFps = true; } /** @@ -117,28 +111,10 @@ export default class VideoDecoder * Step 5: releaseRtcEngine */ protected releaseRtcEngine() { - this.engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this.engine?.unregisterEventHandler(this); this.engine?.release(); } - onEncodedVideoFrameReceived( - uid: number, - imageBuffer: Uint8Array, - length: number, - videoEncodedFrameInfo: EncodedVideoFrameInfo - ) { - if (uid == SCREEN_UID) { - // start decode - this.decoder?.decodeFrame( - imageBuffer, - videoEncodedFrameInfo, - new Date().getTime() - ); - this.setState({ fps: this.decoder?.getFps() || 0 }); - } - } - onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { this.engine?.setRemoteVideoSubscriptionOptions(remoteUid, { type: VideoStreamType.VideoStreamHigh, @@ -152,19 +128,44 @@ export default class VideoDecoder remoteUid: number, reason: UserOfflineReasonType ) { - if (remoteUid == SCREEN_UID) { - // stop decode - this.decoder?.release(); - } + // if (remoteUid == SCREEN_UID) { + // // stop decode + // this.decoder?.release(); + // } super.onUserOffline(connection, remoteUid, reason); } + // protected renderUsers(): ReactElement | undefined { + // let { fps } = this.state; + // return ( + // <> + //

Current Fps: {fps}

+ // + // { + // + // } + // + // ); + // } + protected renderUsers(): ReactElement | undefined { - let { fps } = this.state; + let { remoteUsers } = this.state; return ( <> -

Current Fps: {fps}

- + + this.renderUser({ + uid: item, + sourceType: VideoSourceType.VideoSourceRemote, + }) + } + /> ); } diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index 03e59483e..97ae29978 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -1,8 +1,8 @@ import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; -import { logDebug, logError } from '../Utils'; +import { logDebug } from '../Utils'; -import { WebGLRenderer } from './renderer_webgl'; +import { WebCodecsRenderer } from './WebCodecsRenderer'; const frameTypeMapping = { [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', @@ -14,7 +14,7 @@ export class WebCodecsDecoder { private _decoder: VideoDecoder; private _startTime: number | null = null; - private renderer: any; + private renderers: WebCodecsRenderer[] = []; private pendingFrame: VideoFrame | null = null; private _frameCount = 0; @@ -23,27 +23,20 @@ export class WebCodecsDecoder { private _base_ts_ntp = 1; private _last_ts_ntp = 1; - constructor() { - this.renderer = new WebGLRenderer( - 'webgl2', - document.querySelector('canvas')!.transferControlToOffscreen() - ); + constructor(renders: WebCodecsRenderer[]) { + this.renderers = renders; this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), error: this._error.bind(this), }); - this.decoder!.configure({ + this._decoder!.configure({ codec: 'hvc1.1.2.H153.90', codedWidth: 3840, codedHeight: 2160, }); } - getDecoder(): VideoDecoder { - return this._decoder; - } - _output(frame: VideoFrame) { this.getFps(); // Schedule the frame to be rendered. @@ -54,11 +47,7 @@ export class WebCodecsDecoder { console.error('Decoder error:', e); } - get decoder() { - return this._decoder; - } - - getFps(): number { + public getFps(): number { let fps = 0; if (!this.enableFps) { return fps; @@ -74,7 +63,7 @@ export class WebCodecsDecoder { return fps; } - _renderFrame(frame: VideoFrame) { + private _renderFrame(frame: VideoFrame) { if (!this.pendingFrame) { // Schedule rendering in the next animation frame. // eslint-disable-next-line auto-import/auto-import @@ -88,8 +77,10 @@ export class WebCodecsDecoder { } renderAnimationFrame() { - this.renderer.draw(this.pendingFrame); - this.pendingFrame = null; + for (let renderer of this.renderers) { + renderer.drawFrame(this.pendingFrame); + this.pendingFrame = null; + } } // @ts-ignore @@ -99,7 +90,16 @@ export class WebCodecsDecoder { ts: number ) { if (!imageBuffer) { - logError('imageBuffer is empty, cannot decode frame'); + logDebug('imageBuffer is empty, skip decode frame'); + return; + } + let frameType: string | undefined; + if (frameInfo.frameType !== undefined) { + // @ts-ignore + frameType = frameTypeMapping[frameInfo.frameType]; + } + if (!frameType) { + logDebug('frameType is not in frameTypeMapping, skip decode frame'); return; } this._frame_ts.push(ts); @@ -116,15 +116,6 @@ export class WebCodecsDecoder { this._base_ts = ts; this._last_ts_ntp = 1; } - let frameType: string | undefined; - if (frameInfo.frameType !== undefined) { - // @ts-ignore - frameType = frameTypeMapping[frameInfo.frameType]; - } - if (!frameType) { - logError('frameType is incorrect, cannot decode frame'); - return; - } this._decoder.decode( new EncodedVideoChunk({ data: imageBuffer, diff --git a/ts/Decoder/WebCodecsRenderer.ts b/ts/Decoder/WebCodecsRenderer.ts new file mode 100755 index 000000000..52e8e6b99 --- /dev/null +++ b/ts/Decoder/WebCodecsRenderer.ts @@ -0,0 +1,125 @@ +import { IRenderer } from '../Renderer/IRenderer'; + +import { getContextByCanvas } from '../Utils'; + +export class WebCodecsRenderer extends IRenderer { + gl?: WebGLRenderingContext | WebGL2RenderingContext | null; + // eslint-disable-next-line auto-import/auto-import + offscreenCanvas: OffscreenCanvas | undefined; + static vertexShaderSource = ` + attribute vec2 xy; + varying highp vec2 uv; + void main(void) { + gl_Position = vec4(xy, 0.0, 1.0); + // Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1). + // UV coordinates are Y-flipped relative to vertex coordinates. + uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0); + } + `; + static fragmentShaderSource = ` + varying highp vec2 uv; + uniform sampler2D texture; + void main(void) { + gl_FragColor = texture2D(texture, uv); + } + `; + + bind(element: HTMLElement) { + super.bind(element); + if (!this.canvas) return; + this.offscreenCanvas = this.canvas.transferControlToOffscreen(); + this.gl = getContextByCanvas(this.offscreenCanvas); + if (!this.gl) return; + const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER); + if (!vertexShader) return; + this.gl.shaderSource(vertexShader, WebCodecsRenderer.vertexShaderSource); + this.gl.compileShader(vertexShader); + if (!this.gl.getShaderParameter(vertexShader, this.gl.COMPILE_STATUS)) { + throw this.gl.getShaderInfoLog(vertexShader); + } + const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER); + if (!fragmentShader) return; + this.gl.shaderSource( + fragmentShader, + WebCodecsRenderer.fragmentShaderSource + ); + this.gl.compileShader(fragmentShader); + if (!this.gl.getShaderParameter(fragmentShader, this.gl.COMPILE_STATUS)) { + throw this.gl.getShaderInfoLog(fragmentShader); + } + const shaderProgram = this.gl.createProgram(); + if (!shaderProgram) return; + this.gl.attachShader(shaderProgram, vertexShader); + this.gl.attachShader(shaderProgram, fragmentShader); + this.gl.linkProgram(shaderProgram); + if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) { + throw this.gl.getProgramInfoLog(shaderProgram); + } + this.gl.useProgram(shaderProgram); + // Vertex coordinates, clockwise from bottom-left. + const vertexBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer); + 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 + ); + const xyLocation = this.gl.getAttribLocation(shaderProgram, 'xy'); + this.gl.vertexAttribPointer(xyLocation, 2, this.gl.FLOAT, false, 0, 0); + this.gl.enableVertexAttribArray(xyLocation); + // Create one texture to upload frames to. + const texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MAG_FILTER, + this.gl.NEAREST + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MIN_FILTER, + this.gl.NEAREST + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_S, + this.gl.CLAMP_TO_EDGE + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_T, + this.gl.CLAMP_TO_EDGE + ); + } + + drawFrame(frame: any) { + if (!this.offscreenCanvas) return; + this.offscreenCanvas.width = frame.displayWidth; + this.offscreenCanvas.height = frame.displayHeight; + if (!this.gl) return; + + if (this.gl) { + // Upload the frame. + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RGBA, + this.gl.RGBA, + this.gl.UNSIGNED_BYTE, + frame + ); + frame.close(); + // Configure and clear the drawing area. + this.gl.viewport( + 0, + 0, + this.gl.drawingBufferWidth, + this.gl.drawingBufferHeight + ); + this.gl.clearColor(1.0, 0.0, 0.0, 1.0); + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + // Draw the frame. + this.gl.drawArrays(this.gl.TRIANGLE_FAN, 0, 4); + } + } +} diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Decoder/WebCodecsRendererCache.ts new file mode 100644 index 000000000..b90d3691c --- /dev/null +++ b/ts/Decoder/WebCodecsRendererCache.ts @@ -0,0 +1,58 @@ +import { createAgoraRtcEngine } from '../AgoraSdk'; +import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; +import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; +import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; +import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; +import { IRendererCache } from '../Renderer/IRendererCache'; +import { RendererContext } from '../Types'; + +import { WebCodecsDecoder } from './WebCodecsDecoder'; +import { WebCodecsRenderer } from './WebCodecsRenderer'; + +export class WebCodecsRendererCache + extends IRendererCache + implements IVideoEncodedFrameObserver, IRtcEngineEventHandler +{ + private _decoder?: WebCodecsDecoder; + private _engine?: IRtcEngineEx; + + constructor({ channelId, uid, sourceType }: RendererContext) { + super({ channelId, uid, sourceType }); + this._engine = createAgoraRtcEngine(); + this._decoder = new WebCodecsDecoder( + this._renderers as WebCodecsRenderer[] + ); + this._decoder.enableFps = true; + this._engine.registerEventHandler(this); + } + + onEncodedVideoFrameReceived( + uid: number, + imageBuffer: Uint8Array, + length: number, + videoEncodedFrameInfo: EncodedVideoFrameInfo + ) { + if (!this._decoder) return; + this._decoder.decodeFrame( + imageBuffer, + videoEncodedFrameInfo, + new Date().getTime() + ); + } + + onUserJoined(connection: RtcConnection, remoteUid: number, _elapsed: number) { + if ( + remoteUid === this.context.uid && + connection.channelId === this.context.channelId + ) { + this._engine?.setRemoteVideoSubscriptionOptions(remoteUid, { + type: VideoStreamType.VideoStreamHigh, + encodedFrameOnly: true, + }); + } + } + + public draw() { + this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); + } +} diff --git a/ts/Decoder/renderer_webgl.ts b/ts/Decoder/renderer_webgl.ts deleted file mode 100755 index 5a74df4e1..000000000 --- a/ts/Decoder/renderer_webgl.ts +++ /dev/null @@ -1,86 +0,0 @@ -export class WebGLRenderer { - private _canvas: any = null; - private _ctx: any = null; - static vertexShaderSource = ` - attribute vec2 xy; - varying highp vec2 uv; - void main(void) { - gl_Position = vec4(xy, 0.0, 1.0); - // Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1). - // UV coordinates are Y-flipped relative to vertex coordinates. - uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0); - } - `; - static fragmentShaderSource = ` - varying highp vec2 uv; - uniform sampler2D texture; - void main(void) { - gl_FragColor = texture2D(texture, uv); - } - `; - constructor(type: any, canvas: any) { - this._canvas = canvas; - const gl = (this._ctx = canvas.getContext(type)); - const vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, WebGLRenderer.vertexShaderSource); - gl.compileShader(vertexShader); - if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { - throw gl.getShaderInfoLog(vertexShader); - } - const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, WebGLRenderer.fragmentShaderSource); - gl.compileShader(fragmentShader); - if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { - throw gl.getShaderInfoLog(fragmentShader); - } - const shaderProgram = gl.createProgram(); - gl.attachShader(shaderProgram, vertexShader); - gl.attachShader(shaderProgram, fragmentShader); - gl.linkProgram(shaderProgram); - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - throw gl.getProgramInfoLog(shaderProgram); - } - gl.useProgram(shaderProgram); - // Vertex coordinates, clockwise from bottom-left. - const vertexBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - new Float32Array([-1.0, -1.0, -1.0, +1.0, +1.0, +1.0, +1.0, -1.0]), - gl.STATIC_DRAW - ); - const xyLocation = gl.getAttribLocation(shaderProgram, 'xy'); - gl.vertexAttribPointer(xyLocation, 2, gl.FLOAT, false, 0, 0); - gl.enableVertexAttribArray(xyLocation); - // Create one texture to upload frames to. - const texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - draw(frame: any) { - this._canvas.width = frame.displayWidth; - this._canvas.height = frame.displayHeight; - const gl = this._ctx; - if (gl) { - // Upload the frame. - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.RGBA, - gl.RGBA, - gl.UNSIGNED_BYTE, - frame - ); - frame.close(); - // Configure and clear the drawing area. - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - gl.clearColor(1.0, 0.0, 0.0, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT); - // Draw the frame. - gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); - } - } -} diff --git a/ts/Renderer/IRenderer.ts b/ts/Renderer/IRenderer.ts index d37016b21..9082a13dd 100644 --- a/ts/Renderer/IRenderer.ts +++ b/ts/Renderer/IRenderer.ts @@ -1,6 +1,6 @@ import { VideoMirrorModeType } from '../Private/AgoraBase'; import { RenderModeType, VideoFrame } from '../Private/AgoraMediaBase'; -import { RendererContext } from '../Types'; +import { RendererContext, RendererType } from '../Types'; type Context = Pick; @@ -8,6 +8,7 @@ export abstract class IRenderer { parentElement?: HTMLElement; container?: HTMLElement; canvas?: HTMLCanvasElement; + rendererType: RendererType | undefined; _context: Context = {}; public bind(element: HTMLElement) { diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts new file mode 100644 index 000000000..d9b87920b --- /dev/null +++ b/ts/Renderer/IRendererCache.ts @@ -0,0 +1,84 @@ +import { RendererCacheContext, RendererContext } from '../Types'; + +import { IRenderer } from './IRenderer'; + +export function generateRendererCacheKey({ + channelId, + uid, + sourceType, +}: RendererContext): string { + return `${channelId}_${uid}_${sourceType}`; +} + +export abstract class IRendererCache { + _renderers: IRenderer[]; + _context: RendererCacheContext; + + constructor({ channelId, uid, sourceType }: RendererContext) { + this._renderers = []; + this._context = { channelId, uid, sourceType }; + } + + public get key(): string { + return generateRendererCacheKey(this._context); + } + + public get renderers(): IRenderer[] { + return this._renderers; + } + + public get context(): RendererCacheContext { + return this._context; + } + + /** + * @deprecated Use renderers instead + */ + public get renders(): IRenderer[] { + return this.renderers; + } + + public abstract draw(): void; + + public findRenderer(view: Element): IRenderer | undefined { + return this._renderers.find((renderer) => renderer.parentElement === view); + } + + public addRenderer(renderer: IRenderer): void { + this._renderers.push(renderer); + } + + /** + * Remove the specified renderer if it is specified, otherwise remove all renderers + */ + public removeRenderer(renderer?: IRenderer): void { + let start = 0; + let deleteCount = this._renderers.length; + if (renderer) { + start = this._renderers.indexOf(renderer); + if (start < 0) return; + deleteCount = 1; + } + this._renderers.splice(start, deleteCount).forEach((it) => it.unbind()); + } + + public setRendererContext({ + view, + renderMode, + mirrorMode, + }: RendererContext): boolean { + if (view) { + const renderer = this.findRenderer(view); + if (renderer) { + renderer.context = { renderMode, mirrorMode }; + return true; + } + return false; + } else { + this._renderers.forEach((it) => { + it.context = { renderMode, mirrorMode }; + }); + return this._renderers.length > 0; + } + } +} diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index f4cab0830..5a6783a6d 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -1,10 +1,13 @@ +import { WebCodecsRendererCache } from '../Decoder/WebCodecsRendererCache'; + import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { RendererContext, RendererType } from '../Types'; -import { logDebug } from '../Utils'; +import { RendererCacheType, RendererContext, RendererType } from '../Types'; +import { AgoraEnv, logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; -import { RendererCache, generateRendererCacheKey } from './RendererCache'; +import { generateRendererCacheKey } from './IRendererCache'; +import { RendererCache } from './RendererCache'; /** * @ignore @@ -29,20 +32,14 @@ export abstract class IRendererManager { /** * @ignore */ - private _rendererCaches: RendererCache[]; + private _rendererCaches: RendererCacheType[]; /** * @ignore */ private _context: RendererContext; - /** - * @ignore - */ - private _webCodecDecoderEnabled: boolean; constructor() { this._renderingFps = 15; - //todo Enable the WebCodecDecoder by default temporarily - this._webCodecDecoderEnabled = true; this._currentFrameCount = 0; this._previousFirstFrameTime = 0; this._rendererCaches = []; @@ -52,14 +49,6 @@ export abstract class IRendererManager { }; } - public set webCodecDecoderEnabled(value: boolean) { - this._webCodecDecoderEnabled = value; - } - - public get webCodecDecoderEnabled(): boolean { - return this._webCodecDecoderEnabled; - } - public set renderingFps(fps: number) { if (this._renderingFps !== fps) { this._renderingFps = fps; @@ -133,7 +122,7 @@ export abstract class IRendererManager { public addOrRemoveRenderer( context: RendererContext - ): RendererCache | undefined { + ): RendererCacheType | undefined { // To be compatible with the old API let { setupMode = VideoViewSetupMode.VideoViewSetupAdd } = context; if (!context.view) setupMode = VideoViewSetupMode.VideoViewSetupRemove; @@ -151,7 +140,7 @@ export abstract class IRendererManager { private addRendererToCache( context: RendererContext - ): RendererCache | undefined { + ): RendererCacheType | undefined { const checkedContext = this.precheckRendererContext(context); if (!checkedContext.view) return undefined; @@ -162,7 +151,11 @@ export abstract class IRendererManager { let rendererCache = this.getRendererCache(checkedContext); if (!rendererCache) { - rendererCache = new RendererCache(checkedContext); + if (AgoraEnv.enableWebCodecDecode) { + rendererCache = new WebCodecsRendererCache(checkedContext); + } else { + rendererCache = new RendererCache(checkedContext); + } this._rendererCaches.push(rendererCache); } rendererCache.addRenderer(this.createRenderer(checkedContext)); @@ -197,7 +190,9 @@ export abstract class IRendererManager { this._rendererCaches.splice(0); } - public getRendererCache(context: RendererContext): RendererCache | undefined { + public getRendererCache( + context: RendererContext + ): RendererCacheType | undefined { return this._rendererCaches.find( (cache) => cache.key === generateRendererCacheKey(context) ); @@ -280,7 +275,7 @@ export abstract class IRendererManager { renderingLooper(); } - public abstract doRendering(rendererCache: RendererCache): void; + public abstract doRendering(rendererCache: RendererCacheType): void; public stopRendering(): void { if (this._renderingTimer) { diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index 782f2c4f4..b771b1a87 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -1,25 +1,16 @@ import { VideoFrame } from '../Private/AgoraMediaBase'; -import { RendererCacheContext, RendererContext } from '../Types'; +import { RendererContext } from '../Types'; import { AgoraEnv, logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; +import { IRendererCache } from './IRendererCache'; -export function generateRendererCacheKey({ - channelId, - uid, - sourceType, -}: RendererContext): string { - return `${channelId}_${uid}_${sourceType}`; -} - -export class RendererCache { - private _renderers: IRenderer[]; +export class RendererCache extends IRendererCache { private _videoFrame: VideoFrame; - private _context: RendererCacheContext; private _enabled: boolean; constructor({ channelId, uid, sourceType }: RendererContext) { - this._renderers = []; + super({ channelId, uid, sourceType }); this._videoFrame = { yBuffer: Buffer.alloc(0), uBuffer: Buffer.alloc(0), @@ -31,33 +22,13 @@ export class RendererCache { vStride: 0, rotation: 0, }; - this._context = { channelId, uid, sourceType }; this._enabled = false; } - public get key(): string { - return generateRendererCacheKey(this._context); - } - - public get renderers(): IRenderer[] { - return this._renderers; - } - public get videoFrame(): VideoFrame { return this._videoFrame; } - public get context(): RendererCacheContext { - return this._context; - } - - /** - * @deprecated Use renderers instead - */ - public get renders(): IRenderer[] { - return this.renderers; - } - /** * @deprecated Use videoFrame instead */ @@ -89,7 +60,7 @@ export class RendererCache { } } - public draw() { + override draw() { let { ret, isNewFrame } = this.bridge.GetVideoFrame( this.context, this.videoFrame @@ -121,47 +92,16 @@ export class RendererCache { } } - public findRenderer(view: Element): IRenderer | undefined { - return this._renderers.find((renderer) => renderer.parentElement === view); - } - - public addRenderer(renderer: IRenderer): void { - this._renderers.push(renderer); + override addRenderer(renderer: IRenderer): void { + super.addRenderer(renderer); this.shouldEnable(); } /** * Remove the specified renderer if it is specified, otherwise remove all renderers */ - public removeRenderer(renderer?: IRenderer): void { - let start = 0; - let deleteCount = this._renderers.length; - if (renderer) { - start = this._renderers.indexOf(renderer); - if (start < 0) return; - deleteCount = 1; - } - this._renderers.splice(start, deleteCount).forEach((it) => it.unbind()); + override removeRenderer(renderer?: IRenderer): void { + super.removeRenderer(renderer); this.shouldEnable(); } - - public setRendererContext({ - view, - renderMode, - mirrorMode, - }: RendererContext): boolean { - if (view) { - const renderer = this.findRenderer(view); - if (renderer) { - renderer.context = { renderMode, mirrorMode }; - return true; - } - return false; - } else { - this._renderers.forEach((it) => { - it.context = { renderMode, mirrorMode }; - }); - return this._renderers.length > 0; - } - } } diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 09ed6b3f0..3ade933f0 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,14 +1,16 @@ +import { WebCodecsRenderer } from '../Decoder/WebCodecsRenderer'; + import { RENDER_MODE, RendererCacheContext, + RendererCacheType, RendererContext, RendererType, } from '../Types'; -import { isSupportWebGL } from '../Utils'; +import { AgoraEnv, isSupportWebGL } from '../Utils'; import { IRenderer } from './IRenderer'; import { IRendererManager } from './IRendererManager'; -import { RendererCache } from './RendererCache'; import { WebGLFallback, WebGLRenderer } from './WebGLRenderer'; import { YUVCanvasRenderer } from './YUVCanvasRenderer'; @@ -55,7 +57,9 @@ export class RendererManager extends IRendererManager { /** * @deprecated Use getRendererCache instead */ - public getRender(context: RendererCacheContext): RendererCache | undefined { + public getRender( + context: RendererCacheContext + ): RendererCacheType | undefined { return this.getRendererCache(context); } @@ -70,9 +74,13 @@ export class RendererManager extends IRendererManager { let renderer: IRenderer; switch (rendererType) { case RendererType.WEBGL: - renderer = new WebGLRenderer( - this.handleWebGLFallback(context).bind(this) - ); + if (AgoraEnv.enableWebCodecDecode) { + renderer = new WebCodecsRenderer(); + } else { + renderer = new WebGLRenderer( + this.handleWebGLFallback(context).bind(this) + ); + } break; case RendererType.SOFTWARE: renderer = new YUVCanvasRenderer(); @@ -89,7 +97,7 @@ export class RendererManager extends IRendererManager { return renderer; } - public override doRendering(rendererCache: RendererCache): void { + public override doRendering(rendererCache: RendererCacheType): void { rendererCache.draw(); } diff --git a/ts/Types.ts b/ts/Types.ts index d75aa4cd5..d7a5508a1 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,7 +1,9 @@ +import { WebCodecsRendererCache } from './Decoder/WebCodecsRendererCache'; import { VideoCanvas } from './Private/AgoraBase'; import { VideoFrame } from './Private/AgoraMediaBase'; import { RtcConnection } from './Private/IAgoraRtcEngineEx'; import { IRendererManager } from './Renderer'; +import { RendererCache } from './Renderer/RendererCache'; /** * @ignore @@ -19,6 +21,10 @@ export interface AgoraEnvOptions { * @ignore */ webEnvReady?: boolean; + /** + * @ignore + */ + enableWebCodecDecode?: boolean; } /** @@ -52,6 +58,7 @@ export enum RendererType { export type RENDER_MODE = RendererType; export type RendererContext = VideoCanvas & RtcConnection; +export type RendererCacheType = RendererCache | WebCodecsRendererCache; export type RendererCacheContext = Pick< RendererContext, diff --git a/ts/Utils.ts b/ts/Utils.ts index 0933cccce..770e530ff 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -123,6 +123,36 @@ export function isSupportWebGL(): boolean { return flag; } +/** + * @ignore + */ +export function getContextByCanvas( + // eslint-disable-next-line auto-import/auto-import + canvas: OffscreenCanvas +): WebGLRenderingContext | WebGL2RenderingContext | null { + const contextNames = ['webgl2', 'webgl', 'experimental-webgl']; + + for (const contextName of contextNames) { + //@ts-ignore + const context = canvas.getContext(contextName, { + depth: true, + stencil: true, + alpha: false, + antialias: false, + premultipliedAlpha: true, + preserveDrawingBuffer: true, + powerPreference: 'default', + failIfMajorPerformanceCaveat: false, + }) as WebGLRenderingContext | WebGL2RenderingContext | null; + + if (context) { + return context; + } + } + + return null; +} + const AgoraNode = require('../build/Release/agora_node_ext'); /** @@ -131,6 +161,7 @@ const AgoraNode = require('../build/Release/agora_node_ext'); export const AgoraEnv: AgoraEnvType = { enableLogging: true, enableDebugLogging: false, + enableWebCodecDecode: false, webEnvReady: true, AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From 9576797af8ee574cf6e31bcf63be9fac6186e0d4 Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 2 Apr 2024 16:11:30 +0800 Subject: [PATCH 006/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 45 +------------------ ts/Decoder/WebCodecsDecoder.ts | 21 ++++++++- ts/Decoder/WebCodecsRenderer.ts | 1 + ts/Decoder/WebCodecsRendererCache.ts | 7 +++ ts/Renderer/IRenderer.ts | 1 - ts/Renderer/IRendererCache.ts | 4 ++ ts/Renderer/IRendererManager.ts | 10 +++-- ts/Renderer/RendererCache.ts | 4 ++ 8 files changed, 44 insertions(+), 49 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index f9be35cec..b147080e0 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -4,10 +4,8 @@ import { ClientRoleType, IRtcEngineEventHandler, IRtcEngineEx, - RtcConnection, - UserOfflineReasonType, + RenderModeType, VideoSourceType, - VideoStreamType, createAgoraRtcEngine, } from 'agora-electron-sdk'; import React, { ReactElement } from 'react'; @@ -28,9 +26,7 @@ export default class VideoDecoder extends BaseComponent<{}, State> implements IRtcEngineEventHandler { - // @ts-ignore protected engine?: IRtcEngineEx; - // private decoder?: WebCodecsDecoder; protected createState(): State { return { @@ -115,44 +111,6 @@ export default class VideoDecoder this.engine?.release(); } - onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { - this.engine?.setRemoteVideoSubscriptionOptions(remoteUid, { - type: VideoStreamType.VideoStreamHigh, - encodedFrameOnly: true, - }); - super.onUserJoined(connection, remoteUid, elapsed); - } - - onUserOffline( - connection: RtcConnection, - remoteUid: number, - reason: UserOfflineReasonType - ) { - // if (remoteUid == SCREEN_UID) { - // // stop decode - // this.decoder?.release(); - // } - super.onUserOffline(connection, remoteUid, reason); - } - - // protected renderUsers(): ReactElement | undefined { - // let { fps } = this.state; - // return ( - // <> - //

Current Fps: {fps}

- // - // { - // - // } - // - // ); - // } - protected renderUsers(): ReactElement | undefined { let { remoteUsers } = this.state; return ( @@ -163,6 +121,7 @@ export default class VideoDecoder this.renderUser({ uid: item, sourceType: VideoSourceType.VideoSourceRemote, + renderMode: RenderModeType.RenderModeFit, }) } /> diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index 97ae29978..6a409ae23 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -1,6 +1,6 @@ import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; -import { logDebug } from '../Utils'; +import { AgoraEnv, logDebug } from '../Utils'; import { WebCodecsRenderer } from './WebCodecsRenderer'; @@ -58,8 +58,18 @@ export class WebCodecsDecoder { } else { const elapsed = (performance.now() - this._startTime) / 1000; fps = ++this._frameCount / elapsed; - logDebug('render', `${fps.toFixed(0)} fps`); + // logDebug('render', `${fps.toFixed(0)} fps`); } + + if (AgoraEnv.enableWebCodecDecode) { + let span = document.createElement('span'); + span.innerText = `fps: ${fps.toFixed(0)}`; + + for (let renderer of this.renderers) { + renderer.container?.appendChild(span); + } + } + return fps; } @@ -89,6 +99,13 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { + console.log( + 'FRAMETYPE', + frameInfo.frameType, + frameInfo, + imageBuffer, + imageBuffer.length + ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; diff --git a/ts/Decoder/WebCodecsRenderer.ts b/ts/Decoder/WebCodecsRenderer.ts index 52e8e6b99..32c287640 100755 --- a/ts/Decoder/WebCodecsRenderer.ts +++ b/ts/Decoder/WebCodecsRenderer.ts @@ -96,6 +96,7 @@ export class WebCodecsRenderer extends IRenderer { if (!this.offscreenCanvas) return; this.offscreenCanvas.width = frame.displayWidth; this.offscreenCanvas.height = frame.displayHeight; + this.updateRenderMode(); if (!this.gl) return; if (this.gl) { diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Decoder/WebCodecsRendererCache.ts index b90d3691c..279de7675 100644 --- a/ts/Decoder/WebCodecsRendererCache.ts +++ b/ts/Decoder/WebCodecsRendererCache.ts @@ -55,4 +55,11 @@ export class WebCodecsRendererCache public draw() { this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } + + public release(): void { + this._decoder?.release(); + this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); + this._engine?.unregisterEventHandler(this); + super.release(); + } } diff --git a/ts/Renderer/IRenderer.ts b/ts/Renderer/IRenderer.ts index 9082a13dd..d13af9ebc 100644 --- a/ts/Renderer/IRenderer.ts +++ b/ts/Renderer/IRenderer.ts @@ -71,7 +71,6 @@ export abstract class IRenderer { const canvasAspectRatio = width / height; const widthScale = clientWidth / width; const heightScale = clientHeight / height; - const isHidden = this.context?.renderMode === RenderModeType.RenderModeHidden; diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index d9b87920b..079bc782f 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -81,4 +81,8 @@ export abstract class IRendererCache { return this._renderers.length > 0; } } + + public release(): void { + this.removeRenderer(); + } } diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index 5a6783a6d..266d852c0 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -60,7 +60,11 @@ export abstract class IRendererManager { } public get renderingFps(): number { - return this._renderingFps; + if (AgoraEnv.enableWebCodecDecode) { + return new Error('Not supported') as any; + } else { + return this._renderingFps; + } } public set defaultChannelId(channelId: string) { @@ -185,7 +189,7 @@ export abstract class IRendererManager { public clearRendererCache(): void { for (const rendererCache of this._rendererCaches) { - rendererCache.removeRenderer(); + rendererCache.release(); } this._rendererCaches.splice(0); } @@ -216,7 +220,7 @@ export abstract class IRendererManager { ): IRenderer; public startRendering(): void { - if (this._renderingTimer) return; + if (AgoraEnv.enableWebCodecDecode && this._renderingTimer) return; const renderingLooper = () => { if (this._previousFirstFrameTime === 0) { diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index b771b1a87..4c357f1ff 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -104,4 +104,8 @@ export class RendererCache extends IRendererCache { super.removeRenderer(renderer); this.shouldEnable(); } + + public release(): void { + super.release(); + } } From 32f56ec815fbb5a4b41568aa2d82445b89fc5200 Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 2 Apr 2024 18:19:55 +0800 Subject: [PATCH 007/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 1 + ts/Decoder/WebCodecsDecoder.ts | 42 +++++++++++++------ ts/Decoder/WebCodecsRendererCache.ts | 5 ++- ts/Private/internal/RtcEngineExInternal.ts | 11 ++++- ts/Renderer/IRendererManager.ts | 1 + 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index b147080e0..aed0004a3 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -109,6 +109,7 @@ export default class VideoDecoder protected releaseRtcEngine() { this.engine?.unregisterEventHandler(this); this.engine?.release(); + AgoraEnv.enableWebCodecDecode = false; } protected renderUsers(): ReactElement | undefined { diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index 6a409ae23..6a8cccc6f 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -58,15 +58,31 @@ export class WebCodecsDecoder { } else { const elapsed = (performance.now() - this._startTime) / 1000; fps = ++this._frameCount / elapsed; - // logDebug('render', `${fps.toFixed(0)} fps`); } if (AgoraEnv.enableWebCodecDecode) { - let span = document.createElement('span'); - span.innerText = `fps: ${fps.toFixed(0)}`; - for (let renderer of this.renderers) { - renderer.container?.appendChild(span); + if (!renderer.container) continue; + + let span = renderer.container.querySelector('span'); + if (!span) { + span = document.createElement('span'); + + Object.assign(span.style, { + position: 'absolute', + bottom: '0', + left: '0', + zIndex: '10', + width: '50px', + background: '#fff', + }); + + renderer.container.style.position = 'relative'; + + renderer.container.appendChild(span); + } + + span.innerText = `fps: ${fps.toFixed(0)}`; } } @@ -99,13 +115,13 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { - console.log( - 'FRAMETYPE', - frameInfo.frameType, - frameInfo, - imageBuffer, - imageBuffer.length - ); + // console.log( + // 'FRAMETYPE', + // frameInfo.frameType, + // frameInfo, + // imageBuffer, + // imageBuffer.length + // ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; @@ -146,7 +162,7 @@ export class WebCodecsDecoder { } release() { - this._decoder.reset(); + this.pendingFrame = null; this._decoder.close(); } } diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Decoder/WebCodecsRendererCache.ts index 279de7675..da985531d 100644 --- a/ts/Decoder/WebCodecsRendererCache.ts +++ b/ts/Decoder/WebCodecsRendererCache.ts @@ -13,7 +13,7 @@ export class WebCodecsRendererCache extends IRendererCache implements IVideoEncodedFrameObserver, IRtcEngineEventHandler { - private _decoder?: WebCodecsDecoder; + private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; constructor({ channelId, uid, sourceType }: RendererContext) { @@ -57,9 +57,10 @@ export class WebCodecsRendererCache } public release(): void { - this._decoder?.release(); this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); + this._decoder?.release(); + this._decoder = null; super.release(); } } diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index a2b917f4c..780774d20 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -111,6 +111,9 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { this._video_device_manager.release(); this._media_engine.release(); this._local_spatial_audio_engine.release(); + RtcEngineExInternal._event_handlers.map((it) => { + super.unregisterEventHandler(it); + }); RtcEngineExInternal._event_handlers = []; RtcEngineExInternal._direct_cdn_streaming_event_handler = []; RtcEngineExInternal._metadata_observer = []; @@ -231,6 +234,8 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { } override registerEventHandler(eventHandler: IRtcEngineEventHandler): boolean { + // only call iris when no event handler registered + let callIris = RtcEngineExInternal._event_handlers.length === 0; if ( !RtcEngineExInternal._event_handlers.find( (value) => value === eventHandler @@ -238,7 +243,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { ) { RtcEngineExInternal._event_handlers.push(eventHandler); } - return super.registerEventHandler(eventHandler); + return callIris ? super.registerEventHandler(eventHandler) : true; } override unregisterEventHandler( @@ -248,7 +253,9 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { RtcEngineExInternal._event_handlers.filter( (value) => value !== eventHandler ); - return super.unregisterEventHandler(eventHandler); + // only call iris when no event handler registered + let callIris = RtcEngineExInternal._event_handlers.length === 0; + return callIris ? super.unregisterEventHandler(eventHandler) : true; } override createMediaPlayer(): IMediaPlayer { diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index 266d852c0..ff102b946 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -180,6 +180,7 @@ export abstract class IRendererManager { rendererCache.removeRenderer(); } if (rendererCache.renderers.length === 0) { + rendererCache.release(); this._rendererCaches.splice( this._rendererCaches.indexOf(rendererCache), 1 From efdd91cce11ee4de4a2bcaacc62d9ee49987406a Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 2 Apr 2024 21:07:07 +0800 Subject: [PATCH 008/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 12 ++- ts/Decoder/WebCodecsDecoder.ts | 80 ++++++++++++------- ts/Decoder/WebCodecsRendererCache.ts | 8 +- ts/Private/extension/AgoraBaseExtension.ts | 11 ++- ts/Renderer/IRendererCache.ts | 1 + ts/Renderer/IRendererManager.ts | 16 ++-- ts/Renderer/RendererCache.ts | 1 + ts/Renderer/RendererManager.ts | 4 +- ts/Types.ts | 6 +- ts/Utils.ts | 1 - 10 files changed, 89 insertions(+), 51 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index aed0004a3..34d978d4e 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -1,5 +1,4 @@ import { - AgoraEnv, ChannelProfileType, ClientRoleType, IRtcEngineEventHandler, @@ -50,7 +49,6 @@ export default class VideoDecoder if (!appId) { this.error(`appId is invalid`); } - AgoraEnv.enableWebCodecDecode = true; this.engine = createAgoraRtcEngine() as IRtcEngineEx; this.engine.initialize({ appId, @@ -67,6 +65,7 @@ export default class VideoDecoder // If you only call `enableAudio`, only relay the audio stream to the target channel this.engine.enableVideo(); // Start preview before joinChannel + this.engine?.startPreview(); this.setState({ startPreview: true }); } @@ -109,19 +108,24 @@ export default class VideoDecoder protected releaseRtcEngine() { this.engine?.unregisterEventHandler(this); this.engine?.release(); - AgoraEnv.enableWebCodecDecode = false; } protected renderUsers(): ReactElement | undefined { - let { remoteUsers } = this.state; + let { remoteUsers, startPreview, joinChannelSuccess } = this.state; return ( <> + {!!startPreview || joinChannelSuccess + ? this.renderUser({ + sourceType: VideoSourceType.VideoSourceCamera, + }) + : undefined} this.renderUser({ uid: item, sourceType: VideoSourceType.VideoSourceRemote, + useWebCodecsDecoder: true, renderMode: RenderModeType.RenderModeFit, }) } diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index 6a8cccc6f..d6ff6fc41 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -1,6 +1,10 @@ -import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; +import { + EncodedVideoFrameInfo, + VideoCodecType, + VideoFrameType, +} from '../Private/AgoraBase'; -import { AgoraEnv, logDebug } from '../Utils'; +import { logDebug, logInfo } from '../Utils'; import { WebCodecsRenderer } from './WebCodecsRenderer'; @@ -9,6 +13,13 @@ const frameTypeMapping = { [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', }; +export const frameCodecMapping = { + [VideoCodecType.VideoCodecH265]: 'hvc1.1.6.L5.90', + [VideoCodecType.VideoCodecH264]: 'avc1.64e01f', + [VideoCodecType.VideoCodecVp8]: 'vp8', + [VideoCodecType.VideoCodecVp9]: 'vp9', +}; + export class WebCodecsDecoder { public enableFps = false; @@ -30,11 +41,6 @@ export class WebCodecsDecoder { output: this._output.bind(this), error: this._error.bind(this), }); - this._decoder!.configure({ - codec: 'hvc1.1.2.H153.90', - codedWidth: 3840, - codedHeight: 2160, - }); } _output(frame: VideoFrame) { @@ -44,6 +50,7 @@ export class WebCodecsDecoder { } _error(e: any) { + window.alert(`Decoder error:${JSON.stringify(e)}`); console.error('Decoder error:', e); } @@ -60,30 +67,28 @@ export class WebCodecsDecoder { fps = ++this._frameCount / elapsed; } - if (AgoraEnv.enableWebCodecDecode) { - for (let renderer of this.renderers) { - if (!renderer.container) continue; - - let span = renderer.container.querySelector('span'); - if (!span) { - span = document.createElement('span'); + for (let renderer of this.renderers) { + if (!renderer.container) continue; - Object.assign(span.style, { - position: 'absolute', - bottom: '0', - left: '0', - zIndex: '10', - width: '50px', - background: '#fff', - }); + let span = renderer.container.querySelector('span'); + if (!span) { + span = document.createElement('span'); - renderer.container.style.position = 'relative'; + Object.assign(span.style, { + position: 'absolute', + bottom: '0', + left: '0', + zIndex: '10', + width: '55px', + background: '#fff', + }); - renderer.container.appendChild(span); - } + renderer.container.style.position = 'relative'; - span.innerText = `fps: ${fps.toFixed(0)}`; + renderer.container.appendChild(span); } + + span.innerText = `fps: ${fps.toFixed(0)}`; } return fps; @@ -113,7 +118,8 @@ export class WebCodecsDecoder { decodeFrame( imageBuffer: Uint8Array, frameInfo: EncodedVideoFrameInfo, - ts: number + ts: number, + firstFrame: boolean ) { // console.log( // 'FRAMETYPE', @@ -135,6 +141,22 @@ export class WebCodecsDecoder { logDebug('frameType is not in frameTypeMapping, skip decode frame'); return; } + // @ts-ignore + let codec = frameCodecMapping[frameInfo.codecType]; + if (!codec) { + logDebug('codec is not in frameCodecMapping, skip decode frame'); + return; + } + if (firstFrame) { + this._decoder!.configure({ + codec: codec, + codedWidth: frameInfo.width, + codedHeight: frameInfo.height, + }); + logInfo( + `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` + ); + } this._frame_ts.push(ts); if (this._base_ts !== 0) { if (ts > this._base_ts) { @@ -163,6 +185,8 @@ export class WebCodecsDecoder { release() { this.pendingFrame = null; - this._decoder.close(); + try { + this._decoder.close(); + } catch (e) {} } } diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Decoder/WebCodecsRendererCache.ts index da985531d..ad4ccb9f3 100644 --- a/ts/Decoder/WebCodecsRendererCache.ts +++ b/ts/Decoder/WebCodecsRendererCache.ts @@ -15,6 +15,7 @@ export class WebCodecsRendererCache { private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; + private _firstFrame = true; constructor({ channelId, uid, sourceType }: RendererContext) { super({ channelId, uid, sourceType }); @@ -23,6 +24,7 @@ export class WebCodecsRendererCache this._renderers as WebCodecsRenderer[] ); this._decoder.enableFps = true; + this.selfDecode = true; this._engine.registerEventHandler(this); } @@ -36,8 +38,12 @@ export class WebCodecsRendererCache this._decoder.decodeFrame( imageBuffer, videoEncodedFrameInfo, - new Date().getTime() + new Date().getTime(), + this._firstFrame ); + if (this._firstFrame) { + this._firstFrame = false; + } } onUserJoined(connection: RtcConnection, remoteUid: number, _elapsed: number) { diff --git a/ts/Private/extension/AgoraBaseExtension.ts b/ts/Private/extension/AgoraBaseExtension.ts index cb0ff5c3b..d21d90bff 100644 --- a/ts/Private/extension/AgoraBaseExtension.ts +++ b/ts/Private/extension/AgoraBaseExtension.ts @@ -1 +1,10 @@ -export {}; +import '../AgoraBase'; + +declare module '../AgoraBase' { + interface VideoCanvas { + /** + * @ignore + */ + useWebCodecsDecoder?: boolean; + } +} diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index 079bc782f..a8ca0b2c9 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -13,6 +13,7 @@ export function generateRendererCacheKey({ export abstract class IRendererCache { _renderers: IRenderer[]; _context: RendererCacheContext; + selfDecode: boolean = false; constructor({ channelId, uid, sourceType }: RendererContext) { this._renderers = []; diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index ff102b946..c1642fa43 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -3,7 +3,7 @@ import { WebCodecsRendererCache } from '../Decoder/WebCodecsRendererCache'; import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; -import { AgoraEnv, logDebug } from '../Utils'; +import { logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; import { generateRendererCacheKey } from './IRendererCache'; @@ -60,11 +60,7 @@ export abstract class IRendererManager { } public get renderingFps(): number { - if (AgoraEnv.enableWebCodecDecode) { - return new Error('Not supported') as any; - } else { - return this._renderingFps; - } + return this._renderingFps; } public set defaultChannelId(channelId: string) { @@ -155,7 +151,7 @@ export abstract class IRendererManager { let rendererCache = this.getRendererCache(checkedContext); if (!rendererCache) { - if (AgoraEnv.enableWebCodecDecode) { + if (context.useWebCodecsDecoder) { rendererCache = new WebCodecsRendererCache(checkedContext); } else { rendererCache = new RendererCache(checkedContext); @@ -163,7 +159,9 @@ export abstract class IRendererManager { this._rendererCaches.push(rendererCache); } rendererCache.addRenderer(this.createRenderer(checkedContext)); - this.startRendering(); + if (!context.useWebCodecsDecoder) { + this.startRendering(); + } return rendererCache; } @@ -221,7 +219,7 @@ export abstract class IRendererManager { ): IRenderer; public startRendering(): void { - if (AgoraEnv.enableWebCodecDecode && this._renderingTimer) return; + if (this._renderingTimer) return; const renderingLooper = () => { if (this._previousFirstFrameTime === 0) { diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index 4c357f1ff..fee31f1c6 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -23,6 +23,7 @@ export class RendererCache extends IRendererCache { rotation: 0, }; this._enabled = false; + this.selfDecode = false; } public get videoFrame(): VideoFrame { diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 3ade933f0..7571dca8e 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -7,7 +7,7 @@ import { RendererContext, RendererType, } from '../Types'; -import { AgoraEnv, isSupportWebGL } from '../Utils'; +import { isSupportWebGL } from '../Utils'; import { IRenderer } from './IRenderer'; import { IRendererManager } from './IRendererManager'; @@ -74,7 +74,7 @@ export class RendererManager extends IRendererManager { let renderer: IRenderer; switch (rendererType) { case RendererType.WEBGL: - if (AgoraEnv.enableWebCodecDecode) { + if (context.useWebCodecsDecoder) { renderer = new WebCodecsRenderer(); } else { renderer = new WebGLRenderer( diff --git a/ts/Types.ts b/ts/Types.ts index d7a5508a1..74b0af8a1 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -21,10 +21,6 @@ export interface AgoraEnvOptions { * @ignore */ webEnvReady?: boolean; - /** - * @ignore - */ - enableWebCodecDecode?: boolean; } /** @@ -62,7 +58,7 @@ export type RendererCacheType = RendererCache | WebCodecsRendererCache; export type RendererCacheContext = Pick< RendererContext, - 'channelId' | 'uid' | 'sourceType' + 'channelId' | 'uid' | 'sourceType' | 'useWebCodecsDecoder' >; /** diff --git a/ts/Utils.ts b/ts/Utils.ts index 770e530ff..82bf1b393 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -161,7 +161,6 @@ const AgoraNode = require('../build/Release/agora_node_ext'); export const AgoraEnv: AgoraEnvType = { enableLogging: true, enableDebugLogging: false, - enableWebCodecDecode: false, webEnvReady: true, AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From 9e37e84400f42b5d7de58ac033779731e84228d2 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 3 Apr 2024 11:35:52 +0800 Subject: [PATCH 009/101] chore: optimize --- ts/Decoder/WebCodecsDecoder.ts | 68 +++++++++++++++------------- ts/Decoder/WebCodecsRenderer.ts | 17 ++++++- ts/Decoder/WebCodecsRendererCache.ts | 26 ++++++++--- 3 files changed, 70 insertions(+), 41 deletions(-) diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts index d6ff6fc41..ff50bf6bd 100644 --- a/ts/Decoder/WebCodecsDecoder.ts +++ b/ts/Decoder/WebCodecsDecoder.ts @@ -34,12 +34,12 @@ export class WebCodecsDecoder { private _base_ts_ntp = 1; private _last_ts_ntp = 1; - constructor(renders: WebCodecsRenderer[]) { + constructor(renders: WebCodecsRenderer[], onError: (e: any) => void) { this.renderers = renders; this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), - error: this._error.bind(this), + error: onError, }); } @@ -49,11 +49,6 @@ export class WebCodecsDecoder { this._renderFrame(frame); } - _error(e: any) { - window.alert(`Decoder error:${JSON.stringify(e)}`); - console.error('Decoder error:', e); - } - public getFps(): number { let fps = 0; if (!this.enableFps) { @@ -114,20 +109,45 @@ export class WebCodecsDecoder { } } + decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { + // @ts-ignore + let codec = frameCodecMapping[frameInfo.codecType]; + if (!codec) { + logInfo('codec is not in frameCodecMapping, stop decode frame'); + return false; + } + this._decoder!.configure({ + codec: codec, + codedWidth: frameInfo.width, + codedHeight: frameInfo.height, + }); + logInfo( + `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` + ); + for (let renderer of this.renderers) { + renderer.setFrameSize({ + width: frameInfo.width!, + height: frameInfo.height!, + }); + this.pendingFrame = null; + } + return true; + } + // @ts-ignore decodeFrame( imageBuffer: Uint8Array, frameInfo: EncodedVideoFrameInfo, - ts: number, - firstFrame: boolean + ts: number ) { - // console.log( - // 'FRAMETYPE', - // frameInfo.frameType, - // frameInfo, - // imageBuffer, - // imageBuffer.length - // ); + console.log( + 'FRAMETYPE', + frameInfo.uid, + // frameInfo.frameType, + // frameInfo, + // imageBuffer, + imageBuffer.length + ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; @@ -141,22 +161,6 @@ export class WebCodecsDecoder { logDebug('frameType is not in frameTypeMapping, skip decode frame'); return; } - // @ts-ignore - let codec = frameCodecMapping[frameInfo.codecType]; - if (!codec) { - logDebug('codec is not in frameCodecMapping, skip decode frame'); - return; - } - if (firstFrame) { - this._decoder!.configure({ - codec: codec, - codedWidth: frameInfo.width, - codedHeight: frameInfo.height, - }); - logInfo( - `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` - ); - } this._frame_ts.push(ts); if (this._base_ts !== 0) { if (ts > this._base_ts) { diff --git a/ts/Decoder/WebCodecsRenderer.ts b/ts/Decoder/WebCodecsRenderer.ts index 32c287640..78192ac81 100755 --- a/ts/Decoder/WebCodecsRenderer.ts +++ b/ts/Decoder/WebCodecsRenderer.ts @@ -2,6 +2,11 @@ import { IRenderer } from '../Renderer/IRenderer'; import { getContextByCanvas } from '../Utils'; +type frameSize = { + width: number; + height: number; +}; + export class WebCodecsRenderer extends IRenderer { gl?: WebGLRenderingContext | WebGL2RenderingContext | null; // eslint-disable-next-line auto-import/auto-import @@ -92,10 +97,18 @@ export class WebCodecsRenderer extends IRenderer { ); } + setFrameSize(frameSize: frameSize) { + if (!this.offscreenCanvas) return; + this.offscreenCanvas.width = frameSize.width; + this.offscreenCanvas.height = frameSize.height; + } + drawFrame(frame: any) { if (!this.offscreenCanvas) return; - this.offscreenCanvas.width = frame.displayWidth; - this.offscreenCanvas.height = frame.displayHeight; + this.setFrameSize({ + width: frame.displayWidth, + height: frame.displayHeight, + }); this.updateRenderMode(); if (!this.gl) return; diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Decoder/WebCodecsRendererCache.ts index ad4ccb9f3..3877d7083 100644 --- a/ts/Decoder/WebCodecsRendererCache.ts +++ b/ts/Decoder/WebCodecsRendererCache.ts @@ -1,4 +1,4 @@ -import { createAgoraRtcEngine } from '../AgoraSdk'; +import { createAgoraRtcEngine, logInfo } from '../AgoraSdk'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; @@ -21,13 +21,20 @@ export class WebCodecsRendererCache super({ channelId, uid, sourceType }); this._engine = createAgoraRtcEngine(); this._decoder = new WebCodecsDecoder( - this._renderers as WebCodecsRenderer[] + this._renderers as WebCodecsRenderer[], + this.onDecoderError ); this._decoder.enableFps = true; this.selfDecode = true; this._engine.registerEventHandler(this); } + onDecoderError(e: any) { + window.alert(`Decoder error:${JSON.stringify(e)}`); + console.error('Decoder error:', e); + this.release(); + } + onEncodedVideoFrameReceived( uid: number, imageBuffer: Uint8Array, @@ -35,15 +42,20 @@ export class WebCodecsRendererCache videoEncodedFrameInfo: EncodedVideoFrameInfo ) { if (!this._decoder) return; + if (this._firstFrame) { + let result = this._decoder.decoderConfigure(videoEncodedFrameInfo); + if (!result) { + logInfo('Failed to configure decoder, stop decoding frames.'); + this.release(); + return; + } + this._firstFrame = false; + } this._decoder.decodeFrame( imageBuffer, videoEncodedFrameInfo, - new Date().getTime(), - this._firstFrame + new Date().getTime() ); - if (this._firstFrame) { - this._firstFrame = false; - } } onUserJoined(connection: RtcConnection, remoteUid: number, _elapsed: number) { From f09605d752d379bf2155a0b7ca222730103e18e4 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 3 Apr 2024 15:32:22 +0800 Subject: [PATCH 010/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 2 + ts/Decoder/WebCodecsDecoder.ts | 61 +++-------------- ts/Decoder/WebCodecsRenderer.ts | 1 + ts/Decoder/WebCodecsRendererCache.ts | 3 +- ts/Private/extension/AgoraBaseExtension.ts | 4 ++ ts/Renderer/IRenderer.ts | 54 +++++++++++---- ts/Renderer/IRendererCache.ts | 53 +++++---------- ts/Renderer/IRendererManager.ts | 67 ++++++++----------- ts/Renderer/RendererCache.ts | 12 ++-- ts/Renderer/RendererManager.ts | 40 ++--------- ts/Renderer/WebGLRenderer/index.ts | 1 + ts/Types.ts | 2 +- 12 files changed, 115 insertions(+), 185 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 34d978d4e..ed86951fe 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -117,6 +117,7 @@ export default class VideoDecoder {!!startPreview || joinChannelSuccess ? this.renderUser({ sourceType: VideoSourceType.VideoSourceCamera, + enableFps: true, }) : undefined} ; - export abstract class IRenderer { parentElement?: HTMLElement; container?: HTMLElement; canvas?: HTMLCanvasElement; rendererType: RendererType | undefined; - _context: Context = {}; + context: RendererContext = {}; + private _frameCount = 0; + private _startTime: number | null = null; public bind(element: HTMLElement) { this.parentElement = element; @@ -45,20 +45,15 @@ export abstract class IRenderer { public abstract drawFrame(videoFrame: VideoFrame): void; - public set context({ renderMode, mirrorMode }: Context) { - if (this.context.renderMode !== renderMode) { - this.context.renderMode = renderMode; + public setContext(context: RendererContext) { + if (this.context.renderMode !== context.renderMode) { this.updateRenderMode(); } - if (this.context.mirrorMode !== mirrorMode) { - this.context.mirrorMode = mirrorMode; + if (this.context.mirrorMode !== context.mirrorMode) { this.updateMirrorMode(); } - } - - public get context(): Context { - return this._context; + this.context = context; } protected updateRenderMode() { @@ -114,4 +109,39 @@ export abstract class IRenderer { ); } } + + public getFps(): number { + let fps = 0; + if (!this.context.enableFps || !this.container) { + return fps; + } + if (this._startTime == null) { + this._startTime = performance.now(); + } else { + const elapsed = (performance.now() - this._startTime) / 1000; + fps = ++this._frameCount / elapsed; + } + + let span = this.container.querySelector('span'); + if (!span) { + span = document.createElement('span'); + + Object.assign(span.style, { + position: 'absolute', + bottom: '0', + left: '0', + zIndex: '10', + width: '55px', + background: '#fff', + }); + + this.container.style.position = 'relative'; + + this.container.appendChild(span); + } + + span.innerText = `fps: ${fps.toFixed(0)}`; + + return fps; + } } diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index a8ca0b2c9..c950b2b9d 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -11,42 +11,27 @@ export function generateRendererCacheKey({ } export abstract class IRendererCache { - _renderers: IRenderer[]; - _context: RendererCacheContext; + renderers: IRenderer[]; + context: RendererCacheContext; selfDecode: boolean = false; constructor({ channelId, uid, sourceType }: RendererContext) { - this._renderers = []; - this._context = { channelId, uid, sourceType }; + this.renderers = []; + this.context = { channelId, uid, sourceType }; } public get key(): string { - return generateRendererCacheKey(this._context); - } - - public get renderers(): IRenderer[] { - return this._renderers; - } - - public get context(): RendererCacheContext { - return this._context; - } - - /** - * @deprecated Use renderers instead - */ - public get renders(): IRenderer[] { - return this.renderers; + return generateRendererCacheKey(this.context); } public abstract draw(): void; public findRenderer(view: Element): IRenderer | undefined { - return this._renderers.find((renderer) => renderer.parentElement === view); + return this.renderers.find((renderer) => renderer.parentElement === view); } public addRenderer(renderer: IRenderer): void { - this._renderers.push(renderer); + this.renderers.push(renderer); } /** @@ -54,32 +39,28 @@ export abstract class IRendererCache { */ public removeRenderer(renderer?: IRenderer): void { let start = 0; - let deleteCount = this._renderers.length; + let deleteCount = this.renderers.length; if (renderer) { - start = this._renderers.indexOf(renderer); + start = this.renderers.indexOf(renderer); if (start < 0) return; deleteCount = 1; } - this._renderers.splice(start, deleteCount).forEach((it) => it.unbind()); + this.renderers.splice(start, deleteCount).forEach((it) => it.unbind()); } - public setRendererContext({ - view, - renderMode, - mirrorMode, - }: RendererContext): boolean { - if (view) { - const renderer = this.findRenderer(view); + public setRendererContext(context: RendererContext): boolean { + if (context.view) { + const renderer = this.findRenderer(context.view); if (renderer) { - renderer.context = { renderMode, mirrorMode }; + renderer.context = context; return true; } return false; } else { - this._renderers.forEach((it) => { - it.context = { renderMode, mirrorMode }; + this.renderers.forEach((it) => { + it.context = context; }); - return this._renderers.length > 0; + return this.renderers.length > 0; } } diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index c1642fa43..3876fdd51 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -16,7 +16,7 @@ export abstract class IRendererManager { /** * @ignore */ - private _renderingFps: number; + private renderingFps: number; /** * @ignore */ @@ -39,7 +39,7 @@ export abstract class IRendererManager { private _context: RendererContext; constructor() { - this._renderingFps = 15; + this.renderingFps = 60; this._currentFrameCount = 0; this._previousFirstFrameTime = 0; this._rendererCaches = []; @@ -49,20 +49,14 @@ export abstract class IRendererManager { }; } - public set renderingFps(fps: number) { - if (this._renderingFps !== fps) { - this._renderingFps = fps; - if (this._renderingTimer) { - this.stopRendering(); - this.startRendering(); - } + public setRenderingFps(fps: number) { + this.renderingFps = fps; + if (this._renderingTimer) { + this.stopRendering(); + this.startRendering(); } } - public get renderingFps(): number { - return this._renderingFps; - } - public set defaultChannelId(channelId: string) { this._context.channelId = channelId; } @@ -84,40 +78,38 @@ export abstract class IRendererManager { this.clearRendererCache(); } - private precheckRendererContext(context: RendererContext): RendererContext { - let { - sourceType, - uid, - channelId, - mediaPlayerId, - renderMode = this.defaultRenderMode, - mirrorMode = this.defaultMirrorMode, - } = context; - switch (sourceType) { + private presetRendererContext(context: RendererContext): RendererContext { + //this is for preset default value + context.renderMode = context.renderMode || this.defaultRenderMode; + context.mirrorMode = context.mirrorMode || this.defaultMirrorMode; + context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; + context.enableFps = context.enableFps || false; + + switch (context.sourceType) { case VideoSourceType.VideoSourceRemote: - if (uid === undefined) { + if (context.uid === undefined) { throw new Error('uid is required'); } - channelId = channelId ?? this.defaultChannelId; + context.channelId = context.channelId ?? this.defaultChannelId; break; case VideoSourceType.VideoSourceMediaPlayer: - if (mediaPlayerId === undefined) { + if (context.mediaPlayerId === undefined) { throw new Error('mediaPlayerId is required'); } - channelId = ''; - uid = mediaPlayerId; + context.channelId = ''; + context.uid = context.mediaPlayerId; break; case undefined: - if (uid) { - sourceType = VideoSourceType.VideoSourceRemote; + if (context.uid) { + context.sourceType = VideoSourceType.VideoSourceRemote; } break; default: - channelId = ''; - uid = 0; + context.channelId = ''; + context.uid = 0; break; } - return { ...context, sourceType, uid, channelId, renderMode, mirrorMode }; + return context; } public addOrRemoveRenderer( @@ -141,7 +133,7 @@ export abstract class IRendererManager { private addRendererToCache( context: RendererContext ): RendererCacheType | undefined { - const checkedContext = this.precheckRendererContext(context); + const checkedContext = this.presetRendererContext(context); if (!checkedContext.view) return undefined; @@ -166,7 +158,7 @@ export abstract class IRendererManager { } public removeRendererFromCache(context: RendererContext): void { - const checkedContext = this.precheckRendererContext(context); + const checkedContext = this.presetRendererContext(context); const rendererCache = this.getRendererCache(checkedContext); if (!rendererCache) return; @@ -237,8 +229,7 @@ export abstract class IRendererManager { // Calculate the time difference between the current frame and the previous frame const deltaTime = currentFrameTime - this._previousFirstFrameTime; // Calculate the expected time of the current frame - const expectedTime = - (this._currentFrameCount * 1000) / this._renderingFps; + const expectedTime = (this._currentFrameCount * 1000) / this.renderingFps; logDebug( new Date().toLocaleTimeString(), 'currentFrameCount', @@ -288,7 +279,7 @@ export abstract class IRendererManager { } public setRendererContext(context: RendererContext): boolean { - const checkedContext = this.precheckRendererContext(context); + const checkedContext = this.presetRendererContext(context); for (const rendererCache of this._rendererCaches) { const result = rendererCache.setRendererContext(checkedContext); diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index fee31f1c6..8d6854564 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -6,12 +6,12 @@ import { IRenderer } from './IRenderer'; import { IRendererCache } from './IRendererCache'; export class RendererCache extends IRendererCache { - private _videoFrame: VideoFrame; + private videoFrame: VideoFrame; private _enabled: boolean; constructor({ channelId, uid, sourceType }: RendererContext) { super({ channelId, uid, sourceType }); - this._videoFrame = { + this.videoFrame = { yBuffer: Buffer.alloc(0), uBuffer: Buffer.alloc(0), vBuffer: Buffer.alloc(0), @@ -26,10 +26,6 @@ export class RendererCache extends IRendererCache { this.selfDecode = false; } - public get videoFrame(): VideoFrame { - return this._videoFrame; - } - /** * @deprecated Use videoFrame instead */ @@ -43,13 +39,13 @@ export class RendererCache extends IRendererCache { private enable() { if (this._enabled) return; - this.bridge.EnableVideoFrameCache(this._context); + this.bridge.EnableVideoFrameCache(this.context); this._enabled = true; } private disable() { if (!this._enabled) return; - this.bridge.DisableVideoFrameCache(this._context); + this.bridge.DisableVideoFrameCache(this.context); this._enabled = false; } diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 7571dca8e..0c43bb5bc 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -21,21 +21,11 @@ export class RendererManager extends IRendererManager { /** * @ignore */ - private _rendererType: RendererType; - - public set rendererType(rendererType: RendererType) { - if (this._rendererType !== rendererType) { - this._rendererType = rendererType; - } - } - - public get rendererType(): RendererType { - return this._rendererType; - } + rendererType: RendererType; constructor() { super(); - this._rendererType = isSupportWebGL() + this.rendererType = isSupportWebGL() ? RendererType.WEBGL : RendererType.SOFTWARE; } @@ -47,13 +37,6 @@ export class RendererManager extends IRendererManager { this.rendererType = mode; } - /** - * @deprecated Use renderingFps instead - */ - public setFPS(fps: number) { - this.renderingFps = fps; - } - /** * @deprecated Use getRendererCache instead */ @@ -65,12 +48,8 @@ export class RendererManager extends IRendererManager { protected override createRenderer( context: RendererContext, - rendererType?: RendererType + rendererType: RendererType = this.rendererType ): IRenderer { - if (rendererType === undefined) { - rendererType = this.rendererType; - } - let renderer: IRenderer; switch (rendererType) { case RendererType.WEBGL: @@ -90,10 +69,7 @@ export class RendererManager extends IRendererManager { } renderer.bind(context.view); - renderer.context = { - renderMode: context.renderMode, - mirrorMode: context.mirrorMode, - }; + renderer.setContext(context); return renderer; } @@ -103,15 +79,9 @@ export class RendererManager extends IRendererManager { private handleWebGLFallback(context: RendererContext): WebGLFallback { return (renderer: WebGLRenderer) => { - const { - context: { renderMode, mirrorMode }, - } = renderer; const renderers = this.getRenderers(context); renderer.unbind(); - const newRenderer = this.createRenderer( - { ...context, renderMode, mirrorMode }, - RendererType.SOFTWARE - ); + const newRenderer = this.createRenderer(context, RendererType.SOFTWARE); renderers.splice(renderers.indexOf(renderer), 1, newRenderer); }; } diff --git a/ts/Renderer/WebGLRenderer/index.ts b/ts/Renderer/WebGLRenderer/index.ts index dea01c80d..cd3f89599 100644 --- a/ts/Renderer/WebGLRenderer/index.ts +++ b/ts/Renderer/WebGLRenderer/index.ts @@ -250,6 +250,7 @@ export class WebGLRenderer extends IRenderer { ); this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); + this.getFps(); } protected override rotateCanvas({ width, height, rotation }: VideoFrame) { diff --git a/ts/Types.ts b/ts/Types.ts index 74b0af8a1..868ee0175 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -58,7 +58,7 @@ export type RendererCacheType = RendererCache | WebCodecsRendererCache; export type RendererCacheContext = Pick< RendererContext, - 'channelId' | 'uid' | 'sourceType' | 'useWebCodecsDecoder' + 'channelId' | 'uid' | 'sourceType' | 'useWebCodecsDecoder' | 'enableFps' >; /** From 01180954c440c9fa0bc6d9f86c8a8fdf0088579a Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 3 Apr 2024 15:36:54 +0800 Subject: [PATCH 011/101] chore: optimize --- example/src/renderer/components/BaseComponent.tsx | 1 + .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/src/renderer/components/BaseComponent.tsx b/example/src/renderer/components/BaseComponent.tsx index d8b52a8b7..86fec26d3 100644 --- a/example/src/renderer/components/BaseComponent.tsx +++ b/example/src/renderer/components/BaseComponent.tsx @@ -210,6 +210,7 @@ export abstract class BaseComponent< protected renderUser(user: VideoCanvas): ReactElement | undefined { const { enableVideo } = this.state; + user.enableFps = true; return ( Date: Wed, 3 Apr 2024 15:58:37 +0800 Subject: [PATCH 012/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 1 + ts/AgoraSdk.ts | 1 - ts/Decoder/WebCodecsDecoder.ts | 151 ------------------ ts/Decoder/index.ts | 151 +++++++++++++++++- ts/Renderer/IRendererManager.ts | 3 +- ts/Renderer/RendererManager.ts | 3 +- .../WebCodecsRenderer/index.ts} | 5 +- .../WebCodecsRendererCache.ts | 7 +- ts/Types.ts | 2 +- 9 files changed, 160 insertions(+), 164 deletions(-) delete mode 100644 ts/Decoder/WebCodecsDecoder.ts rename ts/{Decoder/WebCodecsRenderer.ts => Renderer/WebCodecsRenderer/index.ts} (97%) rename ts/{Decoder => Renderer}/WebCodecsRendererCache.ts (93%) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 34d978d4e..133f6c698 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -125,6 +125,7 @@ export default class VideoDecoder this.renderUser({ uid: item, sourceType: VideoSourceType.VideoSourceRemote, + // Use WebCodecs to decode video stream useWebCodecsDecoder: true, renderMode: RenderModeType.RenderModeFit, }) diff --git a/ts/AgoraSdk.ts b/ts/AgoraSdk.ts index a59017846..071f575e8 100644 --- a/ts/AgoraSdk.ts +++ b/ts/AgoraSdk.ts @@ -19,7 +19,6 @@ export * from './Private/IAgoraRtcEngineEx'; export * from './Private/IAgoraSpatialAudio'; export * from './Private/IAudioDeviceManager'; export * from './Renderer'; -export * from './Decoder'; export * from './Types'; export * from './Utils'; diff --git a/ts/Decoder/WebCodecsDecoder.ts b/ts/Decoder/WebCodecsDecoder.ts deleted file mode 100644 index 609430763..000000000 --- a/ts/Decoder/WebCodecsDecoder.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { - EncodedVideoFrameInfo, - VideoCodecType, - VideoFrameType, -} from '../Private/AgoraBase'; - -import { logDebug, logInfo } from '../Utils'; - -import { WebCodecsRenderer } from './WebCodecsRenderer'; - -const frameTypeMapping = { - [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', - [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', -}; - -export const frameCodecMapping = { - [VideoCodecType.VideoCodecH265]: 'hvc1.1.6.L5.90', - [VideoCodecType.VideoCodecH264]: 'avc1.64e01f', - [VideoCodecType.VideoCodecVp8]: 'vp8', - [VideoCodecType.VideoCodecVp9]: 'vp9', -}; - -export class WebCodecsDecoder { - private _decoder: VideoDecoder; - private renderers: WebCodecsRenderer[] = []; - private pendingFrame: VideoFrame | null = null; - - private _frame_ts: number[] = []; - private _base_ts = 0; - private _base_ts_ntp = 1; - private _last_ts_ntp = 1; - - constructor(renders: WebCodecsRenderer[], onError: (e: any) => void) { - this.renderers = renders; - this._decoder = new VideoDecoder({ - // @ts-ignore - output: this._output.bind(this), - error: onError, - }); - } - - _output(frame: VideoFrame) { - // Schedule the frame to be rendered. - this._renderFrame(frame); - } - - private _renderFrame(frame: VideoFrame) { - if (!this.pendingFrame) { - // Schedule rendering in the next animation frame. - // eslint-disable-next-line auto-import/auto-import - requestAnimationFrame(this.renderAnimationFrame.bind(this)); - } else { - // Close the current pending frame before replacing it. - this.pendingFrame.close(); - } - // Set or replace the pending frame. - this.pendingFrame = frame; - } - - renderAnimationFrame() { - for (let renderer of this.renderers) { - renderer.drawFrame(this.pendingFrame); - this.pendingFrame = null; - } - } - - decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { - // @ts-ignore - let codec = frameCodecMapping[frameInfo.codecType]; - if (!codec) { - logInfo('codec is not in frameCodecMapping, stop decode frame'); - return false; - } - this._decoder!.configure({ - codec: codec, - codedWidth: frameInfo.width, - codedHeight: frameInfo.height, - }); - logInfo( - `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` - ); - for (let renderer of this.renderers) { - renderer.setFrameSize({ - width: frameInfo.width!, - height: frameInfo.height!, - }); - this.pendingFrame = null; - } - return true; - } - - // @ts-ignore - decodeFrame( - imageBuffer: Uint8Array, - frameInfo: EncodedVideoFrameInfo, - ts: number - ) { - // console.log( - // 'FRAMETYPE', - // frameInfo.uid, - // // frameInfo.frameType, - // // frameInfo, - // // imageBuffer, - // imageBuffer.length - // ); - if (!imageBuffer) { - logDebug('imageBuffer is empty, skip decode frame'); - return; - } - let frameType: string | undefined; - if (frameInfo.frameType !== undefined) { - // @ts-ignore - frameType = frameTypeMapping[frameInfo.frameType]; - } - if (!frameType) { - logDebug('frameType is not in frameTypeMapping, skip decode frame'); - return; - } - this._frame_ts.push(ts); - if (this._base_ts !== 0) { - if (ts > this._base_ts) { - this._last_ts_ntp = - this._base_ts_ntp + Math.floor(((ts - this._base_ts) * 1000) / 90); - } else { - this._base_ts = ts; - this._last_ts_ntp++; - this._base_ts_ntp = this._last_ts_ntp; - } - } else { - this._base_ts = ts; - this._last_ts_ntp = 1; - } - this._decoder.decode( - new EncodedVideoChunk({ - data: imageBuffer, - timestamp: this._last_ts_ntp, - // @ts-ignore - type: frameType, - // @ts-ignore - transfer: [imageBuffer.buffer], - }) - ); - } - - release() { - this.pendingFrame = null; - try { - this._decoder.close(); - } catch (e) {} - } -} diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index da3150b87..e08868b19 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -1 +1,150 @@ -export * from './WebCodecsDecoder'; +import { + EncodedVideoFrameInfo, + VideoCodecType, + VideoFrameType, +} from '../Private/AgoraBase'; + +import { WebCodecsRenderer } from '../Renderer/WebCodecsRenderer/index'; +import { logDebug, logInfo } from '../Utils'; + +const frameTypeMapping = { + [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', + [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', +}; + +export const frameCodecMapping = { + [VideoCodecType.VideoCodecH265]: 'hvc1.1.6.L5.90', + [VideoCodecType.VideoCodecH264]: 'avc1.64e01f', + [VideoCodecType.VideoCodecVp8]: 'vp8', + [VideoCodecType.VideoCodecVp9]: 'vp9', +}; + +export class WebCodecsDecoder { + private _decoder: VideoDecoder; + private renderers: WebCodecsRenderer[] = []; + private pendingFrame: VideoFrame | null = null; + + private _frame_ts: number[] = []; + private _base_ts = 0; + private _base_ts_ntp = 1; + private _last_ts_ntp = 1; + + constructor(renders: WebCodecsRenderer[], onError: (e: any) => void) { + this.renderers = renders; + this._decoder = new VideoDecoder({ + // @ts-ignore + output: this._output.bind(this), + error: onError, + }); + } + + _output(frame: VideoFrame) { + // Schedule the frame to be rendered. + this._renderFrame(frame); + } + + private _renderFrame(frame: VideoFrame) { + if (!this.pendingFrame) { + // Schedule rendering in the next animation frame. + // eslint-disable-next-line auto-import/auto-import + requestAnimationFrame(this.renderAnimationFrame.bind(this)); + } else { + // Close the current pending frame before replacing it. + this.pendingFrame.close(); + } + // Set or replace the pending frame. + this.pendingFrame = frame; + } + + renderAnimationFrame() { + for (let renderer of this.renderers) { + renderer.drawFrame(this.pendingFrame); + this.pendingFrame = null; + } + } + + decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { + // @ts-ignore + let codec = frameCodecMapping[frameInfo.codecType]; + if (!codec) { + logInfo('codec is not in frameCodecMapping, stop decode frame'); + return false; + } + this._decoder!.configure({ + codec: codec, + codedWidth: frameInfo.width, + codedHeight: frameInfo.height, + }); + logInfo( + `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` + ); + for (let renderer of this.renderers) { + renderer.setFrameSize({ + width: frameInfo.width!, + height: frameInfo.height!, + }); + this.pendingFrame = null; + } + return true; + } + + // @ts-ignore + decodeFrame( + imageBuffer: Uint8Array, + frameInfo: EncodedVideoFrameInfo, + ts: number + ) { + // console.log( + // 'FRAMETYPE', + // frameInfo.uid, + // // frameInfo.frameType, + // // frameInfo, + // // imageBuffer, + // imageBuffer.length + // ); + if (!imageBuffer) { + logDebug('imageBuffer is empty, skip decode frame'); + return; + } + let frameType: string | undefined; + if (frameInfo.frameType !== undefined) { + // @ts-ignore + frameType = frameTypeMapping[frameInfo.frameType]; + } + if (!frameType) { + logDebug('frameType is not in frameTypeMapping, skip decode frame'); + return; + } + this._frame_ts.push(ts); + if (this._base_ts !== 0) { + if (ts > this._base_ts) { + this._last_ts_ntp = + this._base_ts_ntp + Math.floor(((ts - this._base_ts) * 1000) / 90); + } else { + this._base_ts = ts; + this._last_ts_ntp++; + this._base_ts_ntp = this._last_ts_ntp; + } + } else { + this._base_ts = ts; + this._last_ts_ntp = 1; + } + this._decoder.decode( + new EncodedVideoChunk({ + data: imageBuffer, + timestamp: this._last_ts_ntp, + // @ts-ignore + type: frameType, + // @ts-ignore + transfer: [imageBuffer.buffer], + }) + ); + } + + release() { + this.pendingFrame = null; + try { + this._decoder.close(); + } catch (e) {} + } +} diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts index 3876fdd51..ff6f3dd50 100644 --- a/ts/Renderer/IRendererManager.ts +++ b/ts/Renderer/IRendererManager.ts @@ -1,5 +1,3 @@ -import { WebCodecsRendererCache } from '../Decoder/WebCodecsRendererCache'; - import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; @@ -8,6 +6,7 @@ import { logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; import { generateRendererCacheKey } from './IRendererCache'; import { RendererCache } from './RendererCache'; +import { WebCodecsRendererCache } from './WebCodecsRendererCache'; /** * @ignore diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 0c43bb5bc..3b87f101a 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,5 +1,3 @@ -import { WebCodecsRenderer } from '../Decoder/WebCodecsRenderer'; - import { RENDER_MODE, RendererCacheContext, @@ -11,6 +9,7 @@ import { isSupportWebGL } from '../Utils'; import { IRenderer } from './IRenderer'; import { IRendererManager } from './IRendererManager'; +import { WebCodecsRenderer } from './WebCodecsRenderer/index'; import { WebGLFallback, WebGLRenderer } from './WebGLRenderer'; import { YUVCanvasRenderer } from './YUVCanvasRenderer'; diff --git a/ts/Decoder/WebCodecsRenderer.ts b/ts/Renderer/WebCodecsRenderer/index.ts similarity index 97% rename from ts/Decoder/WebCodecsRenderer.ts rename to ts/Renderer/WebCodecsRenderer/index.ts index 66ea7a45f..af2541749 100755 --- a/ts/Decoder/WebCodecsRenderer.ts +++ b/ts/Renderer/WebCodecsRenderer/index.ts @@ -1,6 +1,5 @@ -import { IRenderer } from '../Renderer/IRenderer'; - -import { getContextByCanvas } from '../Utils'; +import { getContextByCanvas } from '../../Utils'; +import { IRenderer } from '../IRenderer'; type frameSize = { width: number; diff --git a/ts/Decoder/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts similarity index 93% rename from ts/Decoder/WebCodecsRendererCache.ts rename to ts/Renderer/WebCodecsRendererCache.ts index 9504301d8..70f369a61 100644 --- a/ts/Decoder/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,13 +1,14 @@ import { createAgoraRtcEngine, logInfo } from '../AgoraSdk'; +import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; -import { IRendererCache } from '../Renderer/IRendererCache'; + import { RendererContext } from '../Types'; -import { WebCodecsDecoder } from './WebCodecsDecoder'; -import { WebCodecsRenderer } from './WebCodecsRenderer'; +import { IRendererCache } from './IRendererCache'; +import { WebCodecsRenderer } from './WebCodecsRenderer/index'; export class WebCodecsRendererCache extends IRendererCache diff --git a/ts/Types.ts b/ts/Types.ts index 868ee0175..ccd296da8 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,9 +1,9 @@ -import { WebCodecsRendererCache } from './Decoder/WebCodecsRendererCache'; import { VideoCanvas } from './Private/AgoraBase'; import { VideoFrame } from './Private/AgoraMediaBase'; import { RtcConnection } from './Private/IAgoraRtcEngineEx'; import { IRendererManager } from './Renderer'; import { RendererCache } from './Renderer/RendererCache'; +import { WebCodecsRendererCache } from './Renderer/WebCodecsRendererCache'; /** * @ignore From 35babb2e80ff611fcf19ce6ac625b97b7a6aafb6 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 3 Apr 2024 20:18:03 +0800 Subject: [PATCH 013/101] chore: optimize --- .../advanced/ScreenShare/ScreenShare.tsx | 35 ++++++++++++++++--- ts/Renderer/WebCodecsRendererCache.ts | 3 +- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 57b628158..5eafb88ca 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -1,16 +1,20 @@ import { ChannelProfileType, ClientRoleType, + DegradationPreference, IRtcEngineEventHandler, IRtcEngineEx, LocalVideoStreamError, LocalVideoStreamState, + OrientationMode, RenderModeType, RtcConnection, RtcStats, ScreenCaptureSourceInfo, ScreenCaptureSourceType, UserOfflineReasonType, + VideoCodecType, + VideoMirrorModeType, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -73,13 +77,13 @@ export default class ScreenShare remoteUsers: [], startPreview: false, token2: '', - uid2: 0, + uid2: 7, sources: [], targetSource: undefined, - width: 1920, - height: 1080, - frameRate: 15, - bitrate: 0, + width: 3840, + height: 2160, + frameRate: 60, + bitrate: 20000, captureMouseCursor: true, windowFocus: false, excludeWindowList: [], @@ -118,6 +122,27 @@ export default class ScreenShare // Start preview before joinChannel this.engine.startPreview(); + this.engine.setParameters( + JSON.stringify({ 'che.video.h265_screen_enable': 1 }) + ); + this.engine.setVideoEncoderConfigurationEx( + { + codecType: VideoCodecType.VideoCodecH265, + frameRate: 65, + bitrate: 2000, + orientationMode: OrientationMode.OrientationModeAdaptive, + degradationPreference: DegradationPreference.MaintainQuality, + mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, + dimensions: { + width: 3840, + height: 2160, + }, + }, + { + localUid: this.state.uid, + channelId: this.state.channelId, + } + ); this.setState({ startPreview: true }); this.getScreenCaptureSources(); diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 70f369a61..05e8e467a 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -26,7 +26,7 @@ export class WebCodecsRendererCache this.onDecoderError ); this.selfDecode = true; - this._engine.registerEventHandler(this); + this.draw(); } onDecoderError(e: any) { @@ -71,6 +71,7 @@ export class WebCodecsRendererCache } public draw() { + this._engine?.registerEventHandler(this); this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } From d0cc76ff85811b0677dab6c83ce79693c741e34d Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 3 Apr 2024 20:44:05 +0800 Subject: [PATCH 014/101] chore: optimize --- ts/Renderer/IRendererManager.ts | 291 ------------------------------- ts/Renderer/RendererManager.ts | 298 +++++++++++++++++++++++++++++--- ts/Renderer/index.ts | 2 +- ts/Types.ts | 4 +- 4 files changed, 276 insertions(+), 319 deletions(-) delete mode 100644 ts/Renderer/IRendererManager.ts diff --git a/ts/Renderer/IRendererManager.ts b/ts/Renderer/IRendererManager.ts deleted file mode 100644 index ff6f3dd50..000000000 --- a/ts/Renderer/IRendererManager.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; -import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { RendererCacheType, RendererContext, RendererType } from '../Types'; -import { logDebug } from '../Utils'; - -import { IRenderer } from './IRenderer'; -import { generateRendererCacheKey } from './IRendererCache'; -import { RendererCache } from './RendererCache'; -import { WebCodecsRendererCache } from './WebCodecsRendererCache'; - -/** - * @ignore - */ -export abstract class IRendererManager { - /** - * @ignore - */ - private renderingFps: number; - /** - * @ignore - */ - private _currentFrameCount: number; - /** - * @ignore - */ - private _previousFirstFrameTime: number; - /** - * @ignore - */ - private _renderingTimer?: number; - /** - * @ignore - */ - private _rendererCaches: RendererCacheType[]; - /** - * @ignore - */ - private _context: RendererContext; - - constructor() { - this.renderingFps = 60; - this._currentFrameCount = 0; - this._previousFirstFrameTime = 0; - this._rendererCaches = []; - this._context = { - renderMode: RenderModeType.RenderModeHidden, - mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, - }; - } - - public setRenderingFps(fps: number) { - this.renderingFps = fps; - if (this._renderingTimer) { - this.stopRendering(); - this.startRendering(); - } - } - - public set defaultChannelId(channelId: string) { - this._context.channelId = channelId; - } - - public get defaultChannelId(): string { - return this._context.channelId ?? ''; - } - - public get defaultRenderMode(): RenderModeType { - return this._context.renderMode!; - } - - public get defaultMirrorMode(): VideoMirrorModeType { - return this._context.mirrorMode!; - } - - public release(): void { - this.stopRendering(); - this.clearRendererCache(); - } - - private presetRendererContext(context: RendererContext): RendererContext { - //this is for preset default value - context.renderMode = context.renderMode || this.defaultRenderMode; - context.mirrorMode = context.mirrorMode || this.defaultMirrorMode; - context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; - context.enableFps = context.enableFps || false; - - switch (context.sourceType) { - case VideoSourceType.VideoSourceRemote: - if (context.uid === undefined) { - throw new Error('uid is required'); - } - context.channelId = context.channelId ?? this.defaultChannelId; - break; - case VideoSourceType.VideoSourceMediaPlayer: - if (context.mediaPlayerId === undefined) { - throw new Error('mediaPlayerId is required'); - } - context.channelId = ''; - context.uid = context.mediaPlayerId; - break; - case undefined: - if (context.uid) { - context.sourceType = VideoSourceType.VideoSourceRemote; - } - break; - default: - context.channelId = ''; - context.uid = 0; - break; - } - return context; - } - - public addOrRemoveRenderer( - context: RendererContext - ): RendererCacheType | undefined { - // To be compatible with the old API - let { setupMode = VideoViewSetupMode.VideoViewSetupAdd } = context; - if (!context.view) setupMode = VideoViewSetupMode.VideoViewSetupRemove; - switch (setupMode) { - case VideoViewSetupMode.VideoViewSetupAdd: - return this.addRendererToCache(context); - case VideoViewSetupMode.VideoViewSetupRemove: - this.removeRendererFromCache(context); - return undefined; - case VideoViewSetupMode.VideoViewSetupReplace: - this.removeRendererFromCache(context); - return this.addRendererToCache(context); - } - } - - private addRendererToCache( - context: RendererContext - ): RendererCacheType | undefined { - const checkedContext = this.presetRendererContext(context); - - if (!checkedContext.view) return undefined; - - if (this.findRenderer(checkedContext.view)) { - throw new Error('You have already added this view to the renderer'); - } - - let rendererCache = this.getRendererCache(checkedContext); - if (!rendererCache) { - if (context.useWebCodecsDecoder) { - rendererCache = new WebCodecsRendererCache(checkedContext); - } else { - rendererCache = new RendererCache(checkedContext); - } - this._rendererCaches.push(rendererCache); - } - rendererCache.addRenderer(this.createRenderer(checkedContext)); - if (!context.useWebCodecsDecoder) { - this.startRendering(); - } - return rendererCache; - } - - public removeRendererFromCache(context: RendererContext): void { - const checkedContext = this.presetRendererContext(context); - - const rendererCache = this.getRendererCache(checkedContext); - if (!rendererCache) return; - if (checkedContext.view) { - const renderer = rendererCache.findRenderer(checkedContext.view); - if (!renderer) return; - rendererCache.removeRenderer(renderer); - } else { - rendererCache.removeRenderer(); - } - if (rendererCache.renderers.length === 0) { - rendererCache.release(); - this._rendererCaches.splice( - this._rendererCaches.indexOf(rendererCache), - 1 - ); - } - } - - public clearRendererCache(): void { - for (const rendererCache of this._rendererCaches) { - rendererCache.release(); - } - this._rendererCaches.splice(0); - } - - public getRendererCache( - context: RendererContext - ): RendererCacheType | undefined { - return this._rendererCaches.find( - (cache) => cache.key === generateRendererCacheKey(context) - ); - } - - public getRenderers(context: RendererContext): IRenderer[] { - return this.getRendererCache(context)?.renderers || []; - } - - public findRenderer(view: Element): IRenderer | undefined { - for (const rendererCache of this._rendererCaches) { - const renderer = rendererCache.findRenderer(view); - if (renderer) return renderer; - } - return undefined; - } - - protected abstract createRenderer( - context: RendererContext, - rendererType?: RendererType - ): IRenderer; - - public startRendering(): void { - if (this._renderingTimer) return; - - const renderingLooper = () => { - if (this._previousFirstFrameTime === 0) { - // Get the current time as the time of the first frame of per second - this._previousFirstFrameTime = performance.now(); - // Reset the frame count - this._currentFrameCount = 0; - } - - // Increase the frame count - ++this._currentFrameCount; - - // Get the current time - const currentFrameTime = performance.now(); - // Calculate the time difference between the current frame and the previous frame - const deltaTime = currentFrameTime - this._previousFirstFrameTime; - // Calculate the expected time of the current frame - const expectedTime = (this._currentFrameCount * 1000) / this.renderingFps; - logDebug( - new Date().toLocaleTimeString(), - 'currentFrameCount', - this._currentFrameCount, - 'expectedTime', - expectedTime, - 'deltaTime', - deltaTime - ); - - if (this._rendererCaches.length === 0) { - // If there is no renderer, stop rendering - this.stopRendering(); - return; - } - - // Render all renderers - for (const rendererCache of this._rendererCaches) { - this.doRendering(rendererCache); - } - - if (this._currentFrameCount >= this.renderingFps) { - this._previousFirstFrameTime = 0; - } - - if (deltaTime < expectedTime) { - // If the time difference between the current frame and the previous frame is less than the expected time, then wait for the difference - this._renderingTimer = window.setTimeout( - renderingLooper, - expectedTime - deltaTime - ); - } else { - // If the time difference between the current frame and the previous frame is greater than the expected time, then render immediately - renderingLooper(); - } - }; - renderingLooper(); - } - - public abstract doRendering(rendererCache: RendererCacheType): void; - - public stopRendering(): void { - if (this._renderingTimer) { - window.clearTimeout(this._renderingTimer); - this._renderingTimer = undefined; - } - } - - public setRendererContext(context: RendererContext): boolean { - const checkedContext = this.presetRendererContext(context); - - for (const rendererCache of this._rendererCaches) { - const result = rendererCache.setRendererContext(checkedContext); - if (result) { - return true; - } - } - return false; - } -} diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 3b87f101a..f0902006d 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,51 +1,221 @@ -import { - RENDER_MODE, - RendererCacheContext, - RendererCacheType, - RendererContext, - RendererType, -} from '../Types'; -import { isSupportWebGL } from '../Utils'; +import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; +import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; +import { RendererCacheType, RendererContext, RendererType } from '../Types'; +import { isSupportWebGL, logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; -import { IRendererManager } from './IRendererManager'; -import { WebCodecsRenderer } from './WebCodecsRenderer/index'; +import { generateRendererCacheKey } from './IRendererCache'; +import { RendererCache } from './RendererCache'; +import { WebCodecsRenderer } from './WebCodecsRenderer'; +import { WebCodecsRendererCache } from './WebCodecsRendererCache'; import { WebGLFallback, WebGLRenderer } from './WebGLRenderer'; import { YUVCanvasRenderer } from './YUVCanvasRenderer'; /** * @ignore */ -export class RendererManager extends IRendererManager { +export class RendererManager { + /** + * @ignore + */ + private renderingFps: number; + /** + * @ignore + */ + private _currentFrameCount: number; + /** + * @ignore + */ + private _previousFirstFrameTime: number; + /** + * @ignore + */ + private _renderingTimer?: number; + /** + * @ignore + */ + private _rendererCaches: RendererCacheType[]; + /** + * @ignore + */ + private _context: RendererContext; + /** * @ignore */ rendererType: RendererType; constructor() { - super(); + this.renderingFps = 60; + this._currentFrameCount = 0; + this._previousFirstFrameTime = 0; + this._rendererCaches = []; + this._context = { + renderMode: RenderModeType.RenderModeHidden, + mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, + }; this.rendererType = isSupportWebGL() ? RendererType.WEBGL : RendererType.SOFTWARE; } - /** - * @deprecated Use rendererType instead - */ - public setRenderMode(mode: RENDER_MODE) { - this.rendererType = mode; + public setRenderingFps(fps: number) { + this.renderingFps = fps; + if (this._renderingTimer) { + this.stopRendering(); + this.startRendering(); + } } - /** - * @deprecated Use getRendererCache instead - */ - public getRender( - context: RendererCacheContext + public set defaultChannelId(channelId: string) { + this._context.channelId = channelId; + } + + public get defaultChannelId(): string { + return this._context.channelId ?? ''; + } + + public get defaultRenderMode(): RenderModeType { + return this._context.renderMode!; + } + + public get defaultMirrorMode(): VideoMirrorModeType { + return this._context.mirrorMode!; + } + + public release(): void { + this.stopRendering(); + this.clearRendererCache(); + } + + private presetRendererContext(context: RendererContext): RendererContext { + //this is for preset default value + context.renderMode = context.renderMode || this.defaultRenderMode; + context.mirrorMode = context.mirrorMode || this.defaultMirrorMode; + context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; + context.enableFps = context.enableFps || false; + + switch (context.sourceType) { + case VideoSourceType.VideoSourceRemote: + if (context.uid === undefined) { + throw new Error('uid is required'); + } + context.channelId = context.channelId ?? this.defaultChannelId; + break; + case VideoSourceType.VideoSourceMediaPlayer: + if (context.mediaPlayerId === undefined) { + throw new Error('mediaPlayerId is required'); + } + context.channelId = ''; + context.uid = context.mediaPlayerId; + break; + case undefined: + if (context.uid) { + context.sourceType = VideoSourceType.VideoSourceRemote; + } + break; + default: + context.channelId = ''; + context.uid = 0; + break; + } + return context; + } + + public addOrRemoveRenderer( + context: RendererContext + ): RendererCacheType | undefined { + // To be compatible with the old API + let { setupMode = VideoViewSetupMode.VideoViewSetupAdd } = context; + if (!context.view) setupMode = VideoViewSetupMode.VideoViewSetupRemove; + switch (setupMode) { + case VideoViewSetupMode.VideoViewSetupAdd: + return this.addRendererToCache(context); + case VideoViewSetupMode.VideoViewSetupRemove: + this.removeRendererFromCache(context); + return undefined; + case VideoViewSetupMode.VideoViewSetupReplace: + this.removeRendererFromCache(context); + return this.addRendererToCache(context); + } + } + + private addRendererToCache( + context: RendererContext + ): RendererCacheType | undefined { + const checkedContext = this.presetRendererContext(context); + + if (!checkedContext.view) return undefined; + + if (this.findRenderer(checkedContext.view)) { + throw new Error('You have already added this view to the renderer'); + } + + let rendererCache = this.getRendererCache(checkedContext); + if (!rendererCache) { + if (context.useWebCodecsDecoder) { + rendererCache = new WebCodecsRendererCache(checkedContext); + } else { + rendererCache = new RendererCache(checkedContext); + } + this._rendererCaches.push(rendererCache); + } + rendererCache.addRenderer(this.createRenderer(checkedContext)); + if (!context.useWebCodecsDecoder) { + this.startRendering(); + } + return rendererCache; + } + + public removeRendererFromCache(context: RendererContext): void { + const checkedContext = this.presetRendererContext(context); + + const rendererCache = this.getRendererCache(checkedContext); + if (!rendererCache) return; + if (checkedContext.view) { + const renderer = rendererCache.findRenderer(checkedContext.view); + if (!renderer) return; + rendererCache.removeRenderer(renderer); + } else { + rendererCache.removeRenderer(); + } + if (rendererCache.renderers.length === 0) { + rendererCache.release(); + this._rendererCaches.splice( + this._rendererCaches.indexOf(rendererCache), + 1 + ); + } + } + + public clearRendererCache(): void { + for (const rendererCache of this._rendererCaches) { + rendererCache.release(); + } + this._rendererCaches.splice(0); + } + + public getRendererCache( + context: RendererContext ): RendererCacheType | undefined { - return this.getRendererCache(context); + return this._rendererCaches.find( + (cache) => cache.key === generateRendererCacheKey(context) + ); } - protected override createRenderer( + public getRenderers(context: RendererContext): IRenderer[] { + return this.getRendererCache(context)?.renderers || []; + } + + public findRenderer(view: Element): IRenderer | undefined { + for (const rendererCache of this._rendererCaches) { + const renderer = rendererCache.findRenderer(view); + if (renderer) return renderer; + } + return undefined; + } + + protected createRenderer( context: RendererContext, rendererType: RendererType = this.rendererType ): IRenderer { @@ -72,7 +242,66 @@ export class RendererManager extends IRendererManager { return renderer; } - public override doRendering(rendererCache: RendererCacheType): void { + public startRendering(): void { + if (this._renderingTimer) return; + + const renderingLooper = () => { + if (this._previousFirstFrameTime === 0) { + // Get the current time as the time of the first frame of per second + this._previousFirstFrameTime = performance.now(); + // Reset the frame count + this._currentFrameCount = 0; + } + + // Increase the frame count + ++this._currentFrameCount; + + // Get the current time + const currentFrameTime = performance.now(); + // Calculate the time difference between the current frame and the previous frame + const deltaTime = currentFrameTime - this._previousFirstFrameTime; + // Calculate the expected time of the current frame + const expectedTime = (this._currentFrameCount * 1000) / this.renderingFps; + logDebug( + new Date().toLocaleTimeString(), + 'currentFrameCount', + this._currentFrameCount, + 'expectedTime', + expectedTime, + 'deltaTime', + deltaTime + ); + + if (this._rendererCaches.length === 0) { + // If there is no renderer, stop rendering + this.stopRendering(); + return; + } + + // Render all renderers + for (const rendererCache of this._rendererCaches) { + this.doRendering(rendererCache); + } + + if (this._currentFrameCount >= this.renderingFps) { + this._previousFirstFrameTime = 0; + } + + if (deltaTime < expectedTime) { + // If the time difference between the current frame and the previous frame is less than the expected time, then wait for the difference + this._renderingTimer = window.setTimeout( + renderingLooper, + expectedTime - deltaTime + ); + } else { + // If the time difference between the current frame and the previous frame is greater than the expected time, then render immediately + renderingLooper(); + } + }; + renderingLooper(); + } + + public doRendering(rendererCache: RendererCacheType): void { rendererCache.draw(); } @@ -84,4 +313,23 @@ export class RendererManager extends IRendererManager { renderers.splice(renderers.indexOf(renderer), 1, newRenderer); }; } + + public stopRendering(): void { + if (this._renderingTimer) { + window.clearTimeout(this._renderingTimer); + this._renderingTimer = undefined; + } + } + + public setRendererContext(context: RendererContext): boolean { + const checkedContext = this.presetRendererContext(context); + + for (const rendererCache of this._rendererCaches) { + const result = rendererCache.setRendererContext(checkedContext); + if (result) { + return true; + } + } + return false; + } } diff --git a/ts/Renderer/index.ts b/ts/Renderer/index.ts index 26cd4c4db..854c360dc 100644 --- a/ts/Renderer/index.ts +++ b/ts/Renderer/index.ts @@ -1,2 +1,2 @@ export * from './IRenderer'; -export * from './IRendererManager'; +export * from './RendererManager'; diff --git a/ts/Types.ts b/ts/Types.ts index ccd296da8..5a77e339d 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,8 +1,8 @@ import { VideoCanvas } from './Private/AgoraBase'; import { VideoFrame } from './Private/AgoraMediaBase'; import { RtcConnection } from './Private/IAgoraRtcEngineEx'; -import { IRendererManager } from './Renderer'; import { RendererCache } from './Renderer/RendererCache'; +import { RendererManager } from './Renderer/RendererManager'; import { WebCodecsRendererCache } from './Renderer/WebCodecsRendererCache'; /** @@ -34,7 +34,7 @@ export interface AgoraEnvType extends AgoraEnvOptions { /** * @ignore */ - AgoraRendererManager?: IRendererManager; + AgoraRendererManager?: RendererManager; } /** From 89bc83adf17091e77b8e430c4f206bf598fc5544 Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 7 Apr 2024 11:38:24 +0800 Subject: [PATCH 015/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 58 ++++++++++++++++--- ts/Decoder/index.ts | 7 +++ ts/Renderer/RendererManager.ts | 6 +- ts/Renderer/WebCodecsRenderer/index.ts | 7 +++ ts/Renderer/WebGLRenderer/index.ts | 2 + ts/Types.ts | 4 ++ 6 files changed, 74 insertions(+), 10 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 133f6c698..4368fba9e 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -4,6 +4,7 @@ import { IRtcEngineEventHandler, IRtcEngineEx, RenderModeType, + RtcConnection, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -13,14 +14,17 @@ import { BaseAudioComponentState, BaseComponent, } from '../../../components/BaseComponent'; -import { AgoraList } from '../../../components/ui'; +import { AgoraTextInput } from '../../../components/ui'; import Config from '../../../config/agora.config'; import { askMediaAccess } from '../../../utils/permissions'; interface State extends BaseAudioComponentState { fps: number; + decodeRemoteUserUid: number; } +const SCREEN_UID = 7; + export default class VideoDecoder extends BaseComponent<{}, State> implements IRtcEngineEventHandler @@ -36,6 +40,7 @@ export default class VideoDecoder token: Config.token, uid: Config.uid, joinChannelSuccess: false, + decodeRemoteUserUid: SCREEN_UID, remoteUsers: [], startPreview: false, }; @@ -110,8 +115,28 @@ export default class VideoDecoder this.engine?.release(); } + onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { + this.info( + 'onUserJoined', + 'connection', + connection, + 'remoteUid', + remoteUid, + 'elapsed', + elapsed + ); + // only support one decoder at the same time for now + if (remoteUid === SCREEN_UID) { + this.setState((preState) => { + return { + remoteUsers: [...(preState.remoteUsers ?? []), remoteUid], + }; + }); + } + } + protected renderUsers(): ReactElement | undefined { - let { remoteUsers, startPreview, joinChannelSuccess } = this.state; + let { decodeRemoteUserUid, startPreview, joinChannelSuccess } = this.state; return ( <> {!!startPreview || joinChannelSuccess @@ -119,17 +144,34 @@ export default class VideoDecoder sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} - - this.renderUser({ - uid: item, + {joinChannelSuccess && decodeRemoteUserUid + ? this.renderUser({ + uid: decodeRemoteUserUid, sourceType: VideoSourceType.VideoSourceRemote, // Use WebCodecs to decode video stream useWebCodecsDecoder: true, renderMode: RenderModeType.RenderModeFit, }) - } + : undefined} + + ); + } + + protected renderConfiguration(): ReactElement | undefined { + return ( + <> + { + if (isNaN(+text)) return; + this.setState({ + decodeRemoteUserUid: + text === '' ? this.createState().decodeRemoteUserUid : +text, + }); + }} + numberKeyboard={true} + placeholder={`remoteUserUid (defaults: ${ + this.createState().decodeRemoteUserUid + })`} /> ); diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index e08868b19..21d1fd30c 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -5,6 +5,7 @@ import { } from '../Private/AgoraBase'; import { WebCodecsRenderer } from '../Renderer/WebCodecsRenderer/index'; +import { RendererType } from '../Types'; import { logDebug, logInfo } from '../Utils'; const frameTypeMapping = { @@ -58,6 +59,9 @@ export class WebCodecsDecoder { renderAnimationFrame() { for (let renderer of this.renderers) { + if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { + continue; + } renderer.drawFrame(this.pendingFrame); this.pendingFrame = null; } @@ -79,6 +83,9 @@ export class WebCodecsDecoder { `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` ); for (let renderer of this.renderers) { + if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { + continue; + } renderer.setFrameSize({ width: frameInfo.width!, height: frameInfo.height!, diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index f0902006d..77802429e 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -278,8 +278,10 @@ export class RendererManager { return; } - // Render all renderers - for (const rendererCache of this._rendererCaches) { + // Render all renderers that do not use WebCodecs + for (const rendererCache of this._rendererCaches.filter( + (cache) => !cache.selfDecode + )) { this.doRendering(rendererCache); } diff --git a/ts/Renderer/WebCodecsRenderer/index.ts b/ts/Renderer/WebCodecsRenderer/index.ts index af2541749..dd8582fa7 100755 --- a/ts/Renderer/WebCodecsRenderer/index.ts +++ b/ts/Renderer/WebCodecsRenderer/index.ts @@ -1,3 +1,4 @@ +import { RendererType } from '../../Types'; import { getContextByCanvas } from '../../Utils'; import { IRenderer } from '../IRenderer'; @@ -10,6 +11,12 @@ export class WebCodecsRenderer extends IRenderer { gl?: WebGLRenderingContext | WebGL2RenderingContext | null; // eslint-disable-next-line auto-import/auto-import offscreenCanvas: OffscreenCanvas | undefined; + + constructor() { + super(); + this.rendererType = RendererType.WEBCODECSRENDERER; + } + static vertexShaderSource = ` attribute vec2 xy; varying highp vec2 uv; diff --git a/ts/Renderer/WebGLRenderer/index.ts b/ts/Renderer/WebGLRenderer/index.ts index cd3f89599..90deaf8a8 100644 --- a/ts/Renderer/WebGLRenderer/index.ts +++ b/ts/Renderer/WebGLRenderer/index.ts @@ -1,4 +1,5 @@ import { VideoFrame } from '../../Private/AgoraMediaBase'; +import { RendererType } from '../../Types'; import { logWarn } from '../../Utils'; import { IRenderer } from '../IRenderer'; @@ -57,6 +58,7 @@ export class WebGLRenderer extends IRenderer { constructor(fallback?: WebGLFallback) { super(); this.gl = undefined; + this.rendererType = RendererType.WEBGL; this.yTexture = null; this.uTexture = null; this.vTexture = null; diff --git a/ts/Types.ts b/ts/Types.ts index 5a77e339d..95776e88b 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -49,6 +49,10 @@ export enum RendererType { * @ignore */ SOFTWARE = 2, + /** + * @ignore + */ + WEBCODECSRENDERER = 3, } export type RENDER_MODE = RendererType; From 73b6327d6fc9ea6d0402b3c1dab76852ec152264 Mon Sep 17 00:00:00 2001 From: guoxianzhe Date: Sun, 7 Apr 2024 12:01:16 +0800 Subject: [PATCH 016/101] chore: optimize --- ts/Decoder/index.ts | 2 +- ts/Renderer/WebCodecsRenderer/index.ts | 2 +- ts/Renderer/WebCodecsRendererCache.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 21d1fd30c..e218ad760 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -35,7 +35,7 @@ export class WebCodecsDecoder { this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), - error: onError, + error: onError.bind(this), }); } diff --git a/ts/Renderer/WebCodecsRenderer/index.ts b/ts/Renderer/WebCodecsRenderer/index.ts index dd8582fa7..6d7989942 100755 --- a/ts/Renderer/WebCodecsRenderer/index.ts +++ b/ts/Renderer/WebCodecsRenderer/index.ts @@ -110,7 +110,7 @@ export class WebCodecsRenderer extends IRenderer { } drawFrame(frame: any) { - if (!this.offscreenCanvas) return; + if (!this.offscreenCanvas || !frame) return; this.setFrameSize({ width: frame.displayWidth, height: frame.displayHeight, diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 05e8e467a..dd23ed1f5 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,4 +1,4 @@ -import { createAgoraRtcEngine, logInfo } from '../AgoraSdk'; +import { createAgoraRtcEngine, logError, logInfo } from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; @@ -30,8 +30,8 @@ export class WebCodecsRendererCache } onDecoderError(e: any) { - window.alert(`Decoder error:${JSON.stringify(e)}`); - console.error('Decoder error:', e); + logError('Decoder error:', e); + //todo need add some fallback logic this.release(); } @@ -76,10 +76,10 @@ export class WebCodecsRendererCache } public release(): void { + super.release(); this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); this._decoder?.release(); this._decoder = null; - super.release(); } } From 1418f3d5e8217dc51cdc0e4cde7f6bcc6c75c54c Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 7 Apr 2024 16:34:29 +0800 Subject: [PATCH 017/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 48 ++++++++++++++----- ts/Decoder/index.ts | 2 +- ts/Renderer/WebCodecsRendererCache.ts | 2 +- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 4368fba9e..f7a32813e 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -5,6 +5,7 @@ import { IRtcEngineEx, RenderModeType, RtcConnection, + UserOfflineReasonType, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -21,10 +22,9 @@ import { askMediaAccess } from '../../../utils/permissions'; interface State extends BaseAudioComponentState { fps: number; decodeRemoteUserUid: number; + decodeRemoteUserUidJoined: boolean; } -const SCREEN_UID = 7; - export default class VideoDecoder extends BaseComponent<{}, State> implements IRtcEngineEventHandler @@ -40,7 +40,8 @@ export default class VideoDecoder token: Config.token, uid: Config.uid, joinChannelSuccess: false, - decodeRemoteUserUid: SCREEN_UID, + decodeRemoteUserUid: 7, + decodeRemoteUserUidJoined: false, remoteUsers: [], startPreview: false, }; @@ -115,6 +116,27 @@ export default class VideoDecoder this.engine?.release(); } + onUserOffline( + connection: RtcConnection, + remoteUid: number, + reason: UserOfflineReasonType + ) { + this.info( + 'onUserOffline', + 'connection', + connection, + 'remoteUid', + remoteUid, + 'reason', + reason + ); + if (remoteUid === this.state.decodeRemoteUserUid) { + this.setState({ + decodeRemoteUserUidJoined: false, + }); + } + } + onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { this.info( 'onUserJoined', @@ -125,18 +147,20 @@ export default class VideoDecoder 'elapsed', elapsed ); - // only support one decoder at the same time for now - if (remoteUid === SCREEN_UID) { - this.setState((preState) => { - return { - remoteUsers: [...(preState.remoteUsers ?? []), remoteUid], - }; + if (remoteUid === this.state.decodeRemoteUserUid) { + this.setState({ + decodeRemoteUserUidJoined: true, }); } } protected renderUsers(): ReactElement | undefined { - let { decodeRemoteUserUid, startPreview, joinChannelSuccess } = this.state; + let { + decodeRemoteUserUid, + decodeRemoteUserUidJoined, + startPreview, + joinChannelSuccess, + } = this.state; return ( <> {!!startPreview || joinChannelSuccess @@ -144,11 +168,12 @@ export default class VideoDecoder sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} - {joinChannelSuccess && decodeRemoteUserUid + {joinChannelSuccess && decodeRemoteUserUid && decodeRemoteUserUidJoined ? this.renderUser({ uid: decodeRemoteUserUid, sourceType: VideoSourceType.VideoSourceRemote, // Use WebCodecs to decode video stream + // only support one remote stream to decode at the same time for now useWebCodecsDecoder: true, renderMode: RenderModeType.RenderModeFit, }) @@ -161,6 +186,7 @@ export default class VideoDecoder return ( <> { if (isNaN(+text)) return; this.setState({ diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index e218ad760..21d1fd30c 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -35,7 +35,7 @@ export class WebCodecsDecoder { this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), - error: onError.bind(this), + error: onError, }); } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index dd23ed1f5..2dd9c25e3 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -23,7 +23,7 @@ export class WebCodecsRendererCache this._engine = createAgoraRtcEngine(); this._decoder = new WebCodecsDecoder( this.renderers as WebCodecsRenderer[], - this.onDecoderError + this.onDecoderError.bind(this) ); this.selfDecode = true; this.draw(); From 6516a7ff117fa9f24757809c2368054f6470c88e Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 7 Apr 2024 17:48:32 +0800 Subject: [PATCH 018/101] chore: optimize --- .../advanced/ScreenShare/ScreenShare.tsx | 61 +++++++++++-------- package.json | 2 +- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 5eafb88ca..4825d307a 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -1,20 +1,16 @@ import { ChannelProfileType, ClientRoleType, - DegradationPreference, IRtcEngineEventHandler, IRtcEngineEx, LocalVideoStreamError, LocalVideoStreamState, - OrientationMode, RenderModeType, RtcConnection, RtcStats, ScreenCaptureSourceInfo, ScreenCaptureSourceType, UserOfflineReasonType, - VideoCodecType, - VideoMirrorModeType, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -55,6 +51,8 @@ interface State extends BaseVideoComponentState { highLightWidth: number; highLightColor: number; enableHighLight: boolean; + videoCodec: number; + videoCodecList: { key: string; value: number }[]; startScreenCapture: boolean; publishScreenCapture: boolean; } @@ -90,6 +88,17 @@ export default class ScreenShare highLightWidth: 0, highLightColor: 0xff8cbf26, enableHighLight: false, + videoCodec: 2, + videoCodecList: [ + { + key: 'h264', + value: 1, + }, + { + key: 'h265', + value: 2, + }, + ], startScreenCapture: false, publishScreenCapture: false, }; @@ -122,27 +131,6 @@ export default class ScreenShare // Start preview before joinChannel this.engine.startPreview(); - this.engine.setParameters( - JSON.stringify({ 'che.video.h265_screen_enable': 1 }) - ); - this.engine.setVideoEncoderConfigurationEx( - { - codecType: VideoCodecType.VideoCodecH265, - frameRate: 65, - bitrate: 2000, - orientationMode: OrientationMode.OrientationModeAdaptive, - degradationPreference: DegradationPreference.MaintainQuality, - mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled, - dimensions: { - width: 3840, - height: 2160, - }, - }, - { - localUid: this.state.uid, - channelId: this.state.channelId, - } - ); this.setState({ startPreview: true }); this.getScreenCaptureSources(); @@ -205,6 +193,7 @@ export default class ScreenShare highLightWidth, highLightColor, enableHighLight, + videoCodec, } = this.state; if (!targetSource) { @@ -212,6 +201,11 @@ export default class ScreenShare return; } + this.engine?.setParameters( + JSON.stringify({ 'che.video.videoCodecIndex': videoCodec }) + ); + console.log('che.video.videoCodecIndex', videoCodec); + if ( targetSource.type === ScreenCaptureSourceType.ScreencapturesourcetypeScreen @@ -445,6 +439,8 @@ export default class ScreenShare highLightColor, enableHighLight, publishScreenCapture, + videoCodecList, + videoCodec, } = this.state; return ( <> @@ -594,6 +590,21 @@ export default class ScreenShare this.setState({ enableHighLight: value }); }} /> + { + return { + value: value.value!, + label: value.key!, + }; + })} + value={videoCodec} + onValueChange={(value, index) => { + this.setState((preState) => { + return { videoCodec: preState.videoCodecList?.at(index)?.value! }; + }); + }} + /> {enableHighLight ? ( <> diff --git a/package.json b/package.json index 9d0368ed6..dfb4021a7 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,6 @@ }, "agora_electron": { "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-build.1_DCG_Windows_Video_20240329_1152.zip", - "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.2.136-build.1_DCG_Mac_Video_20230922_0351.zip" + "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } From 5d17e960e625ead7d41c9c815f93fc8921281ad2 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 8 Apr 2024 17:55:21 +0800 Subject: [PATCH 019/101] chore: optimize --- package.json | 1 + ts/Renderer/RendererManager.ts | 8 ++++++++ yarn.lock | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/package.json b/package.json index dfb4021a7..13460c89d 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "jsonfile": "^6.1.0", "lodash.isequal": "^4.5.0", "minimist": "^1.2.5", + "semver": "^7.6.0", "shelljs": "^0.8.4", "ts-interface-checker": "^1.0.2", "winston": "^3.3.3", diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 77802429e..a3de90d09 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,3 +1,5 @@ +import semver from 'semver'; + import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; @@ -95,6 +97,12 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; + //videoDecoder is not supported in electron version < 22.0.0 + //@ts-ignore + if (semver.lt(process.versions.electron, '20.0.0')) { + context.useWebCodecsDecoder = false; + } + switch (context.sourceType) { case VideoSourceType.VideoSourceRemote: if (context.uid === undefined) { diff --git a/yarn.lock b/yarn.lock index c1fd6a061..12f0c9d76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8674,6 +8674,13 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.6.0: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" From fc055fb84484957296ebde3583ac38a828957e2e Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 8 Apr 2024 17:56:19 +0800 Subject: [PATCH 020/101] chore: optimize --- ts/Renderer/RendererManager.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index a3de90d09..c7cd680a0 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -3,7 +3,7 @@ import semver from 'semver'; import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; -import { isSupportWebGL, logDebug } from '../Utils'; +import { isSupportWebGL, logDebug, logError } from '../Utils'; import { IRenderer } from './IRenderer'; import { generateRendererCacheKey } from './IRendererCache'; @@ -97,10 +97,13 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; - //videoDecoder is not supported in electron version < 22.0.0 + //videoDecoder is not supported in electron version < 20.0.0 //@ts-ignore if (semver.lt(process.versions.electron, '20.0.0')) { context.useWebCodecsDecoder = false; + logError( + 'WebCodecsDecoder is not supported in electron version < 20.0.0, please upgrade electron to 20.0.0 or later.' + ); } switch (context.sourceType) { From 179917c9e641a01877aab43d0b7a78950eeeb9db Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 9 Apr 2024 17:38:11 +0800 Subject: [PATCH 021/101] chore: optimize --- ts/Private/internal/MediaEngineInternal.ts | 10 ++++++++-- ts/Private/internal/RtcEngineExInternal.ts | 8 ++++---- ts/Renderer/WebCodecsRendererCache.ts | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ts/Private/internal/MediaEngineInternal.ts b/ts/Private/internal/MediaEngineInternal.ts index e8f81d299..4a26860d3 100644 --- a/ts/Private/internal/MediaEngineInternal.ts +++ b/ts/Private/internal/MediaEngineInternal.ts @@ -62,6 +62,9 @@ export class MediaEngineInternal extends IMediaEngineImpl { override registerVideoEncodedFrameObserver( observer: IVideoEncodedFrameObserver ): number { + // only call iris when no event handler registered + let callIris = + MediaEngineInternal._video_encoded_frame_observers.length === 0; if ( !MediaEngineInternal._video_encoded_frame_observers.find( (value) => value === observer @@ -69,7 +72,7 @@ export class MediaEngineInternal extends IMediaEngineImpl { ) { MediaEngineInternal._video_encoded_frame_observers.push(observer); } - return super.registerVideoEncodedFrameObserver(observer); + return callIris ? super.registerVideoEncodedFrameObserver(observer) : 1; } override unregisterVideoEncodedFrameObserver( @@ -79,7 +82,10 @@ export class MediaEngineInternal extends IMediaEngineImpl { MediaEngineInternal._video_encoded_frame_observers.filter( (value) => value !== observer ); - return super.unregisterVideoEncodedFrameObserver(observer); + // only call iris when no event handler registered + let callIris = + MediaEngineInternal._video_encoded_frame_observers.length === 0; + return callIris ? super.unregisterVideoEncodedFrameObserver(observer) : 1; } override release() { diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index 780774d20..f798d50ef 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -88,6 +88,10 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { new LocalSpatialAudioEngineInternal(); override initialize(context: RtcEngineContext): number { + const ret = super.initialize(context); + callIrisApi.call(this, 'RtcEngine_setAppType', { + appType: 3, + }); if (AgoraEnv.webEnvReady) { // @ts-ignore window.AgoraEnv = AgoraEnv; @@ -96,10 +100,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { AgoraEnv.AgoraRendererManager = new RendererManager(); } } - const ret = super.initialize(context); - callIrisApi.call(this, 'RtcEngine_setAppType', { - appType: 3, - }); return ret; } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 2dd9c25e3..8ccd990e0 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -76,10 +76,10 @@ export class WebCodecsRendererCache } public release(): void { - super.release(); this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); this._decoder?.release(); this._decoder = null; + super.release(); } } From bbbac3ac25ada4f66846583ff407a4fd42d478f0 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 10 Apr 2024 11:44:34 +0800 Subject: [PATCH 022/101] chore: optimize --- .../JoinChannelVideo/JoinChannelVideo.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx index 412fbbcf2..7ff3c1196 100644 --- a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx +++ b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx @@ -18,7 +18,7 @@ import { BaseComponent, BaseVideoComponentState, } from '../../../components/BaseComponent'; -import { AgoraDropdown } from '../../../components/ui'; +import { AgoraDropdown, AgoraList } from '../../../components/ui'; import Config from '../../../config/agora.config'; import { arrayToItems } from '../../../utils'; import { askMediaAccess } from '../../../utils/permissions'; @@ -170,7 +170,24 @@ export default class JoinChannelVideo } protected renderUsers(): ReactElement | undefined { - return super.renderUsers(); + const { startPreview, joinChannelSuccess, remoteUsers } = this.state; + return ( + <> + {!!startPreview || joinChannelSuccess + ? this.renderUser({ + sourceType: VideoSourceType.VideoSourceCamera, + }) + : undefined} + {!!startPreview || joinChannelSuccess + ? remoteUsers.map((item) => + this.renderUser({ + uid: item, + sourceType: VideoSourceType.VideoSourceRemote, + }) + ) + : undefined} + + ); } protected renderVideo(user: VideoCanvas): ReactElement | undefined { From 257c9834695b14c9cfe870e4776efe5153e0d9c6 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 10 Apr 2024 15:40:41 +0800 Subject: [PATCH 023/101] chore: optimize --- .../basic/JoinChannelVideo/JoinChannelVideo.tsx | 2 +- .../basic/VideoDecoder/VideoDecoder.tsx | 2 ++ ts/Decoder/index.ts | 16 ++++++++-------- ts/Utils.ts | 17 ++++++++++++++++- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx index 7ff3c1196..4cfdc3722 100644 --- a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx +++ b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx @@ -18,7 +18,7 @@ import { BaseComponent, BaseVideoComponentState, } from '../../../components/BaseComponent'; -import { AgoraDropdown, AgoraList } from '../../../components/ui'; +import { AgoraDropdown } from '../../../components/ui'; import Config from '../../../config/agora.config'; import { arrayToItems } from '../../../utils'; import { askMediaAccess } from '../../../utils/permissions'; diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index f7a32813e..ca04c2a83 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -3,6 +3,7 @@ import { ClientRoleType, IRtcEngineEventHandler, IRtcEngineEx, + LogFilterType, RenderModeType, RtcConnection, UserOfflineReasonType, @@ -56,6 +57,7 @@ export default class VideoDecoder this.error(`appId is invalid`); } this.engine = createAgoraRtcEngine() as IRtcEngineEx; + this.engine.setLogFilter(LogFilterType.LogFilterDebug); this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 21d1fd30c..feab5f05e 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -101,14 +101,14 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { - // console.log( - // 'FRAMETYPE', - // frameInfo.uid, - // // frameInfo.frameType, - // // frameInfo, - // // imageBuffer, - // imageBuffer.length - // ); + logInfo( + 'FRAMETYPE', + frameInfo.uid, + frameInfo.frameType, + frameInfo, + imageBuffer, + imageBuffer.length + ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; diff --git a/ts/Utils.ts b/ts/Utils.ts index 82bf1b393..834363fe3 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -29,6 +29,21 @@ export const logError = (msg: string, ...optParams: any[]) => { console.error(`${TAG} ${msg}`, ...optParams); }; +const getCurrentTime = () => { + const date = new Date(); + + const year = date.getFullYear().toString().slice(-2); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + const seconds = date.getSeconds().toString().padStart(2, '0'); + const milliseconds = date.getMilliseconds().toString().padStart(3, '0'); + + return `${month}/${day}/${year} ${hours}:${minutes}:${seconds}:${milliseconds}`; +}; + /** * @ignore */ @@ -36,7 +51,7 @@ export const logInfo = (msg: string, ...optParams: any[]) => { if (!AgoraEnv.enableLogging) { return; } - console.info(`${TAG} ${msg}`, ...optParams); + console.info(`[${getCurrentTime()}]${TAG} ${msg}`, ...optParams); }; /** From 28b88bc8407e13a55780fbbd4c899321572d6f70 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 10 Apr 2024 17:21:57 +0800 Subject: [PATCH 024/101] chore: optimize --- .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 4 ++++ package.json | 2 +- ts/Private/internal/MediaEngineInternal.ts | 4 ++++ ts/Private/internal/RtcEngineExInternal.ts | 4 ++++ ts/Types.ts | 4 ++++ ts/Utils.ts | 1 + 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index ca04c2a83..0cf30aae5 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -1,4 +1,5 @@ import { + AgoraEnv, ChannelProfileType, ClientRoleType, IRtcEngineEventHandler, @@ -58,6 +59,9 @@ export default class VideoDecoder } this.engine = createAgoraRtcEngine() as IRtcEngineEx; this.engine.setLogFilter(LogFilterType.LogFilterDebug); + // register video encoded frame observer after initialize the engine + // need to enable WebCodecsDecoder before call engine.initialize + AgoraEnv.enableWebCodecsDecoder = true; this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, diff --git a/package.json b/package.json index 13460c89d..c92093ca2 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-build.1_DCG_Windows_Video_20240329_1152.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.1_DCG_Windows_Video_20240410_0427.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } diff --git a/ts/Private/internal/MediaEngineInternal.ts b/ts/Private/internal/MediaEngineInternal.ts index 4a26860d3..5bb932fc9 100644 --- a/ts/Private/internal/MediaEngineInternal.ts +++ b/ts/Private/internal/MediaEngineInternal.ts @@ -1,5 +1,6 @@ import { createCheckers } from 'ts-interface-checker'; +import { AgoraEnv } from '../../Utils'; import { IAudioFrameObserver, IVideoEncodedFrameObserver, @@ -92,6 +93,9 @@ export class MediaEngineInternal extends IMediaEngineImpl { MediaEngineInternal._audio_frame_observers = []; MediaEngineInternal._video_frame_observers = []; MediaEngineInternal._video_encoded_frame_observers = []; + if (AgoraEnv.enableWebCodecsDecoder) { + this.unregisterVideoEncodedFrameObserver({}); + } this.removeAllListeners(); super.release(); } diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index f798d50ef..ec87ac773 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -92,6 +92,10 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { callIrisApi.call(this, 'RtcEngine_setAppType', { appType: 3, }); + if (AgoraEnv.enableWebCodecsDecoder) { + this._media_engine.registerVideoEncodedFrameObserver({}); + MediaEngineInternal._video_encoded_frame_observers = []; + } if (AgoraEnv.webEnvReady) { // @ts-ignore window.AgoraEnv = AgoraEnv; diff --git a/ts/Types.ts b/ts/Types.ts index 95776e88b..579f71ba0 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -21,6 +21,10 @@ export interface AgoraEnvOptions { * @ignore */ webEnvReady?: boolean; + /** + * @ignore + */ + enableWebCodecsDecoder?: boolean; } /** diff --git a/ts/Utils.ts b/ts/Utils.ts index 834363fe3..c6c301cbb 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -177,5 +177,6 @@ export const AgoraEnv: AgoraEnvType = { enableLogging: true, enableDebugLogging: false, webEnvReady: true, + enableWebCodecsDecoder: true, AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From c37b338fb0bd0227e3db846b7b7125a243c68791 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 11 Apr 2024 09:40:23 +0800 Subject: [PATCH 025/101] chore: optimize --- example/package.json | 2 +- example/src/main/index.js | 26 +++++++++ .../basic/VideoDecoder/VideoDecoder.tsx | 9 +-- example/yarn.lock | 25 ++++++--- ts/Decoder/GPU.ts | 55 +++++++++++++++++++ ts/Private/internal/RtcEngineExInternal.ts | 1 - ts/Utils.ts | 2 +- 7 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 ts/Decoder/GPU.ts diff --git a/example/package.json b/example/package.json index 3629877e0..a5970d047 100644 --- a/example/package.json +++ b/example/package.json @@ -94,7 +94,7 @@ "@types/react-dom": "^18.0.3", "@types/react-router-dom": "^5.1.6", "@types/ref-napi": "^3.0.7", - "electron": "22.0.0", + "electron": "24.8.8", "electron-builder": "^23.1.0", "electron-webpack": "^2.8.2", "fork-ts-checker-webpack-plugin": "^4.1.2", diff --git a/example/src/main/index.js b/example/src/main/index.js index 3497489ba..ed6a204cb 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -81,3 +81,29 @@ app.on('activate', () => { app.on('ready', () => { mainWindow = createMainWindow(); }); + +app.commandLine.appendSwitch('--disable-software-rasterizer'); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + show: false, + webPreferences: { contextIsolation: true }, + }); + w.webContents.once('did-finish-load', () => { + app.getGPUInfo('complete').then( + (gpuInfo) => { + console.log( + 'HERE COMES THE JSON: ' + + JSON.stringify(gpuInfo) + + ' AND THERE IT WAS' + ); + setImmediate(() => app.exit(0)); + }, + (error) => { + console.error(error); + setImmediate(() => app.exit(1)); + } + ); + }); + w.loadURL('data:text/html;'); +}); diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 0cf30aae5..d5d108c46 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -1,5 +1,4 @@ import { - AgoraEnv, ChannelProfileType, ClientRoleType, IRtcEngineEventHandler, @@ -58,16 +57,18 @@ export default class VideoDecoder this.error(`appId is invalid`); } this.engine = createAgoraRtcEngine() as IRtcEngineEx; - this.engine.setLogFilter(LogFilterType.LogFilterDebug); - // register video encoded frame observer after initialize the engine // need to enable WebCodecsDecoder before call engine.initialize - AgoraEnv.enableWebCodecsDecoder = true; + // if enableWebCodecsDecoder is true, the video stream will be decoded by WebCodecs + // will automatically register videoEncodedFrameObserver + // videoEncodedFrameObserver will be released when engine.release + // AgoraEnv.enableWebCodecsDecoder = true; this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, // Should use ChannelProfileLiveBroadcasting on most of cases channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, }); + this.engine.setLogFilter(LogFilterType.LogFilterDebug); this.engine.registerEventHandler(this); // Need granted the microphone and camera permission diff --git a/example/yarn.lock b/example/yarn.lock index 8676324d5..b09f070b3 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1402,10 +1402,12 @@ resolved "https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz#081d9afd28421be956c1a47ced1c9a0034b467e2" integrity sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw== -"@types/node@^16.11.26": - version "16.18.25" - resolved "https://registry.npmjs.org/@types/node/-/node-16.18.25.tgz#8863940fefa1234d3fcac7a4b7a48a6c992d67af" - integrity sha512-rUDO6s9Q/El1R1I21HG4qw/LstTHCPO/oQNAwI/4b2f9EWvMnqt4d3HJwPMawfZ3UvodB8516Yg+VAq54YM+eA== +"@types/node@^18.11.18": + version "18.19.31" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz#b7d4a00f7cb826b60a543cebdbda5d189aaecdcd" + integrity sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA== + dependencies: + undici-types "~5.26.4" "@types/plist@^3.0.1": version "3.0.2" @@ -4098,13 +4100,13 @@ electron-webpack@^2.8.2: webpack-merge "^4.2.2" yargs "^15.3.1" -electron@22.0.0: - version "22.0.0" - resolved "https://registry.npmjs.org/electron/-/electron-22.0.0.tgz#ef84ab9cf23aa3f8c2f42a1e8e000ad7fd941058" - integrity sha512-cgRc4wjyM+81A0E8UGv1HNJjL1HBI5cWNh/DUIjzYvoUuiEM0SS0hAH/zaFQ18xOz2ced6Yih8SybpOiOYJhdg== +electron@24.8.8: + version "24.8.8" + resolved "https://registry.npmjs.org/electron/-/electron-24.8.8.tgz#b369e8f8910d41e94817b79ea3d37e0f0822e884" + integrity sha512-0A2tGwG/0hxnD32Lil9wgSydQ0HCP5AdkgcH+qee3QgaC2jVq55YIbrj/0ZAq4L7yiZvQTzYIrc6kie7OahJKQ== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^16.11.26" + "@types/node" "^18.11.18" extract-zip "^2.0.1" elliptic@^6.5.3: @@ -10080,6 +10082,11 @@ undertaker@^1.2.1: object.reduce "^1.0.0" undertaker-registry "^1.0.0" +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" diff --git a/ts/Decoder/GPU.ts b/ts/Decoder/GPU.ts new file mode 100644 index 000000000..bcd0089c4 --- /dev/null +++ b/ts/Decoder/GPU.ts @@ -0,0 +1,55 @@ +export enum VideoCodecProfile { + VIDEO_CODEC_PROFILE_UNKNOWN = -1, + H264PROFILE_BASELINE = 0, + H264PROFILE_MAIN, + H264PROFILE_EXTENDED, + H264PROFILE_HIGH, + H264PROFILE_HIGH10PROFILE, + H264PROFILE_HIGH422PROFILE, + H264PROFILE_HIGH444PREDICTIVEPROFILE, + H264PROFILE_SCALABLEBASELINE, + H264PROFILE_SCALABLEHIGH, + H264PROFILE_STEREOHIGH, + H264PROFILE_MULTIVIEWHIGH, + VP8PROFILE_ANY, + VP9PROFILE_PROFILE0, + VP9PROFILE_PROFILE1, + VP9PROFILE_PROFILE2, + VP9PROFILE_PROFILE3, + HEVCPROFILE_MAIN, + HEVCPROFILE_MAIN10, + HEVCPROFILE_MAIN_STILL_PICTURE, + DOLBYVISION_PROFILE0, + // Deprecated: DOLBYVISION_PROFILE4 = 20, + DOLBYVISION_PROFILE5 = 21, + DOLBYVISION_PROFILE7, + THEORAPROFILE_ANY, + AV1PROFILE_PROFILE_MAIN, + AV1PROFILE_PROFILE_HIGH, + AV1PROFILE_PROFILE_PRO, + DOLBYVISION_PROFILE8, + DOLBYVISION_PROFILE9, + HEVCPROFILE_REXT, + HEVCPROFILE_HIGH_THROUGHPUT, + HEVCPROFILE_MULTIVIEW_MAIN, + HEVCPROFILE_SCALABLE_MAIN, + HEVCPROFILE_3D_MAIN, + HEVCPROFILE_SCREEN_EXTENDED, + HEVCPROFILE_SCALABLE_REXT, + HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED, + VVCPROFILE_MAIN10, + VVCPROFILE_MAIN12, + VVCPROFILE_MAIN12_INTRA, + VVCPROIFLE_MULTILAYER_MAIN10, + VVCPROFILE_MAIN10_444, + VVCPROFILE_MAIN12_444, + VVCPROFILE_MAIN16_444, + VVCPROFILE_MAIN12_444_INTRA, + VVCPROFILE_MAIN16_444_INTRA, + VVCPROFILE_MULTILAYER_MAIN10_444, + VVCPROFILE_MAIN10_STILL_PICTURE, + VVCPROFILE_MAIN12_STILL_PICTURE, + VVCPROFILE_MAIN10_444_STILL_PICTURE, + VVCPROFILE_MAIN12_444_STILL_PICTURE, + VVCPROFILE_MAIN16_444_STILL_PICTURE, +} diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index ec87ac773..e190de43d 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -94,7 +94,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { }); if (AgoraEnv.enableWebCodecsDecoder) { this._media_engine.registerVideoEncodedFrameObserver({}); - MediaEngineInternal._video_encoded_frame_observers = []; } if (AgoraEnv.webEnvReady) { // @ts-ignore diff --git a/ts/Utils.ts b/ts/Utils.ts index c6c301cbb..c1962f585 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -177,6 +177,6 @@ export const AgoraEnv: AgoraEnvType = { enableLogging: true, enableDebugLogging: false, webEnvReady: true, - enableWebCodecsDecoder: true, + enableWebCodecsDecoder: false, AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From 781faead491710d66f1ee95b0405e9d705a3aff6 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 11 Apr 2024 15:10:55 +0800 Subject: [PATCH 026/101] chore: optimize --- example/package.json | 2 +- example/src/main/index.js | 50 ++++++++++------- .../basic/VideoDecoder/VideoDecoder.tsx | 3 + example/yarn.lock | 25 +++------ ts/AgoraSdk.ts | 1 + ts/Decoder/GPU.ts | 55 ------------------- ts/Decoder/gpu-utils.ts | 37 +++++++++++++ ts/Private/internal/ipc.ts | 39 +++++++++++++ ts/Utils.ts | 13 +++++ 9 files changed, 133 insertions(+), 92 deletions(-) delete mode 100644 ts/Decoder/GPU.ts create mode 100644 ts/Decoder/gpu-utils.ts create mode 100644 ts/Private/internal/ipc.ts diff --git a/example/package.json b/example/package.json index a5970d047..3629877e0 100644 --- a/example/package.json +++ b/example/package.json @@ -94,7 +94,7 @@ "@types/react-dom": "^18.0.3", "@types/react-router-dom": "^5.1.6", "@types/ref-napi": "^3.0.7", - "electron": "24.8.8", + "electron": "22.0.0", "electron-builder": "^23.1.0", "electron-webpack": "^2.8.2", "fork-ts-checker-webpack-plugin": "^4.1.2", diff --git a/example/src/main/index.js b/example/src/main/index.js index ed6a204cb..6a69d21a9 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -82,28 +82,38 @@ app.on('ready', () => { mainWindow = createMainWindow(); }); -app.commandLine.appendSwitch('--disable-software-rasterizer'); - app.whenReady().then(() => { - const w = new BrowserWindow({ + const gpu = new BrowserWindow({ show: false, - webPreferences: { contextIsolation: true }, + webPreferences: { offscreen: true }, }); - w.webContents.once('did-finish-load', () => { - app.getGPUInfo('complete').then( - (gpuInfo) => { - console.log( - 'HERE COMES THE JSON: ' + - JSON.stringify(gpuInfo) + - ' AND THERE IT WAS' - ); - setImmediate(() => app.exit(0)); - }, - (error) => { - console.error(error); - setImmediate(() => app.exit(1)); - } - ); + gpu.loadURL('chrome://gpu'); + gpu.webContents.on('did-finish-load', () => { + let executeJavaScriptText = + `` + + `let videoAccelerationInfo = [];` + + `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + + `for (node of nodeList) {` + + ` videoAccelerationInfo.push({` + + ` title: node.shadowRoot.querySelector('#title')?.innerText,` + + ` value: node.shadowRoot.querySelector('#value')?.innerText,` + + ` })` + + `}` + + `JSON.stringify(videoAccelerationInfo)`; + gpu.webContents + .executeJavaScript(executeJavaScriptText) + .then((result) => { + if (!result) { + return; + } + let filterResult = JSON.parse(result).filter((item) => { + return item.title.indexOf('Decode') !== -1; + }); + console.log(filterResult); + gpu.close(); + }) + .catch((error) => { + console.log(error); + }); }); - w.loadURL('data:text/html;'); }); diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index d5d108c46..fd631e133 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -9,6 +9,7 @@ import { UserOfflineReasonType, VideoSourceType, createAgoraRtcEngine, + getGpuInfo, } from 'agora-electron-sdk'; import React, { ReactElement } from 'react'; @@ -26,6 +27,8 @@ interface State extends BaseAudioComponentState { decodeRemoteUserUidJoined: boolean; } +getGpuInfo(); + export default class VideoDecoder extends BaseComponent<{}, State> implements IRtcEngineEventHandler diff --git a/example/yarn.lock b/example/yarn.lock index b09f070b3..a571e7992 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1402,12 +1402,10 @@ resolved "https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz#081d9afd28421be956c1a47ced1c9a0034b467e2" integrity sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw== -"@types/node@^18.11.18": - version "18.19.31" - resolved "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz#b7d4a00f7cb826b60a543cebdbda5d189aaecdcd" - integrity sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA== - dependencies: - undici-types "~5.26.4" +"@types/node@^16.11.26": + version "16.18.96" + resolved "https://registry.npmjs.org/@types/node/-/node-16.18.96.tgz#eb0012d23ff53d14d64ec8a352bf89792de6aade" + integrity sha512-84iSqGXoO+Ha16j8pRZ/L90vDMKX04QTYMTfYeE1WrjWaZXuchBehGUZEpNgx7JnmlrIHdnABmpjrQjhCnNldQ== "@types/plist@^3.0.1": version "3.0.2" @@ -4100,13 +4098,13 @@ electron-webpack@^2.8.2: webpack-merge "^4.2.2" yargs "^15.3.1" -electron@24.8.8: - version "24.8.8" - resolved "https://registry.npmjs.org/electron/-/electron-24.8.8.tgz#b369e8f8910d41e94817b79ea3d37e0f0822e884" - integrity sha512-0A2tGwG/0hxnD32Lil9wgSydQ0HCP5AdkgcH+qee3QgaC2jVq55YIbrj/0ZAq4L7yiZvQTzYIrc6kie7OahJKQ== +electron@22.0.0: + version "22.0.0" + resolved "https://registry.npmjs.org/electron/-/electron-22.0.0.tgz#ef84ab9cf23aa3f8c2f42a1e8e000ad7fd941058" + integrity sha512-cgRc4wjyM+81A0E8UGv1HNJjL1HBI5cWNh/DUIjzYvoUuiEM0SS0hAH/zaFQ18xOz2ced6Yih8SybpOiOYJhdg== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^18.11.18" + "@types/node" "^16.11.26" extract-zip "^2.0.1" elliptic@^6.5.3: @@ -10082,11 +10080,6 @@ undertaker@^1.2.1: object.reduce "^1.0.0" undertaker-registry "^1.0.0" -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" diff --git a/ts/AgoraSdk.ts b/ts/AgoraSdk.ts index 071f575e8..bbd261fd2 100644 --- a/ts/AgoraSdk.ts +++ b/ts/AgoraSdk.ts @@ -18,6 +18,7 @@ export * from './Private/IAgoraRtcEngine'; export * from './Private/IAgoraRtcEngineEx'; export * from './Private/IAgoraSpatialAudio'; export * from './Private/IAudioDeviceManager'; +export * from './Private/internal/ipc'; export * from './Renderer'; export * from './Types'; export * from './Utils'; diff --git a/ts/Decoder/GPU.ts b/ts/Decoder/GPU.ts deleted file mode 100644 index bcd0089c4..000000000 --- a/ts/Decoder/GPU.ts +++ /dev/null @@ -1,55 +0,0 @@ -export enum VideoCodecProfile { - VIDEO_CODEC_PROFILE_UNKNOWN = -1, - H264PROFILE_BASELINE = 0, - H264PROFILE_MAIN, - H264PROFILE_EXTENDED, - H264PROFILE_HIGH, - H264PROFILE_HIGH10PROFILE, - H264PROFILE_HIGH422PROFILE, - H264PROFILE_HIGH444PREDICTIVEPROFILE, - H264PROFILE_SCALABLEBASELINE, - H264PROFILE_SCALABLEHIGH, - H264PROFILE_STEREOHIGH, - H264PROFILE_MULTIVIEWHIGH, - VP8PROFILE_ANY, - VP9PROFILE_PROFILE0, - VP9PROFILE_PROFILE1, - VP9PROFILE_PROFILE2, - VP9PROFILE_PROFILE3, - HEVCPROFILE_MAIN, - HEVCPROFILE_MAIN10, - HEVCPROFILE_MAIN_STILL_PICTURE, - DOLBYVISION_PROFILE0, - // Deprecated: DOLBYVISION_PROFILE4 = 20, - DOLBYVISION_PROFILE5 = 21, - DOLBYVISION_PROFILE7, - THEORAPROFILE_ANY, - AV1PROFILE_PROFILE_MAIN, - AV1PROFILE_PROFILE_HIGH, - AV1PROFILE_PROFILE_PRO, - DOLBYVISION_PROFILE8, - DOLBYVISION_PROFILE9, - HEVCPROFILE_REXT, - HEVCPROFILE_HIGH_THROUGHPUT, - HEVCPROFILE_MULTIVIEW_MAIN, - HEVCPROFILE_SCALABLE_MAIN, - HEVCPROFILE_3D_MAIN, - HEVCPROFILE_SCREEN_EXTENDED, - HEVCPROFILE_SCALABLE_REXT, - HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED, - VVCPROFILE_MAIN10, - VVCPROFILE_MAIN12, - VVCPROFILE_MAIN12_INTRA, - VVCPROIFLE_MULTILAYER_MAIN10, - VVCPROFILE_MAIN10_444, - VVCPROFILE_MAIN12_444, - VVCPROFILE_MAIN16_444, - VVCPROFILE_MAIN12_444_INTRA, - VVCPROFILE_MAIN16_444_INTRA, - VVCPROFILE_MULTILAYER_MAIN10_444, - VVCPROFILE_MAIN10_STILL_PICTURE, - VVCPROFILE_MAIN12_STILL_PICTURE, - VVCPROFILE_MAIN10_444_STILL_PICTURE, - VVCPROFILE_MAIN12_444_STILL_PICTURE, - VVCPROFILE_MAIN16_444_STILL_PICTURE, -} diff --git a/ts/Decoder/gpu-utils.ts b/ts/Decoder/gpu-utils.ts new file mode 100644 index 000000000..2c873d83d --- /dev/null +++ b/ts/Decoder/gpu-utils.ts @@ -0,0 +1,37 @@ +import { BrowserWindow } from 'electron'; + +/** + * @ignore + */ +export const getGpuInfoInternal = () => { + const gpuPage = new BrowserWindow({ + show: false, + webPreferences: { offscreen: true }, + }); + gpuPage.loadURL('chrome://gpu'); + gpuPage.webContents.on('did-finish-load', () => { + let executeJavaScriptText = + `` + + `let videoAccelerationInfo = [];` + + `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + + `for (node of nodeList) {` + + ` videoAccelerationInfo.push({` + + ` title: node.shadowRoot.querySelector('#title')?.innerText,` + + ` value: node.shadowRoot.querySelector('#value')?.innerText,` + + ` })` + + `}` + + `JSON.stringify(videoAccelerationInfo)`; + gpuPage.webContents + .executeJavaScript(executeJavaScriptText) + .then((result: string) => { + if (!result) { + return; + } + let filterResult = JSON.parse(result).filter((item: any) => { + return item.title.indexOf('Decode') !== -1; + }); + console.log(filterResult); + }) + .catch((error: any) => {}); + }); +}; diff --git a/ts/Private/internal/ipc.ts b/ts/Private/internal/ipc.ts new file mode 100644 index 000000000..97c3ec2d2 --- /dev/null +++ b/ts/Private/internal/ipc.ts @@ -0,0 +1,39 @@ +import { app, ipcMain, ipcRenderer } from 'electron'; + +import { logError } from 'types/Utils'; + +import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; + +import { logInfo } from '../../Utils'; + +export enum IPCMessageType { + AGORA_IPC_GET_GPU_INFO = 'AGORA_IPC_GET_GPU_INFO', +} + +if (process.type === 'browser') { + ipcMain.handle(IPCMessageType.AGORA_IPC_GET_GPU_INFO, async (event, arg) => { + getGpuInfoInternal(); + }); + + app.on('quit', () => { + // release resource + ipcMain.removeHandler(IPCMessageType.AGORA_IPC_GET_GPU_INFO); + }); +} else { + logInfo('Not in main process, skip ipc registration'); +} + +export async function ipcSend( + channel: IPCMessageType, + ...args: any[] +): Promise { + if (!Object.values(IPCMessageType).includes(channel)) { + logError('Invalid IPCMessageType'); + return; + } + if (process.type === 'renderer') { + return await ipcRenderer.invoke(channel, ...args); + } else { + logError('Not in renderer process, cannot send ipc message'); + } +} diff --git a/ts/Utils.ts b/ts/Utils.ts index c1962f585..912305d8d 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -1,3 +1,5 @@ +import { getGpuInfoInternal } from './Decoder/gpu-utils'; +import { IPCMessageType, ipcSend } from './Private/internal/ipc'; import { AgoraEnvType } from './Types'; /** @@ -168,6 +170,17 @@ export function getContextByCanvas( return null; } +export function getGpuInfo() { + if (process.type === 'browser') { + getGpuInfoInternal(); + } else if (process.type === 'renderer') { + // + } else { + ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO); + console.log('This function only works in main process or renderer process'); + } +} + const AgoraNode = require('../build/Release/agora_node_ext'); /** From ca338ffda4ea66fa16f79c96038029c44d728ae4 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 11 Apr 2024 18:05:15 +0800 Subject: [PATCH 027/101] chore: optimize --- example/src/main/index.js | 71 +++++++-------- .../basic/VideoDecoder/VideoDecoder.tsx | 6 +- ts/AgoraSdk.ts | 1 - ts/Decoder/gpu-utils.ts | 88 +++++++++++++------ ts/Private/internal/ipc.ts | 39 -------- ts/Private/ipc/main.js | 15 ++++ ts/Private/ipc/renderer.ts | 21 +++++ ts/Renderer/RendererManager.ts | 40 ++++++++- ts/Types.ts | 7 ++ ts/Utils.ts | 13 --- 10 files changed, 180 insertions(+), 121 deletions(-) delete mode 100644 ts/Private/internal/ipc.ts create mode 100644 ts/Private/ipc/main.js create mode 100644 ts/Private/ipc/renderer.ts diff --git a/example/src/main/index.js b/example/src/main/index.js index 6a69d21a9..7531d86f7 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -1,6 +1,7 @@ import path from 'path'; import { format as formatUrl } from 'url'; +require('agora-electron-sdk/js/Private/ipc/main'); import { BrowserWindow, app, ipcMain, systemPreferences } from 'electron'; const isDevelopment = process.env.NODE_ENV !== 'production'; @@ -82,38 +83,38 @@ app.on('ready', () => { mainWindow = createMainWindow(); }); -app.whenReady().then(() => { - const gpu = new BrowserWindow({ - show: false, - webPreferences: { offscreen: true }, - }); - gpu.loadURL('chrome://gpu'); - gpu.webContents.on('did-finish-load', () => { - let executeJavaScriptText = - `` + - `let videoAccelerationInfo = [];` + - `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + - `for (node of nodeList) {` + - ` videoAccelerationInfo.push({` + - ` title: node.shadowRoot.querySelector('#title')?.innerText,` + - ` value: node.shadowRoot.querySelector('#value')?.innerText,` + - ` })` + - `}` + - `JSON.stringify(videoAccelerationInfo)`; - gpu.webContents - .executeJavaScript(executeJavaScriptText) - .then((result) => { - if (!result) { - return; - } - let filterResult = JSON.parse(result).filter((item) => { - return item.title.indexOf('Decode') !== -1; - }); - console.log(filterResult); - gpu.close(); - }) - .catch((error) => { - console.log(error); - }); - }); -}); +// app.whenReady().then(() => { +// const gpu = new BrowserWindow({ +// show: false, +// webPreferences: { offscreen: true }, +// }); +// gpu.loadURL('chrome://gpu'); +// // gpu.webContents.on('did-finish-load', () => { +// let executeJavaScriptText = +// `` + +// `let videoAccelerationInfo = [];` + +// `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + +// `for (node of nodeList) {` + +// ` videoAccelerationInfo.push({` + +// ` title: node.shadowRoot.querySelector('#title')?.innerText,` + +// ` value: node.shadowRoot.querySelector('#value')?.innerText,` + +// ` })` + +// `}` + +// `JSON.stringify(videoAccelerationInfo)`; +// gpu.webContents +// .executeJavaScript(executeJavaScriptText) +// .then((result) => { +// if (!result) { +// return; +// } +// let filterResult = JSON.parse(result).filter((item) => { +// return item.title.indexOf('Decode') !== -1; +// }); +// console.log(filterResult); +// gpu.close(); +// }) +// .catch((error) => { +// console.log(error); +// }); +// // }); +// }); diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index fd631e133..e8fdca3b3 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -1,4 +1,5 @@ import { + AgoraEnv, ChannelProfileType, ClientRoleType, IRtcEngineEventHandler, @@ -9,7 +10,6 @@ import { UserOfflineReasonType, VideoSourceType, createAgoraRtcEngine, - getGpuInfo, } from 'agora-electron-sdk'; import React, { ReactElement } from 'react'; @@ -27,8 +27,6 @@ interface State extends BaseAudioComponentState { decodeRemoteUserUidJoined: boolean; } -getGpuInfo(); - export default class VideoDecoder extends BaseComponent<{}, State> implements IRtcEngineEventHandler @@ -64,7 +62,7 @@ export default class VideoDecoder // if enableWebCodecsDecoder is true, the video stream will be decoded by WebCodecs // will automatically register videoEncodedFrameObserver // videoEncodedFrameObserver will be released when engine.release - // AgoraEnv.enableWebCodecsDecoder = true; + AgoraEnv.enableWebCodecsDecoder = true; this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, diff --git a/ts/AgoraSdk.ts b/ts/AgoraSdk.ts index bbd261fd2..071f575e8 100644 --- a/ts/AgoraSdk.ts +++ b/ts/AgoraSdk.ts @@ -18,7 +18,6 @@ export * from './Private/IAgoraRtcEngine'; export * from './Private/IAgoraRtcEngineEx'; export * from './Private/IAgoraSpatialAudio'; export * from './Private/IAudioDeviceManager'; -export * from './Private/internal/ipc'; export * from './Renderer'; export * from './Types'; export * from './Utils'; diff --git a/ts/Decoder/gpu-utils.ts b/ts/Decoder/gpu-utils.ts index 2c873d83d..3fb762887 100644 --- a/ts/Decoder/gpu-utils.ts +++ b/ts/Decoder/gpu-utils.ts @@ -1,37 +1,73 @@ +//@ts-ignore import { BrowserWindow } from 'electron'; +import { logError } from '../Utils'; + +/** + * @ignore + */ + +export type VideoDecodeAcceleratorSupportedProfile = { + title: string; + value: string; +}; + +/** + * @ignore + */ +export class GpuInfo { + videoDecodeAcceleratorSupportedProfile: VideoDecodeAcceleratorSupportedProfile[] = + []; +} + /** * @ignore */ -export const getGpuInfoInternal = () => { +export const getGpuInfoInternal = (callback: any): void => { + //@ts-ignore + if (process.type !== 'browser') { + logError('getGpuInfoInternal should be called in main process'); + return; + } const gpuPage = new BrowserWindow({ show: false, webPreferences: { offscreen: true }, }); gpuPage.loadURL('chrome://gpu'); - gpuPage.webContents.on('did-finish-load', () => { - let executeJavaScriptText = - `` + - `let videoAccelerationInfo = [];` + - `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + - `for (node of nodeList) {` + - ` videoAccelerationInfo.push({` + - ` title: node.shadowRoot.querySelector('#title')?.innerText,` + - ` value: node.shadowRoot.querySelector('#value')?.innerText,` + - ` })` + - `}` + - `JSON.stringify(videoAccelerationInfo)`; - gpuPage.webContents - .executeJavaScript(executeJavaScriptText) - .then((result: string) => { - if (!result) { - return; - } - let filterResult = JSON.parse(result).filter((item: any) => { - return item.title.indexOf('Decode') !== -1; - }); - console.log(filterResult); - }) - .catch((error: any) => {}); - }); + let executeJavaScriptText = + `` + + `let videoAccelerationInfo = [];` + + `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + + `for (node of nodeList) {` + + ` videoAccelerationInfo.push({` + + ` title: node.shadowRoot.querySelector('#title')?.innerText,` + + ` value: node.shadowRoot.querySelector('#value')?.innerText,` + + ` })` + + `}` + + `JSON.stringify(videoAccelerationInfo)`; + gpuPage.webContents + .executeJavaScript(executeJavaScriptText) + .then((result: string) => { + if (!result) { + logError( + 'Failed to get GPU info, chrome://gpu is not available in this environment.' + ); + } + let filterResult: VideoDecodeAcceleratorSupportedProfile[] = JSON.parse( + result + ).filter((item: any) => { + return item.title.indexOf('Decode') !== -1; + }); + typeof callback === 'function' && callback(filterResult); + }) + .catch((error: any) => { + logError( + 'Failed to get GPU info, please import agora-electron-sdk in main process', + error + ); + typeof callback === 'function' && callback(error); + }) + .finally(() => { + gpuPage.close(); + }); }; diff --git a/ts/Private/internal/ipc.ts b/ts/Private/internal/ipc.ts deleted file mode 100644 index 97c3ec2d2..000000000 --- a/ts/Private/internal/ipc.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { app, ipcMain, ipcRenderer } from 'electron'; - -import { logError } from 'types/Utils'; - -import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; - -import { logInfo } from '../../Utils'; - -export enum IPCMessageType { - AGORA_IPC_GET_GPU_INFO = 'AGORA_IPC_GET_GPU_INFO', -} - -if (process.type === 'browser') { - ipcMain.handle(IPCMessageType.AGORA_IPC_GET_GPU_INFO, async (event, arg) => { - getGpuInfoInternal(); - }); - - app.on('quit', () => { - // release resource - ipcMain.removeHandler(IPCMessageType.AGORA_IPC_GET_GPU_INFO); - }); -} else { - logInfo('Not in main process, skip ipc registration'); -} - -export async function ipcSend( - channel: IPCMessageType, - ...args: any[] -): Promise { - if (!Object.values(IPCMessageType).includes(channel)) { - logError('Invalid IPCMessageType'); - return; - } - if (process.type === 'renderer') { - return await ipcRenderer.invoke(channel, ...args); - } else { - logError('Not in renderer process, cannot send ipc message'); - } -} diff --git a/ts/Private/ipc/main.js b/ts/Private/ipc/main.js new file mode 100644 index 000000000..1fc83639f --- /dev/null +++ b/ts/Private/ipc/main.js @@ -0,0 +1,15 @@ +import { ipcMain } from 'electron'; + +import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; + +import { IPCMessageType } from '../../Types'; + +if (process.type === 'browser') { + ipcMain.handleOnce(IPCMessageType.AGORA_IPC_GET_GPU_INFO, () => { + return new Promise((resolve) => { + getGpuInfoInternal((result) => { + resolve(result); + }); + }); + }); +} diff --git a/ts/Private/ipc/renderer.ts b/ts/Private/ipc/renderer.ts new file mode 100644 index 000000000..a6b14a026 --- /dev/null +++ b/ts/Private/ipc/renderer.ts @@ -0,0 +1,21 @@ +//@ts-ignore +import { ipcRenderer } from 'electron'; + +import { IPCMessageType } from '../../Types'; +import { logError } from '../../Utils'; + +export async function ipcSend( + channel: IPCMessageType, + ...args: any[] +): Promise { + if (!Object.values(IPCMessageType).includes(channel)) { + logError('Invalid IPCMessageType'); + return; + } + //@ts-ignore + if (process.type === 'renderer') { + return await ipcRenderer.invoke(channel, ...args); + } else { + logError('Not in renderer process, cannot send ipc message'); + } +} diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index c7cd680a0..d4b70ebba 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,9 +1,17 @@ import semver from 'semver'; +import { GpuInfo } from '../Decoder/gpu-utils'; + import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { RendererCacheType, RendererContext, RendererType } from '../Types'; -import { isSupportWebGL, logDebug, logError } from '../Utils'; +import { ipcSend } from '../Private/ipc/renderer'; +import { + IPCMessageType, + RendererCacheType, + RendererContext, + RendererType, +} from '../Types'; +import { AgoraEnv, isSupportWebGL, logDebug, logError } from '../Utils'; import { IRenderer } from './IRenderer'; import { generateRendererCacheKey } from './IRendererCache'; @@ -45,7 +53,12 @@ export class RendererManager { /** * @ignore */ - rendererType: RendererType; + private rendererType: RendererType; + + /** + * @ignore + */ + gpuInfo: GpuInfo = new GpuInfo(); constructor() { this.renderingFps = 60; @@ -59,6 +72,9 @@ export class RendererManager { this.rendererType = isSupportWebGL() ? RendererType.WEBGL : RendererType.SOFTWARE; + if (AgoraEnv.enableWebCodecsDecoder) { + this.getGpuInfo(); + } } public setRenderingFps(fps: number) { @@ -85,6 +101,24 @@ export class RendererManager { return this._context.mirrorMode!; } + public getGpuInfo(): void { + //@ts-ignore + if (process.type === 'renderer') { + ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) + .then((result) => { + this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; + }) + .catch((error) => { + logError( + 'Failed to get GPU info, please check if you are already import agora-electron-sdk in the main process.', + error + ); + }); + } else { + logError('This function only works in renderer process'); + } + } + public release(): void { this.stopRendering(); this.clearRendererCache(); diff --git a/ts/Types.ts b/ts/Types.ts index 579f71ba0..b7bf82066 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -135,3 +135,10 @@ export interface AgoraElectronBridge { bufferCount?: number ) => Result; } + +/** + * @ignore + */ +export enum IPCMessageType { + AGORA_IPC_GET_GPU_INFO = 'AGORA_IPC_GET_GPU_INFO', +} diff --git a/ts/Utils.ts b/ts/Utils.ts index 912305d8d..c1962f585 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -1,5 +1,3 @@ -import { getGpuInfoInternal } from './Decoder/gpu-utils'; -import { IPCMessageType, ipcSend } from './Private/internal/ipc'; import { AgoraEnvType } from './Types'; /** @@ -170,17 +168,6 @@ export function getContextByCanvas( return null; } -export function getGpuInfo() { - if (process.type === 'browser') { - getGpuInfoInternal(); - } else if (process.type === 'renderer') { - // - } else { - ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO); - console.log('This function only works in main process or renderer process'); - } -} - const AgoraNode = require('../build/Release/agora_node_ext'); /** From 01a413713c5a1e98d8c73e2f70d90a81fe28e048 Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 10:58:48 +0800 Subject: [PATCH 028/101] chore: optimize --- ts/Private/ipc/main.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ts/Private/ipc/main.js b/ts/Private/ipc/main.js index 1fc83639f..5a6bf4453 100644 --- a/ts/Private/ipc/main.js +++ b/ts/Private/ipc/main.js @@ -1,15 +1,22 @@ -import { ipcMain } from 'electron'; +import { app, ipcMain } from 'electron'; import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; import { IPCMessageType } from '../../Types'; +import { logInfo } from '../../Utils'; if (process.type === 'browser') { - ipcMain.handleOnce(IPCMessageType.AGORA_IPC_GET_GPU_INFO, () => { + ipcMain.handle(IPCMessageType.AGORA_IPC_GET_GPU_INFO, () => { return new Promise((resolve) => { getGpuInfoInternal((result) => { resolve(result); }); }); }); + logInfo('main process AgoraIPCMain handler registered'); + + app.on('quit', () => { + ipcMain.removeHandler(IPCMessageType.AGORA_IPC_GET_GPU_INFO); + logInfo('main process AgoraIPCMain handler removed'); + }); } From 4838842c744eee713a1723714b9df1b2c7cf2b2a Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 14:56:09 +0800 Subject: [PATCH 029/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 8ccd990e0..3019b5912 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -41,7 +41,7 @@ export class WebCodecsRendererCache length: number, videoEncodedFrameInfo: EncodedVideoFrameInfo ) { - if (!this._decoder) return; + if (!this._decoder || this.context.uid !== uid) return; if (this._firstFrame) { let result = this._decoder.decoderConfigure(videoEncodedFrameInfo); if (!result) { From 594dfb10853c3f116fdda67d28dbcc3b412d27db Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 15:56:22 +0800 Subject: [PATCH 030/101] chore: optimize --- example/src/renderer/components/BaseComponent.tsx | 1 + .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/example/src/renderer/components/BaseComponent.tsx b/example/src/renderer/components/BaseComponent.tsx index 86fec26d3..fbebc3b89 100644 --- a/example/src/renderer/components/BaseComponent.tsx +++ b/example/src/renderer/components/BaseComponent.tsx @@ -1,4 +1,5 @@ import { + AgoraEnv, ErrorCodeType, IRtcEngine, IRtcEngineEventHandler, diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index e8fdca3b3..0e613402a 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -120,6 +120,7 @@ export default class VideoDecoder * Step 5: releaseRtcEngine */ protected releaseRtcEngine() { + AgoraEnv.enableWebCodecsDecoder = false; this.engine?.unregisterEventHandler(this); this.engine?.release(); } From 2498fd222f668b7923bf42e7898c3099e59c66a1 Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 17:25:36 +0800 Subject: [PATCH 031/101] chore: optimize --- .../src/renderer/components/BaseComponent.tsx | 1 - .../examples/basic/VideoDecoder/VideoDecoder.tsx | 16 ++++++++++++++-- ts/Decoder/index.ts | 2 +- ts/Private/internal/RtcEngineExInternal.ts | 1 + ts/Renderer/WebCodecsRendererCache.ts | 6 ++++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/example/src/renderer/components/BaseComponent.tsx b/example/src/renderer/components/BaseComponent.tsx index fbebc3b89..86fec26d3 100644 --- a/example/src/renderer/components/BaseComponent.tsx +++ b/example/src/renderer/components/BaseComponent.tsx @@ -1,5 +1,4 @@ import { - AgoraEnv, ErrorCodeType, IRtcEngine, IRtcEngineEventHandler, diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 0e613402a..552fd2193 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -120,7 +120,6 @@ export default class VideoDecoder * Step 5: releaseRtcEngine */ protected releaseRtcEngine() { - AgoraEnv.enableWebCodecsDecoder = false; this.engine?.unregisterEventHandler(this); this.engine?.release(); } @@ -144,6 +143,7 @@ export default class VideoDecoder decodeRemoteUserUidJoined: false, }); } + super.onUserOffline(connection, remoteUid, reason); } onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { @@ -161,6 +161,7 @@ export default class VideoDecoder decodeRemoteUserUidJoined: true, }); } + super.onUserJoined(connection, remoteUid, elapsed); } protected renderUsers(): ReactElement | undefined { @@ -169,6 +170,7 @@ export default class VideoDecoder decodeRemoteUserUidJoined, startPreview, joinChannelSuccess, + remoteUsers, } = this.state; return ( <> @@ -177,6 +179,16 @@ export default class VideoDecoder sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} + {!!startPreview || joinChannelSuccess + ? remoteUsers.map( + (item) => + item != decodeRemoteUserUid && + this.renderUser({ + uid: item, + sourceType: VideoSourceType.VideoSourceRemote, + }) + ) + : undefined} {joinChannelSuccess && decodeRemoteUserUid && decodeRemoteUserUidJoined ? this.renderUser({ uid: decodeRemoteUserUid, @@ -204,7 +216,7 @@ export default class VideoDecoder }); }} numberKeyboard={true} - placeholder={`remoteUserUid (defaults: ${ + placeholder={`VideoDecode remoteUserUid (defaults: ${ this.createState().decodeRemoteUserUid })`} /> diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index feab5f05e..5b59ce962 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -101,7 +101,7 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { - logInfo( + logDebug( 'FRAMETYPE', frameInfo.uid, frameInfo.frameType, diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index e190de43d..1e11ef48d 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -110,6 +110,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { AgoraEnv.AgoraElectronBridge.ReleaseRenderer(); AgoraEnv.AgoraRendererManager?.release(); AgoraEnv.AgoraRendererManager = undefined; + AgoraEnv.enableWebCodecsDecoder = false; this._audio_device_manager.release(); this._video_device_manager.release(); this._media_engine.release(); diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 3019b5912..8dfd43c0c 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -32,6 +32,12 @@ export class WebCodecsRendererCache onDecoderError(e: any) { logError('Decoder error:', e); //todo need add some fallback logic + if (this.context.uid) { + this._engine?.setRemoteVideoSubscriptionOptions(this.context.uid, { + type: VideoStreamType.VideoStreamHigh, + encodedFrameOnly: false, + }); + } this.release(); } From 954236be00d6cdd7ebdf624804583d5d5865e7b8 Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 17:30:49 +0800 Subject: [PATCH 032/101] chore: optimize --- .../src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 4825d307a..20603a1d5 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -204,7 +204,6 @@ export default class ScreenShare this.engine?.setParameters( JSON.stringify({ 'che.video.videoCodecIndex': videoCodec }) ); - console.log('che.video.videoCodecIndex', videoCodec); if ( targetSource.type === From 0fd0f815c2bdc453bc6c7f09ccec7a51755ac8ea Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 18:46:31 +0800 Subject: [PATCH 033/101] chore: optimize --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c92093ca2..87d2a5d86 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.1_DCG_Windows_Video_20240410_0427.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.2_DCG_Windows_Video_20240412_0628.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } From 47c17027a5c7ec0895e81c0df1ae6527a968a86c Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 12 Apr 2024 19:00:50 +0800 Subject: [PATCH 034/101] chore: optimize --- .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 552fd2193..81b42ab51 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -63,6 +63,7 @@ export default class VideoDecoder // will automatically register videoEncodedFrameObserver // videoEncodedFrameObserver will be released when engine.release AgoraEnv.enableWebCodecsDecoder = true; + this.engine.setLogLevel(16); this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, From a3ad7868f1f3636445788f8f4f687324b5ae7c4b Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 11:39:26 +0800 Subject: [PATCH 035/101] chore: optimize --- .../node_iris_event_handler.cpp | 46 ++++++++++++++++++- .../agora_node_ext/node_iris_event_handler.h | 3 ++ ts/Renderer/WebCodecsRendererCache.ts | 46 ++++++++++++------- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 3b45a45c0..83613133c 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -44,8 +44,14 @@ void NodeIrisEventHandler::addEvent(const std::string &eventName, napi_env &env, } void NodeIrisEventHandler::OnEvent(EventParam *param) { - fireEvent(_callback_key, param->event, param->data, param->buffer, - param->length, param->buffer_count); + const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; + + if (strcmp(event, param->event) == 0) { + onEncodedVideoFrameReceived(param->data, param->buffer[0], param->length); + } else { + fireEvent(_callback_key, param->event, param->data, param->buffer, + param->length, param->buffer_count); + } } void NodeIrisEventHandler::fireEvent(const char *callback_name, @@ -119,6 +125,42 @@ void NodeIrisEventHandler::fireEvent(const char *callback_name, }); } +void NodeIrisEventHandler::onEncodedVideoFrameReceived(const char *data, + void *buffer, + unsigned int *length) { + std::string eventData = ""; + if (data) { eventData = data; } + std::vector buffer_data(length[0]); + memcpy(buffer_data.data(), buffer, length[0]); + + unsigned int buffer_length = length[0]; + + node_async_call::async_call([this, eventData, buffer_data, buffer_length] { + auto it = _callbacks.find("call_back_with_encoded_video_frame"); + if (it != _callbacks.end()) { + size_t argc = 2; + napi_value args[2]; + napi_value result; + napi_status status; + status = napi_create_string_utf8(it->second->env, eventData.c_str(), + eventData.length(), &args[0]); + + napi_create_buffer_copy(it->second->env, buffer_length, + buffer_data.data(), nullptr, &args[1]); + + napi_value call_back_value; + status = napi_get_reference_value( + it->second->env, it->second->call_back_ref, &call_back_value); + + napi_value recv_value; + status = napi_get_undefined(it->second->env, &recv_value); + + status = napi_call_function(it->second->env, recv_value, call_back_value, + argc, args, &result); + } + }); +} + }// namespace electron }// namespace rtc }// namespace agora diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index c1e88b85f..b7d3bc0d9 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -31,6 +31,9 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void **buffer, unsigned int *length, unsigned int buffer_count); + void onEncodedVideoFrameReceived(const char *data, void *buffer, + unsigned int *length); + void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 8dfd43c0c..ba7d654ff 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,7 +1,6 @@ -import { createAgoraRtcEngine, logError, logInfo } from '../AgoraSdk'; +import { AgoraEnv, createAgoraRtcEngine, logError, logInfo } from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; -import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; -import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; +import { VideoStreamType } from '../Private/AgoraBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; @@ -12,7 +11,7 @@ import { WebCodecsRenderer } from './WebCodecsRenderer/index'; export class WebCodecsRendererCache extends IRendererCache - implements IVideoEncodedFrameObserver, IRtcEngineEventHandler + implements IRtcEngineEventHandler { private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; @@ -21,6 +20,18 @@ export class WebCodecsRendererCache constructor({ channelId, uid, sourceType }: RendererContext) { super({ channelId, uid, sourceType }); this._engine = createAgoraRtcEngine(); + + const AgoraRtcNg = AgoraEnv.AgoraElectronBridge; + AgoraRtcNg.OnEvent( + 'call_back_with_encoded_video_frame', + (...params: any) => { + try { + this.onEncodedVideoFrameReceived(...params); + } catch (e) { + console.error(e); + } + } + ); this._decoder = new WebCodecsDecoder( this.renderers as WebCodecsRenderer[], this.onDecoderError.bind(this) @@ -41,15 +52,18 @@ export class WebCodecsRendererCache this.release(); } - onEncodedVideoFrameReceived( - uid: number, - imageBuffer: Uint8Array, - length: number, - videoEncodedFrameInfo: EncodedVideoFrameInfo - ) { - if (!this._decoder || this.context.uid !== uid) return; + onEncodedVideoFrameReceived(...[data, buffer]: any) { + console.log('onEncodedVideoFrameReceived', data, buffer); + + let _data: any; + try { + _data = JSON.parse(data) ?? {}; + } catch (e) { + _data = {}; + } + if (!this._decoder || this.context.uid !== _data.uid) return; if (this._firstFrame) { - let result = this._decoder.decoderConfigure(videoEncodedFrameInfo); + let result = this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); if (!result) { logInfo('Failed to configure decoder, stop decoding frames.'); this.release(); @@ -58,8 +72,8 @@ export class WebCodecsRendererCache this._firstFrame = false; } this._decoder.decodeFrame( - imageBuffer, - videoEncodedFrameInfo, + buffer, + _data.videoEncodedFrameInfo, new Date().getTime() ); } @@ -78,11 +92,11 @@ export class WebCodecsRendererCache public draw() { this._engine?.registerEventHandler(this); - this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); + // this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } public release(): void { - this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); + // this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); this._decoder?.release(); this._decoder = null; From e74389a07f0ff56b34a7a80dde6876af2f5f5235 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 11:51:06 +0800 Subject: [PATCH 036/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index ba7d654ff..5c1773c79 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -53,15 +53,18 @@ export class WebCodecsRendererCache } onEncodedVideoFrameReceived(...[data, buffer]: any) { - console.log('onEncodedVideoFrameReceived', data, buffer); - let _data: any; try { _data = JSON.parse(data) ?? {}; } catch (e) { _data = {}; } - if (!this._decoder || this.context.uid !== _data.uid) return; + if ( + Object.keys(_data).length === 0 || + !this._decoder || + this.context.uid !== _data.uid + ) + return; if (this._firstFrame) { let result = this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); if (!result) { From fb0d41a83761d793d15896eb01ae1941de67c745 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 14:48:12 +0800 Subject: [PATCH 037/101] chore: optimize --- source_code/agora_node_ext/agora_electron_bridge.cpp | 7 +++++++ source_code/agora_node_ext/agora_electron_bridge.h | 6 ++++++ source_code/agora_node_ext/node_api_header.cpp | 9 +++++++++ source_code/agora_node_ext/node_api_header.h | 3 +++ ts/Private/internal/IrisApiEngine.ts | 2 +- ts/Types.ts | 2 +- 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index 82549f026..b239dbe10 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -475,6 +475,13 @@ napi_value AgoraElectronBridge::InitializeEnv(napi_env env, status = napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); + napi_value obj0 = args[0]; + AgoraEnv _agora_env; + std::string enableWebCodecsDecoder; + napi_obj_get_property(env, obj0, "enableWebCodecsDecoder", + _agora_env.enable_web_codecs_decoder); + agoraElectronBridge->SetAgoraEnv(_agora_env); + agoraElectronBridge->Init(); LOG_F(INFO, __FUNCTION__); napi_value retValue = nullptr; diff --git a/source_code/agora_node_ext/agora_electron_bridge.h b/source_code/agora_node_ext/agora_electron_bridge.h index 8e0064cbd..bd8672002 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.h +++ b/source_code/agora_node_ext/agora_electron_bridge.h @@ -18,6 +18,10 @@ namespace electron { class NodeIrisEventHandler; +struct AgoraEnv { + bool enable_web_codecs_decoder = false; +}; + class AgoraElectronBridge { public: explicit AgoraElectronBridge(); @@ -43,8 +47,10 @@ class AgoraElectronBridge { void OnApiError(const char *errorMessage); void Init(); void Release(); + void SetAgoraEnv(const AgoraEnv &agoraEnv) { _agoraEnv = agoraEnv; } private: + AgoraEnv _agoraEnv; static const char *_class_name; static napi_ref *_ref_construcotr_ptr; static const char *_ret_code_str; diff --git a/source_code/agora_node_ext/node_api_header.cpp b/source_code/agora_node_ext/node_api_header.cpp index cc000df82..94f6f0bba 100644 --- a/source_code/agora_node_ext/node_api_header.cpp +++ b/source_code/agora_node_ext/node_api_header.cpp @@ -127,6 +127,15 @@ napi_status napi_obj_get_property(napi_env &env, napi_value &object, return status; } +napi_status napi_obj_get_property(napi_env &env, napi_value &object, + const char *utf8name, bool &result) { + napi_status status; + napi_value retValue; + napi_get_named_property(env, object, utf8name, &retValue); + status = napi_get_value_bool(env, retValue, &result); + return status; +} + napi_status napi_obj_get_property(napi_env &env, napi_value &object, const char *utf8name, uint32_t &result) { napi_status status; diff --git a/source_code/agora_node_ext/node_api_header.h b/source_code/agora_node_ext/node_api_header.h index a8e8263d9..d447b54d9 100644 --- a/source_code/agora_node_ext/node_api_header.h +++ b/source_code/agora_node_ext/node_api_header.h @@ -68,6 +68,9 @@ napi_status napi_obj_set_property(napi_env &env, napi_value &object, napi_status napi_obj_get_property(napi_env &env, napi_value &object, const char *utf8name, int &result); +napi_status napi_obj_get_property(napi_env &env, napi_value &object, + const char *utf8name, bool &result); + napi_status napi_obj_get_property(napi_env &env, napi_value &object, const char *utf8name, uint32_t &result); diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 5b66ee449..6f561a6e7 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -459,7 +459,7 @@ export function callIrisApi(funcName: string, params: any): any { } else if (funcName.startsWith('RtcEngine_')) { switch (funcName) { case 'RtcEngine_initialize': - AgoraRtcNg.InitializeEnv(); + AgoraRtcNg.InitializeEnv(AgoraEnv); break; case 'RtcEngine_release': AgoraRtcNg.CallApi( diff --git a/ts/Types.ts b/ts/Types.ts index b7bf82066..15d63b14e 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -108,7 +108,7 @@ export interface AgoraElectronBridge { bufferCount?: number ): Result; - InitializeEnv(): void; + InitializeEnv(env: AgoraEnvType): void; ReleaseEnv(): void; From b3ef48154e6b076fc106db62321e3d16df15e76c Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 14:55:02 +0800 Subject: [PATCH 038/101] chore: optimize --- ts/Decoder/index.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 5b59ce962..dffcc8d20 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -101,14 +101,6 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { - logDebug( - 'FRAMETYPE', - frameInfo.uid, - frameInfo.frameType, - frameInfo, - imageBuffer, - imageBuffer.length - ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; From 49e6bee0dcd1497bc7ee7af337749ca5fd690cd5 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 15:18:16 +0800 Subject: [PATCH 039/101] chore: optimize --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 87d2a5d86..13460c89d 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.2_DCG_Windows_Video_20240412_0628.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-build.1_DCG_Windows_Video_20240329_1152.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } From fd065cb81e81a201f146830eda9fd0c3fcc8d812 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 15:31:47 +0800 Subject: [PATCH 040/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 5c1773c79..447e42b43 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -95,11 +95,11 @@ export class WebCodecsRendererCache public draw() { this._engine?.registerEventHandler(this); - // this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); + this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } public release(): void { - // this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); + this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); this._decoder?.release(); this._decoder = null; From 8f70fd0f55f9e30bca685704932699336104ea5c Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 17:32:57 +0800 Subject: [PATCH 041/101] chore: optimize --- example/src/renderer/components/BaseComponent.tsx | 1 - .../renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/src/renderer/components/BaseComponent.tsx b/example/src/renderer/components/BaseComponent.tsx index 86fec26d3..d8b52a8b7 100644 --- a/example/src/renderer/components/BaseComponent.tsx +++ b/example/src/renderer/components/BaseComponent.tsx @@ -210,7 +210,6 @@ export abstract class BaseComponent< protected renderUser(user: VideoCanvas): ReactElement | undefined { const { enableVideo } = this.state; - user.enableFps = true; return ( item != decodeRemoteUserUid && @@ -189,7 +189,7 @@ export default class VideoDecoder sourceType: VideoSourceType.VideoSourceRemote, }) ) - : undefined} + : undefined} */} {joinChannelSuccess && decodeRemoteUserUid && decodeRemoteUserUidJoined ? this.renderUser({ uid: decodeRemoteUserUid, @@ -197,6 +197,7 @@ export default class VideoDecoder // Use WebCodecs to decode video stream // only support one remote stream to decode at the same time for now useWebCodecsDecoder: true, + enableFps: true, renderMode: RenderModeType.RenderModeFit, }) : undefined} From a0e3f970bb061fff6a78230c076f9da8742f2139 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 17:59:31 +0800 Subject: [PATCH 042/101] chore: optimize --- .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 1 - ts/Private/internal/RtcEngineExInternal.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 6598d9f9d..ec3a9e4fd 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -171,7 +171,6 @@ export default class VideoDecoder decodeRemoteUserUidJoined, startPreview, joinChannelSuccess, - remoteUsers, } = this.state; return ( <> diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index 1e11ef48d..01b6930a7 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -110,7 +110,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { AgoraEnv.AgoraElectronBridge.ReleaseRenderer(); AgoraEnv.AgoraRendererManager?.release(); AgoraEnv.AgoraRendererManager = undefined; - AgoraEnv.enableWebCodecsDecoder = false; this._audio_device_manager.release(); this._video_device_manager.release(); this._media_engine.release(); @@ -129,6 +128,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { MediaPlayerInternal._audio_spectrum_observers.clear(); MediaRecorderInternal._observers.clear(); this.removeAllListeners(); + AgoraEnv.enableWebCodecsDecoder = false; super.release(sync); } From a0970f4e9d05c1383c80d2e53a1d02534f99c732 Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 15 Apr 2024 18:03:39 +0800 Subject: [PATCH 043/101] chore: optimize --- .../examples/advanced/ScreenShare/ScreenShare.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 20603a1d5..7eaaf3509 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -121,6 +121,19 @@ export default class ScreenShare channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, }); this.engine.registerEventHandler(this); + this.engine.setScreenCaptureScenario(2); + this.engine.setParameters( + JSON.stringify({ 'engine.video.enable_hw_encoder': true }) + ); + this.engine.setParameters( + JSON.stringify({ 'che.video.show_wgc_border': 1 }) + ); + this.engine.setParameters( + JSON.stringify({ 'rtc.win_allow_directx': false }) + ); + this.engine.setParameters( + JSON.stringify({ 'che.video.enable_promote_gpu_priority': true }) + ); // Need granted the microphone and camera permission await askMediaAccess(['microphone', 'camera', 'screen']); From c44361bc0333e39d555621b699306f249f861908 Mon Sep 17 00:00:00 2001 From: guoxianzhe Date: Mon, 15 Apr 2024 18:31:52 +0800 Subject: [PATCH 044/101] chore: optimize --- .../src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index 7eaaf3509..da81838c3 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -10,6 +10,7 @@ import { RtcStats, ScreenCaptureSourceInfo, ScreenCaptureSourceType, + ScreenScenarioType, UserOfflineReasonType, VideoSourceType, createAgoraRtcEngine, @@ -121,7 +122,7 @@ export default class ScreenShare channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, }); this.engine.registerEventHandler(this); - this.engine.setScreenCaptureScenario(2); + this.engine.setScreenCaptureScenario(ScreenScenarioType.ScreenScenarioGaming); this.engine.setParameters( JSON.stringify({ 'engine.video.enable_hw_encoder': true }) ); diff --git a/package.json b/package.json index 13460c89d..dce9ebd08 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-build.1_DCG_Windows_Video_20240329_1152.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Windows_Video_20240407_0427.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } From f32881c2662acc981e9754959ee0fc265137304d Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 16 Apr 2024 13:57:11 +0800 Subject: [PATCH 045/101] chore: optimize --- ts/Renderer/RendererManager.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index d4b70ebba..5b62da638 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -102,6 +102,11 @@ export class RendererManager { } public getGpuInfo(): void { + //getGpuInfo and videoDecoder is not supported in electron version < 20.0.0 + //@ts-ignore + if (semver.lt(process.versions.electron, '20.0.0')) { + return; + } //@ts-ignore if (process.type === 'renderer') { ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) @@ -124,6 +129,11 @@ export class RendererManager { this.clearRendererCache(); } + private checkIfSupportWebCodecsDecoder(): boolean { + return (AgoraEnv.enableWebCodecsDecoder && + this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; + } + private presetRendererContext(context: RendererContext): RendererContext { //this is for preset default value context.renderMode = context.renderMode || this.defaultRenderMode; @@ -131,9 +141,7 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; - //videoDecoder is not supported in electron version < 20.0.0 - //@ts-ignore - if (semver.lt(process.versions.electron, '20.0.0')) { + if (this.checkIfSupportWebCodecsDecoder()) { context.useWebCodecsDecoder = false; logError( 'WebCodecsDecoder is not supported in electron version < 20.0.0, please upgrade electron to 20.0.0 or later.' From bab682d030a0a44cb227ea07c9ed170eeab5eab2 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 11:09:26 +0800 Subject: [PATCH 046/101] chore: optimize --- .../basic/VideoDecoder/VideoDecoder.tsx | 84 +++---------------- .../agora_node_ext/agora_electron_bridge.cpp | 25 ++++++ .../agora_node_ext/agora_electron_bridge.h | 1 + .../node_iris_event_handler.cpp | 10 +++ .../agora_node_ext/node_iris_event_handler.h | 2 + ts/Private/internal/MediaEngineInternal.ts | 1 + ts/Private/internal/RtcEngineExInternal.ts | 3 + ts/Renderer/IRendererCache.ts | 1 - ts/Renderer/RendererCache.ts | 1 - ts/Renderer/RendererManager.ts | 6 +- ts/Renderer/WebCodecsRendererCache.ts | 33 ++++---- ts/Types.ts | 2 + 12 files changed, 77 insertions(+), 92 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index ec3a9e4fd..454f1487b 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -5,9 +5,6 @@ import { IRtcEngineEventHandler, IRtcEngineEx, LogFilterType, - RenderModeType, - RtcConnection, - UserOfflineReasonType, VideoSourceType, createAgoraRtcEngine, } from 'agora-electron-sdk'; @@ -24,7 +21,6 @@ import { askMediaAccess } from '../../../utils/permissions'; interface State extends BaseAudioComponentState { fps: number; decodeRemoteUserUid: number; - decodeRemoteUserUidJoined: boolean; } export default class VideoDecoder @@ -43,7 +39,6 @@ export default class VideoDecoder uid: Config.uid, joinChannelSuccess: false, decodeRemoteUserUid: 7, - decodeRemoteUserUidJoined: false, remoteUsers: [], startPreview: false, }; @@ -125,53 +120,9 @@ export default class VideoDecoder this.engine?.release(); } - onUserOffline( - connection: RtcConnection, - remoteUid: number, - reason: UserOfflineReasonType - ) { - this.info( - 'onUserOffline', - 'connection', - connection, - 'remoteUid', - remoteUid, - 'reason', - reason - ); - if (remoteUid === this.state.decodeRemoteUserUid) { - this.setState({ - decodeRemoteUserUidJoined: false, - }); - } - super.onUserOffline(connection, remoteUid, reason); - } - - onUserJoined(connection: RtcConnection, remoteUid: number, elapsed: number) { - this.info( - 'onUserJoined', - 'connection', - connection, - 'remoteUid', - remoteUid, - 'elapsed', - elapsed - ); - if (remoteUid === this.state.decodeRemoteUserUid) { - this.setState({ - decodeRemoteUserUidJoined: true, - }); - } - super.onUserJoined(connection, remoteUid, elapsed); - } - protected renderUsers(): ReactElement | undefined { - let { - decodeRemoteUserUid, - decodeRemoteUserUidJoined, - startPreview, - joinChannelSuccess, - } = this.state; + let { decodeRemoteUserUid, startPreview, remoteUsers, joinChannelSuccess } = + this.state; return ( <> {!!startPreview || joinChannelSuccess @@ -179,26 +130,17 @@ export default class VideoDecoder sourceType: VideoSourceType.VideoSourceCamera, }) : undefined} - {/* {!!startPreview || joinChannelSuccess - ? remoteUsers.map( - (item) => - item != decodeRemoteUserUid && - this.renderUser({ - uid: item, - sourceType: VideoSourceType.VideoSourceRemote, - }) + {!!startPreview || joinChannelSuccess + ? remoteUsers.map((item) => + this.renderUser({ + uid: item, + // Use WebCodecs to decode video stream + // only support one remote stream to decode at the same time for now + useWebCodecsDecoder: item === decodeRemoteUserUid, + enableFps: item === decodeRemoteUserUid, + sourceType: VideoSourceType.VideoSourceRemote, + }) ) - : undefined} */} - {joinChannelSuccess && decodeRemoteUserUid && decodeRemoteUserUidJoined - ? this.renderUser({ - uid: decodeRemoteUserUid, - sourceType: VideoSourceType.VideoSourceRemote, - // Use WebCodecs to decode video stream - // only support one remote stream to decode at the same time for now - useWebCodecsDecoder: true, - enableFps: true, - renderMode: RenderModeType.RenderModeFit, - }) : undefined} ); @@ -217,7 +159,7 @@ export default class VideoDecoder }); }} numberKeyboard={true} - placeholder={`VideoDecode remoteUserUid (defaults: ${ + placeholder={`useWebCodecsDecoder Uid (defaults: ${ this.createState().decodeRemoteUserUid })`} /> diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index b239dbe10..20f04579b 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -40,6 +40,7 @@ napi_value AgoraElectronBridge::Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_METHOD("CallApi", CallApi), DECLARE_NAPI_METHOD("OnEvent", OnEvent), + DECLARE_NAPI_METHOD("UnEvent", UnEvent), DECLARE_NAPI_METHOD("GetBuffer", GetBuffer), DECLARE_NAPI_METHOD("EnableVideoFrameCache", EnableVideoFrameCache), DECLARE_NAPI_METHOD("DisableVideoFrameCache", DisableVideoFrameCache), @@ -250,6 +251,30 @@ napi_value AgoraElectronBridge::OnEvent(napi_env env, napi_callback_info info) { RETURE_NAPI_OBJ(); } +napi_value AgoraElectronBridge::UnEvent(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 2; + napi_value args[2]; + napi_value jsthis; + int ret = ERR_FAILED; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + AgoraElectronBridge *agoraElectronBridge; + status = + napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); + assert(status == napi_ok); + + std::string eventName = ""; + status = napi_get_value_utf8string(env, args[0], eventName); + assert(status == napi_ok); + + agoraElectronBridge->_iris_rtc_event_handler->removeEvent(eventName); + ret = ERR_OK; + + RETURE_NAPI_OBJ(); +} + napi_value AgoraElectronBridge::SetAddonLogFile(napi_env env, napi_callback_info info) { napi_status status; diff --git a/source_code/agora_node_ext/agora_electron_bridge.h b/source_code/agora_node_ext/agora_electron_bridge.h index bd8672002..dcdafcfee 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.h +++ b/source_code/agora_node_ext/agora_electron_bridge.h @@ -34,6 +34,7 @@ class AgoraElectronBridge { static napi_value CallApi(napi_env env, napi_callback_info info); static napi_value GetBuffer(napi_env env, napi_callback_info info); static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value UnEvent(napi_env env, napi_callback_info info); static napi_value EnableVideoFrameCache(napi_env env, napi_callback_info info); static napi_value DisableVideoFrameCache(napi_env env, diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 83613133c..e4ed55224 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -6,6 +6,7 @@ */ #include "node_iris_event_handler.h" #include "agora_electron_bridge.h" +#include #include #include @@ -43,6 +44,15 @@ void NodeIrisEventHandler::addEvent(const std::string &eventName, napi_env &env, env, call_bcak, 1, &(_callbacks[eventName]->call_back_ref)); } +void NodeIrisEventHandler::removeEvent(const std::string &eventName) { + auto it = _callbacks.find(eventName); + if (it != _callbacks.end()) { + napi_delete_reference(it->second->env, it->second->call_back_ref); + delete it->second; + _callbacks.erase(it); + } +} + void NodeIrisEventHandler::OnEvent(EventParam *param) { const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index b7d3bc0d9..863674ebd 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -37,6 +37,8 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); + void removeEvent(const std::string &eventName); + private: std::unordered_map _callbacks; const char *_callback_key = "call_back_with_buffer"; diff --git a/ts/Private/internal/MediaEngineInternal.ts b/ts/Private/internal/MediaEngineInternal.ts index 5bb932fc9..f436b70e3 100644 --- a/ts/Private/internal/MediaEngineInternal.ts +++ b/ts/Private/internal/MediaEngineInternal.ts @@ -95,6 +95,7 @@ export class MediaEngineInternal extends IMediaEngineImpl { MediaEngineInternal._video_encoded_frame_observers = []; if (AgoraEnv.enableWebCodecsDecoder) { this.unregisterVideoEncodedFrameObserver({}); + // this.unregisterVideoFrameObserver({}); } this.removeAllListeners(); super.release(); diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index 01b6930a7..5daf5d13c 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -94,6 +94,9 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { }); if (AgoraEnv.enableWebCodecsDecoder) { this._media_engine.registerVideoEncodedFrameObserver({}); + //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error + //when the webCodecsDecoder is error, the video stream will be decoded by native + // this._media_engine.registerVideoFrameObserver({}); } if (AgoraEnv.webEnvReady) { // @ts-ignore diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index c950b2b9d..9dc21670b 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -13,7 +13,6 @@ export function generateRendererCacheKey({ export abstract class IRendererCache { renderers: IRenderer[]; context: RendererCacheContext; - selfDecode: boolean = false; constructor({ channelId, uid, sourceType }: RendererContext) { this.renderers = []; diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index 8d6854564..3c482ac31 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -23,7 +23,6 @@ export class RendererCache extends IRendererCache { rotation: 0, }; this._enabled = false; - this.selfDecode = false; } /** diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 5b62da638..a194a8230 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -102,9 +102,9 @@ export class RendererManager { } public getGpuInfo(): void { - //getGpuInfo and videoDecoder is not supported in electron version < 20.0.0 + //getGpuInfo and videoDecoder is not supported in electron version >= 20.0.0 //@ts-ignore - if (semver.lt(process.versions.electron, '20.0.0')) { + if (semver.gte(process.versions.electron, '20.0.0')) { return; } //@ts-ignore @@ -333,7 +333,7 @@ export class RendererManager { // Render all renderers that do not use WebCodecs for (const rendererCache of this._rendererCaches.filter( - (cache) => !cache.selfDecode + (cache) => cache instanceof RendererCache )) { this.doRendering(rendererCache); } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 447e42b43..df293ea34 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -16,27 +16,15 @@ export class WebCodecsRendererCache private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; private _firstFrame = true; + private _agoraRtcNg = AgoraEnv.AgoraElectronBridge; constructor({ channelId, uid, sourceType }: RendererContext) { super({ channelId, uid, sourceType }); this._engine = createAgoraRtcEngine(); - - const AgoraRtcNg = AgoraEnv.AgoraElectronBridge; - AgoraRtcNg.OnEvent( - 'call_back_with_encoded_video_frame', - (...params: any) => { - try { - this.onEncodedVideoFrameReceived(...params); - } catch (e) { - console.error(e); - } - } - ); this._decoder = new WebCodecsDecoder( this.renderers as WebCodecsRenderer[], this.onDecoderError.bind(this) ); - this.selfDecode = true; this.draw(); } @@ -88,19 +76,32 @@ export class WebCodecsRendererCache ) { this._engine?.setRemoteVideoSubscriptionOptions(remoteUid, { type: VideoStreamType.VideoStreamHigh, - encodedFrameOnly: true, + encodedFrameOnly: false, }); } } public draw() { + this._agoraRtcNg.OnEvent( + 'call_back_with_encoded_video_frame', + (...params: any) => { + try { + this.onEncodedVideoFrameReceived(...params); + } catch (e) { + console.error(e); + } + } + ); this._engine?.registerEventHandler(this); - this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); + // this._engine?.getMediaEngine().registerVideoEncodedFrameObserver({}); + // this._engine?.getMediaEngine().registerVideoFrameObserver({}); } public release(): void { - this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._engine?.unregisterEventHandler(this); + // this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver({}); + // this._engine?.getMediaEngine().unregisterVideoFrameObserver({}); + this._agoraRtcNg.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; super.release(); diff --git a/ts/Types.ts b/ts/Types.ts index 15d63b14e..befd24201 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -101,6 +101,8 @@ export interface AgoraElectronBridge { ) => void ): void; + UnEvent(callbackName: string): void; + CallApi( funcName: string, params: any, From a6ebf696fed090dae665016d5a5619fd7f057d6c Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 14:52:42 +0800 Subject: [PATCH 047/101] chore: optimize --- .../agora_node_ext/agora_electron_bridge.cpp | 5 -- ts/Private/internal/IrisApiEngine.ts | 2 +- ts/Private/internal/MediaEngineInternal.ts | 2 +- ts/Private/internal/RtcEngineExInternal.ts | 21 ++++--- ts/Renderer/CapabilityManager.ts | 56 +++++++++++++++++++ ts/Renderer/RendererManager.ts | 50 +---------------- ts/Types.ts | 9 ++- 7 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 ts/Renderer/CapabilityManager.ts diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index 20f04579b..b06b508b4 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -501,11 +501,6 @@ napi_value AgoraElectronBridge::InitializeEnv(napi_env env, napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); napi_value obj0 = args[0]; - AgoraEnv _agora_env; - std::string enableWebCodecsDecoder; - napi_obj_get_property(env, obj0, "enableWebCodecsDecoder", - _agora_env.enable_web_codecs_decoder); - agoraElectronBridge->SetAgoraEnv(_agora_env); agoraElectronBridge->Init(); LOG_F(INFO, __FUNCTION__); diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 6f561a6e7..5b66ee449 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -459,7 +459,7 @@ export function callIrisApi(funcName: string, params: any): any { } else if (funcName.startsWith('RtcEngine_')) { switch (funcName) { case 'RtcEngine_initialize': - AgoraRtcNg.InitializeEnv(AgoraEnv); + AgoraRtcNg.InitializeEnv(); break; case 'RtcEngine_release': AgoraRtcNg.CallApi( diff --git a/ts/Private/internal/MediaEngineInternal.ts b/ts/Private/internal/MediaEngineInternal.ts index f436b70e3..d0164a5e0 100644 --- a/ts/Private/internal/MediaEngineInternal.ts +++ b/ts/Private/internal/MediaEngineInternal.ts @@ -93,7 +93,7 @@ export class MediaEngineInternal extends IMediaEngineImpl { MediaEngineInternal._audio_frame_observers = []; MediaEngineInternal._video_frame_observers = []; MediaEngineInternal._video_encoded_frame_observers = []; - if (AgoraEnv.enableWebCodecsDecoder) { + if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { this.unregisterVideoEncodedFrameObserver({}); // this.unregisterVideoFrameObserver({}); } diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index 5daf5d13c..fe5f40321 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -92,12 +92,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { callIrisApi.call(this, 'RtcEngine_setAppType', { appType: 3, }); - if (AgoraEnv.enableWebCodecsDecoder) { - this._media_engine.registerVideoEncodedFrameObserver({}); - //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error - //when the webCodecsDecoder is error, the video stream will be decoded by native - // this._media_engine.registerVideoFrameObserver({}); - } if (AgoraEnv.webEnvReady) { // @ts-ignore window.AgoraEnv = AgoraEnv; @@ -105,6 +99,18 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { const { RendererManager } = require('../../Renderer/RendererManager'); AgoraEnv.AgoraRendererManager = new RendererManager(); } + if (AgoraEnv.CapabilityManager === undefined) { + const { + CapabilityManager, + } = require('../../Renderer/CapabilityManager'); + AgoraEnv.CapabilityManager = new CapabilityManager(); + } + } + if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { + this._media_engine.registerVideoEncodedFrameObserver({}); + //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error + //when the webCodecsDecoder is error, the video stream will be decoded by native + // this._media_engine.registerVideoFrameObserver({}); } return ret; } @@ -131,7 +137,8 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { MediaPlayerInternal._audio_spectrum_observers.clear(); MediaRecorderInternal._observers.clear(); this.removeAllListeners(); - AgoraEnv.enableWebCodecsDecoder = false; + AgoraEnv.CapabilityManager?.release(); + AgoraEnv.CapabilityManager = undefined; super.release(sync); } diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts new file mode 100644 index 000000000..310fa5876 --- /dev/null +++ b/ts/Renderer/CapabilityManager.ts @@ -0,0 +1,56 @@ +import semver from 'semver'; + +import { ipcSend } from 'ts/Private/ipc/renderer'; + +import { GpuInfo } from '../Decoder/gpu-utils'; +import { IPCMessageType } from '../Types'; +import { AgoraEnv, logError } from '../Utils'; + +/** + * @ignore + */ +export class CapabilityManager { + gpuInfo: GpuInfo = new GpuInfo(); + isSupportH265: boolean = false; + isSupportH264: boolean = false; + enableWebCodecsDecoder: boolean = AgoraEnv.enableWebCodecsDecoder; + + constructor() { + if (AgoraEnv.enableWebCodecsDecoder) { + this.getGpuInfo(); + this.checkIfSupportWebCodecsDecoder(); + } + } + + public getGpuInfo(): void { + //getGpuInfo and videoDecoder is not supported in electron version >= 20.0.0 + //@ts-ignore + if (semver.gte(process.versions.electron, '20.0.0')) { + return; + } + //@ts-ignore + if (process.type === 'renderer') { + ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) + .then((result) => { + this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; + }) + .catch((error) => { + logError( + 'Failed to get GPU info, please check if you are already import agora-electron-sdk in the main process.', + error + ); + }); + } else { + logError('This function only works in renderer process'); + } + } + + private checkIfSupportWebCodecsDecoder() { + this.enableWebCodecsDecoder = (AgoraEnv.enableWebCodecsDecoder && + this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; + } + + release(): void { + AgoraEnv.enableWebCodecsDecoder = false; + } +} diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index a194a8230..3c3ffe6c3 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,16 +1,6 @@ -import semver from 'semver'; - -import { GpuInfo } from '../Decoder/gpu-utils'; - import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { ipcSend } from '../Private/ipc/renderer'; -import { - IPCMessageType, - RendererCacheType, - RendererContext, - RendererType, -} from '../Types'; +import { RendererCacheType, RendererContext, RendererType } from '../Types'; import { AgoraEnv, isSupportWebGL, logDebug, logError } from '../Utils'; import { IRenderer } from './IRenderer'; @@ -55,11 +45,6 @@ export class RendererManager { */ private rendererType: RendererType; - /** - * @ignore - */ - gpuInfo: GpuInfo = new GpuInfo(); - constructor() { this.renderingFps = 60; this._currentFrameCount = 0; @@ -72,9 +57,6 @@ export class RendererManager { this.rendererType = isSupportWebGL() ? RendererType.WEBGL : RendererType.SOFTWARE; - if (AgoraEnv.enableWebCodecsDecoder) { - this.getGpuInfo(); - } } public setRenderingFps(fps: number) { @@ -101,39 +83,11 @@ export class RendererManager { return this._context.mirrorMode!; } - public getGpuInfo(): void { - //getGpuInfo and videoDecoder is not supported in electron version >= 20.0.0 - //@ts-ignore - if (semver.gte(process.versions.electron, '20.0.0')) { - return; - } - //@ts-ignore - if (process.type === 'renderer') { - ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) - .then((result) => { - this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; - }) - .catch((error) => { - logError( - 'Failed to get GPU info, please check if you are already import agora-electron-sdk in the main process.', - error - ); - }); - } else { - logError('This function only works in renderer process'); - } - } - public release(): void { this.stopRendering(); this.clearRendererCache(); } - private checkIfSupportWebCodecsDecoder(): boolean { - return (AgoraEnv.enableWebCodecsDecoder && - this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; - } - private presetRendererContext(context: RendererContext): RendererContext { //this is for preset default value context.renderMode = context.renderMode || this.defaultRenderMode; @@ -141,7 +95,7 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; - if (this.checkIfSupportWebCodecsDecoder()) { + if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { context.useWebCodecsDecoder = false; logError( 'WebCodecsDecoder is not supported in electron version < 20.0.0, please upgrade electron to 20.0.0 or later.' diff --git a/ts/Types.ts b/ts/Types.ts index befd24201..e6354bd9f 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,6 +1,7 @@ import { VideoCanvas } from './Private/AgoraBase'; import { VideoFrame } from './Private/AgoraMediaBase'; import { RtcConnection } from './Private/IAgoraRtcEngineEx'; +import { CapabilityManager } from './Renderer/CapabilityManager'; import { RendererCache } from './Renderer/RendererCache'; import { RendererManager } from './Renderer/RendererManager'; import { WebCodecsRendererCache } from './Renderer/WebCodecsRendererCache'; @@ -24,7 +25,7 @@ export interface AgoraEnvOptions { /** * @ignore */ - enableWebCodecsDecoder?: boolean; + enableWebCodecsDecoder: boolean; } /** @@ -39,6 +40,10 @@ export interface AgoraEnvType extends AgoraEnvOptions { * @ignore */ AgoraRendererManager?: RendererManager; + /** + * @ignore + */ + CapabilityManager?: CapabilityManager; } /** @@ -110,7 +115,7 @@ export interface AgoraElectronBridge { bufferCount?: number ): Result; - InitializeEnv(env: AgoraEnvType): void; + InitializeEnv(): void; ReleaseEnv(): void; From f82b832506778d166cd1c3a6d537221a3ee5c801 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 15:11:34 +0800 Subject: [PATCH 048/101] chore: optimize --- example/src/main/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/src/main/index.js b/example/src/main/index.js index 7531d86f7..174b9b4a4 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -1,7 +1,7 @@ import path from 'path'; import { format as formatUrl } from 'url'; -require('agora-electron-sdk/js/Private/ipc/main'); +import 'agora-electron-sdk/js/Private/ipc/main'; import { BrowserWindow, app, ipcMain, systemPreferences } from 'electron'; const isDevelopment = process.env.NODE_ENV !== 'production'; From 7229d088137ae67c42490e7636353d426b17cba2 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 15:20:38 +0800 Subject: [PATCH 049/101] chore: optimize --- ts/Renderer/CapabilityManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index 310fa5876..08d2dd960 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -1,8 +1,8 @@ import semver from 'semver'; -import { ipcSend } from 'ts/Private/ipc/renderer'; - import { GpuInfo } from '../Decoder/gpu-utils'; +import { ipcSend } from '../Private/ipc/renderer'; + import { IPCMessageType } from '../Types'; import { AgoraEnv, logError } from '../Utils'; From 1149331b643144c08121cc5e2abad78cf5ff2c01 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 15:53:29 +0800 Subject: [PATCH 050/101] chore: optimize --- ts/Renderer/CapabilityManager.ts | 12 ++++-------- ts/Renderer/RendererManager.ts | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index 08d2dd960..fafe53837 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -18,14 +18,13 @@ export class CapabilityManager { constructor() { if (AgoraEnv.enableWebCodecsDecoder) { this.getGpuInfo(); - this.checkIfSupportWebCodecsDecoder(); } } public getGpuInfo(): void { - //getGpuInfo and videoDecoder is not supported in electron version >= 20.0.0 + //getGpuInfo and videoDecoder is not supported in electron version < 20.0.0 //@ts-ignore - if (semver.gte(process.versions.electron, '20.0.0')) { + if (semver.lt(process.versions.electron, '20.0.0')) { return; } //@ts-ignore @@ -33,6 +32,8 @@ export class CapabilityManager { ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) .then((result) => { this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; + this.enableWebCodecsDecoder = (AgoraEnv.enableWebCodecsDecoder && + this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; }) .catch((error) => { logError( @@ -45,11 +46,6 @@ export class CapabilityManager { } } - private checkIfSupportWebCodecsDecoder() { - this.enableWebCodecsDecoder = (AgoraEnv.enableWebCodecsDecoder && - this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; - } - release(): void { AgoraEnv.enableWebCodecsDecoder = false; } diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 3c3ffe6c3..7a7727b68 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -95,7 +95,7 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; - if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { + if (!AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { context.useWebCodecsDecoder = false; logError( 'WebCodecsDecoder is not supported in electron version < 20.0.0, please upgrade electron to 20.0.0 or later.' From b1525a2b9f525a69d53180cd3038ee5a3f39b061 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 17:40:03 +0800 Subject: [PATCH 051/101] chore: optimize --- ts/Decoder/index.ts | 18 ++++-------------- ts/Renderer/CapabilityManager.ts | 20 ++++++++++++++++---- ts/Types.ts | 26 +++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index dffcc8d20..5ad47edaf 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -1,25 +1,14 @@ -import { - EncodedVideoFrameInfo, - VideoCodecType, - VideoFrameType, -} from '../Private/AgoraBase'; +import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; import { WebCodecsRenderer } from '../Renderer/WebCodecsRenderer/index'; import { RendererType } from '../Types'; -import { logDebug, logInfo } from '../Utils'; +import { AgoraEnv, logDebug, logInfo } from '../Utils'; const frameTypeMapping = { [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', }; -export const frameCodecMapping = { - [VideoCodecType.VideoCodecH265]: 'hvc1.1.6.L5.90', - [VideoCodecType.VideoCodecH264]: 'avc1.64e01f', - [VideoCodecType.VideoCodecVp8]: 'vp8', - [VideoCodecType.VideoCodecVp9]: 'vp9', -}; - export class WebCodecsDecoder { private _decoder: VideoDecoder; private renderers: WebCodecsRenderer[] = []; @@ -69,7 +58,8 @@ export class WebCodecsDecoder { decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { // @ts-ignore - let codec = frameCodecMapping[frameInfo.codecType]; + let codec = + AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!]; if (!codec) { logInfo('codec is not in frameCodecMapping, stop decode frame'); return false; diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index fafe53837..32b2c283c 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -1,9 +1,13 @@ import semver from 'semver'; -import { GpuInfo } from '../Decoder/gpu-utils'; +import { + GpuInfo, + VideoDecodeAcceleratorSupportedProfile, +} from '../Decoder/gpu-utils'; +import { VideoCodecType } from '../Private/AgoraBase'; import { ipcSend } from '../Private/ipc/renderer'; -import { IPCMessageType } from '../Types'; +import { IPCMessageType, codecMapping } from '../Types'; import { AgoraEnv, logError } from '../Utils'; /** @@ -11,8 +15,7 @@ import { AgoraEnv, logError } from '../Utils'; */ export class CapabilityManager { gpuInfo: GpuInfo = new GpuInfo(); - isSupportH265: boolean = false; - isSupportH264: boolean = false; + frameCodecMapping: { [key in VideoCodecType]?: string } = {}; enableWebCodecsDecoder: boolean = AgoraEnv.enableWebCodecsDecoder; constructor() { @@ -34,6 +37,15 @@ export class CapabilityManager { this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; this.enableWebCodecsDecoder = (AgoraEnv.enableWebCodecsDecoder && this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; + + result.forEach((profile: VideoDecodeAcceleratorSupportedProfile) => { + const match = codecMapping.find((item) => + profile.title.includes(item.profile) + ); + if (match) { + this.frameCodecMapping[match.type] = match.codec; + } + }); }) .catch((error) => { logError( diff --git a/ts/Types.ts b/ts/Types.ts index e6354bd9f..6eac9765d 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -1,4 +1,4 @@ -import { VideoCanvas } from './Private/AgoraBase'; +import { VideoCanvas, VideoCodecType } from './Private/AgoraBase'; import { VideoFrame } from './Private/AgoraMediaBase'; import { RtcConnection } from './Private/IAgoraRtcEngineEx'; import { CapabilityManager } from './Renderer/CapabilityManager'; @@ -149,3 +149,27 @@ export interface AgoraElectronBridge { export enum IPCMessageType { AGORA_IPC_GET_GPU_INFO = 'AGORA_IPC_GET_GPU_INFO', } + +interface CodecMappingItem { + codec: string; + type: VideoCodecType; + profile: string; +} + +/** + * @ignore + */ +export const codecMapping: CodecMappingItem[] = [ + { + codec: 'avc1.64e01f', + type: VideoCodecType.VideoCodecH264, + profile: 'h264', + }, + { + codec: 'hvc1.1.6.L5.90', + type: VideoCodecType.VideoCodecH265, + profile: 'hevc', + }, + { codec: 'vp8', type: VideoCodecType.VideoCodecVp8, profile: 'vp8' }, + { codec: 'vp9', type: VideoCodecType.VideoCodecVp9, profile: 'vp9' }, +]; From 39f3c936f43c71922027267229e89ee2b5e2dada Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 19:51:27 +0800 Subject: [PATCH 052/101] chore: optimize --- ts/Decoder/index.ts | 2 -- ts/Renderer/CapabilityManager.ts | 8 ++++++++ ts/Renderer/WebCodecsRendererCache.ts | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 5ad47edaf..58a3ba1dd 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -14,7 +14,6 @@ export class WebCodecsDecoder { private renderers: WebCodecsRenderer[] = []; private pendingFrame: VideoFrame | null = null; - private _frame_ts: number[] = []; private _base_ts = 0; private _base_ts_ntp = 1; private _last_ts_ntp = 1; @@ -104,7 +103,6 @@ export class WebCodecsDecoder { logDebug('frameType is not in frameTypeMapping, skip decode frame'); return; } - this._frame_ts.push(ts); if (this._base_ts !== 0) { if (ts > this._base_ts) { this._last_ts_ntp = diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index 32b2c283c..b54e16acb 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -58,6 +58,14 @@ export class CapabilityManager { } } + public isSupportedH264(): boolean { + return this.frameCodecMapping[VideoCodecType.VideoCodecH264] !== undefined; + } + + public isSupportedH265(): boolean { + return this.frameCodecMapping[VideoCodecType.VideoCodecH265] !== undefined; + } + release(): void { AgoraEnv.enableWebCodecsDecoder = false; } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index df293ea34..bf32ed283 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -76,7 +76,7 @@ export class WebCodecsRendererCache ) { this._engine?.setRemoteVideoSubscriptionOptions(remoteUid, { type: VideoStreamType.VideoStreamHigh, - encodedFrameOnly: false, + encodedFrameOnly: true, }); } } From a623a475094bb4dffc7831b5d27c4432d337e97c Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 17 Apr 2024 20:46:27 +0800 Subject: [PATCH 053/101] chore: optimize --- ts/Renderer/CapabilityManager.ts | 7 +++++-- ts/Renderer/RendererManager.ts | 4 +--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index b54e16acb..9abb7c834 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -25,9 +25,12 @@ export class CapabilityManager { } public getGpuInfo(): void { - //getGpuInfo and videoDecoder is not supported in electron version < 20.0.0 + //getGpuInfo and videoDecoder is not supported in electron version < 22.0.0 //@ts-ignore - if (semver.lt(process.versions.electron, '20.0.0')) { + if (semver.lt(process.versions.electron, '22.0.0')) { + logError( + 'WebCodecsDecoder is not supported in electron version < 22.0.0, please upgrade electron to 22.0.0 or later.' + ); return; } //@ts-ignore diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 7a7727b68..be0039dde 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -97,9 +97,7 @@ export class RendererManager { if (!AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { context.useWebCodecsDecoder = false; - logError( - 'WebCodecsDecoder is not supported in electron version < 20.0.0, please upgrade electron to 20.0.0 or later.' - ); + logError('WebCodecsDecoder is not available now.'); } switch (context.sourceType) { From c0c1d81b271116d0aca3289091a6fafe495f23a0 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 15:49:47 +0800 Subject: [PATCH 054/101] chore: optimize --- example/src/main/index.js | 2 +- .../advanced/ScreenShare/ScreenShare.tsx | 4 +- .../basic/VideoDecoder/VideoDecoder.tsx | 1 + package.json | 4 ++ ts/Decoder/gpu-utils.ts | 29 +++++++++-- ts/Decoder/index.ts | 3 +- ts/Private/internal/IrisApiEngine.ts | 16 ++++++- ts/Private/internal/MediaEngineInternal.ts | 22 ++++----- ts/Private/internal/RtcEngineExInternal.ts | 6 --- ts/Renderer/CapabilityManager.ts | 48 +++++++++++++++---- ts/Renderer/RendererManager.ts | 8 +++- ts/Renderer/WebCodecsRendererCache.ts | 25 ++++++++-- ts/Types.ts | 15 ++++++ ts/Utils.ts | 1 + 14 files changed, 143 insertions(+), 41 deletions(-) diff --git a/example/src/main/index.js b/example/src/main/index.js index 174b9b4a4..8d08f860e 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -1,7 +1,7 @@ import path from 'path'; import { format as formatUrl } from 'url'; -import 'agora-electron-sdk/js/Private/ipc/main'; +import 'agora-electron-sdk/ipc'; import { BrowserWindow, app, ipcMain, systemPreferences } from 'electron'; const isDevelopment = process.env.NODE_ENV !== 'production'; diff --git a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx index da81838c3..409342095 100644 --- a/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx +++ b/example/src/renderer/examples/advanced/ScreenShare/ScreenShare.tsx @@ -122,7 +122,9 @@ export default class ScreenShare channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, }); this.engine.registerEventHandler(this); - this.engine.setScreenCaptureScenario(ScreenScenarioType.ScreenScenarioGaming); + this.engine.setScreenCaptureScenario( + ScreenScenarioType.ScreenScenarioGaming + ); this.engine.setParameters( JSON.stringify({ 'engine.video.enable_hw_encoder': true }) ); diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 454f1487b..5ad1f6797 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -58,6 +58,7 @@ export default class VideoDecoder // will automatically register videoEncodedFrameObserver // videoEncodedFrameObserver will be released when engine.release AgoraEnv.enableWebCodecsDecoder = true; + AgoraEnv.videoFallbackStrategy = 0; this.engine.setLogLevel(16); this.engine.initialize({ appId, diff --git a/package.json b/package.json index dce9ebd08..5c021315f 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,10 @@ "version": "4.2.2-build.142-rc.1", "description": "agora-electron-sdk", "main": "js/AgoraSdk", + "exports": { + ".": "./js/AgoraSdk.js", + "./ipc": "./js/Private/ipc/main.js" + }, "types": "types/AgoraSdk.d.ts", "source": "ts/AgoraSdk", "files": [ diff --git a/ts/Decoder/gpu-utils.ts b/ts/Decoder/gpu-utils.ts index 3fb762887..c2618128b 100644 --- a/ts/Decoder/gpu-utils.ts +++ b/ts/Decoder/gpu-utils.ts @@ -8,8 +8,11 @@ import { logError } from '../Utils'; */ export type VideoDecodeAcceleratorSupportedProfile = { - title: string; - value: string; + codec: string; + minWidth: number; + maxWidth: number; + minHeight: number; + maxHeight: number; }; /** @@ -53,12 +56,30 @@ export const getGpuInfoInternal = (callback: any): void => { 'Failed to get GPU info, chrome://gpu is not available in this environment.' ); } - let filterResult: VideoDecodeAcceleratorSupportedProfile[] = JSON.parse( + let filterResult: { title: string; value: string }[] = JSON.parse( result ).filter((item: any) => { return item.title.indexOf('Decode') !== -1; }); - typeof callback === 'function' && callback(filterResult); + let convertResult: VideoDecodeAcceleratorSupportedProfile[] = []; + const resolutionPattern = /(\d+)x(\d+) to (\d+)x(\d+)/; + for (const profile of filterResult) { + const match = profile.value.match(resolutionPattern); + if (!match) { + continue; + } + + const [_resolution, minWidth, minHeight, maxWidth, maxHeight] = match; + + convertResult.push({ + codec: profile.title, + minWidth: minWidth ? Number(minWidth) : 0, + maxWidth: maxWidth ? Number(maxWidth) : 0, + minHeight: minHeight ? Number(minHeight) : 0, + maxHeight: maxHeight ? Number(maxHeight) : 0, + }); + } + typeof callback === 'function' && callback(convertResult); }) .catch((error: any) => { logError( diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 58a3ba1dd..57bd014f6 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -58,7 +58,8 @@ export class WebCodecsDecoder { decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { // @ts-ignore let codec = - AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!]; + AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!] + ?.codec; if (!codec) { logInfo('codec is not in frameCodecMapping, stop decode frame'); return false; diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 5b66ee449..4ea22aaf2 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -1,6 +1,7 @@ import EventEmitter from 'eventemitter3'; import JSON from 'json-bigint'; +import { createAgoraRtcEngine } from '../../AgoraSdk'; import { AgoraEnv, logDebug, logError, logInfo, logWarn } from '../../Utils'; import { IAudioEncodedFrameObserver } from '../AgoraBase'; import { @@ -414,7 +415,7 @@ function handleEvent(...[event, data, buffers]: any) { export function callIrisApi(funcName: string, params: any): any { try { const buffers: Uint8Array[] = []; - + const rtcEngine = createAgoraRtcEngine(); if (funcName.startsWith('MediaEngine_')) { switch (funcName) { case 'MediaEngine_pushAudioFrame': @@ -494,6 +495,19 @@ export function callIrisApi(funcName: string, params: any): any { break; } } + if (funcName.indexOf('joinChannel') != -1) { + if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { + rtcEngine.getMediaEngine().registerVideoEncodedFrameObserver({}); + //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error + //when the webCodecsDecoder is error, the video stream will be decoded by native + rtcEngine.getMediaEngine().registerVideoFrameObserver({}); + } + } else if (funcName.indexOf('leaveChannel') != -1) { + if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { + rtcEngine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); + rtcEngine.getMediaEngine().unregisterVideoFrameObserver({}); + } + } let { callApiReturnCode, callApiResult } = AgoraRtcNg.CallApi( funcName, diff --git a/ts/Private/internal/MediaEngineInternal.ts b/ts/Private/internal/MediaEngineInternal.ts index d0164a5e0..2a467c4e1 100644 --- a/ts/Private/internal/MediaEngineInternal.ts +++ b/ts/Private/internal/MediaEngineInternal.ts @@ -63,9 +63,6 @@ export class MediaEngineInternal extends IMediaEngineImpl { override registerVideoEncodedFrameObserver( observer: IVideoEncodedFrameObserver ): number { - // only call iris when no event handler registered - let callIris = - MediaEngineInternal._video_encoded_frame_observers.length === 0; if ( !MediaEngineInternal._video_encoded_frame_observers.find( (value) => value === observer @@ -73,7 +70,7 @@ export class MediaEngineInternal extends IMediaEngineImpl { ) { MediaEngineInternal._video_encoded_frame_observers.push(observer); } - return callIris ? super.registerVideoEncodedFrameObserver(observer) : 1; + return super.registerVideoEncodedFrameObserver(observer); } override unregisterVideoEncodedFrameObserver( @@ -83,20 +80,21 @@ export class MediaEngineInternal extends IMediaEngineImpl { MediaEngineInternal._video_encoded_frame_observers.filter( (value) => value !== observer ); - // only call iris when no event handler registered - let callIris = - MediaEngineInternal._video_encoded_frame_observers.length === 0; - return callIris ? super.unregisterVideoEncodedFrameObserver(observer) : 1; + return super.unregisterVideoEncodedFrameObserver(observer); } override release() { + if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { + if (MediaEngineInternal._video_frame_observers.length > 0) { + this.unregisterVideoFrameObserver({}); + } + if (MediaEngineInternal._video_encoded_frame_observers.length > 0) { + this.unregisterVideoEncodedFrameObserver({}); + } + } MediaEngineInternal._audio_frame_observers = []; MediaEngineInternal._video_frame_observers = []; MediaEngineInternal._video_encoded_frame_observers = []; - if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { - this.unregisterVideoEncodedFrameObserver({}); - // this.unregisterVideoFrameObserver({}); - } this.removeAllListeners(); super.release(); } diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index fe5f40321..e30f37d66 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -106,12 +106,6 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { AgoraEnv.CapabilityManager = new CapabilityManager(); } } - if (AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { - this._media_engine.registerVideoEncodedFrameObserver({}); - //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error - //when the webCodecsDecoder is error, the video stream will be decoded by native - // this._media_engine.registerVideoFrameObserver({}); - } return ret; } diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index 9abb7c834..d1c02ee82 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -1,30 +1,53 @@ import semver from 'semver'; +import createAgoraRtcEngine from '../AgoraSdk'; + import { GpuInfo, VideoDecodeAcceleratorSupportedProfile, } from '../Decoder/gpu-utils'; import { VideoCodecType } from '../Private/AgoraBase'; +import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; import { ipcSend } from '../Private/ipc/renderer'; import { IPCMessageType, codecMapping } from '../Types'; -import { AgoraEnv, logError } from '../Utils'; +import { AgoraEnv, logDebug, logError } from '../Utils'; /** * @ignore */ export class CapabilityManager { gpuInfo: GpuInfo = new GpuInfo(); - frameCodecMapping: { [key in VideoCodecType]?: string } = {}; - enableWebCodecsDecoder: boolean = AgoraEnv.enableWebCodecsDecoder; + frameCodecMapping: { + [key in VideoCodecType]?: VideoDecodeAcceleratorSupportedProfile; + } = {}; + webCodecsDecoderEnabled: boolean = AgoraEnv.enableWebCodecsDecoder; + private _engine: IRtcEngineEx; constructor() { + this._engine = createAgoraRtcEngine(); if (AgoraEnv.enableWebCodecsDecoder) { - this.getGpuInfo(); + this.getGpuInfo(() => { + if (AgoraEnv.videoFallbackStrategy === 0) { + if (!this.isSupportedH265()) { + if (this.isSupportedH264()) { + this._engine.setParameters( + JSON.stringify({ 'che.video.h265_dec_enable': false }) + ); + logDebug('H265 is not supported, fallback to H264'); + } else { + this.webCodecsDecoderEnabled = false; + logDebug( + 'H264 and H265 are not supported, fallback to native decoder' + ); + } + } + } + }); } } - public getGpuInfo(): void { + public getGpuInfo(callback?: () => void): void { //getGpuInfo and videoDecoder is not supported in electron version < 22.0.0 //@ts-ignore if (semver.lt(process.versions.electron, '22.0.0')) { @@ -38,17 +61,26 @@ export class CapabilityManager { ipcSend(IPCMessageType.AGORA_IPC_GET_GPU_INFO) .then((result) => { this.gpuInfo.videoDecodeAcceleratorSupportedProfile = result; - this.enableWebCodecsDecoder = (AgoraEnv.enableWebCodecsDecoder && + this.webCodecsDecoderEnabled = (AgoraEnv.enableWebCodecsDecoder && this.gpuInfo.videoDecodeAcceleratorSupportedProfile.length > 0)!; result.forEach((profile: VideoDecodeAcceleratorSupportedProfile) => { const match = codecMapping.find((item) => - profile.title.includes(item.profile) + profile.codec.includes(item.profile) ); if (match) { - this.frameCodecMapping[match.type] = match.codec; + //Normally, the range of compatible widths and heights should be the same under the same codec. + //there is no need to differentiate between different profiles. This could be optimized in the future. + this.frameCodecMapping[match.type] = { + codec: match.codec, + minWidth: profile.minWidth, + minHeight: profile.minHeight, + maxWidth: profile.maxWidth, + maxHeight: profile.maxHeight, + }; } }); + callback && callback(); }) .catch((error) => { logError( diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index be0039dde..ca188ada4 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -95,9 +95,13 @@ export class RendererManager { context.useWebCodecsDecoder = context.useWebCodecsDecoder || false; context.enableFps = context.enableFps || false; - if (!AgoraEnv.CapabilityManager?.enableWebCodecsDecoder) { + if (!AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { + if (context.useWebCodecsDecoder) { + logError( + 'WebCodecsDecoder is not available now, fallback to native decoder' + ); + } context.useWebCodecsDecoder = false; - logError('WebCodecsDecoder is not available now.'); } switch (context.sourceType) { diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index bf32ed283..7a89fad77 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,6 +1,6 @@ import { AgoraEnv, createAgoraRtcEngine, logError, logInfo } from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; -import { VideoStreamType } from '../Private/AgoraBase'; +import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; @@ -93,14 +93,29 @@ export class WebCodecsRendererCache } ); this._engine?.registerEventHandler(this); - // this._engine?.getMediaEngine().registerVideoEncodedFrameObserver({}); - // this._engine?.getMediaEngine().registerVideoFrameObserver({}); + } + + public fallback(frameInfo: EncodedVideoFrameInfo): void { + if ( + !frameInfo.codecType || + AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType] === + undefined + ) { + logInfo('codecType is not supported, fallback to native decoder'); + return; + } + // if ( + // !frameInfo.codecType || + // AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType] === + // undefined + // ) { + // logInfo('codecType is not supported, fallback to native decoder'); + // return; + // } } public release(): void { this._engine?.unregisterEventHandler(this); - // this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver({}); - // this._engine?.getMediaEngine().unregisterVideoFrameObserver({}); this._agoraRtcNg.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; diff --git a/ts/Types.ts b/ts/Types.ts index 6eac9765d..9c107ff1c 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -6,6 +6,17 @@ import { RendererCache } from './Renderer/RendererCache'; import { RendererManager } from './Renderer/RendererManager'; import { WebCodecsRendererCache } from './Renderer/WebCodecsRendererCache'; +export enum VideoFallbackStrategy { + /** + * @ignore + */ + PerformancePriority = 0, + /** + * @ignore + */ + BandwidthPriority = 1, +} + /** * @ignore */ @@ -26,6 +37,10 @@ export interface AgoraEnvOptions { * @ignore */ enableWebCodecsDecoder: boolean; + /** + * @ignore + */ + videoFallbackStrategy: VideoFallbackStrategy; } /** diff --git a/ts/Utils.ts b/ts/Utils.ts index c1962f585..acab4f4cf 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -178,5 +178,6 @@ export const AgoraEnv: AgoraEnvType = { enableDebugLogging: false, webEnvReady: true, enableWebCodecsDecoder: false, + videoFallbackStrategy: 0, AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From 5dd41f7ee2d68070552368039cebc7473c519b17 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 17:22:32 +0800 Subject: [PATCH 055/101] chore: optimize --- example/src/main/index.js | 38 +- example/yarn.lock | 1129 +++++++++------------------ package.json | 4 - ts/Decoder/index.ts | 8 + ts/Private/ipc/{main.js => main.ts} | 5 +- 5 files changed, 373 insertions(+), 811 deletions(-) rename ts/Private/ipc/{main.js => main.ts} (89%) diff --git a/example/src/main/index.js b/example/src/main/index.js index 8d08f860e..571c228af 100644 --- a/example/src/main/index.js +++ b/example/src/main/index.js @@ -1,7 +1,7 @@ import path from 'path'; import { format as formatUrl } from 'url'; -import 'agora-electron-sdk/ipc'; +import 'agora-electron-sdk/js/Private/ipc/main.js'; import { BrowserWindow, app, ipcMain, systemPreferences } from 'electron'; const isDevelopment = process.env.NODE_ENV !== 'production'; @@ -82,39 +82,3 @@ app.on('activate', () => { app.on('ready', () => { mainWindow = createMainWindow(); }); - -// app.whenReady().then(() => { -// const gpu = new BrowserWindow({ -// show: false, -// webPreferences: { offscreen: true }, -// }); -// gpu.loadURL('chrome://gpu'); -// // gpu.webContents.on('did-finish-load', () => { -// let executeJavaScriptText = -// `` + -// `let videoAccelerationInfo = [];` + -// `let nodeList = document.querySelector('info-view')?.shadowRoot?.querySelector('#video-acceleration-info info-view-table')?.shadowRoot?.querySelectorAll('#info-view-table info-view-table-row') || [];` + -// `for (node of nodeList) {` + -// ` videoAccelerationInfo.push({` + -// ` title: node.shadowRoot.querySelector('#title')?.innerText,` + -// ` value: node.shadowRoot.querySelector('#value')?.innerText,` + -// ` })` + -// `}` + -// `JSON.stringify(videoAccelerationInfo)`; -// gpu.webContents -// .executeJavaScript(executeJavaScriptText) -// .then((result) => { -// if (!result) { -// return; -// } -// let filterResult = JSON.parse(result).filter((item) => { -// return item.title.indexOf('Decode') !== -1; -// }); -// console.log(filterResult); -// gpu.close(); -// }) -// .catch((error) => { -// console.log(error); -// }); -// // }); -// }); diff --git a/example/yarn.lock b/example/yarn.lock index a571e7992..87336c53e 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1118,22 +1118,49 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1146,6 +1173,14 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -1327,6 +1362,27 @@ "@types/got" "^9" "@types/node" "*" +"@types/eslint-scope@^3.7.3": + version "3.7.7" + resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.56.9" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz#403e9ced04a34e63f1c383c5b8ee1a94442c8cc4" + integrity sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/ffi-napi@^4.0.7": version "4.0.7" resolved "https://registry.npmjs.org/@types/ffi-napi/-/ffi-napi-4.0.7.tgz#b3a9beeae160c74adca801ca1c9defb1ec0a1a32" @@ -1375,6 +1431,11 @@ resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== +"@types/json-schema@*": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -1580,149 +1641,125 @@ dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" + "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -1748,10 +1785,15 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== agent-base@6, agent-base@^6.0.2: version "6.0.2" @@ -1808,7 +1850,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2153,29 +2195,11 @@ asar@^3.1.0: optionalDependencies: "@types/glob" "^7.1.1" -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -2316,7 +2340,7 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2395,16 +2419,6 @@ bluebird@^3.5.0, bluebird@^3.5.5, bluebird@^3.7.2: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.1" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - body-parser@1.20.1: version "1.20.1" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -2483,71 +2497,15 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== +browserslist@^4.21.10: + version "4.23.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== dependencies: - pako "~1.0.5" + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" browserslist@^4.21.3, browserslist@^4.21.5: version "4.21.5" @@ -2602,20 +2560,6 @@ buffer-indexof@^1.0.0: resolved "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -2663,11 +2607,6 @@ builder-util@23.6.0: stat-mode "^1.0.0" temp-file "^3.4.0" -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== - bytes@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -2678,27 +2617,6 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - cacache@^13.0.1: version "13.0.1" resolved "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" @@ -2824,6 +2742,11 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz#8b3fad73dc35b2674a5c96df2d4f9f1c561435de" integrity sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ== +caniuse-lite@^1.0.30001587: + version "1.0.30001611" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz#4dbe78935b65851c2d2df1868af39f709a93a96e" + integrity sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q== + chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2841,7 +2764,7 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1: +"chokidar@>=3.0.0 <4.0.0": version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -2875,7 +2798,7 @@ chokidar@^2.0.0, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -2900,14 +2823,6 @@ ci-info@^3.2.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -3193,7 +3108,7 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -3208,21 +3123,11 @@ connect-history-api-fallback@^1.6.0: resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== - content-disposition@0.5.4, content-disposition@^0.5.2: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -3311,37 +3216,6 @@ crc@^3.8.0: dependencies: buffer "^5.1.0" -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - crocket@^0.9.11: version "0.9.11" resolved "https://registry.npmjs.org/crocket/-/crocket-0.9.11.tgz#288fca11ef0d3dd239b62c488265f30c8edfb0c5" @@ -3381,23 +3255,6 @@ cross-unzip@0.0.2: resolved "https://registry.npmjs.org/cross-unzip/-/cross-unzip-0.0.2.tgz#5183bc47a09559befcf98cc4657964999359372f" integrity sha512-nRJ5c+aqHz0OJVU4V1bqoaDggydfauK/Gha/H/ScBvuIjhZvl8YIpdWVzSR3vUhzCloqB1tvBdQ4V7J8qK7HzQ== -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - css-hot-loader@^1.4.4: version "1.4.4" resolved "https://registry.npmjs.org/css-hot-loader/-/css-hot-loader-1.4.4.tgz#ae784932cd8b7d092f7f15702af08b3ec9436052" @@ -3457,11 +3314,6 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A== - "d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: version "3.2.3" resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz#39f1f4954e4a09ff69ac597c2d61906b04e84740" @@ -3763,14 +3615,6 @@ depd@~1.1.2: resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - destroy@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -3791,15 +3635,6 @@ detect-node@^2.0.4: resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - dir-compare@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631" @@ -3886,11 +3721,6 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" @@ -3964,7 +3794,7 @@ duplexer3@^0.1.4: resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== -duplexify@^3.4.2, duplexify@^3.6.0: +duplexify@^3.6.0: version "3.7.1" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== @@ -4052,6 +3882,11 @@ electron-to-chromium@^1.4.284: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.384.tgz#5c23b5579930dec9af2a93edafddbe991542eace" integrity sha512-I97q0MmRAAqj53+a8vZsDkEXBZki+ehYAOPzwtQzALip52aEp2+BJqHFtTlsfjoqVZYwPpHC8wM6MbsSZQ/Eqw== +electron-to-chromium@^1.4.668: + version "1.4.740" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz#89c82421332ee425e5b193e3db2dea019d423419" + integrity sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg== + electron-webpack-js@~2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/electron-webpack-js/-/electron-webpack-js-2.4.1.tgz#5389cc22f34c71f6416d5ba1e043f9b0fd6130af" @@ -4107,19 +3942,6 @@ electron@22.0.0: "@types/node" "^16.11.26" extract-zip "^2.0.1" -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -4159,7 +3981,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1: version "4.5.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== @@ -4168,6 +3990,14 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" +enhanced-resolve@^5.16.0: + version "5.16.0" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz#65ec88778083056cb32487faa9aef82ed0864787" + integrity sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + entities@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -4183,7 +4013,7 @@ err-code@^2.0.2: resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -errno@^0.1.3, errno@~0.1.7: +errno@^0.1.3: version "0.1.8" resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== @@ -4249,6 +4079,11 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-module-lexer@^1.2.1: + version "1.5.0" + resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz#4878fee3789ad99e065f975fdd3c645529ff0236" + integrity sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw== + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -4328,12 +4163,12 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: - esrecurse "^4.1.0" + esrecurse "^4.3.0" estraverse "^4.1.1" esprima@^4.0.0: @@ -4341,7 +4176,7 @@ esprima@^4.0.0: resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.1.0: +esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -4378,7 +4213,7 @@ eventemitter3@^5.0.1: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.0.0: +events@^3.2.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -4388,14 +4223,6 @@ eventsource@^2.0.2: resolved "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -4681,15 +4508,6 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -4766,7 +4584,7 @@ flagged-respawn@^1.0.0: resolved "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== -flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: +flush-write-stream@^1.0.2: version "1.1.1" resolved "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== @@ -4851,7 +4669,7 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -from2@^2.1.0, from2@^2.1.1: +from2@^2.1.1: version "2.3.0" resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g== @@ -5078,6 +4896,11 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob-watcher@^5.0.3: version "5.0.5" resolved "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc" @@ -5239,7 +5062,7 @@ got@^8.3.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: +graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -5389,23 +5212,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - he@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -5423,15 +5229,6 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - hoist-non-react-statics@^3.1.0: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -5613,11 +5410,6 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== - https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -5662,7 +5454,7 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5695,7 +5487,7 @@ indent-string@^4.0.0: resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infer-owner@^1.0.3, infer-owner@^1.0.4: +infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== @@ -5708,16 +5500,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA== - inherits@2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -6178,7 +5965,7 @@ isarray@0.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -6243,6 +6030,15 @@ jest-worker@^25.4.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -6290,10 +6086,10 @@ json-buffer@3.0.1: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" @@ -6467,10 +6263,10 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0, loader-utils@^1.4.2: version "1.4.2" @@ -6612,7 +6408,7 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -6690,15 +6486,6 @@ material-colors@^1.2.1: resolved "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -6767,14 +6554,6 @@ micromatch@^4.0.0: braces "^3.0.2" picomatch "^2.3.1" -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -6822,16 +6601,11 @@ mini-css-extract-plugin@^0.9.0: schema-utils "^1.0.0" webpack-sources "^1.1.0" -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: +minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - minimatch@3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -6917,22 +6691,6 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -6941,7 +6699,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.6: +mkdirp@^0.5.1, mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -7030,7 +6788,7 @@ negotiator@0.6.3, negotiator@^0.6.3: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -7103,40 +6861,16 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - node-loader@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/node-loader/-/node-loader-0.6.0.tgz#c797ef51095ed5859902b157f6384f6361e05ae8" integrity sha512-WlUacqHqHWb383Mec656pJmAtg7EXBcijg1sovgy0tI4xevAzv8RqcRARTMlzm0HLXzy1Pdo/DMU19/fxoMnmA== +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -7391,11 +7125,6 @@ ordered-read-streams@^1.0.0: dependencies: readable-stream "^2.0.1" -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== - os-locale@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" @@ -7503,20 +7232,6 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - param-case@^3.0.3: version "3.0.4" resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -7525,17 +7240,6 @@ param-case@^3.0.3: dot-case "^3.0.4" tslib "^2.0.3" -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - parse-filepath@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" @@ -7580,11 +7284,6 @@ pascalcase@^0.1.1: resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -7665,17 +7364,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - pend@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -7851,11 +7539,6 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -7896,18 +7579,6 @@ prr@~1.0.1: resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - pump@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -7924,7 +7595,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3, pumpify@^1.3.5: +pumpify@^1.3.5: version "1.5.1" resolved "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== @@ -7938,11 +7609,6 @@ punycode@1.3.2: resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - punycode@^2.1.0: version "2.3.0" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -7972,11 +7638,6 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== - querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -7992,21 +7653,13 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -8868,14 +8521,6 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - roarr@^2.15.3: version "2.15.4" resolved "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" @@ -8910,7 +8555,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -8936,7 +8581,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -9007,6 +8652,15 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + scroll-into-view-if-needed@^2.2.25: version "2.2.31" resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587" @@ -9100,6 +8754,13 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -9138,11 +8799,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -9153,14 +8809,6 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" @@ -9350,7 +8998,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@~0.5.12: +source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -9449,13 +9097,6 @@ sprintf-js@~1.0.2: resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -ssri@^6.0.1: - version "6.0.2" - resolved "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== - dependencies: - figgy-pudding "^3.5.1" - ssri@^7.0.0: version "7.1.1" resolved "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz#33e44f896a967158e3c63468e47ec46613b95b5f" @@ -9504,38 +9145,11 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - stream-exhaust@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - stream-shift@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" @@ -9605,7 +9219,7 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" -string_decoder@^1.0.0, string_decoder@^1.1.1: +string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -9710,6 +9324,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -9728,6 +9349,11 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" @@ -9761,21 +9387,6 @@ temp-file@^3.4.0: async-exit-hook "^2.0.1" fs-extra "^10.0.0" -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - terser-webpack-plugin@^2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz#894764a19b0743f2f704e7c2a848c5283a696724" @@ -9791,7 +9402,18 @@ terser-webpack-plugin@^2.3.5: terser "^4.6.12" webpack-sources "^1.4.3" -terser@^4.1.2, terser@^4.6.12, terser@^4.6.3: +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^4.6.12, terser@^4.6.3: version "4.8.1" resolved "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== @@ -9800,6 +9422,16 @@ terser@^4.1.2, terser@^4.6.12, terser@^4.6.3: source-map "~0.6.1" source-map-support "~0.5.12" +terser@^5.26.0: + version "5.30.3" + resolved "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz#f1bb68ded42408c316b548e3ec2526d7dd03f4d2" + integrity sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + text-hex@1.0.x: version "1.0.0" resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" @@ -9841,13 +9473,6 @@ timed-out@^4.0.1: resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - tiny-invariant@^1.0.2: version "1.3.1" resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" @@ -9885,11 +9510,6 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA== - to-buffer@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" @@ -9989,11 +9609,6 @@ tslib@^2.0.3: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw== - type-fest@^0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" @@ -10185,6 +9800,14 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -10257,20 +9880,6 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util@0.10.3: - version "0.10.3" - resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - utila@~0.4: version "0.4.0" resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" @@ -10403,28 +10012,13 @@ vinyl@^2.0.0: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.5" - resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== +watchpack@^2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" + integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== dependencies: + glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" @@ -10522,7 +10116,7 @@ webpack-merge@^4.2.2: dependencies: lodash "^4.17.15" -webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.1.0, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -10530,34 +10124,40 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.43.0: - version "4.46.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.73.0: + version "5.91.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9" + integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" + enhanced-resolve "^5.16.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" + webpack-sources "^3.2.3" websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" @@ -10653,13 +10253,6 @@ winston@^3.3.3: triple-beam "^1.3.0" winston-transport "^4.5.0" -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - worker-rpc@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" diff --git a/package.json b/package.json index 5c021315f..dce9ebd08 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,6 @@ "version": "4.2.2-build.142-rc.1", "description": "agora-electron-sdk", "main": "js/AgoraSdk", - "exports": { - ".": "./js/AgoraSdk.js", - "./ipc": "./js/Private/ipc/main.js" - }, "types": "types/AgoraSdk.d.ts", "source": "ts/AgoraSdk", "files": [ diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 57bd014f6..c685f2d9b 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -7,6 +7,7 @@ import { AgoraEnv, logDebug, logInfo } from '../Utils'; const frameTypeMapping = { [VideoFrameType.VideoFrameTypeDeltaFrame]: 'delta', [VideoFrameType.VideoFrameTypeKeyFrame]: 'key', + [VideoFrameType.VideoFrameTypeDroppableFrame]: 'delta', // this is a workaround for the issue that the frameType is not correct }; export class WebCodecsDecoder { @@ -91,6 +92,13 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { + console.log( + frameInfo.frameType, + frameInfo.codecType, + frameInfo.width, + frameInfo.height, + imageBuffer.length + ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; diff --git a/ts/Private/ipc/main.js b/ts/Private/ipc/main.ts similarity index 89% rename from ts/Private/ipc/main.js rename to ts/Private/ipc/main.ts index 5a6bf4453..71adea051 100644 --- a/ts/Private/ipc/main.js +++ b/ts/Private/ipc/main.ts @@ -1,14 +1,15 @@ +//@ts-ignore import { app, ipcMain } from 'electron'; import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; import { IPCMessageType } from '../../Types'; import { logInfo } from '../../Utils'; - +//@ts-ignore if (process.type === 'browser') { ipcMain.handle(IPCMessageType.AGORA_IPC_GET_GPU_INFO, () => { return new Promise((resolve) => { - getGpuInfoInternal((result) => { + getGpuInfoInternal((result: any) => { resolve(result); }); }); From 3f814417bab3b1c9b0c4b9eded0abd9d86a8c19c Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 17:27:16 +0800 Subject: [PATCH 056/101] chore: optimize --- example/yarn.lock | 1146 +++++++++++++++++++++++++++++++-------------- 1 file changed, 786 insertions(+), 360 deletions(-) diff --git a/example/yarn.lock b/example/yarn.lock index 87336c53e..dd93654a9 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1118,49 +1118,22 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10": version "1.4.15" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1173,14 +1146,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -1362,27 +1327,6 @@ "@types/got" "^9" "@types/node" "*" -"@types/eslint-scope@^3.7.3": - version "3.7.7" - resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" - integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.56.9" - resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz#403e9ced04a34e63f1c383c5b8ee1a94442c8cc4" - integrity sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - "@types/ffi-napi@^4.0.7": version "4.0.7" resolved "https://registry.npmjs.org/@types/ffi-napi/-/ffi-napi-4.0.7.tgz#b3a9beeae160c74adca801ca1c9defb1ec0a1a32" @@ -1431,11 +1375,6 @@ resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== -"@types/json-schema@*": - version "7.0.15" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -1641,125 +1580,149 @@ dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" - integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== +"@webassemblyjs/floating-point-hex-parser@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== -"@webassemblyjs/helper-buffer@1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" - integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@xtuc/long" "4.2.2" + "@webassemblyjs/wast-printer" "1.9.0" -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== -"@webassemblyjs/helper-wasm-section@1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" - integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/ast" "1.9.0" -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== + +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + +"@webassemblyjs/ieee754@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - -"@webassemblyjs/wasm-gen@1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" - integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" - integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - -"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" - integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.12.1": - version "1.12.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" - integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== - dependencies: - "@webassemblyjs/ast" "1.12.1" +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== + +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/helper-wasm-section" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-opt" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/wasm-gen@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wasm-opt@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + +"@webassemblyjs/wasm-parser@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wast-parser@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-code-frame" "1.9.0" + "@webassemblyjs/helper-fsm" "1.9.0" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -1785,15 +1748,10 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== - -acorn@^8.7.1, acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== agent-base@6, agent-base@^6.0.2: version "6.0.2" @@ -1850,7 +1808,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2195,11 +2153,28 @@ asar@^3.1.0: optionalDependencies: "@types/glob" "^7.1.1" +asn1.js@^4.10.1: + version "4.10.1" + resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== +assert@^1.1.1: + version "1.5.1" + resolved "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz#038ab248e4ff078e7bc2485ba6e6388466c78f76" + integrity sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A== + dependencies: + object.assign "^4.1.4" + util "^0.10.4" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -2340,7 +2315,7 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2419,6 +2394,16 @@ bluebird@^3.5.0, bluebird@^3.5.5, bluebird@^3.7.2: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + body-parser@1.20.1: version "1.20.1" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -2497,15 +2482,72 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.10: - version "4.23.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.3" + resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" + integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.5" + hash-base "~3.0" + inherits "^2.0.4" + parse-asn1 "^5.1.7" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" browserslist@^4.21.3, browserslist@^4.21.5: version "4.21.5" @@ -2560,6 +2602,20 @@ buffer-indexof@^1.0.0: resolved "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -2607,6 +2663,11 @@ builder-util@23.6.0: stat-mode "^1.0.0" temp-file "^3.4.0" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + bytes@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -2617,6 +2678,27 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cacache@^12.0.2: + version "12.0.4" + resolved "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + cacache@^13.0.1: version "13.0.1" resolved "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" @@ -2742,11 +2824,6 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz#8b3fad73dc35b2674a5c96df2d4f9f1c561435de" integrity sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ== -caniuse-lite@^1.0.30001587: - version "1.0.30001611" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz#4dbe78935b65851c2d2df1868af39f709a93a96e" - integrity sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q== - chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2798,7 +2875,22 @@ chokidar@^2.0.0, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chownr@^1.1.2: +chokidar@^3.4.1: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -2823,6 +2915,14 @@ ci-info@^3.2.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -3108,7 +3208,7 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -3123,11 +3223,21 @@ connect-history-api-fallback@^1.6.0: resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== + content-disposition@0.5.4, content-disposition@^0.5.2: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -3216,6 +3326,37 @@ crc@^3.8.0: dependencies: buffer "^5.1.0" +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + crocket@^0.9.11: version "0.9.11" resolved "https://registry.npmjs.org/crocket/-/crocket-0.9.11.tgz#288fca11ef0d3dd239b62c488265f30c8edfb0c5" @@ -3255,6 +3396,23 @@ cross-unzip@0.0.2: resolved "https://registry.npmjs.org/cross-unzip/-/cross-unzip-0.0.2.tgz#5183bc47a09559befcf98cc4657964999359372f" integrity sha512-nRJ5c+aqHz0OJVU4V1bqoaDggydfauK/Gha/H/ScBvuIjhZvl8YIpdWVzSR3vUhzCloqB1tvBdQ4V7J8qK7HzQ== +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + css-hot-loader@^1.4.4: version "1.4.4" resolved "https://registry.npmjs.org/css-hot-loader/-/css-hot-loader-1.4.4.tgz#ae784932cd8b7d092f7f15702af08b3ec9436052" @@ -3314,6 +3472,11 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +cyclist@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz#673b5f233bf34d8e602b949429f8171d9121bea3" + integrity sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA== + "d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: version "3.2.3" resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz#39f1f4954e4a09ff69ac597c2d61906b04e84740" @@ -3615,6 +3778,14 @@ depd@~1.1.2: resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -3635,6 +3806,15 @@ detect-node@^2.0.4: resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + dir-compare@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631" @@ -3721,6 +3901,11 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" @@ -3794,7 +3979,7 @@ duplexer3@^0.1.4: resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== -duplexify@^3.6.0: +duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== @@ -3882,11 +4067,6 @@ electron-to-chromium@^1.4.284: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.384.tgz#5c23b5579930dec9af2a93edafddbe991542eace" integrity sha512-I97q0MmRAAqj53+a8vZsDkEXBZki+ehYAOPzwtQzALip52aEp2+BJqHFtTlsfjoqVZYwPpHC8wM6MbsSZQ/Eqw== -electron-to-chromium@^1.4.668: - version "1.4.740" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz#89c82421332ee425e5b193e3db2dea019d423419" - integrity sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg== - electron-webpack-js@~2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/electron-webpack-js/-/electron-webpack-js-2.4.1.tgz#5389cc22f34c71f6416d5ba1e043f9b0fd6130af" @@ -3942,6 +4122,19 @@ electron@22.0.0: "@types/node" "^16.11.26" extract-zip "^2.0.1" +elliptic@^6.5.3, elliptic@^6.5.5: + version "6.5.5" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" + integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -3981,7 +4174,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1: +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== @@ -3990,14 +4183,6 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^5.16.0: - version "5.16.0" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz#65ec88778083056cb32487faa9aef82ed0864787" - integrity sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - entities@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -4013,7 +4198,7 @@ err-code@^2.0.2: resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -errno@^0.1.3: +errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== @@ -4079,11 +4264,6 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== -es-module-lexer@^1.2.1: - version "1.5.0" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz#4878fee3789ad99e065f975fdd3c645529ff0236" - integrity sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw== - es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -4163,12 +4343,12 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== dependencies: - esrecurse "^4.3.0" + esrecurse "^4.1.0" estraverse "^4.1.1" esprima@^4.0.0: @@ -4176,7 +4356,7 @@ esprima@^4.0.0: resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.3.0: +esrecurse@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -4213,7 +4393,7 @@ eventemitter3@^5.0.1: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.2.0: +events@^3.0.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -4223,6 +4403,14 @@ eventsource@^2.0.2: resolved "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -4508,6 +4696,15 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -4584,7 +4781,7 @@ flagged-respawn@^1.0.0: resolved "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== -flush-write-stream@^1.0.2: +flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.1.1" resolved "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== @@ -4669,7 +4866,7 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -from2@^2.1.1: +from2@^2.1.0, from2@^2.1.1: version "2.3.0" resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g== @@ -4896,11 +5093,6 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - glob-watcher@^5.0.3: version "5.0.5" resolved "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc" @@ -5062,7 +5254,7 @@ got@^8.3.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6: +graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -5212,6 +5404,31 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash-base@~3.0: + version "3.0.4" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + he@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -5229,6 +5446,15 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hoist-non-react-statics@^3.1.0: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -5410,6 +5636,11 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -5454,7 +5685,7 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5487,7 +5718,7 @@ indent-string@^4.0.0: resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infer-owner@^1.0.4: +infer-owner@^1.0.3, infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== @@ -5500,7 +5731,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -5965,7 +6196,7 @@ isarray@0.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -6030,15 +6261,6 @@ jest-worker@^25.4.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -6086,10 +6308,10 @@ json-buffer@3.0.1: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-even-better-errors@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-schema-traverse@^0.4.1: version "0.4.1" @@ -6263,10 +6485,10 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0, loader-utils@^1.4.2: version "1.4.2" @@ -6408,7 +6630,7 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-dir@^2.1.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -6486,6 +6708,15 @@ material-colors@^1.2.1: resolved "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -6554,6 +6785,14 @@ micromatch@^4.0.0: braces "^3.0.2" picomatch "^2.3.1" +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -6601,11 +6840,16 @@ mini-css-extract-plugin@^0.9.0: schema-utils "^1.0.0" webpack-sources "^1.1.0" -minimalistic-assert@^1.0.0: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -6691,6 +6935,22 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -6699,7 +6959,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.1, mkdirp@^0.5.6: +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -6788,7 +7048,7 @@ negotiator@0.6.3, negotiator@^0.6.3: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.6.2: +neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -6861,16 +7121,40 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + node-loader@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/node-loader/-/node-loader-0.6.0.tgz#c797ef51095ed5859902b157f6384f6361e05ae8" integrity sha512-WlUacqHqHWb383Mec656pJmAtg7EXBcijg1sovgy0tI4xevAzv8RqcRARTMlzm0HLXzy1Pdo/DMU19/fxoMnmA== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - node-releases@^2.0.8: version "2.0.10" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -7125,6 +7409,11 @@ ordered-read-streams@^1.0.0: dependencies: readable-stream "^2.0.1" +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + os-locale@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" @@ -7232,6 +7521,20 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + param-case@^3.0.3: version "3.0.4" resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -7240,6 +7543,18 @@ param-case@^3.0.3: dot-case "^3.0.4" tslib "^2.0.3" +parse-asn1@^5.0.0, parse-asn1@^5.1.7: + version "5.1.7" + resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06" + integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg== + dependencies: + asn1.js "^4.10.1" + browserify-aes "^1.2.0" + evp_bytestokey "^1.0.3" + hash-base "~3.0" + pbkdf2 "^3.1.2" + safe-buffer "^5.2.1" + parse-filepath@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" @@ -7284,6 +7599,11 @@ pascalcase@^0.1.1: resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -7364,6 +7684,17 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +pbkdf2@^3.0.3, pbkdf2@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + pend@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -7539,6 +7870,11 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -7579,6 +7915,18 @@ prr@~1.0.1: resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + pump@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -7595,7 +7943,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.5: +pumpify@^1.3.3, pumpify@^1.3.5: version "1.5.1" resolved "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== @@ -7609,6 +7957,11 @@ punycode@1.3.2: resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + punycode@^2.1.0: version "2.3.0" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -7638,6 +7991,11 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== + querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -7653,13 +8011,21 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.1.0: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -8192,7 +8558,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -8521,6 +8887,14 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + roarr@^2.15.3: version "2.15.4" resolved "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" @@ -8555,7 +8929,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -8652,15 +9026,6 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -schema-utils@^3.1.1, schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - scroll-into-view-if-needed@^2.2.25: version "2.2.31" resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587" @@ -8754,13 +9119,6 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" -serialize-javascript@^6.0.1: - version "6.0.2" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - serve-index@^1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -8799,6 +9157,11 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -8809,6 +9172,14 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" @@ -8998,7 +9369,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@~0.5.12, source-map-support@~0.5.20: +source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@~0.5.12: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -9097,6 +9468,13 @@ sprintf-js@~1.0.2: resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +ssri@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" + integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== + dependencies: + figgy-pudding "^3.5.1" + ssri@^7.0.0: version "7.1.1" resolved "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz#33e44f896a967158e3c63468e47ec46613b95b5f" @@ -9145,11 +9523,38 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + stream-exhaust@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + stream-shift@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" @@ -9219,7 +9624,7 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" -string_decoder@^1.1.1: +string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -9324,13 +9729,6 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -9349,11 +9747,6 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" @@ -9387,6 +9780,21 @@ temp-file@^3.4.0: async-exit-hook "^2.0.1" fs-extra "^10.0.0" +terser-webpack-plugin@^1.4.3: + version "1.4.5" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" + integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^4.0.0" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + terser-webpack-plugin@^2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz#894764a19b0743f2f704e7c2a848c5283a696724" @@ -9402,18 +9810,7 @@ terser-webpack-plugin@^2.3.5: terser "^4.6.12" webpack-sources "^1.4.3" -terser-webpack-plugin@^5.3.10: - version "5.3.10" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" - integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== - dependencies: - "@jridgewell/trace-mapping" "^0.3.20" - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.26.0" - -terser@^4.6.12, terser@^4.6.3: +terser@^4.1.2, terser@^4.6.12, terser@^4.6.3: version "4.8.1" resolved "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== @@ -9422,16 +9819,6 @@ terser@^4.6.12, terser@^4.6.3: source-map "~0.6.1" source-map-support "~0.5.12" -terser@^5.26.0: - version "5.30.3" - resolved "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz#f1bb68ded42408c316b548e3ec2526d7dd03f4d2" - integrity sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - text-hex@1.0.x: version "1.0.0" resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" @@ -9473,6 +9860,13 @@ timed-out@^4.0.1: resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + tiny-invariant@^1.0.2: version "1.3.1" resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" @@ -9510,6 +9904,11 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA== + to-buffer@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" @@ -9609,6 +10008,11 @@ tslib@^2.0.3: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw== + type-fest@^0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" @@ -9800,14 +10204,6 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - uri-js@^4.2.2: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -9880,6 +10276,20 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +util@^0.10.4: + version "0.10.4" + resolved "https://registry.npmjs.org/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.npmjs.org/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + utila@~0.4: version "0.4.0" resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" @@ -10012,13 +10422,28 @@ vinyl@^2.0.0: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -watchpack@^2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" - integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchpack-chokidar2@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== + dependencies: + chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.5" + resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== dependencies: - glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" + neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.1" wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" @@ -10116,7 +10541,7 @@ webpack-merge@^4.2.2: dependencies: lodash "^4.17.15" -webpack-sources@^1.1.0, webpack-sources@^1.4.3: +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -10124,40 +10549,34 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@^5.73.0: - version "5.91.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9" - integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.12.1" - "@webassemblyjs/wasm-edit" "^1.12.1" - "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.21.10" +webpack@^4.43.0: + version "4.47.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz#8b8a02152d7076aeb03b61b47dad2eeed9810ebc" + integrity sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/wasm-edit" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + acorn "^6.4.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.16.0" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.11" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.10" - watchpack "^2.4.1" - webpack-sources "^3.2.3" + enhanced-resolve "^4.5.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.3" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.3" + watchpack "^1.7.4" + webpack-sources "^1.4.1" websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" @@ -10253,6 +10672,13 @@ winston@^3.3.3: triple-beam "^1.3.0" winston-transport "^4.5.0" +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + worker-rpc@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" From b80f3808355de205b49fb1755aee3858c7c71911 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 17:51:52 +0800 Subject: [PATCH 057/101] chore: optimize --- ts/Private/ipc/main.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ts/Private/ipc/main.ts b/ts/Private/ipc/main.ts index 71adea051..d4e46ced6 100644 --- a/ts/Private/ipc/main.ts +++ b/ts/Private/ipc/main.ts @@ -4,7 +4,6 @@ import { app, ipcMain } from 'electron'; import { getGpuInfoInternal } from '../../Decoder/gpu-utils'; import { IPCMessageType } from '../../Types'; -import { logInfo } from '../../Utils'; //@ts-ignore if (process.type === 'browser') { ipcMain.handle(IPCMessageType.AGORA_IPC_GET_GPU_INFO, () => { @@ -14,10 +13,10 @@ if (process.type === 'browser') { }); }); }); - logInfo('main process AgoraIPCMain handler registered'); + console.log('main process AgoraIPCMain handler registered'); app.on('quit', () => { ipcMain.removeHandler(IPCMessageType.AGORA_IPC_GET_GPU_INFO); - logInfo('main process AgoraIPCMain handler removed'); + console.log('main process AgoraIPCMain handler removed'); }); } From 9039ef045a535fdae19bd5434703ca50db1125cb Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 17:55:43 +0800 Subject: [PATCH 058/101] chore: optimize --- ts/Decoder/index.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index c685f2d9b..955285fa4 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -92,13 +92,6 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { - console.log( - frameInfo.frameType, - frameInfo.codecType, - frameInfo.width, - frameInfo.height, - imageBuffer.length - ); if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; From 1890736f262213a4125ff403a52518698d3372e7 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 19:02:15 +0800 Subject: [PATCH 059/101] chore: optimize --- ts/Private/internal/IrisApiEngine.ts | 18 +++++++++++------- ts/Private/internal/RtcEngineExInternal.ts | 7 ++++--- ts/Renderer/RendererCache.ts | 19 ++++++++++--------- ts/Renderer/WebCodecsRendererCache.ts | 9 +++++---- ts/Types.ts | 6 +----- ts/Utils.ts | 3 --- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 4ea22aaf2..2ca29e7e9 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -1,7 +1,8 @@ import EventEmitter from 'eventemitter3'; import JSON from 'json-bigint'; -import { createAgoraRtcEngine } from '../../AgoraSdk'; +import createAgoraRtcEngine from '../../AgoraSdk'; +import { IAgoraElectronBridge } from '../../Types'; import { AgoraEnv, logDebug, logError, logInfo, logWarn } from '../../Utils'; import { IAudioEncodedFrameObserver } from '../AgoraBase'; import { @@ -61,8 +62,11 @@ import { RtcEngineExInternal } from './RtcEngineExInternal'; // @ts-ignore export const DeviceEventEmitter: EventEmitter = new EventEmitter(); -const AgoraRtcNg = AgoraEnv.AgoraElectronBridge; -AgoraRtcNg.OnEvent('call_back_with_buffer', (...params: any) => { +const AgoraNode = require('../../../build/Release/agora_node_ext'); +export const AgoraElectronBridge: IAgoraElectronBridge = + new AgoraNode.AgoraElectronBridge(); + +AgoraElectronBridge.OnEvent('call_back_with_buffer', (...params: any) => { try { handleEvent(...params); } catch (e) { @@ -460,16 +464,16 @@ export function callIrisApi(funcName: string, params: any): any { } else if (funcName.startsWith('RtcEngine_')) { switch (funcName) { case 'RtcEngine_initialize': - AgoraRtcNg.InitializeEnv(); + AgoraElectronBridge.InitializeEnv(); break; case 'RtcEngine_release': - AgoraRtcNg.CallApi( + AgoraElectronBridge.CallApi( funcName, JSON.stringify(params), buffers, buffers.length ); - AgoraRtcNg.ReleaseEnv(); + AgoraElectronBridge.ReleaseEnv(); return; case 'RtcEngine_sendMetaData': // metadata.buffer @@ -509,7 +513,7 @@ export function callIrisApi(funcName: string, params: any): any { } } - let { callApiReturnCode, callApiResult } = AgoraRtcNg.CallApi( + let { callApiReturnCode, callApiResult } = AgoraElectronBridge.CallApi( funcName, JSON.stringify(params), buffers, diff --git a/ts/Private/internal/RtcEngineExInternal.ts b/ts/Private/internal/RtcEngineExInternal.ts index e30f37d66..6ed5be909 100644 --- a/ts/Private/internal/RtcEngineExInternal.ts +++ b/ts/Private/internal/RtcEngineExInternal.ts @@ -1,5 +1,6 @@ import { createCheckers } from 'ts-interface-checker'; +import { AgoraElectronBridge } from '../../Private/internal/IrisApiEngine'; import { AgoraEnv, logError } from '../../Utils'; import { AudioEncodedFrameObserverConfig, @@ -110,7 +111,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { } override release(sync: boolean = false) { - AgoraEnv.AgoraElectronBridge.ReleaseRenderer(); + AgoraElectronBridge.ReleaseRenderer(); AgoraEnv.AgoraRendererManager?.release(); AgoraEnv.AgoraRendererManager = undefined; this._audio_device_manager.release(); @@ -569,7 +570,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { if (!value.thumbImage?.buffer || !value.thumbImage?.length) { value.thumbImage!.buffer = undefined; } else { - value.thumbImage!.buffer = AgoraEnv.AgoraElectronBridge.GetBuffer( + value.thumbImage!.buffer = AgoraElectronBridge.GetBuffer( value.thumbImage!.buffer as unknown as number, value.thumbImage.length! ); @@ -577,7 +578,7 @@ export class RtcEngineExInternal extends IRtcEngineExImpl { if (!value.iconImage?.buffer || !value.iconImage?.length) { value.iconImage!.buffer = undefined; } else { - value.iconImage.buffer = AgoraEnv.AgoraElectronBridge.GetBuffer( + value.iconImage.buffer = AgoraElectronBridge.GetBuffer( value.iconImage!.buffer as unknown as number, value.iconImage.length! ); diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index 3c482ac31..e1ecc4333 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -1,6 +1,8 @@ import { VideoFrame } from '../Private/AgoraMediaBase'; +import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; + import { RendererContext } from '../Types'; -import { AgoraEnv, logDebug } from '../Utils'; +import { logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; import { IRendererCache } from './IRendererCache'; @@ -32,19 +34,15 @@ export class RendererCache extends IRendererCache { return this.videoFrame; } - private get bridge() { - return AgoraEnv.AgoraElectronBridge; - } - private enable() { if (this._enabled) return; - this.bridge.EnableVideoFrameCache(this.context); + AgoraElectronBridge.EnableVideoFrameCache(this.context); this._enabled = true; } private disable() { if (!this._enabled) return; - this.bridge.DisableVideoFrameCache(this.context); + AgoraElectronBridge.DisableVideoFrameCache(this.context); this._enabled = false; } @@ -57,7 +55,7 @@ export class RendererCache extends IRendererCache { } override draw() { - let { ret, isNewFrame } = this.bridge.GetVideoFrame( + let { ret, isNewFrame } = AgoraElectronBridge.GetVideoFrame( this.context, this.videoFrame ); @@ -72,7 +70,10 @@ export class RendererCache extends IRendererCache { this.videoFrame.uBuffer = Buffer.alloc(uStride! * height!); this.videoFrame.vBuffer = Buffer.alloc(vStride! * height!); - const result = this.bridge.GetVideoFrame(this.context, this.videoFrame); + const result = AgoraElectronBridge.GetVideoFrame( + this.context, + this.videoFrame + ); ret = result.ret; isNewFrame = result.isNewFrame; break; diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 7a89fad77..a7d0f8279 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,10 +1,12 @@ -import { AgoraEnv, createAgoraRtcEngine, logError, logInfo } from '../AgoraSdk'; +import createAgoraRtcEngine, { logError, logInfo } from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; +import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; import { RendererContext } from '../Types'; +import { AgoraEnv } from '../Utils'; import { IRendererCache } from './IRendererCache'; import { WebCodecsRenderer } from './WebCodecsRenderer/index'; @@ -16,7 +18,6 @@ export class WebCodecsRendererCache private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; private _firstFrame = true; - private _agoraRtcNg = AgoraEnv.AgoraElectronBridge; constructor({ channelId, uid, sourceType }: RendererContext) { super({ channelId, uid, sourceType }); @@ -82,7 +83,7 @@ export class WebCodecsRendererCache } public draw() { - this._agoraRtcNg.OnEvent( + AgoraElectronBridge.OnEvent( 'call_back_with_encoded_video_frame', (...params: any) => { try { @@ -116,7 +117,7 @@ export class WebCodecsRendererCache public release(): void { this._engine?.unregisterEventHandler(this); - this._agoraRtcNg.UnEvent('call_back_with_encoded_video_frame'); + AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; super.release(); diff --git a/ts/Types.ts b/ts/Types.ts index 9c107ff1c..2752ccc3f 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -47,10 +47,6 @@ export interface AgoraEnvOptions { * @ignore */ export interface AgoraEnvType extends AgoraEnvOptions { - /** - * @ignore - */ - AgoraElectronBridge: AgoraElectronBridge; /** * @ignore */ @@ -106,7 +102,7 @@ export interface Result { /** * @ignore */ -export interface AgoraElectronBridge { +export interface IAgoraElectronBridge { /** * @ignore */ diff --git a/ts/Utils.ts b/ts/Utils.ts index acab4f4cf..b3346d7db 100644 --- a/ts/Utils.ts +++ b/ts/Utils.ts @@ -168,8 +168,6 @@ export function getContextByCanvas( return null; } -const AgoraNode = require('../build/Release/agora_node_ext'); - /** * @ignore */ @@ -179,5 +177,4 @@ export const AgoraEnv: AgoraEnvType = { webEnvReady: true, enableWebCodecsDecoder: false, videoFallbackStrategy: 0, - AgoraElectronBridge: new AgoraNode.AgoraElectronBridge(), }; From cbe5ffc7a8bb0527881bc91ef016dba0b7eb98fc Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 19:12:40 +0800 Subject: [PATCH 060/101] chore: optimize --- ts/Decoder/gpu-utils.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ts/Decoder/gpu-utils.ts b/ts/Decoder/gpu-utils.ts index c2618128b..a973b65ef 100644 --- a/ts/Decoder/gpu-utils.ts +++ b/ts/Decoder/gpu-utils.ts @@ -1,8 +1,6 @@ //@ts-ignore import { BrowserWindow } from 'electron'; -import { logError } from '../Utils'; - /** * @ignore */ @@ -29,7 +27,7 @@ export class GpuInfo { export const getGpuInfoInternal = (callback: any): void => { //@ts-ignore if (process.type !== 'browser') { - logError('getGpuInfoInternal should be called in main process'); + console.error('getGpuInfoInternal should be called in main process'); return; } const gpuPage = new BrowserWindow({ @@ -52,7 +50,7 @@ export const getGpuInfoInternal = (callback: any): void => { .executeJavaScript(executeJavaScriptText) .then((result: string) => { if (!result) { - logError( + console.error( 'Failed to get GPU info, chrome://gpu is not available in this environment.' ); } @@ -82,7 +80,7 @@ export const getGpuInfoInternal = (callback: any): void => { typeof callback === 'function' && callback(convertResult); }) .catch((error: any) => { - logError( + console.error( 'Failed to get GPU info, please import agora-electron-sdk in main process', error ); From d73a6f95787564e6379368b72da800a47c6ff4e8 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 19:18:24 +0800 Subject: [PATCH 061/101] chore: optimize --- ts/Renderer/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ts/Renderer/index.ts b/ts/Renderer/index.ts index 854c360dc..0fa58f585 100644 --- a/ts/Renderer/index.ts +++ b/ts/Renderer/index.ts @@ -1,2 +1 @@ export * from './IRenderer'; -export * from './RendererManager'; From 5a3db354d37380caaeb8b0dd7318f6b4a1ea0291 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 18 Apr 2024 20:49:34 +0800 Subject: [PATCH 062/101] chore: optimize --- ts/Renderer/CapabilityManager.ts | 4 ++ ts/Renderer/RendererManager.ts | 22 ++++++++- ts/Renderer/WebCodecsRendererCache.ts | 70 ++++++++++++++------------- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index d1c02ee82..b7cbfa98b 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -24,6 +24,10 @@ export class CapabilityManager { webCodecsDecoderEnabled: boolean = AgoraEnv.enableWebCodecsDecoder; private _engine: IRtcEngineEx; + setWebCodecsDecoderEnabled(enabled: boolean): void { + this.webCodecsDecoderEnabled = enabled; + } + constructor() { this._engine = createAgoraRtcEngine(); if (AgoraEnv.enableWebCodecsDecoder) { diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index ca188ada4..5b919b230 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -1,4 +1,9 @@ -import { VideoMirrorModeType, VideoViewSetupMode } from '../Private/AgoraBase'; +import createAgoraRtcEngine from '../AgoraSdk'; +import { + VideoMirrorModeType, + VideoStreamType, + VideoViewSetupMode, +} from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; import { AgoraEnv, isSupportWebGL, logDebug, logError } from '../Utils'; @@ -325,6 +330,21 @@ export class RendererManager { }; } + public handleWebCodecsFallback(rendererCache: WebCodecsRendererCache): void { + //todo need add some fallback logic + let engine = createAgoraRtcEngine(); + engine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); + if (rendererCache.context.uid) { + engine.setRemoteVideoSubscriptionOptions(rendererCache.context.uid, { + type: VideoStreamType.VideoStreamHigh, + encodedFrameOnly: false, + }); + } + rendererCache.release(); + AgoraEnv.enableWebCodecsDecoder = false; + AgoraEnv.CapabilityManager?.setWebCodecsDecoderEnabled(false); + } + public stopRendering(): void { if (this._renderingTimer) { window.clearTimeout(this._renderingTimer); diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index a7d0f8279..89930dc8e 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,4 +1,4 @@ -import createAgoraRtcEngine, { logError, logInfo } from '../AgoraSdk'; +import createAgoraRtcEngine from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; @@ -6,7 +6,7 @@ import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; import { RendererContext } from '../Types'; -import { AgoraEnv } from '../Utils'; +import { AgoraEnv, logInfo } from '../Utils'; import { IRendererCache } from './IRendererCache'; import { WebCodecsRenderer } from './WebCodecsRenderer/index'; @@ -29,16 +29,9 @@ export class WebCodecsRendererCache this.draw(); } - onDecoderError(e: any) { - logError('Decoder error:', e); - //todo need add some fallback logic - if (this.context.uid) { - this._engine?.setRemoteVideoSubscriptionOptions(this.context.uid, { - type: VideoStreamType.VideoStreamHigh, - encodedFrameOnly: false, - }); - } - this.release(); + onDecoderError() { + logInfo('webCodecsDecoder decode failed, fallback to native decoder'); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); } onEncodedVideoFrameReceived(...[data, buffer]: any) { @@ -57,17 +50,21 @@ export class WebCodecsRendererCache if (this._firstFrame) { let result = this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); if (!result) { - logInfo('Failed to configure decoder, stop decoding frames.'); - this.release(); + logInfo('failed to configure decoder, fallback to native decoder'); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); return; } this._firstFrame = false; } - this._decoder.decodeFrame( - buffer, - _data.videoEncodedFrameInfo, - new Date().getTime() - ); + if (this.fallback(_data.videoEncodedFrameInfo)) { + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); + } else { + this._decoder.decodeFrame( + buffer, + _data.videoEncodedFrameInfo, + new Date().getTime() + ); + } } onUserJoined(connection: RtcConnection, remoteUid: number, _elapsed: number) { @@ -96,23 +93,28 @@ export class WebCodecsRendererCache this._engine?.registerEventHandler(this); } - public fallback(frameInfo: EncodedVideoFrameInfo): void { - if ( - !frameInfo.codecType || - AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType] === - undefined - ) { + public fallback(frameInfo: EncodedVideoFrameInfo): boolean { + let shouldFallback = false; + if (!frameInfo.codecType) { + shouldFallback = true; logInfo('codecType is not supported, fallback to native decoder'); - return; + } else { + const mapping = + AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType]; + if (mapping === undefined) { + shouldFallback = true; + logInfo('codecType is not supported, fallback to native decoder'); + } else if ( + mapping.minWidth >= frameInfo.width! && + mapping.minHeight >= frameInfo.height! && + mapping.maxWidth <= frameInfo.width! && + mapping.maxHeight <= frameInfo.height! + ) { + shouldFallback = true; + logInfo('frame size is not supported, fallback to native decoder'); + } } - // if ( - // !frameInfo.codecType || - // AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType] === - // undefined - // ) { - // logInfo('codecType is not supported, fallback to native decoder'); - // return; - // } + return shouldFallback; } public release(): void { From 5cb72f66289a226f30f3cb5a9077785b0175cc84 Mon Sep 17 00:00:00 2001 From: gxz Date: Fri, 19 Apr 2024 19:12:00 +0800 Subject: [PATCH 063/101] chore: optimize --- ts/Renderer/IRendererCache.ts | 8 +++--- ts/Renderer/RendererCache.ts | 4 +-- ts/Renderer/RendererManager.ts | 16 ++++------- ts/Renderer/WebCodecsRendererCache.ts | 40 +++++++++------------------ ts/Types.ts | 11 ++------ 5 files changed, 28 insertions(+), 51 deletions(-) diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index 9dc21670b..43b6b920b 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -1,4 +1,4 @@ -import { RendererCacheContext, RendererContext } from '../Types'; +import { RendererContext } from '../Types'; import { IRenderer } from './IRenderer'; @@ -12,11 +12,11 @@ export function generateRendererCacheKey({ export abstract class IRendererCache { renderers: IRenderer[]; - context: RendererCacheContext; + context: RendererContext; - constructor({ channelId, uid, sourceType }: RendererContext) { + constructor(context: RendererContext) { this.renderers = []; - this.context = { channelId, uid, sourceType }; + this.context = context; } public get key(): string { diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index e1ecc4333..40051a8eb 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -11,8 +11,8 @@ export class RendererCache extends IRendererCache { private videoFrame: VideoFrame; private _enabled: boolean; - constructor({ channelId, uid, sourceType }: RendererContext) { - super({ channelId, uid, sourceType }); + constructor(context: RendererContext) { + super(context); this.videoFrame = { yBuffer: Buffer.alloc(0), uBuffer: Buffer.alloc(0), diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 5b919b230..71e3ced33 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -6,7 +6,7 @@ import { } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; import { RendererCacheType, RendererContext, RendererType } from '../Types'; -import { AgoraEnv, isSupportWebGL, logDebug, logError } from '../Utils'; +import { AgoraEnv, isSupportWebGL, logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; import { generateRendererCacheKey } from './IRendererCache'; @@ -101,11 +101,6 @@ export class RendererManager { context.enableFps = context.enableFps || false; if (!AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { - if (context.useWebCodecsDecoder) { - logError( - 'WebCodecsDecoder is not available now, fallback to native decoder' - ); - } context.useWebCodecsDecoder = false; } @@ -330,19 +325,20 @@ export class RendererManager { }; } - public handleWebCodecsFallback(rendererCache: WebCodecsRendererCache): void { + public handleWebCodecsFallback(context: RendererContext): void { //todo need add some fallback logic let engine = createAgoraRtcEngine(); engine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); - if (rendererCache.context.uid) { - engine.setRemoteVideoSubscriptionOptions(rendererCache.context.uid, { + if (context.uid) { + engine.setRemoteVideoSubscriptionOptions(context.uid, { type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: false, }); } - rendererCache.release(); + context.setupMode = VideoViewSetupMode.VideoViewSetupReplace; AgoraEnv.enableWebCodecsDecoder = false; AgoraEnv.CapabilityManager?.setWebCodecsDecoderEnabled(false); + this.addOrRemoveRenderer(context); } public stopRendering(): void { diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 89930dc8e..45380af28 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,8 +1,7 @@ import createAgoraRtcEngine from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; -import { IRtcEngineEventHandler } from '../Private/IAgoraRtcEngine'; -import { IRtcEngineEx, RtcConnection } from '../Private/IAgoraRtcEngineEx'; +import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; import { RendererContext } from '../Types'; @@ -11,16 +10,13 @@ import { AgoraEnv, logInfo } from '../Utils'; import { IRendererCache } from './IRendererCache'; import { WebCodecsRenderer } from './WebCodecsRenderer/index'; -export class WebCodecsRendererCache - extends IRendererCache - implements IRtcEngineEventHandler -{ +export class WebCodecsRendererCache extends IRendererCache { private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; private _firstFrame = true; - constructor({ channelId, uid, sourceType }: RendererContext) { - super({ channelId, uid, sourceType }); + constructor(context: RendererContext) { + super(context); this._engine = createAgoraRtcEngine(); this._decoder = new WebCodecsDecoder( this.renderers as WebCodecsRenderer[], @@ -31,7 +27,7 @@ export class WebCodecsRendererCache onDecoderError() { logInfo('webCodecsDecoder decode failed, fallback to native decoder'); - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); } onEncodedVideoFrameReceived(...[data, buffer]: any) { @@ -51,13 +47,13 @@ export class WebCodecsRendererCache let result = this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); if (!result) { logInfo('failed to configure decoder, fallback to native decoder'); - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); return; } this._firstFrame = false; } - if (this.fallback(_data.videoEncodedFrameInfo)) { - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this); + if (this.shouldFallback(_data.videoEncodedFrameInfo)) { + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); } else { this._decoder.decodeFrame( buffer, @@ -67,19 +63,11 @@ export class WebCodecsRendererCache } } - onUserJoined(connection: RtcConnection, remoteUid: number, _elapsed: number) { - if ( - remoteUid === this.context.uid && - connection.channelId === this.context.channelId - ) { - this._engine?.setRemoteVideoSubscriptionOptions(remoteUid, { - type: VideoStreamType.VideoStreamHigh, - encodedFrameOnly: true, - }); - } - } - public draw() { + this._engine?.setRemoteVideoSubscriptionOptions(this.context.uid!, { + type: VideoStreamType.VideoStreamHigh, + encodedFrameOnly: true, + }); AgoraElectronBridge.OnEvent( 'call_back_with_encoded_video_frame', (...params: any) => { @@ -90,10 +78,9 @@ export class WebCodecsRendererCache } } ); - this._engine?.registerEventHandler(this); } - public fallback(frameInfo: EncodedVideoFrameInfo): boolean { + public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean { let shouldFallback = false; if (!frameInfo.codecType) { shouldFallback = true; @@ -118,7 +105,6 @@ export class WebCodecsRendererCache } public release(): void { - this._engine?.unregisterEventHandler(this); AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; diff --git a/ts/Types.ts b/ts/Types.ts index 2752ccc3f..a66925950 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -80,11 +80,6 @@ export type RENDER_MODE = RendererType; export type RendererContext = VideoCanvas & RtcConnection; export type RendererCacheType = RendererCache | WebCodecsRendererCache; -export type RendererCacheContext = Pick< - RendererContext, - 'channelId' | 'uid' | 'sourceType' | 'useWebCodecsDecoder' | 'enableFps' ->; - /** * @ignore */ @@ -132,14 +127,14 @@ export interface IAgoraElectronBridge { ReleaseRenderer(): void; - EnableVideoFrameCache(context: RendererCacheContext): void; + EnableVideoFrameCache(context: RendererContext): void; - DisableVideoFrameCache(context: RendererCacheContext): void; + DisableVideoFrameCache(context: RendererContext): void; GetBuffer(ptr: number, length: number): Buffer; GetVideoFrame( - context: RendererCacheContext, + context: RendererContext, videoFrame: VideoFrame ): { ret: number; From 43ef0b5a616693c4d712578b0e780845f9806d7b Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 22 Apr 2024 12:02:58 +0800 Subject: [PATCH 064/101] chore: optimize --- ts/Decoder/index.ts | 5 ++++- ts/Renderer/CapabilityManager.ts | 27 +++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 955285fa4..f11658b6b 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -131,9 +131,12 @@ export class WebCodecsDecoder { } release() { - this.pendingFrame = null; try { + if (this.pendingFrame) { + this.pendingFrame.close(); + } this._decoder.close(); } catch (e) {} + this.pendingFrame = null; } } diff --git a/ts/Renderer/CapabilityManager.ts b/ts/Renderer/CapabilityManager.ts index b7cbfa98b..360208fd2 100644 --- a/ts/Renderer/CapabilityManager.ts +++ b/ts/Renderer/CapabilityManager.ts @@ -10,8 +10,8 @@ import { VideoCodecType } from '../Private/AgoraBase'; import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; import { ipcSend } from '../Private/ipc/renderer'; -import { IPCMessageType, codecMapping } from '../Types'; -import { AgoraEnv, logDebug, logError } from '../Utils'; +import { IPCMessageType, VideoFallbackStrategy, codecMapping } from '../Types'; +import { AgoraEnv, logError, logInfo } from '../Utils'; /** * @ignore @@ -32,20 +32,35 @@ export class CapabilityManager { this._engine = createAgoraRtcEngine(); if (AgoraEnv.enableWebCodecsDecoder) { this.getGpuInfo(() => { - if (AgoraEnv.videoFallbackStrategy === 0) { + if ( + AgoraEnv.videoFallbackStrategy === + VideoFallbackStrategy.PerformancePriority + ) { if (!this.isSupportedH265()) { if (this.isSupportedH264()) { this._engine.setParameters( JSON.stringify({ 'che.video.h265_dec_enable': false }) ); - logDebug('H265 is not supported, fallback to H264'); + logInfo( + 'the videoFallbackStrategy is PerformancePriority, H265 is not supported, fallback to H264' + ); } else { this.webCodecsDecoderEnabled = false; - logDebug( - 'H264 and H265 are not supported, fallback to native decoder' + logInfo( + 'the videoFallbackStrategy is PerformancePriority, H264 and H265 are not supported, fallback to native decoder' ); } } + } else if ( + AgoraEnv.videoFallbackStrategy === + VideoFallbackStrategy.BandwidthPriority + ) { + if (!this.isSupportedH265()) { + this.webCodecsDecoderEnabled = false; + logInfo( + 'the videoFallbackStrategy is BandwidthPriority, H265 is not supported, fallback to native decoder' + ); + } } }); } From f5ce76e950626935ecd8d1ccacdaf52386d23bb5 Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 23 Apr 2024 18:28:35 +0800 Subject: [PATCH 065/101] chore: optimize --- ts/Decoder/index.ts | 2 +- ts/Renderer/IRenderer.ts | 4 +++- ts/Renderer/RendererManager.ts | 3 ++- ts/Renderer/WebCodecsRenderer/index.ts | 18 ++++++------------ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index f11658b6b..21fc17ece 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -77,7 +77,7 @@ export class WebCodecsDecoder { if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { continue; } - renderer.setFrameSize({ + renderer.bind(renderer.context.view, { width: frameInfo.width!, height: frameInfo.height!, }); diff --git a/ts/Renderer/IRenderer.ts b/ts/Renderer/IRenderer.ts index 6a7c9f10c..ab5ca3e2b 100644 --- a/ts/Renderer/IRenderer.ts +++ b/ts/Renderer/IRenderer.ts @@ -2,6 +2,8 @@ import { VideoMirrorModeType } from '../Private/AgoraBase'; import { RenderModeType, VideoFrame } from '../Private/AgoraMediaBase'; import { RendererContext, RendererType } from '../Types'; +import { frameSize } from './WebCodecsRenderer'; + export abstract class IRenderer { parentElement?: HTMLElement; container?: HTMLElement; @@ -11,7 +13,7 @@ export abstract class IRenderer { private _frameCount = 0; private _startTime: number | null = null; - public bind(element: HTMLElement) { + public bind(element: HTMLElement, _frameSize?: frameSize) { this.parentElement = element; this.container = document.createElement('div'); Object.assign(this.container.style, { diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index 71e3ced33..a3b8fb380 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -237,16 +237,17 @@ export class RendererManager { renderer = new WebGLRenderer( this.handleWebGLFallback(context).bind(this) ); + renderer.bind(context.view); } break; case RendererType.SOFTWARE: renderer = new YUVCanvasRenderer(); + renderer.bind(context.view); break; default: throw new Error('Unknown renderer type'); } - renderer.bind(context.view); renderer.setContext(context); return renderer; } diff --git a/ts/Renderer/WebCodecsRenderer/index.ts b/ts/Renderer/WebCodecsRenderer/index.ts index 6d7989942..833817c01 100755 --- a/ts/Renderer/WebCodecsRenderer/index.ts +++ b/ts/Renderer/WebCodecsRenderer/index.ts @@ -2,7 +2,7 @@ import { RendererType } from '../../Types'; import { getContextByCanvas } from '../../Utils'; import { IRenderer } from '../IRenderer'; -type frameSize = { +export type frameSize = { width: number; height: number; }; @@ -35,9 +35,11 @@ export class WebCodecsRenderer extends IRenderer { } `; - bind(element: HTMLElement) { + bind(element: HTMLElement, frameSize: frameSize) { super.bind(element); if (!this.canvas) return; + this.canvas.width = frameSize.width; + this.canvas.height = frameSize.height; this.offscreenCanvas = this.canvas.transferControlToOffscreen(); this.gl = getContextByCanvas(this.offscreenCanvas); if (!this.gl) return; @@ -103,18 +105,10 @@ export class WebCodecsRenderer extends IRenderer { ); } - setFrameSize(frameSize: frameSize) { - if (!this.offscreenCanvas) return; - this.offscreenCanvas.width = frameSize.width; - this.offscreenCanvas.height = frameSize.height; - } - drawFrame(frame: any) { if (!this.offscreenCanvas || !frame) return; - this.setFrameSize({ - width: frame.displayWidth, - height: frame.displayHeight, - }); + this.offscreenCanvas.width = frame.displayWidth; + this.offscreenCanvas.height = frame.displayHeight; this.updateRenderMode(); if (!this.gl) return; From 2a76c5a0463bc2a88251f9aaf1d5737fcc976697 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 24 Apr 2024 11:26:28 +0800 Subject: [PATCH 066/101] chore: optimize --- ts/Decoder/index.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 21fc17ece..8d33e952a 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -57,6 +57,16 @@ export class WebCodecsDecoder { } decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { + for (let renderer of this.renderers) { + if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { + continue; + } + renderer.bind(renderer.context.view, { + width: frameInfo.width!, + height: frameInfo.height!, + }); + this.pendingFrame = null; + } // @ts-ignore let codec = AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!] @@ -73,16 +83,6 @@ export class WebCodecsDecoder { logInfo( `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` ); - for (let renderer of this.renderers) { - if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { - continue; - } - renderer.bind(renderer.context.view, { - width: frameInfo.width!, - height: frameInfo.height!, - }); - this.pendingFrame = null; - } return true; } From eb04ca43bdc98ac6b5dfc35a73381bb2dda58ff6 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 25 Apr 2024 14:27:26 +0800 Subject: [PATCH 067/101] chore: optimize --- .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 5ad1f6797..454f1487b 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -58,7 +58,6 @@ export default class VideoDecoder // will automatically register videoEncodedFrameObserver // videoEncodedFrameObserver will be released when engine.release AgoraEnv.enableWebCodecsDecoder = true; - AgoraEnv.videoFallbackStrategy = 0; this.engine.setLogLevel(16); this.engine.initialize({ appId, From 614148317b59d9d0de1e564735aa213ef9011648 Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 28 Apr 2024 14:45:50 +0800 Subject: [PATCH 068/101] chore: optimize --- ts/Decoder/index.ts | 93 ++++++++++++++++++--------- ts/Renderer/WebCodecsRendererCache.ts | 23 +++++-- 2 files changed, 80 insertions(+), 36 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 8d33e952a..a7ad14e9a 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -1,7 +1,11 @@ -import { EncodedVideoFrameInfo, VideoFrameType } from '../Private/AgoraBase'; +import { + EncodedVideoFrameInfo, + VideoCodecType, + VideoFrameType, +} from '../Private/AgoraBase'; import { WebCodecsRenderer } from '../Renderer/WebCodecsRenderer/index'; -import { RendererType } from '../Types'; +import { RendererContext, RendererType } from '../Types'; import { AgoraEnv, logDebug, logInfo } from '../Utils'; const frameTypeMapping = { @@ -13,14 +17,21 @@ const frameTypeMapping = { export class WebCodecsDecoder { private _decoder: VideoDecoder; private renderers: WebCodecsRenderer[] = []; + private _context: RendererContext; private pendingFrame: VideoFrame | null = null; + private _currentCodecType: VideoCodecType | undefined; private _base_ts = 0; private _base_ts_ntp = 1; private _last_ts_ntp = 1; - constructor(renders: WebCodecsRenderer[], onError: (e: any) => void) { + constructor( + renders: WebCodecsRenderer[], + onError: (e: any) => void, + context: RendererContext + ) { this.renderers = renders; + this._context = context; this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), @@ -56,25 +67,19 @@ export class WebCodecsDecoder { } } - decoderConfigure(frameInfo: EncodedVideoFrameInfo): boolean { - for (let renderer of this.renderers) { - if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { - continue; - } - renderer.bind(renderer.context.view, { - width: frameInfo.width!, - height: frameInfo.height!, - }); - this.pendingFrame = null; - } + decoderConfigure(frameInfo: EncodedVideoFrameInfo) { + this.pendingFrame = null; // @ts-ignore let codec = AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!] ?.codec; if (!codec) { - logInfo('codec is not in frameCodecMapping, stop decode frame'); - return false; + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this._context); + throw new Error( + 'codec is not in frameCodecMapping,failed to configure decoder, fallback to native decoder' + ); } + this._currentCodecType = frameInfo.codecType; this._decoder!.configure({ codec: codec, codedWidth: frameInfo.width, @@ -83,7 +88,30 @@ export class WebCodecsDecoder { logInfo( `configure decoder: codedWidth: ${frameInfo.width}, codedHeight: ${frameInfo.height},codec: ${codec}` ); - return true; + } + + updateTimestamps(ts: number) { + if (this._base_ts !== 0) { + if (ts > this._base_ts) { + this._last_ts_ntp = + this._base_ts_ntp + Math.floor(((ts - this._base_ts) * 1000) / 90); + } else { + this._base_ts = ts; + this._last_ts_ntp++; + this._base_ts_ntp = this._last_ts_ntp; + } + } else { + this._base_ts = ts; + this._last_ts_ntp = 1; + } + } + + handleCodecIsChanged(frameInfo: EncodedVideoFrameInfo) { + if (this._currentCodecType !== frameInfo.codecType) { + logInfo('codecType is changed, reconfigure decoder'); + this._decoder.reset(); + this.decoderConfigure(frameInfo); + } } // @ts-ignore @@ -92,10 +120,18 @@ export class WebCodecsDecoder { frameInfo: EncodedVideoFrameInfo, ts: number ) { + try { + this.handleCodecIsChanged(frameInfo); + } catch (error: any) { + logInfo(error); + return; + } + if (!imageBuffer) { logDebug('imageBuffer is empty, skip decode frame'); return; } + let frameType: string | undefined; if (frameInfo.frameType !== undefined) { // @ts-ignore @@ -105,19 +141,9 @@ export class WebCodecsDecoder { logDebug('frameType is not in frameTypeMapping, skip decode frame'); return; } - if (this._base_ts !== 0) { - if (ts > this._base_ts) { - this._last_ts_ntp = - this._base_ts_ntp + Math.floor(((ts - this._base_ts) * 1000) / 90); - } else { - this._base_ts = ts; - this._last_ts_ntp++; - this._base_ts_ntp = this._last_ts_ntp; - } - } else { - this._base_ts = ts; - this._last_ts_ntp = 1; - } + + this.updateTimestamps(ts); + this._decoder.decode( new EncodedVideoChunk({ data: imageBuffer, @@ -130,6 +156,13 @@ export class WebCodecsDecoder { ); } + reset() { + this._base_ts = 0; + this._base_ts_ntp = 1; + this._last_ts_ntp = 1; + this._decoder.reset(); + } + release() { try { if (this.pendingFrame) { diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 45380af28..9894d1efa 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -4,7 +4,7 @@ import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; -import { RendererContext } from '../Types'; +import { RendererContext, RendererType } from '../Types'; import { AgoraEnv, logInfo } from '../Utils'; import { IRendererCache } from './IRendererCache'; @@ -20,7 +20,8 @@ export class WebCodecsRendererCache extends IRendererCache { this._engine = createAgoraRtcEngine(); this._decoder = new WebCodecsDecoder( this.renderers as WebCodecsRenderer[], - this.onDecoderError.bind(this) + this.onDecoderError.bind(this), + context ); this.draw(); } @@ -44,10 +45,20 @@ export class WebCodecsRendererCache extends IRendererCache { ) return; if (this._firstFrame) { - let result = this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); - if (!result) { - logInfo('failed to configure decoder, fallback to native decoder'); - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); + for (let renderer of this.renderers) { + if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { + continue; + } + renderer.bind(renderer.context.view, { + width: _data.videoEncodedFrameInfo.width!, + height: _data.videoEncodedFrameInfo.height!, + }); + } + + try { + this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); + } catch (error: any) { + logInfo(error); return; } this._firstFrame = false; From 0b2109bffcc865c1398c4bf20187bfbe9e485516 Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 28 Apr 2024 15:33:17 +0800 Subject: [PATCH 069/101] chore: optimize --- ts/Decoder/index.ts | 12 +++++++----- ts/Renderer/IRendererCache.ts | 22 +++++++++++++++++----- ts/Renderer/RendererCache.ts | 8 ++++---- ts/Renderer/RendererManager.ts | 19 ++++++++++++++----- ts/Renderer/WebCodecsRendererCache.ts | 8 ++++---- ts/Types.ts | 11 ++++++++--- 6 files changed, 54 insertions(+), 26 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index a7ad14e9a..f276e8dde 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -5,7 +5,7 @@ import { } from '../Private/AgoraBase'; import { WebCodecsRenderer } from '../Renderer/WebCodecsRenderer/index'; -import { RendererContext, RendererType } from '../Types'; +import { RendererCacheContext, RendererType } from '../Types'; import { AgoraEnv, logDebug, logInfo } from '../Utils'; const frameTypeMapping = { @@ -17,7 +17,7 @@ const frameTypeMapping = { export class WebCodecsDecoder { private _decoder: VideoDecoder; private renderers: WebCodecsRenderer[] = []; - private _context: RendererContext; + private _cacheContext: RendererCacheContext; private pendingFrame: VideoFrame | null = null; private _currentCodecType: VideoCodecType | undefined; @@ -28,10 +28,10 @@ export class WebCodecsDecoder { constructor( renders: WebCodecsRenderer[], onError: (e: any) => void, - context: RendererContext + context: RendererCacheContext ) { this.renderers = renders; - this._context = context; + this._cacheContext = context; this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), @@ -74,7 +74,9 @@ export class WebCodecsDecoder { AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType!] ?.codec; if (!codec) { - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this._context); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback( + this._cacheContext + ); throw new Error( 'codec is not in frameCodecMapping,failed to configure decoder, fallback to native decoder' ); diff --git a/ts/Renderer/IRendererCache.ts b/ts/Renderer/IRendererCache.ts index 43b6b920b..ff024aa01 100644 --- a/ts/Renderer/IRendererCache.ts +++ b/ts/Renderer/IRendererCache.ts @@ -1,4 +1,4 @@ -import { RendererContext } from '../Types'; +import { RendererCacheContext, RendererContext } from '../Types'; import { IRenderer } from './IRenderer'; @@ -12,15 +12,27 @@ export function generateRendererCacheKey({ export abstract class IRendererCache { renderers: IRenderer[]; - context: RendererContext; + cacheContext: RendererCacheContext; - constructor(context: RendererContext) { + constructor({ + channelId, + uid, + useWebCodecsDecoder, + enableFps, + sourceType, + }: RendererContext) { this.renderers = []; - this.context = context; + this.cacheContext = { + channelId, + uid, + useWebCodecsDecoder, + enableFps, + sourceType, + }; } public get key(): string { - return generateRendererCacheKey(this.context); + return generateRendererCacheKey(this.cacheContext); } public abstract draw(): void; diff --git a/ts/Renderer/RendererCache.ts b/ts/Renderer/RendererCache.ts index 40051a8eb..e67e0f8d2 100644 --- a/ts/Renderer/RendererCache.ts +++ b/ts/Renderer/RendererCache.ts @@ -36,13 +36,13 @@ export class RendererCache extends IRendererCache { private enable() { if (this._enabled) return; - AgoraElectronBridge.EnableVideoFrameCache(this.context); + AgoraElectronBridge.EnableVideoFrameCache(this.cacheContext); this._enabled = true; } private disable() { if (!this._enabled) return; - AgoraElectronBridge.DisableVideoFrameCache(this.context); + AgoraElectronBridge.DisableVideoFrameCache(this.cacheContext); this._enabled = false; } @@ -56,7 +56,7 @@ export class RendererCache extends IRendererCache { override draw() { let { ret, isNewFrame } = AgoraElectronBridge.GetVideoFrame( - this.context, + this.cacheContext, this.videoFrame ); @@ -71,7 +71,7 @@ export class RendererCache extends IRendererCache { this.videoFrame.vBuffer = Buffer.alloc(vStride! * height!); const result = AgoraElectronBridge.GetVideoFrame( - this.context, + this.cacheContext, this.videoFrame ); ret = result.ret; diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index a3b8fb380..f8a80a16c 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -5,7 +5,12 @@ import { VideoViewSetupMode, } from '../Private/AgoraBase'; import { RenderModeType, VideoSourceType } from '../Private/AgoraMediaBase'; -import { RendererCacheType, RendererContext, RendererType } from '../Types'; +import { + RendererCacheContext, + RendererCacheType, + RendererContext, + RendererType, +} from '../Types'; import { AgoraEnv, isSupportWebGL, logDebug } from '../Utils'; import { IRenderer } from './IRenderer'; @@ -326,8 +331,7 @@ export class RendererManager { }; } - public handleWebCodecsFallback(context: RendererContext): void { - //todo need add some fallback logic + public handleWebCodecsFallback(context: RendererCacheContext): void { let engine = createAgoraRtcEngine(); engine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); if (context.uid) { @@ -336,10 +340,15 @@ export class RendererManager { encodedFrameOnly: false, }); } - context.setupMode = VideoViewSetupMode.VideoViewSetupReplace; AgoraEnv.enableWebCodecsDecoder = false; AgoraEnv.CapabilityManager?.setWebCodecsDecoderEnabled(false); - this.addOrRemoveRenderer(context); + let renderers = this.getRenderers(context); + for (let renderer of renderers) { + this.addOrRemoveRenderer({ + ...renderer.context, + setupMode: VideoViewSetupMode.VideoViewSetupReplace, + }); + } } public stopRendering(): void { diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 9894d1efa..ef9a9471a 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -28,7 +28,7 @@ export class WebCodecsRendererCache extends IRendererCache { onDecoderError() { logInfo('webCodecsDecoder decode failed, fallback to native decoder'); - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } onEncodedVideoFrameReceived(...[data, buffer]: any) { @@ -41,7 +41,7 @@ export class WebCodecsRendererCache extends IRendererCache { if ( Object.keys(_data).length === 0 || !this._decoder || - this.context.uid !== _data.uid + this.cacheContext.uid !== _data.uid ) return; if (this._firstFrame) { @@ -64,7 +64,7 @@ export class WebCodecsRendererCache extends IRendererCache { this._firstFrame = false; } if (this.shouldFallback(_data.videoEncodedFrameInfo)) { - AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.context); + AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } else { this._decoder.decodeFrame( buffer, @@ -75,7 +75,7 @@ export class WebCodecsRendererCache extends IRendererCache { } public draw() { - this._engine?.setRemoteVideoSubscriptionOptions(this.context.uid!, { + this._engine?.setRemoteVideoSubscriptionOptions(this.cacheContext.uid!, { type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); diff --git a/ts/Types.ts b/ts/Types.ts index a66925950..2752ccc3f 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -80,6 +80,11 @@ export type RENDER_MODE = RendererType; export type RendererContext = VideoCanvas & RtcConnection; export type RendererCacheType = RendererCache | WebCodecsRendererCache; +export type RendererCacheContext = Pick< + RendererContext, + 'channelId' | 'uid' | 'sourceType' | 'useWebCodecsDecoder' | 'enableFps' +>; + /** * @ignore */ @@ -127,14 +132,14 @@ export interface IAgoraElectronBridge { ReleaseRenderer(): void; - EnableVideoFrameCache(context: RendererContext): void; + EnableVideoFrameCache(context: RendererCacheContext): void; - DisableVideoFrameCache(context: RendererContext): void; + DisableVideoFrameCache(context: RendererCacheContext): void; GetBuffer(ptr: number, length: number): Buffer; GetVideoFrame( - context: RendererContext, + context: RendererCacheContext, videoFrame: VideoFrame ): { ret: number; From ee1c5e8c88a2682a30de7d64a1abc7517f7a8118 Mon Sep 17 00:00:00 2001 From: gxz Date: Sun, 28 Apr 2024 16:01:31 +0800 Subject: [PATCH 070/101] chore: optimize --- .../src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx | 1 - package.json | 2 +- source_code/agora_node_ext/node_iris_event_handler.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx index 454f1487b..86a3610cd 100644 --- a/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx +++ b/example/src/renderer/examples/basic/VideoDecoder/VideoDecoder.tsx @@ -58,7 +58,6 @@ export default class VideoDecoder // will automatically register videoEncodedFrameObserver // videoEncodedFrameObserver will be released when engine.release AgoraEnv.enableWebCodecsDecoder = true; - this.engine.setLogLevel(16); this.engine.initialize({ appId, logConfig: { filePath: Config.logFilePath }, diff --git a/package.json b/package.json index dce9ebd08..c315dea84 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Windows_Video_20240407_0427.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.4_DCG_Windows_Video_20240424_0449.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" } } diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index e4ed55224..33a5dee9c 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -6,7 +6,6 @@ */ #include "node_iris_event_handler.h" #include "agora_electron_bridge.h" -#include #include #include From 86702443fdb98d38ad646de955c4f8799d00c4f7 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 8 May 2024 20:46:20 +0800 Subject: [PATCH 071/101] chore: optimize --- scripts/getConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/getConfig.js b/scripts/getConfig.js index 2589a0b92..924ed148f 100644 --- a/scripts/getConfig.js +++ b/scripts/getConfig.js @@ -21,7 +21,7 @@ const getArgvFromPkgJson = () => { debug = false, silent = false, arch = process.arch, - no_symbol = true, + no_symbol = false, } = agora_electron; return { From afce12211676821575319670db70f38792d91f89 Mon Sep 17 00:00:00 2001 From: gxz Date: Wed, 8 May 2024 21:18:44 +0800 Subject: [PATCH 072/101] chore: optimize --- .github/workflows/build.yml | 72 ++++++++++++++++++------------------- scripts/downloadPrebuild.js | 6 ++-- scripts/getConfig.js | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f9d5a82e..b2ea40aa0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} strategy: matrix: - arch: [ ia32, x64 ] + arch: [ ia32 ] runs-on: windows-latest env: npm_config_arch: ${{ matrix.arch }} @@ -76,41 +76,41 @@ jobs: example/dist/Agora-Electron-API-Example-*-win.zip if-no-files-found: error - build-mac: - if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 + # build-mac: + # if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} + # runs-on: macos-latest + # steps: + # - uses: actions/checkout@v4 - - name: Setup - uses: ./.github/actions/setup + # - name: Setup + # uses: ./.github/actions/setup - - name: Build SDK - run: | - yarn totalBuild - yarn zipBuild - yarn link + # - name: Build SDK + # run: | + # yarn totalBuild + # yarn zipBuild + # yarn link - - name: Build Example - run: | - yarn install - yarn link agora-electron-sdk - yarn dist:mac - yarn unlink agora-electron-sdk - env: - USE_HARD_LINKS: false - working-directory: example - - - uses: actions/upload-artifact@v3 - with: - name: AgoraRtcNgExample-mac - path: | - example/dist/Agora-Electron-API-Example-*-mac.zip - if-no-files-found: error - - notification: - runs-on: ubuntu-latest - needs: [ build-windows, build-mac ] - steps: - - run: | - curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' + # - name: Build Example + # run: | + # yarn install + # yarn link agora-electron-sdk + # yarn dist:mac + # yarn unlink agora-electron-sdk + # env: + # USE_HARD_LINKS: false + # working-directory: example + + # - uses: actions/upload-artifact@v3 + # with: + # name: AgoraRtcNgExample-mac + # path: | + # example/dist/Agora-Electron-API-Example-*-mac.zip + # if-no-files-found: error + + # notification: + # runs-on: ubuntu-latest + # needs: [ build-windows, build-mac ] + # steps: + # - run: | + # curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' diff --git a/scripts/downloadPrebuild.js b/scripts/downloadPrebuild.js index 3e6bcb379..ab60e1d26 100644 --- a/scripts/downloadPrebuild.js +++ b/scripts/downloadPrebuild.js @@ -93,7 +93,7 @@ module.exports = async () => { }, }); - if (no_symbol) { - await removeFileByFilter(); - } + // if (no_symbol) { + // await removeFileByFilter(); + // } }; diff --git a/scripts/getConfig.js b/scripts/getConfig.js index 924ed148f..2589a0b92 100644 --- a/scripts/getConfig.js +++ b/scripts/getConfig.js @@ -21,7 +21,7 @@ const getArgvFromPkgJson = () => { debug = false, silent = false, arch = process.arch, - no_symbol = false, + no_symbol = true, } = agora_electron; return { From 95047cb1ca3e34867ba8571e43fea6b18c71e5f3 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 10:53:17 +0800 Subject: [PATCH 073/101] chore: reconfig when width and height changed --- ts/Decoder/index.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index f276e8dde..7c6cec465 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -19,7 +19,11 @@ export class WebCodecsDecoder { private renderers: WebCodecsRenderer[] = []; private _cacheContext: RendererCacheContext; private pendingFrame: VideoFrame | null = null; - private _currentCodecType: VideoCodecType | undefined; + private _currentCodecConfig: { + codecType: VideoCodecType | undefined; + codedWidth: number | undefined; + codedHeight: number | undefined; + } | null = null; private _base_ts = 0; private _base_ts_ntp = 1; @@ -81,7 +85,11 @@ export class WebCodecsDecoder { 'codec is not in frameCodecMapping,failed to configure decoder, fallback to native decoder' ); } - this._currentCodecType = frameInfo.codecType; + this._currentCodecConfig = { + codecType: frameInfo.codecType, + codedWidth: frameInfo.width, + codedHeight: frameInfo.height, + }; this._decoder!.configure({ codec: codec, codedWidth: frameInfo.width, @@ -109,7 +117,11 @@ export class WebCodecsDecoder { } handleCodecIsChanged(frameInfo: EncodedVideoFrameInfo) { - if (this._currentCodecType !== frameInfo.codecType) { + if ( + this._currentCodecConfig?.codecType !== frameInfo.codecType || + this._currentCodecConfig?.codedWidth !== frameInfo.width || + this._currentCodecConfig?.codedHeight !== frameInfo.height + ) { logInfo('codecType is changed, reconfigure decoder'); this._decoder.reset(); this.decoderConfigure(frameInfo); From 617d16087864ecfa7533f09d869d6b67e0e61a2a Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 10:54:06 +0800 Subject: [PATCH 074/101] chore: optimize --- .github/workflows/build.yml | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b2ea40aa0..00492d361 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} strategy: matrix: - arch: [ ia32 ] + arch: [ ia32, x64 ] runs-on: windows-latest env: npm_config_arch: ${{ matrix.arch }} @@ -76,41 +76,41 @@ jobs: example/dist/Agora-Electron-API-Example-*-win.zip if-no-files-found: error - # build-mac: - # if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} - # runs-on: macos-latest - # steps: - # - uses: actions/checkout@v4 + build-mac: + if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 - # - name: Setup - # uses: ./.github/actions/setup + - name: Setup + uses: ./.github/actions/setup - # - name: Build SDK - # run: | - # yarn totalBuild - # yarn zipBuild - # yarn link + - name: Build SDK + run: | + yarn totalBuild + yarn zipBuild + yarn link - # - name: Build Example - # run: | - # yarn install - # yarn link agora-electron-sdk - # yarn dist:mac - # yarn unlink agora-electron-sdk - # env: - # USE_HARD_LINKS: false - # working-directory: example + - name: Build Example + run: | + yarn install + yarn link agora-electron-sdk + yarn dist:mac + yarn unlink agora-electron-sdk + env: + USE_HARD_LINKS: false + working-directory: example - # - uses: actions/upload-artifact@v3 - # with: - # name: AgoraRtcNgExample-mac - # path: | - # example/dist/Agora-Electron-API-Example-*-mac.zip - # if-no-files-found: error + - uses: actions/upload-artifact@v3 + with: + name: AgoraRtcNgExample-mac + path: | + example/dist/Agora-Electron-API-Example-*-mac.zip + if-no-files-found: error - # notification: - # runs-on: ubuntu-latest - # needs: [ build-windows, build-mac ] - # steps: - # - run: | - # curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' + notification: + runs-on: ubuntu-latest + needs: [ build-windows, build-mac ] + steps: + - run: | + curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' From 4257aa615a415df64e9cae61a24792670ecc99d8 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 12:02:23 +0800 Subject: [PATCH 075/101] chore: optimize --- .github/workflows/build.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00492d361..5fde90846 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,11 @@ on: options: - demo - sdk + debug: + description: 'debug package' + required: false + default: false + type: boolean release: types: [ published ] pull_request: @@ -55,6 +60,12 @@ jobs: - name: Setup uses: ./.github/actions/setup + - name: Debug Config + if: ${{ inputs.debug }} + run: | + export npm_config_debug=true + export npm_config_no_symbol=false + - name: Build SDK run: | yarn totalBuild From ebc4a0718dc37849d79f7fd6996fbdab69bfebe2 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:10:21 +0800 Subject: [PATCH 076/101] chore: optimize --- .github/workflows/build.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5fde90846..b7911b7c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,8 +63,8 @@ jobs: - name: Debug Config if: ${{ inputs.debug }} run: | - export npm_config_debug=true - export npm_config_no_symbol=false + set npm_config_debug=true + set npm_config_no_symbol=false - name: Build SDK run: | @@ -96,6 +96,12 @@ jobs: - name: Setup uses: ./.github/actions/setup + - name: Debug Config + if: ${{ inputs.debug }} + run: | + export npm_config_debug=true + export npm_config_no_symbol=false + - name: Build SDK run: | yarn totalBuild From 53bd3041a12aa49a47de1bb923f33efb42b1f0c7 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:21:55 +0800 Subject: [PATCH 077/101] chore: optimize --- .github/workflows/build.yml | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b7911b7c0..1dedbffd6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ on: default: false type: boolean release: - types: [ published ] + types: [published] pull_request: types: [labeled, synchronize] @@ -47,7 +47,7 @@ jobs: if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} strategy: matrix: - arch: [ ia32, x64 ] + arch: [ia32, x64] runs-on: windows-latest env: npm_config_arch: ${{ matrix.arch }} @@ -60,15 +60,13 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Debug Config - if: ${{ inputs.debug }} - run: | - set npm_config_debug=true - set npm_config_no_symbol=false - - name: Build SDK run: | - yarn totalBuild + if [[ "${{ inputs.debug }}" == "true" ]]; then + yarn totalBuild --debug=true --no_symbol=false + else + yarn totalBuild + fi yarn zipBuild yarn link @@ -96,15 +94,13 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Debug Config - if: ${{ inputs.debug }} - run: | - export npm_config_debug=true - export npm_config_no_symbol=false - - name: Build SDK run: | - yarn totalBuild + if [[ "${{ inputs.debug }}" == "true" ]]; then + yarn totalBuild --debug=true --no_symbol=false + else + yarn totalBuild + fi yarn zipBuild yarn link @@ -127,7 +123,7 @@ jobs: notification: runs-on: ubuntu-latest - needs: [ build-windows, build-mac ] + needs: [build-windows, build-mac] steps: - run: | curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' From 1af394c00f6a4915e75259bc14dd170b452bb0ba Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:27:55 +0800 Subject: [PATCH 078/101] chore: optimize --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1dedbffd6..36981e08f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,11 +62,11 @@ jobs: - name: Build SDK run: | - if [[ "${{ inputs.debug }}" == "true" ]]; then + if ("${{ inputs.debug }}" -eq "true") { yarn totalBuild --debug=true --no_symbol=false - else + } else { yarn totalBuild - fi + } yarn zipBuild yarn link From 83c89fa6a8b37a6a47a452aec056e98b09dde9b2 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:43:15 +0800 Subject: [PATCH 079/101] chore: optimize --- .github/workflows/build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36981e08f..3430601f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,6 +60,14 @@ jobs: - name: Setup uses: ./.github/actions/setup + - name: Add VS to PATH + if: ${{ inputs.debug }} + shell: pwsh + run: | + $vsPath = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -version [16,17) -products * -requires Microsoft.Component.MSBuild -property installationPath + $vsPath = Join-Path $vsPath "Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin" + echo "$vsPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Build SDK run: | if ("${{ inputs.debug }}" -eq "true") { From 732d62b92136f1464b8f0f418a65953abbba18da Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:48:14 +0800 Subject: [PATCH 080/101] chore: optimize --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3430601f1..51dbf5d8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: if: ${{ inputs.debug }} shell: pwsh run: | - $vsPath = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -version [16,17) -products * -requires Microsoft.Component.MSBuild -property installationPath + $vsPath = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -version "16,17" -products * -requires Microsoft.Component.MSBuild -property installationPath $vsPath = Join-Path $vsPath "Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin" echo "$vsPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append From 20e28a0a4e02b74b2d590bf6d7a97b57b9863b72 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 13:54:58 +0800 Subject: [PATCH 081/101] chore: optimize --- .github/workflows/build.yml | 8 -------- package.json | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51dbf5d8b..36981e08f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,14 +60,6 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Add VS to PATH - if: ${{ inputs.debug }} - shell: pwsh - run: | - $vsPath = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -version "16,17" -products * -requires Microsoft.Component.MSBuild -property installationPath - $vsPath = Join-Path $vsPath "Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin" - echo "$vsPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Build SDK run: | if ("${{ inputs.debug }}" -eq "true") { diff --git a/package.json b/package.json index c315dea84..b9c100ecd 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "prepack": "cross-env-shell npm run buildJS \\\"--INIT_CWD=$INIT_CWD\\\"", "build_mac_debug": "cmake-js rebuild --CDCMAKE_BUILD_TYPE=Debug --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" -G Xcode", "build_mac_release": "cmake-js rebuild --CDCMAKE_BUILD_TYPE=Release --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" -G Xcode", - "build_windows_win32_debug": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Debug -G \"Visual Studio 16 2019\" ", + "build_windows_win32_debug": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Debug", "build_windows_win32_release": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Release", - "build_windows_x64_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Debug -G \"Visual Studio 16 2019\"", + "build_windows_x64_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Debug", "build_windows_x64_release": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Release", "build_linux_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_BUILD_TYPE=Debug -G \"Unix Makefiles\"", "build_linux_release": "cmake-js rebuild --arch=x64 --CDCMAKE_BUILD_TYPE=Release -G \"Unix Makefiles\"", From f135da7db7fdec326b9e8050b9b6211a34307653 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 14:12:27 +0800 Subject: [PATCH 082/101] chore: optimize --- .github/workflows/build.yml | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36981e08f..2d07f40ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: strategy: matrix: arch: [ia32, x64] - runs-on: windows-latest + runs-on: windows-2019 env: npm_config_arch: ${{ matrix.arch }} npm_config_agora_electron_arch: ${{ matrix.arch }} diff --git a/package.json b/package.json index b9c100ecd..c315dea84 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "prepack": "cross-env-shell npm run buildJS \\\"--INIT_CWD=$INIT_CWD\\\"", "build_mac_debug": "cmake-js rebuild --CDCMAKE_BUILD_TYPE=Debug --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" -G Xcode", "build_mac_release": "cmake-js rebuild --CDCMAKE_BUILD_TYPE=Release --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" -G Xcode", - "build_windows_win32_debug": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Debug", + "build_windows_win32_debug": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Debug -G \"Visual Studio 16 2019\" ", "build_windows_win32_release": "cmake-js rebuild --arch=ia32 --CDCMAKE_OSX_ARCHITECTURES=\"i386\" --CDCMAKE_BUILD_TYPE=Release", - "build_windows_x64_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Debug", + "build_windows_x64_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Debug -G \"Visual Studio 16 2019\"", "build_windows_x64_release": "cmake-js rebuild --arch=x64 --CDCMAKE_OSX_ARCHITECTURES=\"x86_64\" --CDCMAKE_BUILD_TYPE=Release", "build_linux_debug": "cmake-js rebuild --arch=x64 --CDCMAKE_BUILD_TYPE=Debug -G \"Unix Makefiles\"", "build_linux_release": "cmake-js rebuild --arch=x64 --CDCMAKE_BUILD_TYPE=Release -G \"Unix Makefiles\"", From c8c88f3fef7fd913ae38b036b03b3f8bc3d79184 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 14:52:24 +0800 Subject: [PATCH 083/101] chore: optimize --- .github/workflows/build.yml | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d07f40ea..00492d361 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,13 +22,8 @@ on: options: - demo - sdk - debug: - description: 'debug package' - required: false - default: false - type: boolean release: - types: [published] + types: [ published ] pull_request: types: [labeled, synchronize] @@ -47,8 +42,8 @@ jobs: if: ${{ inputs.type == 'demo' || contains(github.event.pull_request.labels.*.name, 'ci:dep-update') }} strategy: matrix: - arch: [ia32, x64] - runs-on: windows-2019 + arch: [ ia32, x64 ] + runs-on: windows-latest env: npm_config_arch: ${{ matrix.arch }} npm_config_agora_electron_arch: ${{ matrix.arch }} @@ -62,11 +57,7 @@ jobs: - name: Build SDK run: | - if ("${{ inputs.debug }}" -eq "true") { - yarn totalBuild --debug=true --no_symbol=false - } else { - yarn totalBuild - } + yarn totalBuild yarn zipBuild yarn link @@ -96,11 +87,7 @@ jobs: - name: Build SDK run: | - if [[ "${{ inputs.debug }}" == "true" ]]; then - yarn totalBuild --debug=true --no_symbol=false - else - yarn totalBuild - fi + yarn totalBuild yarn zipBuild yarn link @@ -123,7 +110,7 @@ jobs: notification: runs-on: ubuntu-latest - needs: [build-windows, build-mac] + needs: [ build-windows, build-mac ] steps: - run: | curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_KEY }}" -d '{"msgtype":"text","text":{"content":"Electron Example:\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nDownload Link:\nhttps://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}' From 16520bec2ab2f70d404ea0191d800a34bec71aa4 Mon Sep 17 00:00:00 2001 From: gxz Date: Thu, 9 May 2024 15:07:32 +0800 Subject: [PATCH 084/101] chore: optimize --- example/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/example/package.json b/example/package.json index 3629877e0..7d755b1c3 100644 --- a/example/package.json +++ b/example/package.json @@ -15,6 +15,7 @@ }, "build": { "appId": "agora.io.ElectronApiExample", + "includePdb": true, "asar": true, "asarUnpack": [ "node_modules/agora-electron-sdk" From 29aa87d61cc7de6de1b0b40d65555f5e64e3c889 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:02:28 +0800 Subject: [PATCH 085/101] chore: optimize --- .../agora_node_ext/agora_electron_bridge.cpp | 25 --------- .../agora_node_ext/agora_electron_bridge.h | 1 - .../node_iris_event_handler.cpp | 46 +---------------- .../agora_node_ext/node_iris_event_handler.h | 3 -- ts/Decoder/index.ts | 2 +- ts/Renderer/WebCodecsRendererCache.ts | 51 +++++++------------ ts/Types.ts | 2 - 7 files changed, 22 insertions(+), 108 deletions(-) diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index b06b508b4..440e0966a 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -40,7 +40,6 @@ napi_value AgoraElectronBridge::Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_METHOD("CallApi", CallApi), DECLARE_NAPI_METHOD("OnEvent", OnEvent), - DECLARE_NAPI_METHOD("UnEvent", UnEvent), DECLARE_NAPI_METHOD("GetBuffer", GetBuffer), DECLARE_NAPI_METHOD("EnableVideoFrameCache", EnableVideoFrameCache), DECLARE_NAPI_METHOD("DisableVideoFrameCache", DisableVideoFrameCache), @@ -251,30 +250,6 @@ napi_value AgoraElectronBridge::OnEvent(napi_env env, napi_callback_info info) { RETURE_NAPI_OBJ(); } -napi_value AgoraElectronBridge::UnEvent(napi_env env, napi_callback_info info) { - napi_status status; - size_t argc = 2; - napi_value args[2]; - napi_value jsthis; - int ret = ERR_FAILED; - status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); - assert(status == napi_ok); - - AgoraElectronBridge *agoraElectronBridge; - status = - napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); - assert(status == napi_ok); - - std::string eventName = ""; - status = napi_get_value_utf8string(env, args[0], eventName); - assert(status == napi_ok); - - agoraElectronBridge->_iris_rtc_event_handler->removeEvent(eventName); - ret = ERR_OK; - - RETURE_NAPI_OBJ(); -} - napi_value AgoraElectronBridge::SetAddonLogFile(napi_env env, napi_callback_info info) { napi_status status; diff --git a/source_code/agora_node_ext/agora_electron_bridge.h b/source_code/agora_node_ext/agora_electron_bridge.h index dcdafcfee..bd8672002 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.h +++ b/source_code/agora_node_ext/agora_electron_bridge.h @@ -34,7 +34,6 @@ class AgoraElectronBridge { static napi_value CallApi(napi_env env, napi_callback_info info); static napi_value GetBuffer(napi_env env, napi_callback_info info); static napi_value OnEvent(napi_env env, napi_callback_info info); - static napi_value UnEvent(napi_env env, napi_callback_info info); static napi_value EnableVideoFrameCache(napi_env env, napi_callback_info info); static napi_value DisableVideoFrameCache(napi_env env, diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 33a5dee9c..706ef51ea 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -53,14 +53,8 @@ void NodeIrisEventHandler::removeEvent(const std::string &eventName) { } void NodeIrisEventHandler::OnEvent(EventParam *param) { - const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; - - if (strcmp(event, param->event) == 0) { - onEncodedVideoFrameReceived(param->data, param->buffer[0], param->length); - } else { - fireEvent(_callback_key, param->event, param->data, param->buffer, - param->length, param->buffer_count); - } + fireEvent(_callback_key, param->event, param->data, param->buffer, + param->length, param->buffer_count); } void NodeIrisEventHandler::fireEvent(const char *callback_name, @@ -134,42 +128,6 @@ void NodeIrisEventHandler::fireEvent(const char *callback_name, }); } -void NodeIrisEventHandler::onEncodedVideoFrameReceived(const char *data, - void *buffer, - unsigned int *length) { - std::string eventData = ""; - if (data) { eventData = data; } - std::vector buffer_data(length[0]); - memcpy(buffer_data.data(), buffer, length[0]); - - unsigned int buffer_length = length[0]; - - node_async_call::async_call([this, eventData, buffer_data, buffer_length] { - auto it = _callbacks.find("call_back_with_encoded_video_frame"); - if (it != _callbacks.end()) { - size_t argc = 2; - napi_value args[2]; - napi_value result; - napi_status status; - status = napi_create_string_utf8(it->second->env, eventData.c_str(), - eventData.length(), &args[0]); - - napi_create_buffer_copy(it->second->env, buffer_length, - buffer_data.data(), nullptr, &args[1]); - - napi_value call_back_value; - status = napi_get_reference_value( - it->second->env, it->second->call_back_ref, &call_back_value); - - napi_value recv_value; - status = napi_get_undefined(it->second->env, &recv_value); - - status = napi_call_function(it->second->env, recv_value, call_back_value, - argc, args, &result); - } - }); -} - }// namespace electron }// namespace rtc }// namespace agora diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index 863674ebd..7b65bf043 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -31,9 +31,6 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void **buffer, unsigned int *length, unsigned int buffer_count); - void onEncodedVideoFrameReceived(const char *data, void *buffer, - unsigned int *length); - void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 7c6cec465..85deb0007 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -122,7 +122,7 @@ export class WebCodecsDecoder { this._currentCodecConfig?.codedWidth !== frameInfo.width || this._currentCodecConfig?.codedHeight !== frameInfo.height ) { - logInfo('codecType is changed, reconfigure decoder'); + logInfo('frameInfo has changed, reconfigure decoder'); this._decoder.reset(); this.decoderConfigure(frameInfo); } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index ef9a9471a..912a11255 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,8 +1,8 @@ import createAgoraRtcEngine from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; +import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; -import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; import { RendererContext, RendererType } from '../Types'; import { AgoraEnv, logInfo } from '../Utils'; @@ -10,7 +10,10 @@ import { AgoraEnv, logInfo } from '../Utils'; import { IRendererCache } from './IRendererCache'; import { WebCodecsRenderer } from './WebCodecsRenderer/index'; -export class WebCodecsRendererCache extends IRendererCache { +export class WebCodecsRendererCache + extends IRendererCache + implements IVideoEncodedFrameObserver +{ private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; private _firstFrame = true; @@ -31,44 +34,38 @@ export class WebCodecsRendererCache extends IRendererCache { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } - onEncodedVideoFrameReceived(...[data, buffer]: any) { - let _data: any; - try { - _data = JSON.parse(data) ?? {}; - } catch (e) { - _data = {}; - } - if ( - Object.keys(_data).length === 0 || - !this._decoder || - this.cacheContext.uid !== _data.uid - ) - return; + onEncodedVideoFrameReceived( + uid: number, + imageBuffer: Uint8Array, + length: number, + videoEncodedFrameInfo: EncodedVideoFrameInfo + ) { + if (!this._decoder || this.cacheContext.uid !== uid) return; if (this._firstFrame) { for (let renderer of this.renderers) { if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { continue; } renderer.bind(renderer.context.view, { - width: _data.videoEncodedFrameInfo.width!, - height: _data.videoEncodedFrameInfo.height!, + width: videoEncodedFrameInfo.width!, + height: videoEncodedFrameInfo.height!, }); } try { - this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); + this._decoder.decoderConfigure(videoEncodedFrameInfo); } catch (error: any) { logInfo(error); return; } this._firstFrame = false; } - if (this.shouldFallback(_data.videoEncodedFrameInfo)) { + if (this.shouldFallback(videoEncodedFrameInfo)) { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } else { this._decoder.decodeFrame( - buffer, - _data.videoEncodedFrameInfo, + imageBuffer, + videoEncodedFrameInfo, new Date().getTime() ); } @@ -79,16 +76,6 @@ export class WebCodecsRendererCache extends IRendererCache { type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); - AgoraElectronBridge.OnEvent( - 'call_back_with_encoded_video_frame', - (...params: any) => { - try { - this.onEncodedVideoFrameReceived(...params); - } catch (e) { - console.error(e); - } - } - ); } public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean { @@ -116,7 +103,7 @@ export class WebCodecsRendererCache extends IRendererCache { } public release(): void { - AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); + logInfo('call_back_with_encoded_video_frame release'); this._decoder?.release(); this._decoder = null; super.release(); diff --git a/ts/Types.ts b/ts/Types.ts index 2752ccc3f..cfe4c05cc 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -117,8 +117,6 @@ export interface IAgoraElectronBridge { ) => void ): void; - UnEvent(callbackName: string): void; - CallApi( funcName: string, params: any, From e800beaaf5303a5971d0725a6b4de2c46b7e8dd5 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:10:19 +0800 Subject: [PATCH 086/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 912a11255..a5bf7feef 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -76,6 +76,7 @@ export class WebCodecsRendererCache type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); + this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean { @@ -104,6 +105,7 @@ export class WebCodecsRendererCache public release(): void { logInfo('call_back_with_encoded_video_frame release'); + this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._decoder?.release(); this._decoder = null; super.release(); From 3240684eb9e47e464cd321b657797139918653e2 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:13:48 +0800 Subject: [PATCH 087/101] Revert "chore: optimize" This reverts commit e800beaaf5303a5971d0725a6b4de2c46b7e8dd5. --- ts/Renderer/WebCodecsRendererCache.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index a5bf7feef..912a11255 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -76,7 +76,6 @@ export class WebCodecsRendererCache type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); - this._engine?.getMediaEngine().registerVideoEncodedFrameObserver(this); } public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean { @@ -105,7 +104,6 @@ export class WebCodecsRendererCache public release(): void { logInfo('call_back_with_encoded_video_frame release'); - this._engine?.getMediaEngine().unregisterVideoEncodedFrameObserver(this); this._decoder?.release(); this._decoder = null; super.release(); From c844528de5cb301091d9bd39c270db86bd21fa57 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:13:57 +0800 Subject: [PATCH 088/101] Revert "chore: optimize" This reverts commit 29aa87d61cc7de6de1b0b40d65555f5e64e3c889. --- .../agora_node_ext/agora_electron_bridge.cpp | 25 +++++++++ .../agora_node_ext/agora_electron_bridge.h | 1 + .../node_iris_event_handler.cpp | 46 ++++++++++++++++- .../agora_node_ext/node_iris_event_handler.h | 3 ++ ts/Decoder/index.ts | 2 +- ts/Renderer/WebCodecsRendererCache.ts | 51 ++++++++++++------- ts/Types.ts | 2 + 7 files changed, 108 insertions(+), 22 deletions(-) diff --git a/source_code/agora_node_ext/agora_electron_bridge.cpp b/source_code/agora_node_ext/agora_electron_bridge.cpp index 440e0966a..b06b508b4 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.cpp +++ b/source_code/agora_node_ext/agora_electron_bridge.cpp @@ -40,6 +40,7 @@ napi_value AgoraElectronBridge::Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_METHOD("CallApi", CallApi), DECLARE_NAPI_METHOD("OnEvent", OnEvent), + DECLARE_NAPI_METHOD("UnEvent", UnEvent), DECLARE_NAPI_METHOD("GetBuffer", GetBuffer), DECLARE_NAPI_METHOD("EnableVideoFrameCache", EnableVideoFrameCache), DECLARE_NAPI_METHOD("DisableVideoFrameCache", DisableVideoFrameCache), @@ -250,6 +251,30 @@ napi_value AgoraElectronBridge::OnEvent(napi_env env, napi_callback_info info) { RETURE_NAPI_OBJ(); } +napi_value AgoraElectronBridge::UnEvent(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 2; + napi_value args[2]; + napi_value jsthis; + int ret = ERR_FAILED; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + AgoraElectronBridge *agoraElectronBridge; + status = + napi_unwrap(env, jsthis, reinterpret_cast(&agoraElectronBridge)); + assert(status == napi_ok); + + std::string eventName = ""; + status = napi_get_value_utf8string(env, args[0], eventName); + assert(status == napi_ok); + + agoraElectronBridge->_iris_rtc_event_handler->removeEvent(eventName); + ret = ERR_OK; + + RETURE_NAPI_OBJ(); +} + napi_value AgoraElectronBridge::SetAddonLogFile(napi_env env, napi_callback_info info) { napi_status status; diff --git a/source_code/agora_node_ext/agora_electron_bridge.h b/source_code/agora_node_ext/agora_electron_bridge.h index bd8672002..dcdafcfee 100644 --- a/source_code/agora_node_ext/agora_electron_bridge.h +++ b/source_code/agora_node_ext/agora_electron_bridge.h @@ -34,6 +34,7 @@ class AgoraElectronBridge { static napi_value CallApi(napi_env env, napi_callback_info info); static napi_value GetBuffer(napi_env env, napi_callback_info info); static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value UnEvent(napi_env env, napi_callback_info info); static napi_value EnableVideoFrameCache(napi_env env, napi_callback_info info); static napi_value DisableVideoFrameCache(napi_env env, diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 706ef51ea..33a5dee9c 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -53,8 +53,14 @@ void NodeIrisEventHandler::removeEvent(const std::string &eventName) { } void NodeIrisEventHandler::OnEvent(EventParam *param) { - fireEvent(_callback_key, param->event, param->data, param->buffer, - param->length, param->buffer_count); + const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; + + if (strcmp(event, param->event) == 0) { + onEncodedVideoFrameReceived(param->data, param->buffer[0], param->length); + } else { + fireEvent(_callback_key, param->event, param->data, param->buffer, + param->length, param->buffer_count); + } } void NodeIrisEventHandler::fireEvent(const char *callback_name, @@ -128,6 +134,42 @@ void NodeIrisEventHandler::fireEvent(const char *callback_name, }); } +void NodeIrisEventHandler::onEncodedVideoFrameReceived(const char *data, + void *buffer, + unsigned int *length) { + std::string eventData = ""; + if (data) { eventData = data; } + std::vector buffer_data(length[0]); + memcpy(buffer_data.data(), buffer, length[0]); + + unsigned int buffer_length = length[0]; + + node_async_call::async_call([this, eventData, buffer_data, buffer_length] { + auto it = _callbacks.find("call_back_with_encoded_video_frame"); + if (it != _callbacks.end()) { + size_t argc = 2; + napi_value args[2]; + napi_value result; + napi_status status; + status = napi_create_string_utf8(it->second->env, eventData.c_str(), + eventData.length(), &args[0]); + + napi_create_buffer_copy(it->second->env, buffer_length, + buffer_data.data(), nullptr, &args[1]); + + napi_value call_back_value; + status = napi_get_reference_value( + it->second->env, it->second->call_back_ref, &call_back_value); + + napi_value recv_value; + status = napi_get_undefined(it->second->env, &recv_value); + + status = napi_call_function(it->second->env, recv_value, call_back_value, + argc, args, &result); + } + }); +} + }// namespace electron }// namespace rtc }// namespace agora diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index 7b65bf043..863674ebd 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -31,6 +31,9 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void **buffer, unsigned int *length, unsigned int buffer_count); + void onEncodedVideoFrameReceived(const char *data, void *buffer, + unsigned int *length); + void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 85deb0007..7c6cec465 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -122,7 +122,7 @@ export class WebCodecsDecoder { this._currentCodecConfig?.codedWidth !== frameInfo.width || this._currentCodecConfig?.codedHeight !== frameInfo.height ) { - logInfo('frameInfo has changed, reconfigure decoder'); + logInfo('codecType is changed, reconfigure decoder'); this._decoder.reset(); this.decoderConfigure(frameInfo); } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 912a11255..ef9a9471a 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -1,8 +1,8 @@ import createAgoraRtcEngine from '../AgoraSdk'; import { WebCodecsDecoder } from '../Decoder/index'; import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase'; -import { IVideoEncodedFrameObserver } from '../Private/AgoraMediaBase'; import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx'; +import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine'; import { RendererContext, RendererType } from '../Types'; import { AgoraEnv, logInfo } from '../Utils'; @@ -10,10 +10,7 @@ import { AgoraEnv, logInfo } from '../Utils'; import { IRendererCache } from './IRendererCache'; import { WebCodecsRenderer } from './WebCodecsRenderer/index'; -export class WebCodecsRendererCache - extends IRendererCache - implements IVideoEncodedFrameObserver -{ +export class WebCodecsRendererCache extends IRendererCache { private _decoder?: WebCodecsDecoder | null; private _engine?: IRtcEngineEx; private _firstFrame = true; @@ -34,38 +31,44 @@ export class WebCodecsRendererCache AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } - onEncodedVideoFrameReceived( - uid: number, - imageBuffer: Uint8Array, - length: number, - videoEncodedFrameInfo: EncodedVideoFrameInfo - ) { - if (!this._decoder || this.cacheContext.uid !== uid) return; + onEncodedVideoFrameReceived(...[data, buffer]: any) { + let _data: any; + try { + _data = JSON.parse(data) ?? {}; + } catch (e) { + _data = {}; + } + if ( + Object.keys(_data).length === 0 || + !this._decoder || + this.cacheContext.uid !== _data.uid + ) + return; if (this._firstFrame) { for (let renderer of this.renderers) { if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) { continue; } renderer.bind(renderer.context.view, { - width: videoEncodedFrameInfo.width!, - height: videoEncodedFrameInfo.height!, + width: _data.videoEncodedFrameInfo.width!, + height: _data.videoEncodedFrameInfo.height!, }); } try { - this._decoder.decoderConfigure(videoEncodedFrameInfo); + this._decoder.decoderConfigure(_data.videoEncodedFrameInfo); } catch (error: any) { logInfo(error); return; } this._firstFrame = false; } - if (this.shouldFallback(videoEncodedFrameInfo)) { + if (this.shouldFallback(_data.videoEncodedFrameInfo)) { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } else { this._decoder.decodeFrame( - imageBuffer, - videoEncodedFrameInfo, + buffer, + _data.videoEncodedFrameInfo, new Date().getTime() ); } @@ -76,6 +79,16 @@ export class WebCodecsRendererCache type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); + AgoraElectronBridge.OnEvent( + 'call_back_with_encoded_video_frame', + (...params: any) => { + try { + this.onEncodedVideoFrameReceived(...params); + } catch (e) { + console.error(e); + } + } + ); } public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean { @@ -103,7 +116,7 @@ export class WebCodecsRendererCache } public release(): void { - logInfo('call_back_with_encoded_video_frame release'); + AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; super.release(); diff --git a/ts/Types.ts b/ts/Types.ts index cfe4c05cc..2752ccc3f 100644 --- a/ts/Types.ts +++ b/ts/Types.ts @@ -117,6 +117,8 @@ export interface IAgoraElectronBridge { ) => void ): void; + UnEvent(callbackName: string): void; + CallApi( funcName: string, params: any, From 06525d75d9275c4dc968f8db38f0231f5be46604 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:36:06 +0800 Subject: [PATCH 089/101] chore: optimize --- .../node_iris_event_handler.cpp | 39 +------------------ .../agora_node_ext/node_iris_event_handler.h | 4 +- ts/Decoder/index.ts | 6 ++- ts/Renderer/WebCodecsRendererCache.ts | 9 +++-- 4 files changed, 12 insertions(+), 46 deletions(-) diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 33a5dee9c..349942c2c 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -56,7 +56,8 @@ void NodeIrisEventHandler::OnEvent(EventParam *param) { const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; if (strcmp(event, param->event) == 0) { - onEncodedVideoFrameReceived(param->data, param->buffer[0], param->length); + fireEvent(_callback_with_encoded_video_frame_key, param->event, param->data, + param->buffer, param->length, param->buffer_count); } else { fireEvent(_callback_key, param->event, param->data, param->buffer, param->length, param->buffer_count); @@ -134,42 +135,6 @@ void NodeIrisEventHandler::fireEvent(const char *callback_name, }); } -void NodeIrisEventHandler::onEncodedVideoFrameReceived(const char *data, - void *buffer, - unsigned int *length) { - std::string eventData = ""; - if (data) { eventData = data; } - std::vector buffer_data(length[0]); - memcpy(buffer_data.data(), buffer, length[0]); - - unsigned int buffer_length = length[0]; - - node_async_call::async_call([this, eventData, buffer_data, buffer_length] { - auto it = _callbacks.find("call_back_with_encoded_video_frame"); - if (it != _callbacks.end()) { - size_t argc = 2; - napi_value args[2]; - napi_value result; - napi_status status; - status = napi_create_string_utf8(it->second->env, eventData.c_str(), - eventData.length(), &args[0]); - - napi_create_buffer_copy(it->second->env, buffer_length, - buffer_data.data(), nullptr, &args[1]); - - napi_value call_back_value; - status = napi_get_reference_value( - it->second->env, it->second->call_back_ref, &call_back_value); - - napi_value recv_value; - status = napi_get_undefined(it->second->env, &recv_value); - - status = napi_call_function(it->second->env, recv_value, call_back_value, - argc, args, &result); - } - }); -} - }// namespace electron }// namespace rtc }// namespace agora diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index 863674ebd..5e3c5ade7 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -31,9 +31,6 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void **buffer, unsigned int *length, unsigned int buffer_count); - void onEncodedVideoFrameReceived(const char *data, void *buffer, - unsigned int *length); - void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); @@ -42,6 +39,7 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { private: std::unordered_map _callbacks; const char *_callback_key = "call_back_with_buffer"; + const char *_callback_with_encoded_video_frame_key = "call_back_with_encoded_video_frame"; }; }// namespace electron }// namespace rtc diff --git a/ts/Decoder/index.ts b/ts/Decoder/index.ts index 7c6cec465..fdec958f7 100644 --- a/ts/Decoder/index.ts +++ b/ts/Decoder/index.ts @@ -39,7 +39,9 @@ export class WebCodecsDecoder { this._decoder = new VideoDecoder({ // @ts-ignore output: this._output.bind(this), - error: onError, + error: (e) => { + onError(e); + }, }); } @@ -122,7 +124,7 @@ export class WebCodecsDecoder { this._currentCodecConfig?.codedWidth !== frameInfo.width || this._currentCodecConfig?.codedHeight !== frameInfo.height ) { - logInfo('codecType is changed, reconfigure decoder'); + logInfo('frameInfo has changed, reconfigure decoder'); this._decoder.reset(); this.decoderConfigure(frameInfo); } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index ef9a9471a..e72f9371d 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -26,12 +26,12 @@ export class WebCodecsRendererCache extends IRendererCache { this.draw(); } - onDecoderError() { - logInfo('webCodecsDecoder decode failed, fallback to native decoder'); + onDecoderError(e: any) { + logInfo('webCodecsDecoder decode failed, fallback to native decoder', e); AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } - onEncodedVideoFrameReceived(...[data, buffer]: any) { + onEncodedVideoFrameReceived(...[event, data, buffers]: any) { let _data: any; try { _data = JSON.parse(data) ?? {}; @@ -67,7 +67,7 @@ export class WebCodecsRendererCache extends IRendererCache { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } else { this._decoder.decodeFrame( - buffer, + buffers[0], _data.videoEncodedFrameInfo, new Date().getTime() ); @@ -116,6 +116,7 @@ export class WebCodecsRendererCache extends IRendererCache { } public release(): void { + logInfo('call_back_with_encoded_video_frame release'); AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; From 69a8f9bc2fec382d13f3c788deed2930b0e12b1a Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 17:50:51 +0800 Subject: [PATCH 090/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index e72f9371d..fa11d9288 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -79,6 +79,7 @@ export class WebCodecsRendererCache extends IRendererCache { type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); + logInfo('register call_back_with_encoded_video_frame'); AgoraElectronBridge.OnEvent( 'call_back_with_encoded_video_frame', (...params: any) => { @@ -116,7 +117,7 @@ export class WebCodecsRendererCache extends IRendererCache { } public release(): void { - logInfo('call_back_with_encoded_video_frame release'); + logInfo('unregister call_back_with_encoded_video_frame'); AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; From 74fd6c96d0c712382e54e11956a3df768c374143 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 19:32:47 +0800 Subject: [PATCH 091/101] chore: optimize --- ts/Private/internal/IrisApiEngine.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 2ca29e7e9..026c20c26 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -504,12 +504,12 @@ export function callIrisApi(funcName: string, params: any): any { rtcEngine.getMediaEngine().registerVideoEncodedFrameObserver({}); //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error //when the webCodecsDecoder is error, the video stream will be decoded by native - rtcEngine.getMediaEngine().registerVideoFrameObserver({}); + // rtcEngine.getMediaEngine().registerVideoFrameObserver({}); } } else if (funcName.indexOf('leaveChannel') != -1) { if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { rtcEngine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); - rtcEngine.getMediaEngine().unregisterVideoFrameObserver({}); + // rtcEngine.getMediaEngine().unregisterVideoFrameObserver({}); } } From c095a46f102cdf8f5dac28d84ff6e12755a3ea68 Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 19:45:04 +0800 Subject: [PATCH 092/101] chore: optimize --- ts/Renderer/WebCodecsRendererCache.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index fa11d9288..0373c6165 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -79,7 +79,6 @@ export class WebCodecsRendererCache extends IRendererCache { type: VideoStreamType.VideoStreamHigh, encodedFrameOnly: true, }); - logInfo('register call_back_with_encoded_video_frame'); AgoraElectronBridge.OnEvent( 'call_back_with_encoded_video_frame', (...params: any) => { @@ -117,7 +116,6 @@ export class WebCodecsRendererCache extends IRendererCache { } public release(): void { - logInfo('unregister call_back_with_encoded_video_frame'); AgoraElectronBridge.UnEvent('call_back_with_encoded_video_frame'); this._decoder?.release(); this._decoder = null; From 15c3f714f9e037bd0b5094ace7dd5cfb7a960adb Mon Sep 17 00:00:00 2001 From: gxz Date: Sat, 11 May 2024 20:55:24 +0800 Subject: [PATCH 093/101] chore: optimize --- .../node_iris_event_handler.cpp | 39 ++++++++++++++++++- .../agora_node_ext/node_iris_event_handler.h | 4 +- ts/Private/internal/IrisApiEngine.ts | 4 -- ts/Renderer/WebCodecsRendererCache.ts | 4 +- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/source_code/agora_node_ext/node_iris_event_handler.cpp b/source_code/agora_node_ext/node_iris_event_handler.cpp index 349942c2c..33a5dee9c 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.cpp +++ b/source_code/agora_node_ext/node_iris_event_handler.cpp @@ -56,8 +56,7 @@ void NodeIrisEventHandler::OnEvent(EventParam *param) { const char *event = "VideoEncodedFrameObserver_onEncodedVideoFrameReceived"; if (strcmp(event, param->event) == 0) { - fireEvent(_callback_with_encoded_video_frame_key, param->event, param->data, - param->buffer, param->length, param->buffer_count); + onEncodedVideoFrameReceived(param->data, param->buffer[0], param->length); } else { fireEvent(_callback_key, param->event, param->data, param->buffer, param->length, param->buffer_count); @@ -135,6 +134,42 @@ void NodeIrisEventHandler::fireEvent(const char *callback_name, }); } +void NodeIrisEventHandler::onEncodedVideoFrameReceived(const char *data, + void *buffer, + unsigned int *length) { + std::string eventData = ""; + if (data) { eventData = data; } + std::vector buffer_data(length[0]); + memcpy(buffer_data.data(), buffer, length[0]); + + unsigned int buffer_length = length[0]; + + node_async_call::async_call([this, eventData, buffer_data, buffer_length] { + auto it = _callbacks.find("call_back_with_encoded_video_frame"); + if (it != _callbacks.end()) { + size_t argc = 2; + napi_value args[2]; + napi_value result; + napi_status status; + status = napi_create_string_utf8(it->second->env, eventData.c_str(), + eventData.length(), &args[0]); + + napi_create_buffer_copy(it->second->env, buffer_length, + buffer_data.data(), nullptr, &args[1]); + + napi_value call_back_value; + status = napi_get_reference_value( + it->second->env, it->second->call_back_ref, &call_back_value); + + napi_value recv_value; + status = napi_get_undefined(it->second->env, &recv_value); + + status = napi_call_function(it->second->env, recv_value, call_back_value, + argc, args, &result); + } + }); +} + }// namespace electron }// namespace rtc }// namespace agora diff --git a/source_code/agora_node_ext/node_iris_event_handler.h b/source_code/agora_node_ext/node_iris_event_handler.h index 5e3c5ade7..863674ebd 100644 --- a/source_code/agora_node_ext/node_iris_event_handler.h +++ b/source_code/agora_node_ext/node_iris_event_handler.h @@ -31,6 +31,9 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { void **buffer, unsigned int *length, unsigned int buffer_count); + void onEncodedVideoFrameReceived(const char *data, void *buffer, + unsigned int *length); + void addEvent(const std::string &eventName, napi_env &env, napi_value &call_bcak, napi_value &global); @@ -39,7 +42,6 @@ class NodeIrisEventHandler : public iris::IrisEventHandler { private: std::unordered_map _callbacks; const char *_callback_key = "call_back_with_buffer"; - const char *_callback_with_encoded_video_frame_key = "call_back_with_encoded_video_frame"; }; }// namespace electron }// namespace rtc diff --git a/ts/Private/internal/IrisApiEngine.ts b/ts/Private/internal/IrisApiEngine.ts index 026c20c26..e382aecfa 100644 --- a/ts/Private/internal/IrisApiEngine.ts +++ b/ts/Private/internal/IrisApiEngine.ts @@ -502,14 +502,10 @@ export function callIrisApi(funcName: string, params: any): any { if (funcName.indexOf('joinChannel') != -1) { if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { rtcEngine.getMediaEngine().registerVideoEncodedFrameObserver({}); - //need registerVideoFrameObserver here to cover the case that the webCodecsDecoder is error - //when the webCodecsDecoder is error, the video stream will be decoded by native - // rtcEngine.getMediaEngine().registerVideoFrameObserver({}); } } else if (funcName.indexOf('leaveChannel') != -1) { if (AgoraEnv.CapabilityManager?.webCodecsDecoderEnabled) { rtcEngine.getMediaEngine().unregisterVideoEncodedFrameObserver({}); - // rtcEngine.getMediaEngine().unregisterVideoFrameObserver({}); } } diff --git a/ts/Renderer/WebCodecsRendererCache.ts b/ts/Renderer/WebCodecsRendererCache.ts index 0373c6165..b50c6e434 100644 --- a/ts/Renderer/WebCodecsRendererCache.ts +++ b/ts/Renderer/WebCodecsRendererCache.ts @@ -31,7 +31,7 @@ export class WebCodecsRendererCache extends IRendererCache { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } - onEncodedVideoFrameReceived(...[event, data, buffers]: any) { + onEncodedVideoFrameReceived(...[data, buffer]: any) { let _data: any; try { _data = JSON.parse(data) ?? {}; @@ -67,7 +67,7 @@ export class WebCodecsRendererCache extends IRendererCache { AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext); } else { this._decoder.decodeFrame( - buffers[0], + buffer, _data.videoEncodedFrameInfo, new Date().getTime() ); From 0e0d3945883a99dd52734c5514f9ea7a25693bee Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 13 May 2024 16:28:11 +0800 Subject: [PATCH 094/101] chore: optimize --- .../examples/basic/JoinChannelVideo/JoinChannelVideo.tsx | 1 + ts/Renderer/RendererManager.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx index 4cfdc3722..18f37ccda 100644 --- a/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx +++ b/example/src/renderer/examples/basic/JoinChannelVideo/JoinChannelVideo.tsx @@ -182,6 +182,7 @@ export default class JoinChannelVideo ? remoteUsers.map((item) => this.renderUser({ uid: item, + enableFps: true, sourceType: VideoSourceType.VideoSourceRemote, }) ) diff --git a/ts/Renderer/RendererManager.ts b/ts/Renderer/RendererManager.ts index f8a80a16c..6d48448a6 100644 --- a/ts/Renderer/RendererManager.ts +++ b/ts/Renderer/RendererManager.ts @@ -56,7 +56,7 @@ export class RendererManager { private rendererType: RendererType; constructor() { - this.renderingFps = 60; + this.renderingFps = 15; this._currentFrameCount = 0; this._previousFirstFrameTime = 0; this._rendererCaches = []; From 5c5b50f3280224ca0dff51ed414d00bb219850da Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 14 May 2024 15:37:57 +0800 Subject: [PATCH 095/101] chore: optimize --- ts/Renderer/IRenderer.ts | 8 +++++++- ts/Renderer/WebCodecsRenderer/index.ts | 1 + ts/Renderer/WebGLRenderer/index.ts | 1 + ts/Renderer/YUVCanvasRenderer/index.ts | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ts/Renderer/IRenderer.ts b/ts/Renderer/IRenderer.ts index ab5ca3e2b..3fa41df8a 100644 --- a/ts/Renderer/IRenderer.ts +++ b/ts/Renderer/IRenderer.ts @@ -26,6 +26,7 @@ export abstract class IRenderer { }); this.parentElement.appendChild(this.container); this.canvas = document.createElement('canvas'); + this.canvas.style.display = 'none'; this.container.appendChild(this.canvas); } @@ -45,7 +46,12 @@ export abstract class IRenderer { this.parentElement = undefined; } - public abstract drawFrame(videoFrame: VideoFrame): void; + public drawFrame(_videoFrame?: VideoFrame): void { + if (!this.canvas) return; + if (this.canvas.style.display !== '') { + this.canvas.style.display = ''; + } + } public setContext(context: RendererContext) { if (this.context.renderMode !== context.renderMode) { diff --git a/ts/Renderer/WebCodecsRenderer/index.ts b/ts/Renderer/WebCodecsRenderer/index.ts index 833817c01..06aaacc4c 100755 --- a/ts/Renderer/WebCodecsRenderer/index.ts +++ b/ts/Renderer/WebCodecsRenderer/index.ts @@ -135,6 +135,7 @@ export class WebCodecsRenderer extends IRenderer { // Draw the frame. this.gl.drawArrays(this.gl.TRIANGLE_FAN, 0, 4); } + super.drawFrame(); this.getFps(); } } diff --git a/ts/Renderer/WebGLRenderer/index.ts b/ts/Renderer/WebGLRenderer/index.ts index 90deaf8a8..0c0f32c3f 100644 --- a/ts/Renderer/WebGLRenderer/index.ts +++ b/ts/Renderer/WebGLRenderer/index.ts @@ -252,6 +252,7 @@ export class WebGLRenderer extends IRenderer { ); this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); + super.drawFrame(); this.getFps(); } diff --git a/ts/Renderer/YUVCanvasRenderer/index.ts b/ts/Renderer/YUVCanvasRenderer/index.ts index 30fea481a..083fef087 100644 --- a/ts/Renderer/YUVCanvasRenderer/index.ts +++ b/ts/Renderer/YUVCanvasRenderer/index.ts @@ -53,6 +53,7 @@ export class YUVCanvasRenderer extends IRenderer { } ) ); + super.drawFrame(); } protected override rotateCanvas({ width, height, rotation }: VideoFrame) { From d651e75c32aa0d0a96ae58d53f3c967731e114ed Mon Sep 17 00:00:00 2001 From: gxz Date: Mon, 20 May 2024 16:11:56 +0800 Subject: [PATCH 096/101] chore: optimize --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c315dea84..2065ead1e 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.142-gxz.4_DCG_Windows_Video_20240424_0449.zip", - "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.6.9-build.1_DCG_Mac_Video_20240407_0427.zip" + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.143-dev.1_DCG_Windows_Video_20240520_0348.zip", + "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.2.136-build.1_DCG_Mac_Video_20230922_0351.zip" } } From 29aca567231e1a52fca63023270a8a3a867466f0 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Mon, 20 May 2024 09:02:09 +0000 Subject: [PATCH 097/101] chore: release 4.2.2-build.143-rc.1 --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 594576810..15ed99eb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ +## [4.2.2-build.143-rc.1](https://github.com/AgoraIO-Extensions/Electron-SDK/compare/v4.2.2-build.141-rc.2...v4.2.2-build.143-rc.1) (2024-05-20) + + +### Features + +* support native 4.2.2.142 ([#1178](https://github.com/AgoraIO-Extensions/Electron-SDK/issues/1178)) ([473815e](https://github.com/AgoraIO-Extensions/Electron-SDK/commit/473815eb05fc08845e394b4daf9a59c0d5096d6d)) + + +### Reverts + +* Revert "chore: optimize" ([c844528](https://github.com/AgoraIO-Extensions/Electron-SDK/commit/c844528de5cb301091d9bd39c270db86bd21fa57)) +* Revert "chore: optimize" ([3240684](https://github.com/AgoraIO-Extensions/Electron-SDK/commit/3240684eb9e47e464cd321b657797139918653e2)) + ## [4.2.2-build.142-rc.1](https://github.com/AgoraIO-Extensions/Electron-SDK/compare/v4.2.2-build.141-rc.2...v4.2.2-build.142-rc.1) (2024-03-29) ## [4.2.2-build.141-rc.2](https://github.com/AgoraIO-Extensions/Electron-SDK/compare/v4.2.2-build.141-rc.1...v4.2.2-build.141-rc.2) (2023-12-15) diff --git a/package.json b/package.json index 2065ead1e..3f6bb996a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agora-electron-sdk", - "version": "4.2.2-build.142-rc.1", + "version": "4.2.2-build.143-rc.1", "description": "agora-electron-sdk", "main": "js/AgoraSdk", "types": "types/AgoraSdk.d.ts", From 21ab5e2ac65d3ab4e591a62d437603cd2f13d88e Mon Sep 17 00:00:00 2001 From: sda_rob Date: Mon, 20 May 2024 09:02:58 +0000 Subject: [PATCH 098/101] chore(example): update example to install agora-electron-sdk@4.2.2-build.143-rc.1 --- example/package.json | 2 +- example/yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/example/package.json b/example/package.json index 7d755b1c3..cdd3820fc 100644 --- a/example/package.json +++ b/example/package.json @@ -71,7 +71,7 @@ ] }, "dependencies": { - "agora-electron-sdk": "4.2.2-build.142-rc.1", + "agora-electron-sdk": "4.2.2-build.143-rc.1", "antd": "^4.20.3", "download": "^8.0.0", "koffi": "^2.8.0", diff --git a/example/yarn.lock b/example/yarn.lock index dd93654a9..05992dcc9 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1777,10 +1777,10 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -agora-electron-sdk@4.2.2-build.142-rc.1: - version "4.2.2-build.142-rc.1" - resolved "https://registry.npmjs.org/agora-electron-sdk/-/agora-electron-sdk-4.2.2-build.142-rc.1.tgz#f8087c597a9e139f90b8f2dc80386f2037725b8b" - integrity sha512-CD+973GkThf+KhSwnzidh0J/3ssbmlOuA+C6HkoVHZSQLG+188T/gEwpcDoBAJndEUfBMILbcuksvkPnM7KIfA== +agora-electron-sdk@4.2.2-build.143-rc.1: + version "4.2.2-build.143-rc.1" + resolved "https://registry.npmjs.org/agora-electron-sdk/-/agora-electron-sdk-4.2.2-build.143-rc.1.tgz#f0c8517adfafe1d7901ccab1cd94b39e5bd50590" + integrity sha512-JCkxT+jSilICXWl2HjRWFDMaJsPJeWaj2GsBUjfC5hbIhWmf02+ITHryvVe8N6I3AkyfxSOJCDlFJtJH8/hzYw== dependencies: buffer "^6.0.3" cross-env "^7.0.3" @@ -1792,6 +1792,7 @@ agora-electron-sdk@4.2.2-build.142-rc.1: jsonfile "^6.1.0" lodash.isequal "^4.5.0" minimist "^1.2.5" + semver "^7.6.0" shelljs "^0.8.4" ts-interface-checker "^1.0.2" winston "^3.3.3" @@ -9081,6 +9082,11 @@ semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + semver@~7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" From 819bd26fd6597597e9f6d2596d55d817790949f1 Mon Sep 17 00:00:00 2001 From: gxz Date: Tue, 21 May 2024 17:59:25 +0800 Subject: [PATCH 099/101] chore: optimize --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f6bb996a..ce7410af9 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "yuv-canvas": "1.2.6" }, "agora_electron": { - "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.143-dev.1_DCG_Windows_Video_20240520_0348.zip", + "iris_sdk_win": "https://download.agora.io/sdk/release/iris_4.2.2.143-build.1_DCG_Windows_Video_20240521_0544.zip", "iris_sdk_mac": "https://download.agora.io/sdk/release/iris_4.2.2.136-build.1_DCG_Mac_Video_20230922_0351.zip" } } From f685400c413d21e781e83d83377c6f54aa4921b8 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Wed, 22 May 2024 06:46:53 +0000 Subject: [PATCH 100/101] chore: release 4.2.2-build.143-rc.2 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15ed99eb0..b2ec787f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ +## [4.2.2-build.143-rc.2](https://github.com/AgoraIO-Extensions/Electron-SDK/compare/v4.2.2-build.143-rc.1...v4.2.2-build.143-rc.2) (2024-05-22) + ## [4.2.2-build.143-rc.1](https://github.com/AgoraIO-Extensions/Electron-SDK/compare/v4.2.2-build.141-rc.2...v4.2.2-build.143-rc.1) (2024-05-20) diff --git a/package.json b/package.json index ce7410af9..33fc17269 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agora-electron-sdk", - "version": "4.2.2-build.143-rc.1", + "version": "4.2.2-build.143-rc.2", "description": "agora-electron-sdk", "main": "js/AgoraSdk", "types": "types/AgoraSdk.d.ts", From ad50e224ff2c454f7906984466e96b6677e97f25 Mon Sep 17 00:00:00 2001 From: sda_rob Date: Wed, 22 May 2024 06:47:33 +0000 Subject: [PATCH 101/101] chore(example): update example to install agora-electron-sdk@4.2.2-build.143-rc.2 --- example/package.json | 2 +- example/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/package.json b/example/package.json index cdd3820fc..2ebe4b773 100644 --- a/example/package.json +++ b/example/package.json @@ -71,7 +71,7 @@ ] }, "dependencies": { - "agora-electron-sdk": "4.2.2-build.143-rc.1", + "agora-electron-sdk": "4.2.2-build.143-rc.2", "antd": "^4.20.3", "download": "^8.0.0", "koffi": "^2.8.0", diff --git a/example/yarn.lock b/example/yarn.lock index 05992dcc9..c70d37f91 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1777,10 +1777,10 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -agora-electron-sdk@4.2.2-build.143-rc.1: - version "4.2.2-build.143-rc.1" - resolved "https://registry.npmjs.org/agora-electron-sdk/-/agora-electron-sdk-4.2.2-build.143-rc.1.tgz#f0c8517adfafe1d7901ccab1cd94b39e5bd50590" - integrity sha512-JCkxT+jSilICXWl2HjRWFDMaJsPJeWaj2GsBUjfC5hbIhWmf02+ITHryvVe8N6I3AkyfxSOJCDlFJtJH8/hzYw== +agora-electron-sdk@4.2.2-build.143-rc.2: + version "4.2.2-build.143-rc.2" + resolved "https://registry.npmjs.org/agora-electron-sdk/-/agora-electron-sdk-4.2.2-build.143-rc.2.tgz#6bbcf4fc086bc3ee08e58a9789b978a76aa50450" + integrity sha512-mBXt7+4Kuz4xzFgxdPzZAgcmpNVnIFsmc8XIoh21WfeExIjgJrB7+8+KPp8/v0ojQIfuXCrgvlOU7iDKXeUIIA== dependencies: buffer "^6.0.3" cross-env "^7.0.3"