补充:查找手册MDN Web Docs
1、WebRTC中的RTP/RTCP模块
1.1 RTP/RTCP简介
RTP/RTCP协议是流媒体通信的基石。RTP协议定义流媒体数据在互联网上传输的数据包格式,而RTCP协议则负责可靠传输、流量控制和拥塞控制等服务质量保证。
在WebRTC项目中,RTP/RTCP模块作为传输模块的一部分,负责对发送端采集到的媒体数据进行进行封包,然后交给上层网络模块发送;
在接收端RTP/RTCP模块收到上层模块的数据包后,进行解包操作,最后把负载发送到解码模块。
因此,RTP/RTCP 模块在WebRTC通信中发挥非常重要的作用。
2.2 RTP Media(webrtc中真正处理数据传输的模块)
在RTP Media中有两个重要的类:Receiver与Sender
每一个媒体轨都会对应一个对会对应一个Receiver对象(接收时)和一个Sender对象(发送时)
1.3RTCRtpReceiver与RTCRtpSender属性一致(3种)
以RTCRtpReceiver为例:
RTCRtpReceiver.track:返回与当前RTCRtpReceiver实例关联的MediaStreamTrack
通过媒体轨属性可以获取当前轨的类型,是audio/video
RTCRtpReceiver.transport:返回接收到的接收者媒体轨的RTCDTLTransport实例
存放着媒体数据传输相关的属性,其中trnasport用于媒体数据的传输,媒体流通过底层的transport进行传输。transport可以进行复用,多个媒体轨复用一个transport传输!
RTCRtpReceiver.rtcpTransport:返回发送和接收RTCP的RTCDTLTransport实例
与rtcp传输相关的属性,比如传输抖动,丢包数量、延迟....。接受方进行统计,反馈给发送端,发送方根据这些数据进行网络质量的评估,适当调整网络流量的发送,这就是流量控制
1.4RTCRtpReceiver实例的方法(5种)
getParameters:返回一个RTCRtpParameters对象,其中包含有关如何解码RTP数据的信息。
方法返回一个RTCRtpReceiveParameters对象,该对象描述了在接收轨上面的媒体关于编码和传输的配置。
对于第2、3个方法,先查看RTP头部格式:
getSynchronizationSources: 方法返回一个RTCRTPContributionSource实例数组,每个实例对应于当前RTCRtpReceiver在最近10秒内接收到的一个SSRC(同步源)标识符。
返回了一组RTCRtpSynchronizationSource实例,每个实例描述在过去10秒内向传入流提供数据的一个同步源。它继承了RTCRtpContributingSource的属性,包括时间戳、源和音频级别。同步源对象添加了voiceActivityFlag属性,该属性指示接收到的最后一个RTP数据包是否包含语音活动。
getContributingSources:方法返回一个RTCRtpContributingSource实例数组,每个实例对应于当前RTCRtpReceiver在最近10秒内接收到的一个CSRC(贡献源)标识符。
每个实例描述了在过去10秒内向传入流提供数据的一个贡献源。
getStats:异步请求一个RTCStatsReport对象,该对象提供有关所属RTCPeerConnection上传入流量的统计信息,并返回一个Promise,一旦结果可用,将调用该Promise的异步处理程序。
getCapabilities:返回一个RTCRtpCapabilities对象,描述当前设备上RTCRtpReceiver支持的编解码器和功能。类似地,您可以通过调用静态函数RTCRtpSender.getCapabilities()来获取RTCRtpSender的功能。
1.5 RTCRtpSender实例的方法(5种)
getParameters(同receiver):返回一个RTCRtpParameters对象,其中包含有关如何解码RTP数据的信息。
方法返回一个RTCRtpReceiveParameters对象,该对象描述了在发送轨上面的媒体关于编码和传输的配置。
setParameters:由于更改发送方轨的配置,该轨是RTCRtpSender负责的MediaStreamTrack。比如最大码率、帧率都是可以改变的
换句话说,setParameters()更新RTP传输的配置以及WebRTC连接上特定传出媒体轨的编码配置。
getStats(同上):异步请求一个RTCStatsReport对象,该对象提供有关拥有发送方的RTCPeerConnection上传出流量的统计信息,并返回一个Promise,一旦结果可用,将调用该Promise的异步处理程序。
replaceTrack:RTCRtpSender方法replaceTrack将当前用作发送方源的媒体流轨替换为新的MediaStreamTrack。新媒体流轨必须是相同的媒体类型(音频、视频等),切换轨不需要协商。
replaceTrack()的用例之一是在手机的后向和前向摄像头之间切换的常见需求。使用replaceTrack(),可以为每个摄影机设置一个轨迹对象,并根据需要在两者之间切换。
getCapabilities(同上):返回一个RTCRtpCapabilities对象,描述当前设备上RTCRtpSender支持的编解码器和功能。类似地,您可以通过调用静态函数RTCRtpReceiver.getCapabilities()来获取RTCRtpSender的功能。
2、RTP Media结构体
2.1 RTP Media结构体
下图列举了receiver与sender用到的所有的结构,以RTCRtpSendParameters最为关键,继承自RTCRtpParameters
在RTCRtpParameters类中,包含3个成员:
RTCRtpHeaderExtensionParameters:扩展头,包括id,uri,encrypted是否加密,默认false不加密
RTCRtcpParameters:对于没一个Rtp都有一个RTCP与之对应,包括cname(可识别),reduceSize带宽不够时,减少RTCP数量,从而降低带宽
RTCRtpCodecParameters:与编解码相关的参数包括payloadType,mimeType,clockRate,channels,sdpFmtpLine...
除了上面继承的字段之外,RTCRtpSendParameters还包括:
transactionID:事物ID,是唯一标识。使用getParameters会获取到,使用setParameters可以指定要设置的事物的transactionID
encodings:指向RTCRtpEncodingParamters对象,指向一堆编解码器
degradationPreference:指向RTCDegradationPreference对象
priority:指定优先级
RTCRtpEncodingParamters:编解码相关结构体
RTCDegradationPreference:降低码流方法,保持帧率、分辨率或者平衡两者
RTCRtpReceiveParameters相对简单,只进行接收,将数据进行上报给发送端,发送端进行整体的控制,所以发送端的参数会更多些!!
2.2 RTCRtpTransceiver
是sender、receiver对,可以同时处理sender与receiver,是对两者的封装
【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~
3、RTCRtpTransceiver
基于:WebRTC学习(八)1V1音视频实时互动直播系统(2)
3.1 代码实现
index2.html
<html>
<head>
<title> WebRTC PeerConnection </title>
<link href="./css/main.css" rel="stylesheet" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
</head>
<body>
<div>
<button id=connserver>Connect Signal Server</button>
<button id="leave" disabled>Leave</button>
</div>
<div id="preview">
<div>
<h2>Local:</h2>
<video autoplay playsinline id="localvideo"></video>
</div>
<div>
<h2>Remote:</h2>
<video autoplay playsinline id="remotevideo"></video>
</div>
</div>
</body>
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script type="text/javascript" src="./js/main2.js"></script>
</html>
main2.js
'use strict'
var localVideo = document.querySelector("video#localvideo");
var remoteVideo = document.querySelector("video#remotevideo");
var btnConn = document.querySelector("button#connserver");
var btnLeave = document.querySelector("button#leave");
var SltBW = document.querySelector("select#bandwidth");
var localStream = null; //保存本地流为全局变量
var socket = null;
var roomid = "111111";
var state = "init"; //客户端状态机
var pc = null; //定义全局peerconnection变量
function sendMessage(roomid,data){
console.log("send SDP message",roomid,data);
if(socket){
socket.emit("message",roomid,data);
}
}
function getOffer(desc){
pc.setLocalDescription(desc);
sendMessage(roomid,desc); //发送SDP信息到对端
}
//这里我们本机是远端,收到了对方的offer,一会需要把自己本端的数据回去!!!!!
function getAnswer(desc){ //在offer获取后,设置了远端描述
pc.setLocalDescription(desc); //这里只需要设置本端了
sendMessage(roomid,desc);
//本端已经收到offer,开始回复answer,说明本端协商完成
SltBW.disabled = false;
}
//媒体协商方法,发起方调用,创建offer
function call(){
if(state === "joined_conn"){
if(pc){
var options = {
offerToReceiveAudio:1,
offerToReceiveVideo:1
};
pc.createOffer(options)
.then(getOffer)
.catch(handleError);
}
}
}
//创建peerconnection,监听一些事件:candidate,当收到candidate事件之后(TURN服务返回),之后转发给另外一端(SIGNAL 服务器实现)
//将本端的媒体流加入peerconnection中去
function createPeerConnection(){
console.log("Create RTCPeerConnection!");
if(!pc){
//设置ICEservers
var pcConfig = {
"iceServers" : [{
'urls':"turn:82.156.184.3:3478",
'credential':"ssyfj",
'username':"ssyfj"
}]
}
pc = new RTCPeerConnection(pcConfig);
pc.onicecandidate = (e)=>{ //处理turn服务返回的candidate信息,媒体协商之后SDP规范中属性获取
if(e.candidate){
//发送candidate消息给对端
console.log("find a new candidate",e.candidate);
sendMessage(roomid,{
type:"candidate",
label:e.candidate.sdpMLineIndex,
id:e.candidate.sdpMid,
candidate:e.candidate.candidate
});
}
};
pc.ontrack = (e)=>{ //获取到远端的轨数据,设置到页面显示
remoteVideo.srcObject = e.streams[0];
}
}
if(localStream){ //将本端的流加入到peerconnection中去
localStream.getTracks().forEach((track)=>{
pc.addTrack(track,localStream);
});
}
}
//销毁当前peerconnection的流信息
function closeLocalMedia(){
if(localStream && localStream.getTracks()){
localStream.getTra