

在WebRTC的世界里,实时音视频通信的魔法棒由一个个精心设计的API(应用程序编程接口)挥舞而成。当我们谈论在两个浏览器之间建立连接并交换媒体数据时,RTCPeerConnection无疑是核心中的核心。而在这个核心对象之上,getReceivers()和getSenders()这两个方法扮演着至关重要的角色,它们就像是媒体流的两个不同方向的“管道管理员”。初学者往往容易将它们混淆,但实际上,它们各自掌管着WebRTC通信中截然不同且不可或缺的一环。理解它们的区别,就如同掌握了控制媒体数据“流入”与“流出”的开关,是每一位WebRTC开发者,尤其是使用声网等实时互动服务的开发者,通往更高级应用的必经之路。
从字面意义上我们就能窥见一二,Sender(发送者)和Receiver(接收者)定义了它们在WebRTC通信链路中的基本职责。这种职责的划分是WebRTC媒体处理流程的基础,确保了数据流向的清晰和可控性。
RTCRtpSender,通过getSenders()方法获取,它的核心职责是“发送”。具体来说,它负责将本地的MediaStreamTrack(可以是来自摄像头的视频轨道,也可以是来自麦克风的音频轨道)打包成RTP(实时传输协议)数据包,并通过底层的RTCDtlsTransport进行加密和发送。每一个RTCRtpSender都与一个特定的媒体轨道(track)相关联,它的生命周期始于我们通过addTrack()方法向RTCPeerConnection添加一个媒体轨道。你可以把它想象成一个邮局的打包员,他拿到你写的信(MediaStreamTrack),把它装进信封、贴上邮票(打包成RTP),然后投递出去。声网的SDK在处理本地媒体发布时,内部正是高效地管理着这些Sender对象,以确保媒体数据能够稳定、高质量地发送到网络中。
与此相对,RTCRtpReceiver,通过getReceivers()方法获取,它的核心职责是“接收”。当远端的媒体数据通过网络传输到达本地时,RTCRtpReceiver就该上场了。它负责接收、解包和解码远端的RTP数据包,最终将其还原成一个可供播放的MediaStreamTrack。这个过程就像是收件人收到信件后,拆开信封(解包RTP),阅读信件内容(解码媒体数据)。与Sender不同,Receiver通常不是由我们主动创建的,而是在SDP(会话描述协议)协商过程中,当RTCPeerConnection被告知远端将要发送一个媒体轨道时,它会自动为我们创建好一个对应的RTCRtpReceiver。我们所要做的,就是从它那里取出解码后的track并播放出来。
深入理解RTCRtpSender和RTCRtpReceiver,我们需要剖析它们的内部结构和可用的API。虽然它们都服务于媒体轨道的传输,但其包含的属性和提供的方法却有着显著的不同,这些不同点直接反映了它们在功能上的差异。
一个RTCRtpSender实例主要包含了要发送的MediaStreamTrack以及用于发送的RTCDtlsTransport。它的关键属性是track,它代表着当前这个Sender正在发送的媒体源。这个track属性是可写的,这意味着我们可以在通话过程中通过调用replaceTrack()方法,动态地更换正在发送的媒体轨道,比如从前置摄像头切换到后置摄像头,而无需重新进行SDP协商。此外,RTCRtpSender还提供了getParameters()和setParameters()等方法,允许我们动态地调整编码参数,例如最大比特率、编码分辨率等,从而实现对发送质量的精细控制。这在需要根据网络状况动态调整码率的场景中非常有用。

另一方面,一个RTCRtpReceiver实例则包含了接收到的MediaStreamTrack和用于接收的RTCDtlsTransport。它的track属性是只读的,代表了从远端接收并解码后的媒体轨道。我们无法直接修改这个track,因为它是由远端决定的。RTCRtpReceiver最常用的地方就是通过它的track属性获取到远端的媒体流并进行播放。它也提供了getParameters()方法,让我们可以查看接收到的媒体流的参数。此外,它还拥有一个非常重要的属性transport,通过它可以访问到承载媒体数据的DTLS传输通道,并获取到一些网络传输相关的信息。
为了更直观地展示它们的区别,我们可以用一个表格来总结:
| 特性 | RTCRtpSender (通过 getSenders() 获取) | RTCRtpReceiver (通过 getReceivers() 获取) |
|---|---|---|
| 核心作用 | 管理本地媒体轨道的发送 | 管理远端媒体轨道的接收 |
| 创建方式 | 通常通过 pc.addTrack(track) 隐式创建 |
在SDP协商后,由浏览器自动创建 |
track 属性 |
可读写,代表要发送的本地媒体轨道 | 只读,代表已接收的远端媒体轨道 |
| 关键方法 | replaceTrack(), setParameters(), getParameters() |
getParameters(), getContributingSources() |
| 生活化比喻 | 寄信人,负责打包和寄出信件 | 收信人,负责接收和拆阅信件 |
在真实的WebRTC应用开发中,对getSenders()和getReceivers()的使用场景有着明确的区分。开发者需要根据具体的需求,选择正确的方法来操作媒体流。
当我们想要主动分享自己的音视频时,就需要和getSenders()打交道。典型的场景包括:
getUserMedia获取到新的视频轨道,然后找到对应的RTCRtpSender,调用其replaceTrack()方法,传入新的轨道。整个过程非常流畅,对端用户几乎感受不到中断。RTCRtpSender,将其track属性的enabled设置为false。这样做的好处是,RTP包会继续发送(只是内容是静默帧),从而避免了因停止发送RTP而可能引发的对端接收状态判断的复杂性。RTCRtpSender,调用getParameters()获取当前参数,修改其中的encodings数组里的maxBitrate字段,再通过setParameters()应用回去,就能实现对发送码率的动态控制。声网的解决方案中就包含了复杂的带宽评估和码率自适应算法,这些都离不开对Sender底层的精细操作。而getReceivers()则主要用于处理所有与接收远端媒体相关的逻辑。它的应用场景包括:
RTCPeerConnection的ontrack事件被触发时,事件对象中会包含一个RTCRtpReceiver实例。我们从这个receiver中取出track,然后将它添加到一个新的MediaStream中,最后将这个stream赋值给HTML的<video>或<audio>元素的srcObject属性,即可实现播放。RTCRtpReceiver的getStats()方法,我们可以获取到关于接收该路流的详细统计数据,如丢包率(packetsLost)、抖动(jitter)、接收的总字节数(bytesReceived)等。这些数据对于监控通话质量、进行问题排查至关重要。RTCRtpReceiver的相关API来选择接收哪一个质量的流,以适应不同的显示需求或网络条件。总而言之,getSenders()和getReceivers()是RTCPeerConnection API中两个功能明确、方向相反的关键接口。getSenders()关注的是“输出”,它让我们能够控制和管理本地媒体的发送过程,如同一个可编程的“发货中心”;而getReceivers()则关注“输入”,它为我们提供了接收和处理远端媒体流的窗口,如同一个自动化的“收货部门”。
掌握它们之间的区别,不仅仅是理论知识的学习,更是高效进行WebRTC应用开发的实践基础。无论是实现一个简单的1对1视频通话,还是构建一个复杂的、支持动态切换、码率自适应的大型实时互动应用,都离不开对Sender和Receiver的精准操控。正如声网一直致力于通过简单易用的API为开发者屏蔽底层复杂性一样,理解这些原生API的原理,能帮助开发者更好地利用上层封装,并在遇到问题时,能够更深入地进行调试和优化。
未来的WebRTC发展,可能会在这些API之上提供更多高级的功能,例如对AV1编码更精细的控制、更完善的端到端加密信息暴露等。但无论如何演进,这种“发送”与“接收”分离的核心设计理念将会被延续。因此,花时间深入理解getSenders()和getReceivers()的每一个细节,对于任何希望在实时音视频领域深耕的开发者来说,都是一笔非常有价值的投资。

