UNPKG

nertc-electron-sdk

Version:
158 lines (132 loc) 5.79 kB
import { GlRenderer, SoftwareRenderer, IRenderer } from './index'; export type StreamType = 'main' | 'sub' | 'third' | 'fourth'; export interface DisplayConfig { /** 视频缩放模式:0=等比缩放(Fit), 1=非等比填满(Fill), 2=等比裁剪(Crop) */ scalingMode?: number; /** JS 渲染层镜像(CSS transform rotateY 180deg),与 C++ SDK 镜像并存 */ mirrorEnabled?: boolean; /** 视频 letterbox 区域背景色,CSS 颜色字符串,默认 'black' */ backgroundColor?: string; } interface RendererEntry { renderer: IRenderer; config: DisplayConfig; } /** * RendererManager — 渲染器单例管理器(框架无关) * * 职责: * - 管理所有视频流的渲染器实例(按 uid + streamType 索引) * - 统一管理 DisplayConfig(scalingMode / mirrorEnabled / backgroundColor) * - 对 React 或其他 UI 框架提供独立的动态更新接口 * * 与 C++ SDK mirror 的关系: * - C++ setLocalVideoMirrorMode / setLocalVideoMirrorModeWithType:影响帧数据 mirror 标志, * 决定远端用户所见(编码级别),同时也影响本地显示(通过帧头 mirror 位) * - RendererManager.setMirrorMode:JS 层 CSS transform,纯本地显示覆盖, * 不影响编码,不影响远端所见。forceMirror !== undefined 时优先于帧数据 mirror 标志 */ export class RendererManager { private static _instance: RendererManager; private entries: Map<string, RendererEntry> = new Map(); private renderMode: number = 1; // 1=WebGL(GlRenderer), 2=Software(SoftwareRenderer) private constructor() {} static getInstance(): RendererManager { if (!RendererManager._instance) { RendererManager._instance = new RendererManager(); } return RendererManager._instance; } private key(uid: string, streamType: StreamType): string { return `${uid}-${streamType}`; } /** 设置渲染器类型(1=WebGL, 2=Software),在 bind 之前调用 */ setRenderMode(mode: number): void { this.renderMode = mode; } /** * 绑定渲染器到 DOM 元素,并应用初始 DisplayConfig * 如果该 (uid, streamType) 已有渲染器,先销毁再重建 */ bind(uid: string, streamType: StreamType, element: Element, config?: DisplayConfig): void { const k = this.key(uid, streamType); // 销毁已有渲染器 if (this.entries.has(k)) { try { this.entries.get(k)!.renderer.unbind(); } catch (e) { /* ignore */ } this.entries.delete(k); } const renderer: IRenderer = this.renderMode === 2 ? new (SoftwareRenderer as any)() : new GlRenderer(); renderer.bind(element); const cfg: DisplayConfig = { scalingMode: 0, mirrorEnabled: false, backgroundColor: 'black', ...config, }; renderer.setContentMode(cfg.scalingMode ?? 0); renderer.setMirrorMode(cfg.mirrorEnabled ?? false); renderer.setBackgroundColor(cfg.backgroundColor ?? 'black'); this.entries.set(k, { renderer, config: cfg }); } /** 解绑并销毁渲染器 */ unbind(uid: string, streamType: StreamType): void { const k = this.key(uid, streamType); if (this.entries.has(k)) { try { this.entries.get(k)!.renderer.unbind(); } catch (e) { /* ignore */ } this.entries.delete(k); } } /** 推入视频帧数据(由 SDK 帧回调调用) */ drawFrame(uid: string, streamType: StreamType, imageData: any): void { this.entries.get(this.key(uid, streamType))?.renderer.drawFrame(imageData); } // ── 独立动态更新接口 ────────────────────────────────────────────────── /** 动态更新缩放模式(0=Fit, 1=Fill, 2=Crop) */ setScalingMode(uid: string, streamType: StreamType, mode: number): void { const entry = this.entries.get(this.key(uid, streamType)); if (entry) { entry.renderer.setContentMode(mode); entry.renderer.refreshCanvas(); entry.config.scalingMode = mode; } } /** * 动态更新 JS 层镜像(CSS transform) * 与 C++ SDK 的 setLocalVideoMirrorMode 并存,互不影响 */ setMirrorMode(uid: string, streamType: StreamType, enabled: boolean): void { const entry = this.entries.get(this.key(uid, streamType)); if (entry) { entry.renderer.setMirrorMode(enabled); entry.config.mirrorEnabled = enabled; } } /** 动态更新背景色(letterbox 区域),立即生效 */ setBackgroundColor(uid: string, streamType: StreamType, color: string): void { const entry = this.entries.get(this.key(uid, streamType)); if (entry) { entry.renderer.setBackgroundColor(color); entry.config.backgroundColor = color; } } /** 批量更新 DisplayConfig */ setConfig(uid: string, streamType: StreamType, config: DisplayConfig): void { if (config.scalingMode !== undefined) this.setScalingMode(uid, streamType, config.scalingMode); if (config.mirrorEnabled !== undefined) this.setMirrorMode(uid, streamType, config.mirrorEnabled); if (config.backgroundColor !== undefined) this.setBackgroundColor(uid, streamType, config.backgroundColor); } /** 读取当前 DisplayConfig(返回副本) */ getConfig(uid: string, streamType: StreamType): DisplayConfig | null { const entry = this.entries.get(this.key(uid, streamType)); return entry ? { ...entry.config } : null; } hasRenderer(uid: string, streamType: StreamType): boolean { return this.entries.has(this.key(uid, streamType)); } /** 仅供调试:获取渲染器实例 */ getRenderer(uid: string, streamType: StreamType): IRenderer | null { return this.entries.get(this.key(uid, streamType))?.renderer ?? null; } }