Skip to content

Commit

Permalink
fix: jira CSD-61288 CSD-60920 renderer issue
Browse files Browse the repository at this point in the history
  • Loading branch information
LichKing-2234 committed Nov 21, 2023
1 parent 424dbcb commit 341491d
Show file tree
Hide file tree
Showing 9 changed files with 638 additions and 561 deletions.
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import {
BaseComponent,
BaseVideoComponentState,
} from '../../../components/BaseComponent';
import { AgoraDropdown } from '../../../components/ui';
import { AgoraButton, AgoraDropdown, AgoraView } from '../../../components/ui';
import Config from '../../../config/agora.config';
import { arrayToItems } from '../../../utils';
import { askMediaAccess } from '../../../utils/permissions';

interface State extends BaseVideoComponentState {}
interface State extends BaseVideoComponentState {
selectedUser?: number;
}

export default class JoinChannelVideo
extends BaseComponent<{}, State>
Expand Down Expand Up @@ -178,21 +180,53 @@ export default class JoinChannelVideo
}

protected renderConfiguration(): ReactElement | undefined {
const { joinChannelSuccess, remoteUsers } = this.state;
const { joinChannelSuccess, remoteUsers, selectedUser } = this.state;
return (
<>
{joinChannelSuccess ? (
<AgoraDropdown
title={'Append renderer to remote users'}
items={arrayToItems(remoteUsers)}
onValueChange={(value) => {
this.setState((prev) => {
return {
remoteUsers: [...prev.remoteUsers, value],
};
});
}}
/>
<>
<AgoraDropdown
title={'Append renderer to remote users'}
items={arrayToItems(Array.from(new Set(remoteUsers)))}
value={selectedUser}
onValueChange={(value) => {
this.setState({ selectedUser: value });
}}
/>
<AgoraView>
<AgoraButton
title="Add"
onPress={() => {
if (selectedUser !== undefined) {
this.setState((prev) => {
return {
remoteUsers: [...prev.remoteUsers, selectedUser],
};
});
}
}}
/>
<AgoraButton
title="Remove"
onPress={() => {
if (selectedUser !== undefined) {
this.setState((prev) => {
const predicate = (it: number) => it === selectedUser;
const firstIndex = prev.remoteUsers.findIndex(predicate);
const lastIndex =
prev.remoteUsers.findLastIndex(predicate);
if (firstIndex !== lastIndex) {
prev.remoteUsers.splice(lastIndex, 1);
}
return {
remoteUsers: prev.remoteUsers,
};
});
}
}}
/>
</AgoraView>
</>
) : undefined}
</>
);
Expand Down
10 changes: 10 additions & 0 deletions example/src/renderer/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export {};

declare global {
interface Array<T> {
findLastIndex(
predicate: (value: T, index: number, obj: T[]) => unknown,
thisArg?: any
): number;
}
}
47 changes: 30 additions & 17 deletions ts/Renderer/IRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { EventEmitter } from 'events';

import { RenderModeType } from '../Private/AgoraMediaBase';
import { RendererOptions, ShareVideoFrame } from '../Types';

export type RenderFailCallback =
| ((obj: { error: string }) => void)
| undefined
| null;

export abstract class IRenderer {
parentElement?: HTMLElement;
container?: HTMLElement;
canvas?: HTMLCanvasElement;
event?: EventEmitter;
contentMode = RenderModeType.RenderModeFit;
contentMode = RenderModeType.RenderModeHidden;
mirror?: boolean;

public snapshot(fileType = 'image/png') {
Expand All @@ -23,20 +16,40 @@ export abstract class IRenderer {
}

public bind(element: HTMLElement) {
if (!element) {
throw new Error('You have pass a element');
}
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);
}

abstract unbind(): void;
public unbind() {
if (this.container && this.canvas?.parentNode === this.container) {
this.container.removeChild(this.canvas);
}
if (
this.parentElement &&
this.container?.parentNode === this.parentElement
) {
this.parentElement.removeChild(this.container);
}

this.canvas = undefined;
this.container = undefined;
this.parentElement = undefined;
}

public equalsElement(element: Element): boolean {
if (!element) {
throw new Error('You have pass a element');
}
if (!this.parentElement) {
throw new Error('parentElement is null');
console.error('parentElement is null');
}
return element === this.parentElement;
}
Expand Down
77 changes: 51 additions & 26 deletions ts/Renderer/RendererManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import {
logWarn,
} from '../Utils';

import { IRenderer, RenderFailCallback } from './IRenderer';
import { IRenderer } from './IRenderer';
import { IRendererManager } from './IRendererManager';
import WebGLRenderer from './WebGLRenderer';
import { WebGLFallback, WebGLRenderer } from './WebGLRenderer';
import { YUVCanvasRenderer } from './YUVCanvasRenderer';

/**
Expand Down Expand Up @@ -158,19 +158,31 @@ export class RendererManager extends IRendererManager {
* @ignore
*/
public checkWebglEnv(): boolean {
let gl;
let canvas: HTMLCanvasElement = document.createElement('canvas');

let flag = false;
const canvas: HTMLCanvasElement = document.createElement('canvas');
try {
gl =
canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
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');
return false;
flag = false;
}

return !!gl;
return flag;
}

/**
Expand Down Expand Up @@ -429,11 +441,14 @@ export class RendererManager extends IRendererManager {
/**
* @ignore
*/
private createRenderer(failCallback?: RenderFailCallback): IRenderer {
if (this.renderMode === RENDER_MODE.SOFTWARE) {
private createRenderer(
renderMode?: RENDER_MODE,
fallback?: WebGLFallback
): IRenderer {
if (renderMode === RENDER_MODE.SOFTWARE) {
return new YUVCanvasRenderer();
} else {
return new WebGLRenderer(failCallback);
return new WebGLRenderer(fallback);
}
}

Expand Down Expand Up @@ -467,9 +482,9 @@ export class RendererManager extends IRendererManager {
view: HTMLElement
): IRenderer | undefined {
this.ensureRendererConfig(config);
const renders = this.getRenderers(config);
const renderers = this.getRenderers(config);
const filterRenders =
renders?.filter((render) => render.equalsElement(view)) || [];
renderers?.filter((render) => render.equalsElement(view)) || [];
const hasBeenAdd = filterRenders.length > 0;
if (hasBeenAdd) {
logWarn(
Expand All @@ -478,21 +493,31 @@ export class RendererManager extends IRendererManager {
);
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);
});
const renderer = this.createRenderer(
this.renderMode,
this.handleWebGLFallback(config)
);
renderer.bind(view);
renders.push(renderer);
renderers.push(renderer);
return renderer;
}

/**
* @ignore
*/
private handleWebGLFallback =
(config: FormatRendererVideoConfig) => (renderer: WebGLRenderer) => {
const { contentMode, mirror } = renderer;
const view = renderer.parentElement!;
const renderers = this.getRenderers(config);
const index = renderers.indexOf(renderer);
renderer.unbind();
const newRenderer = this.createRenderer(RENDER_MODE.SOFTWARE);
newRenderer.bind(view);
newRenderer.setRenderOption({ contentMode, mirror });
renderers.splice(index, 1, newRenderer);
};

/**
* @ignore
*/
Expand Down
Loading

0 comments on commit 341491d

Please sign in to comment.