mediasoup源码走读(三)Node.js 控制面

3.1. 总体架构图与类图

3.1.1 系统架构图

Node.js 控制面 Channel C++ Worker 数据面 libuv 事件循环 ICE/DTLS 协商 RTP/RTCP 处理 媒体路由管理 Producer/Consumer API WebRTC 客户端 FFmpeg/GStreamer 集成 HTTP HLS 接口

  • 双层架构:Node.js 层负责业务逻辑控制,C++ Worker 层处理媒体底层逻辑
  • 通信桥梁 :Channel 和 PayloadChannel 实现跨进程通信
  • 扩展能力:支持 WebRTC、RTP/RTCP 原生协议、FFmpeg 等多种接入方式

3.1.2 核心类图

1 1 1 N 1 N 1 1..N 1 1..N 1 1 1 1 Channel +emit(event, data) : void +on(event, handler) : void Router +createProducer() : Producer +createConsumer() : Consumer Producer +sendRtp(packet) : void +pause() : void +resume() : void Consumer +onRtp(packet) : void +requestKeyFrame() : void WebRtcTransport +connect(options) : void +produce(stream) : Producer +consume(producerId) : Consumer PayloadChannel +send(data) : void Worker

  • 核心关系 :Router 是媒体流容器,通过 WebRtcTransport 连接客户端
  • 数据传输 :Producer/Consumer 通过 PayloadChannel 发送大包数据
  • 生命周期 :Channel 统一管理控制面事件,Worker 管理数据面实例

3.2. 信令交互模块

3.2.1 Channel 信令通信时序

JS Channel Worker emit('router.create', options) IPC发送消息 回复 routerId 触发 'router.created' 事件 JS Channel Worker

  1. JS 层调用 emit() 发送创建房间请求
  2. Channel 通过 IPC 通道将消息传递给 Worker
  3. Worker 处理完底层逻辑后返回结果
  4. Channel 在 JS 层触发事件通知业务逻辑

源码说明(lib/Channel.js):

javascript 复制代码
/**
 * 信令通道核心类
 * 负责 JS 层与 Worker 的双向通信
 */
class Channel {
  /**
   * 发送信令消息到 Worker
   * @param {string} event - 事件名称
   * @param {Object} data - 消息体
   */
  emit(event, data) {
    // 1. 构建消息对象
    const message = {
      event,
      data
    };
    
    // 2. 通过 IPC 通道发送消息
    this._worker.send(message);
  }

  /**
   * 监听 Worker 返回的事件
   * @param {string} event - 事件名称
   * @param {Function} handler - 事件处理函数
   */
  on(event, handler) {
    if (!this._events[event]) {
      this._events[event] = [];
    }
    
    // 3. 注册事件监听器
    this._events[event].push(handler);
  }
}

3.3. 路由器管理模块

3.3.1 Router 创建时序

JS Channel Worker emit('router.create', options) 创建 Router 请求 返回 routerId 触发 'router.created' 事件 JS Channel Worker

  1. JS 层调用 createRouter() 发起创建请求
  2. Channel 转发请求到 Worker
  3. Worker 创建底层 C++ Router 实例
  4. 通过事件通知 JS 层创建完成

源码说明(lib/Router.js):

javascript 复制代码
/**
 * 房间管理类
 * 对应底层 C++ 的 Router 实例
 */
class Router {
  /**
   * 创建房间实例
   * @param {Channel} channel - 通信通道
   * @param {Object} options - 创建参数
   */
  constructor(channel, options) {
    this._id = options.id || generateId();
    
    // 1. 通过 Channel 发送创建请求
    channel.emit('router.create', {
      id: this._id,
      options
    });
    
    // 2. 监听创建完成事件
    channel.on('router.created', (routerId) => {
      if (routerId === this._id) {
        this._emit('created');
      }
    });
  }
}

3.4. 生产者管理模块

3.4.1 Producer 创建时序

JS Channel Worker emit('producer.create', options) 创建 Producer 请求 返回 producerId 触发 'producer.created' 事件 JS Channel Worker

  1. JS 层调用 produce() 创建生产者
  2. Channel 将请求转发给 Worker
  3. Worker 创建底层 C++ Producer
  4. 通过事件通知 JS 层创建完成

源码说明(lib/Producer.js):

javascript 复制代码
/**
 * 媒体生产者类
 * 负责将媒体流推送到房间
 */
class Producer {
  /**
   * 创建生产者实例
   * @param {Channel} channel - 通信通道
   * @param {string} routerId - 所属房间ID
   * @param {Object} options - 创建参数
   */
  constructor(channel, routerId, options) {
    this._id = options.id || generateId();
    
    // 1. 发送创建请求
    channel.emit('producer.create', {
      routerId,
      producerId: this._id,
      options
    });
    
    // 2. 监听关闭事件
    channel.on('producer.closed', (producerId) => {
      if (producerId === this._id) {
        this._emit('close');
      }
    });
  }
}

3.5. 消费者管理模块

3.5.1 Consumer 创建时序

JS Channel Worker emit('consumer.create', options) 创建 Consumer 请求 返回 consumerId 触发 'consumer.created' 事件 JS Channel Worker

  1. JS 层调用 createConsumer() 创建消费者
  2. Channel 转发请求到 Worker
  3. Worker 创建底层 C++ Consumer
  4. 通过事件通知 JS 层创建完成

源码说明(lib/Consumer.js):

javascript 复制代码
/**
 * 媒体消费者类
 * 负责接收并消费媒体流
 */
class Consumer {
  /**
   * 创建消费者实例
   * @param {Channel} channel - 通信通道
   * @param {string} routerId - 所属房间ID
   * @param {string} producerId - 对应生产者ID
   */
  constructor(channel, routerId, producerId) {
    this._id = generateId();
    
    // 1. 发送创建请求
    channel.emit('consumer.create', {
      routerId,
      producerId,
      consumerId: this._id
    });
    
    // 2. 监听 RTP 包事件
    channel.on('consumer.rtp', (consumerId, packet) => {
      if (consumerId === this._id) {
        this._emit('rtp', packet);
      }
    });
  }
}

3.6. 数据通道模块

3.6.1 WebRtcTransport 连接时序

JS Channel Worker emit('transport.connect', options) 连接请求 返回连接状态 触发 'transport.connected' 事件 JS Channel Worker

  1. JS 层调用 connect() 建立传输通道
  2. Channel 将 DTLS 参数传递给 Worker
  3. Worker 完成 ICE/DTLS 协商
  4. 通过事件通知 JS 层连接建立成功

源码说明(lib/WebRtcTransport.js):

javascript 复制代码
/**
 * WebRTC 传输通道类
 * 负责媒体传输的底层连接
 */
class WebRtcTransport {
  /**
   * 建立连接
   * @param {Object} options - 连接参数(包含 DTLS 参数)
   */
  connect(options) {
    // 1. 通过 Channel 发送连接请求
    this._channel.emit('transport.connect', {
      transportId: this._id,
      options
    });
    
    // 2. 监听连接完成事件
    this._channel.on('transport.connected', (transportId) => {
      if (transportId === this._id) {
        this._emit('connected');
      }
    });
  }
}

3.7. 控制面与数据面交互

3.7.1 RTP 包传输时序

Producer WebRtcTransport Channel Worker sendRtp(packet) emit('transport.sendRtp', packet) 传输 RTP 包 (ACK) 'transport.rtpSent' Producer WebRtcTransport Channel Worker

  1. Producer 调用 sendRtp() 发送 RTP 包
  2. 通过 WebRtcTransport 传递到 Channel
  3. Channel 使用 PayloadChannel 传输大包
  4. Worker 处理后返回确认信息

源码说明(lib/PayloadChannel.js):

javascript 复制代码
/**
 * 大包传输通道
 * 优化 RTP 包的传输效率
 */
class PayloadChannel {
  /**
   * 发送大包数据
   * @param {ArrayBuffer} data - 待发送数据
   */
  send(data) {
    // 1. 使用 UDP 套接字发送
    this._socket.send(
      data,
      0,
      data.byteLength,
      this._port,
      this._host
    );
  }
}

3.8. 完整业务流程

3.8.1 端到端媒体传输流程

Camera Producer WebRtcTransport Consumer Decoder captureFrame() sendRtp(packet) receiveRtp(packet) decode(packet) render(frame) Camera Producer WebRtcTransport Consumer Decoder

  1. 摄像头采集帧数据
  2. Producer 打包为 RTP 包
  3. 通过 WebRtcTransport 传输
  4. Consumer 接收并解码
  5. 最终渲染显示

3.9. 关键设计

模块 核心价值 代码体现
信令交互 解耦业务逻辑 Channel.js 的事件驱动模型
路由管理 隔离媒体拓扑 Router.js 的房间隔离机制
生产者管理 流量控制 Producer.js 的 pause/resume 实现
消费者管理 QoS 保障 Consumer.js 的 NackGenerator 集成
数据通道 低延迟传输 PayloadChannel.js 的 UDP 优化

相关推荐
東隅已逝,桑榆非晚19 分钟前
算法2. 双指针法-复写零
c++·笔记·学习·算法
布莱克60520 分钟前
C++ 中堆和栈的区别详解
开发语言·c++·栈·堆
誰能久伴不乏1 小时前
用 UDP 做一条“可靠“的控制通道
c++·qt·网络协议·udp
十五年专注C++开发1 小时前
FlatBuffers: 一个高效的零拷贝二进制序列化库
c++·序列化·反序列化·flatbuffers
xys_6782 小时前
深挖C++:C++入门基础
开发语言·c++
高冷小鱼殿下2 小时前
C 语言指针与输入输出
c++
路溪非溪3 小时前
C++标准库之智能指针
linux·开发语言·c++
美狐美颜SDK开放平台3 小时前
开发直播APP、电商短视频与视频社交平台时,能否共用一套美颜SDK?
android·图像处理·人工智能·音视频·直播美颜sdk
AI日报派送佬3 小时前
2026年11月02日 AI 行业日报|商汤开源 Loop-9B、Pika 发布 H3 Flex 音视频模型、Meta× 傅利叶推出人形机器人 Max
人工智能·微软·开源·音视频·openai·1024程序员节·ai日报
hetao17338373 小时前
2026-11-02 hetao1733837 的刷题记录
c++·算法