一. previewLocalStream - 预览本地流

流程:

1. — api :previewLocalStream`

 previewLocalStream(config: LocalStreamConfig): Promise<APICommonResponse> {
    return control.previewLocalStream(config);
  }

2. — controlAdpater — meeting — index.ts

import meetingControl from '../../control/meeting';
previewLocalStream(config: LocalStreamConfig) {
    return meetingControl.previewLocalStream(config);
  }

3. — control — meeting — index.ts:

 previewLocalStream(config: LocalStreamConfig) {
    return control.rtcHandler.previewLocalStream(config);
  }

const rtcHandler = new RTCHandler();

import RTCHandler from "../../core/rtc";

4. — core — rtc — index.ts

  // 创建并预览本地流
  async previewLocalStream(config: LocalStreamConfig) {
    if (config.view) {
      RTCCont.localDom = config.view;
    }

    const res = await this._rtcAdapter.previewLocalStream(config);

    if (RTCCont.waterMarks) {
      await this.startWaterMark(RTCCont.waterMarks);
    }
    return res;
  }
this._rtcAdapter.previewLocalStream(config)
this._rtcAdapter = rtcModules[RTCCont.rtcChannel]
const rtcModules = loadRTCModules<RTCAdapter>();
4.1. — utils — load-modules.ts
function loadRTCModules<T>() {
  const rtcModules = { };
  const rtcTypes = publishInfo['rtcConfig']['channel'].split('+');
  for (const rtcType of rtcTypes) {
    const instance = require(`../core/rtc/adapter/${rtcType}-adapter`).default as T;
    rtcModules[rtcType] = instance;
  }  
  return rtcModules;
}

export  {
  loadBuildTypeModules,
  loadIMModules,
  loadRTCModules,//export
  loadVCModules,
};
4.1.1. publish.json
"rtcConfig":{
        "channel": "netease+qq",
        "channelType": "tcp"
    }

-4.

RTCCont.rtcChannel = options.rtcChannel || DEFAULT_RTC_CHANNEL;//default qq

5(1). —core — rtc — adapter — netease-adapter.ts

   // 1. 创建本地流
            clog.warn('uid', RTCCont);
            
            this._localStream = await this._sdk?.createStream({
              uid: RTCCont.accid,
              microphoneId: microphoneId,
              audio: true, //是否启动mic
              video: true, //是否启动camera
              cameraId: cameraId,
              screen: false, //是否启动屏幕共享
            });
this._localStream = await this._sdk?.createStream({
        audio: true,
        video: true,
        cameraId: config?.option?.cameraId ?? cameras[0].deviceId,
        client: this._client,
      });
this._sdk = new neteaseSDK();
import neteaseSDK, { EventTypes } from '../sdk/netease-sdk';

6(1). — core — rtc — sdk — netease-sdk

  /**
   * 创建音视频流
   * @param options 流配置
   */
  createStream(options: StreamOptions): Promise<any> {
    return new Promise((resolve, reject) => {
      try {
        const stream = NERTC.createStream(options);

        if ((stream as any).code) {
          reject(stream);
        } else {
          this._localStream = stream;
          resolve(stream);
        }
      } catch (error) {
        reject(error);
      }
    });
  }
const stream = NERTC.createStream(options);

7(1).

import NERTC from 'nertc-web-sdk'; // 假设这是网易云信SDK的导入方式

5(2). —core — rtc — adapter — qq-adapter.ts

await this._sdk?.startLocalVideo({
            view: options.view,
            publish: false,
            mute: options.video ? (typeof (options.video) === 'boolean' ? !options.video : options.video) : false,
            option: {
              cameraId: RTCCont.cameraId || options.cameraId,
              mirror: RTCCont.localStreamConfig?.mirror || options.mirror,
              profile: RTCCont.localStreamConfig?.videoProfile || options.videoProfile,
              videoTrack: RTCCont.localStreamConfig?.videoTrack || options.videoTrack,
              fillMode: RTCCont.localStreamConfig?.fillMode || options.fillMode,
              small: RTCCont.localStreamConfig?.small || options.small,
            },
          });
this._sdk = new TrtcSDK();
import TrtcSDK from '../sdk/trtc-sdk';

6(2). — core —rtc — sdk —trtc-sdk.ts

startLocalVideo(config?: LocalVideoConfig) {
    return this._trtc.startLocalVideo(config);
  }
 if (publishInfo.rtcConfig.channelType === 'udp') {
      this._trtc = TRTC.create({ assetsPath: params.assetsPath });
    } else {
      this._trtc = TRTC.create({ plugins: [CustomEncryption], assetsPath: params.assetsPath });
    }

7(2).

import TRTC, { EnterRoomConfig, LocalAudioConfig, LocalVideoConfig, RemoteVideoConfig, StopRemoteVideoConfig, TRTCEventTypes, VideoFrameConfig, UpdateScreenShareConfig, AIDenoiserOptions } from 'trtc-sdk-v5';

二. startRemoteVideo - 开始远程视频

流程:

1. — api — meeting — index.ts

  startRemoteVideo(config: RemoteVideoConfig): Promise<APICommonResponse> {
    return control.startRemoteVideo(config);
  }

2. — controlAdpater — meeting — index.ts

  startRemoteVideo(config: RemoteVideoConfig) {
    return meetingControl.startRemoteVideo(config);
  }

3. — control — meeting — index.ts

  startRemoteVideo(config: RemoteVideoConfig) {
    return control.rtcHandler.startRemoteVideo(config);
  }

const rtcHandler = new RTCHandler();

import RTCHandler from "../../core/rtc";

4. — core — rtc — index.ts

  startRemoteVideo(config: RemoteVideoConfig) {
    return this._rtcAdapter.startRemoteVideo(config);
  }
this._rtcAdapter = rtcModules[RTCCont.rtcChannel];
const rtcModules = loadRTCModules<RTCAdapter>();
import { loadRTCModules } from '../../utils/load-modules';
4.1. — utils — load-modules.ts
function loadRTCModules<T>() {
  const rtcModules = { };
  const rtcTypes = publishInfo['rtcConfig']['channel'].split('+');
  for (const rtcType of rtcTypes) {
    const instance = require(`../core/rtc/adapter/${rtcType}-adapter`).default as T;
    rtcModules[rtcType] = instance;
  }  
  return rtcModules;
}

export  {
  loadBuildTypeModules,
  loadIMModules,
  loadRTCModules,//export
  loadVCModules,
};

import publishInfo from '../../publish.json';
4.1.1. publish.json
"rtcConfig":{
        "channel": "netease+qq",
        "channelType": "tcp"
    }

5(1). — core — rtc — adapter — netease-adapter

await this._sdk?.subscribe(config?.stream, {
            video: true,
            audio: true,
          });
          
 constructor() {
    this._sdk = new neteaseSDK();
  }   

import neteaseSDK, { EventTypes } from '../sdk/netease-sdk';

6(1) — core — rtc — sdk — netease-sdk.ts

  /**
   * 订阅远端流
   * @param stream 远端流
   * @param options 订阅选项
   */
  subscribe(stream: Stream, options?: SubscribeOptions): Promise<void> {
    if (!this._client) {
      return Promise.reject(new Error('Client not created'));
    }
    return this._client.subscribe(stream, options);
  }
  /**
   * 创建客户端实例
   * @param options 配置参数
   */
  createClient(options: { appkey: string; debug?: boolean }):Client {
    this._client = NERTC.createClient(options);
    return this._client;
  }

7(1).

import NERTC from 'nertc-web-sdk'; // 假设这是网易云信SDK的导入方式

5(2). — core — rtc — adapter — qq-adapter.ts

  async startRemoteVideo(config: RemoteVideoConfig): Promise<APICommonResponse> {
    return this.handleSdkCall(
      async () => this._sdk?.startRemoteVideo({
        ...config,
        option: {
          ...config.option,
          fillMode: config.option?.fillMode || 'contain',
        },
        streamType: config.streamType as unknown as TRTCStreamType,
      }),
      'RTC-startRemoteVideo success',
    );
  }
  create(params: { assetsPath: string }) {
    if (!this._sdk) {
      this._sdk = new TrtcSDK();
      this._sdk?.create(params);
    }
  }
import TrtcSDK from '../sdk/trtc-sdk';

6(2). — core — rtc — sdk — trtc-sdk.ts

  startRemoteVideo(config: RemoteVideoConfig) {
    return this._trtc.startRemoteVideo(config);
  }
if (publishInfo.rtcConfig.channelType === 'udp') {
      this._trtc = TRTC.create({ assetsPath: params.assetsPath });
    } else {
      this._trtc = TRTC.create({ plugins: [CustomEncryption], assetsPath: params.assetsPath });
    }

7(2).

import TRTC, { EnterRoomConfig, LocalAudioConfig, LocalVideoConfig, RemoteVideoConfig, StopRemoteVideoConfig, TRTCEventTypes, VideoFrameConfig, UpdateScreenShareConfig, AIDenoiserOptions } from 'trtc-sdk-v5';

三. 总结

综上内容,项目API调用链如下

API层(对外暴露的接口) 顶

controlAdapter层(转发) ↓

control层(业务逻辑) 底

core层(核心逻辑)

core - adapter 层(适配器对应不同厂商)

core - sdk层(厂商具体的sdk)

各层级作用

API层:该部分是对外保留的api,统一调用的入口。

controlAdapter层:一个转发层。

control层:业务逻辑,通用模块index,meeting,teller,client

core层:技术核心,将第三方的接口抽象成统一接口,多厂商适配,向上层提供统一的接口。

​ index为上层提供统一的接口Handler,屏蔽底层SDK差异。event对各个事件作统一定义,动态适配器选择,还有状态管理——统一接口代理(如条件代理,转发代理,状态管理等)。简化上层调用(代理模式)。

​ rtc-types定义统一的接口规范。

​ rtc-cont对RTC进行集中状态管理。

core - adapter 层:对应厂商的sdk在这里将他们的差异化处理成统一的。主要是业务封装,关注业务逻辑,业务流程编排。让不同SDK实现相同的业务效果。

core - sdk层:封装第三方sdk,提供统一的调用接口,二次封装。只关注技术封装。

设计模式

设计模式应用场景具体实现优势
适配器模式不同SDK接口适配RTCAdapter接口统一API,易扩展
工厂模式动态创建适配器loadRTCModules()配置驱动,灵活切换
代理模式日志记录和监控Proxy拦截无侵入式增强
单例模式状态管理RTCCont实例全局状态统一
策略模式多SDK选择适配器选择机制运行时切换策略