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 层处理媒体底层逻辑
  • 通信桥梁ChannelPayloadChannel 实现跨进程通信
  • 扩展能力:支持 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 优化

相关推荐
Wang15301 小时前
c++与Java谁的性能更胜一筹
java·c++
Tipriest_1 小时前
C++ 中 std::move 的使用方法与注意事项
c++·move
yuuki2332331 小时前
【C++】vector底层实现全解析
c++·后端·算法
小尧嵌入式1 小时前
C++选择排序插入排序希尔排序快排归并排及大小根堆实现优先级队列
数据结构·c++·windows·算法·排序算法
Dream it possible!2 小时前
LeetCode 面试经典 150_分治_合并 K 个升序链表(108_23_C++_困难)
c++·leetcode·链表·面试·分治
天赐学c语言2 小时前
12.29 - 字符串相加 && vector和map的区别
数据结构·c++·算法·leecode
yuuki2332332 小时前
【C++】 list 实现:双向循环链表解析
c++·链表·list
随意起个昵称2 小时前
【做题总结】顺子(双指针)
c++·算法
郝学胜-神的一滴2 小时前
Linux多线程编程:深入解析pthread_detach函数
linux·服务器·开发语言·c++·程序人生