媒体通道 · BaseChannel 连接协商与媒体

BaseChannel(pc/channel.cc)是 SDP 协商和媒体引擎之间那道最关键的胶水——SetLocalContent/SetRemoteContent 把协商结果落到媒体通道,它同时挂在 worker 和 network 线程上、向 RTP 解复用器注册收包。这一章读真实的 channel.h,看这道缝怎么缝起来。

作者 David更新于 第 90 篇(共 112 篇)

媒体通道 · BaseChannel 连接协商与媒体

媒体引擎据协商建“媒体通道”,但谁在协商成功后调它、把 SDP 里谈定的编解码器 / SSRC / 方向真正落到媒体上?是 BaseChannel(pc/channel.cc)。它是控制面(SDP)和媒体面(引擎 + 管线)之间那道最关键的胶水缝。

一个 BaseChannel,不再分音视频类

读真实源码有个值得注意的点——现在的 WebRTC 没有独立的 VoiceChannel / VideoChannel 类了,统一成一个 BaseChannel,用 media_type_ 区分音视频:

// channel.h(节选,真实源码)
class BaseChannel : public ChannelInterface, ... {
  BaseChannel(
      TaskQueueBase* absl_nonnull worker_thread,
      Thread* absl_nonnull network_thread,
      ...
      MediaType media_type,                                  // AUDIO 还是 VIDEO
      std::unique_ptr<MediaSendChannelInterface> media_send_channel, ...);

  RTCError SetLocalContent(const MediaContentDescription* content, SdpType type);
  RTCError SetRemoteContent(const MediaContentDescription* content, SdpType type);
  void OnRtpPacket(const RtpPacketReceived& packet) override;   // 收到解复用后的包
 private:
  const MediaType media_type_;                               // 音 / 视由它区分
  const std::unique_ptr<MediaSendChannelInterface> media_send_channel_;
};

BaseChannel 是“一路媒体(m= line)”在实现层的化身——它持有媒体引擎建的 MediaSendChannelInterface,并通过 SetLocalContent / SetRemoteContent 把协商出的 MediaContentDescription(编解码器、SSRC、方向)落到那个媒体通道上。 每一条协商出的媒体(SDP 里一个 m= 段),对应一个 BaseChannel。它用 media_type_(AUDIO/VIDEO)区分音视频,而非过去的两个子类——这是源码近年的简化。BaseChannel 干的就是把“纸面协商”变成“媒体通道的实际配置”。

SetLocalContent / SetRemoteContent:缝合点

这道缝具体缝在哪?就在 SetLocalContent / SetRemoteContent 这两个方法——它们是SDP 协商回调到媒体层的落点:

图表加载中…

SetLocalContent/SetRemoteContent 就是整个控制面(“协商”)和整个媒体面(“编解码收发”)的接缝——两大半系统在这里对接。这也是为什么理解 BaseChannel 是打通前 8 部分的关键:它一头连着 SDP,一头连着 Call 流。

BaseChannel 横跨两条线程

BaseChannel 一个精妙处:它同时挂在 worker 和 network 两条线程上(读源码满眼 RTC_RUN_ON(worker_thread()) 和 RTC_RUN_ON(network_thread())):

BaseChannel 的媒体配置(编解码器、方向)在 worker 线程,而包的收发 / 解复用在 network 线程——它是三线程模型在媒体通道这一层的体现。 为什么?因为 BaseChannel 干的事天然跨两个域:

所以 BaseChannel 是network 线程(收发)和 worker 线程(处理)之间的桥——这也是它为什么持有 worker_thread_ 和 network_thread_ 两个线程句柄、方法上密布线程断言。它把“包从哪来”和“媒体怎么处理”这两件在不同线程上的事,安全地连起来。

在整个架构里的位置

至此,第 9 部分把控制面和媒体面彻底接上了。完整的一条链:

图表加载中…

PeerConnection → 协商 → BaseChannel → 媒体引擎 → Call 流 → 管线,另一侧接 RTP 传输。BaseChannel 是这张图正中间那个把左右两半焊起来的节点。 读懂它,前 8 部分就从“一堆分立的子系统”变成“一个贯通的整体”。

小结与下一章

BaseChannel(pc/channel.cc)是控制面和媒体面之间最关键的胶水:一路协商媒体(m=)对应一个 BaseChannel(现已统一为一个类、用 media_type_ 区分音视频,不再分 VoiceChannel/VideoChannel)。它通过 SetLocalContent/SetRemoteContent 把协商出的编解码器 / SSRC / 方向落到媒体引擎的通道——这是协商到媒体的接缝。它横跨 [worker(媒体配置)和 network(收包 / 解复用注册)两线程](/manual/webrtc/threading-model),是两域之间的桥。

第 9 部分把控制面和媒体面接通了。下一章为这一部分收尾。👉 第 9 部分回顾。

参考资料

  • [1] libwebrtc 源码.pc/channel.h / channel.cc(BaseChannel、SetLocalContent/SetRemoteContent、OnRtpPacket、media_type_)。
  • [2] 关联SDP 协商、媒体引擎、RTP 解复用、线程模型。
  • [3] libwebrtc 源码.pc/channel_interface.h(ChannelInterface)。

本页目录