RTCPeerConnection RTP 扩展

作者:追风剑情 发布于:2024-2-29 14:42 分类:Unity3d

在实时通话过程中,WebRTC 网络连接成功建立后,下一步就是发布/接收媒体流。

在发送端,新媒体流的加人将导致重新协商,发起协商的提案包含新加入的媒体信息如果协商顺利完成,发送端开始对媒体流进行编码压缩,并将编码后的媒体流传输给对等端。

接收端收到了新的媒体流后会触发 track 事件,在该事件中获取对应的媒体流。媒体流是经过编码的,编码格式已经在之前的协商中达成了一致,所以接收端能够对媒体流进行解码,接收端随后会将媒体流播放出来,这取决于应用层的行为。

WebRTC在 RTCPeerConnection 扩展接口中提供了API对上述过程进行管理,这些API包括媒体流及媒体设置、RTP 传输层两个主要部分,其结构如下图所示。

RTP 媒体管理接口.png

媒体流及媒体设置包括了添加/获取媒体流、获取媒体能力、设置编码格式等内容。

RTP传输层包括了RTP收发器、RTP发送器、RTP接收器、DTLS传输层、ICE传输层的接口管理。WebRTC为每个媒体轨道分配一个RTP 收发器,每个RTP收发器包含一个RTP发送器和RTP接收器。

RTP 媒体 API对 RTCPeerConnection 进行了扩展,以提供媒体流的收发、编解码能力。

//RTCPeerConnection RTP 扩展
partial interface RTCPeerConnection {
	sequence<RTCRtpSender> getSenders();
	sequence<RTCRtpReceiver> getReceivers();
	sequence<RTCRtpTransceiver> getTransceivers();
	RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams);
	void removeTrack(RTCRtpSender sender);
	RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, optional RTCRtpTransceiverInit init = {});
	attribute EventHandler ontrack;
};  

  当发送媒体流数据时,WebRTC 可能对媒体数据进行调整以满足 SDP 中的媒体约束条件,比如调整视频的宽、高、帧率,调整音频的音量、采样率、通道数等,这会导致对等端看到的部分媒体信息失真。

  RTCRtpTransceiver 描述了一个连接通道,包含发送端(RTCRtpSender)和接收端(RTCRtpReceiver)。

  RTCRtpSender 负责媒体流的编码和传输,相应地,RTCRtpReceiver 负责媒体流的接收和解码。RTCRtpSender、RTCRtpReceiver 与媒体流轨道(MediaStreamTrack)一一对应。

RTCPeerConnection 扩展方法

1.addTransceiver() 方法

该方法创建一个新的 RTCRtpTransceiver 并加入 RTCPeerConnection,RTCRtpTransceiver 代表一个双向流,包含一个 RTCRtpSender 和一个 RTCRtpReceiver。

rtpTransceiver = rtcPeerConnection.addTransceiver(trackOrKind, init);  

参数
trackOrKind: 与该 RTP 收发器相连的 MediaStreamTrack 或媒体轨道 kind 值。
init: 可选参数,类型为 RTCRtpTransceiverInit,包含了创建 RTP 收发器的选型。
返回值
RTCRtpTransceiver 对象。
异常
该方法调用出错时,抛出异常如表下所示。

addTransceiver()异常
异常名称 说明
TypeError 传人的 kind 值无效
InvalidStateError 当前连接处于关闭状态
InvalidAccessError 传参 sendEncodings 中没有包含 rid
RangeError 传参 sendEncodings 中,scaleResolutionDownBy 值越界

 //RTCRtpTransceiverlnit 的定义
dictionary RTCRtpTransceiverInit {
	RTCRtpTransceiverDirection direction = "sendrecv";
	sequence<MediaStream> streams = [];
	sequence<RTCRtpEncodingParameters> sendEncodings = [];
};  

RTCRtpTransceiverlnit 属性说明
属性 说明
direction 可选参数,收发器传输方向,用于初始化 RTCRtpTransceiver.direction 的值,默认值 sendrecv
streams 可选参数,MediaStream 对象数组
sendEncodings 可选参数,编码格式数组,用于发送 RTP 数据,类型为 RTCRtpEncodingParameters

下面的代码清单获取媒体流 stream,调用 addTransceiver() 方法加入音频和视频轨道。

const stream = await navigator.mediaDevices.getUserMedia(constraints);
selfview.srcObject = stream;
pc.addTransceiver(stream.getAudioTracks()[0], {direction: 'sendonly'});
pc.addTransceiver(stream.getVideoTracks()[0],{
	direction:'sendonly',
	sendEncodings: [
		{rid:'q',scaleResolutionDownBy: 4.0},
		{rid:'h',scaleResolutionDownBy: 2.0},
		{rid:'f'}
	]
});  

2.RTCPeerConnection.addTrack() 方法

向连接中添加新的媒体轨道,媒体轨道将被传输到对等端。调用该方法将触发 negotiationneeded 事件,导致 ICE 重新协商。

rtpSender = rtcPeerConnection.addTrack(track, streams...);  

参数: track,MediaStreamTrack 对象; streams,可选参数,一个或多个 MediaStream对象,该参数便于接收端管理媒体轨道,确保多个媒体轨道状态同步,加入同一个媒体流的媒体轨道,也会同时出现在对等端的同一个媒体流中。
返回值:RTCRtpSender 对象,用于传输 RTP 媒体数据。
异常:InvalidAccessError,指定的媒体轨道已经加入连接,InvalidStateError,连接 已关闭。

3.RTCPeerConnection.removeTrack() 方法

停止发送媒体数据,调用该方法将触发 negotiationneeded 事件,导致 ICE 重新协商。

pc.removeTrack(sender);  

参数:sender,从连接中移除的 RTCRtpSender 对象,注意,该方法并不会真正删除RTCRtpSender,getSenders() 方法仍然包含此 RTCRtpSender。
返回值:无。

下面的代码清单获取视频流,将视频轨道加入连接,当点击按钮 closeButton 时,移除视频轨道对应的发送器并关闭连接。

let pc, sender;
navigator.getUserMedia({video: true}, (stream) => {
	pc = new RTCPeerConnection();
	const track = stream.getVideoTracks()[0];
	sender = pc.addTrack(track, stream);
});
document.getElementById("closeButton").addEventListener("click", (event) => {
	pc.removeTrack(sender);
	pc.close();
}, false);  

4.RTCPeerConnection.getTransceivers() 方法

获取 RTCRtpTransceiver 对象列表,RTCRtpTransceiver 对象负责 RTCPeerConnection连接里 RTP 数据的收发管理。

transceiverList = rtcPeerConnection.getTransceivers();  

参数:无。
返回值:包含 RTCRtpTransceiver 对象的数组,数组成员以添加的先后顺序进行排序。

下面的代码清单演示了停止 RTCPeerConnection 连接里的所有 RTP 收发器。

pc.getTransceivers().forEach(transceiver => {
	transceiver.stop();
};  

5.RTCPeerConnection.getSenders() 方法

获取 RTCRtpSender 对象列表,RTCRtpSender 对象负责 RTP 数据的编码及发送。

const senders = RTCPeerConnection.getSenders();  

参数:无。
返回值:RTCRtpSender 对象数组,每个加人连接中的媒体轨道对应一个 RTCRtpSender 对象。

6.RTCPeerConnection.getReceivers() 方法

获取 RTCRtpReceiver 对象列表,RTCRtpReceiver 对象负责 RTP 媒体数据的接收及解码。

const receivers = RTCPeerConnection.getReceivers();  

参数:无。
返回值:RTCRtpReceiver 对象数组。每个加入连接中的媒体轨道对应一个 RTCRtpReceiver 对象。

RTCPeerConnection 扩展事件

  当 RTCRtpReceiver 收到新的媒体轨道时,触发该事件,对应事件句柄 ontrack。事件类型 RTCTrackEvent 的定义如下面代码清单所示。

//RTCTrackEvent 的定义
interface RTCTrackEvent : Event {
	constructor(DOMString type, RTCTrackEventInit eventInitDict);
	readonly attribute RTCRtpReceiver receiver;
	readonly attribute MediaStreamTrack track;
	[SameObject] readonly attribute FrozenArray<MediaStream> streams;
	readonly attribute RTCRtpTransceiver transceiver;
};  

RTCTrackEvent 属性说明
属性 说明
receiver 与事件相关的 RTCRtpReceiver 对象
track 接收到的媒体轨道对象
streams 媒体轨道所在的媒体流
transceiver 与事件相关的 RTCRtpTransceiver 对象

下面的代码清单为 ontrack 事件句柄指定了处理函数,当事件触发时,将媒体流绑定到视频元素 videoElement 进行播放。

pc.ontrack = e => {
	videoElement.srcObject = e.streams[0];
	hangupButton.disabled = false;
	return false;
}  

标签: Unity3d

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号