RTP控制协议-RTCP
RTCP-SR rfc3550
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P| RC | PT=SR=200 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of sender |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sender | NTP timestamp, most significant word |
info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, least significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sender's packet count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sender's octet count |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_1 (SSRC of first source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 | fraction lost | cumulative number of packets lost |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| extended highest sequence number received |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| interarrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| last SR (LSR) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delay since last SR (DLSR) |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_2 (SSRC of second source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2 : ... :
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| profile-specific extensions |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
uint32_t ssrc;
uint32_t ntpSec;
uint32_t ntpFrac;
uint32_t rtpTs;
uint32_t packetCount;
uint32_t octetCount;
/* 变长,根据count决定 */
struct reportHeader report;
};
/* Struct for RTCP report block*/
struct reportHeader
{
uint32_t ssrc;
uint8_t fractionLost; // 丢包率
uint32_t totalLost : 24; // 一共丢包的个数
uint32_t lastSeq; // sequenceNumber
uint32_t jitter; // RTP包到达时间间隔的统计方差
uint32_t lsr; // 上一次收到SR的时间戳
uint32_t dlsr; // 上次从收到SR包到发送本报告的时间差
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 是reportHeader的个数
- packetType: 200,SR(Sender Report),发送者报告:包含发送者的发送、接收统计
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- ssrc: 与sdp中的ssrc一致
- ntpSec: most significant word,高位时间戳,ntpFrac每到最大值就清零,ntpSec加1,
- ntpFrac: least significant word,低位时间戳,单位是微秒。网络时间戳,用于同步不同源
- rtpTs: 相对时间戳,与rtp一致
- packetCount: 一共发送了多少个包
- octetCount: 一共发送了多少字节
- report.ssrc: 信息所属的ssrc
- report.fractionLost: 丢包率
- report.totalLost: 一共丢包的个数。迟到包不算丢包,重传有可能导致负数
- report.lastSeq: rtp头的sequenceNumber是16bit,会循环从0开始。此处低位16bit与rtp一致,高位表示循环次数
- report.jitter: RTP包到达时间间隔的统计方差
- report.lsr: 上一次收到SR的时间戳,lsr = (ntpSec<<16) + (ntpFrac>>16)
- report.dlsr: 上次从收到SR包到发送本报告的时间差
RTCP-RR rfc3550
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P| RC | PT=RR=201 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of packet sender |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_1 (SSRC of first source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 | fraction lost | cumulative number of packets lost |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| extended highest sequence number received |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| interarrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| last SR (LSR) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delay since last SR (DLSR) |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_2 (SSRC of second source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2 : ... :
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| profile-specific extensions |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
uint32_t ssrc;
/* 变长,根据rtcp.count决定 */
struct reportHeader report;
};
/* Struct for RTCP report block*/
struct reportHeader
{
uint32_t ssrc;
uint8_t fractionLost;
uint32_t totalLost : 24;
uint32_t lastSeq;
uint32_t jitter;
uint32_t lsr;
uint32_t dlsr;
};
- packetType: 201,RR(Receiver Report),接收者报告:接受者的接收统计
- 其他字段意思参考RTCP-SR
RTCP-SDES rfc3550
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P| SC | PT=SDES=202 | length |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
chunk | SSRC/CSRC_1 |
1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SDES items |
| ... |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
chunk | SSRC/CSRC_2 |
2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SDES items |
| ... |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
/* 变长,根据rtcp.count决定 */
uint32_t ssrc;
struct SdesItem sdes;
};
struct SdesItem
{
uint8_t type;
uint8_t length;
char value[N]; // N=length
};
enum SdesType
{
END = 0,
CNAME, // cname与SSRC对应,cname为源的唯一表示,详情参考sdp描述
NAME, // 用户名
EMAIL, // email地址
PHONE, // 电话号码
LOC, // 位置
TOOL, // 工具
NOTE, // 备注
PRIV // 私有扩展
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 是ssrc和sdes的个数
- packetType: 202,SDES(SourceDescription),数据源的信息
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- ssrc: 与sdp中的ssrc一致
- sdes.type: 取值SdesType
- sdes.length: value长度
- sdes.value:
RTCP-BYE rfc3550
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| SC | PT=BYE=203 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: ... :
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
(opt) | length | reason for leaving ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
/* 变长,根据count决定有多少个ssrc */
uint32_t ssrc;
/* 可选 */
uint8_t length;
uint8_t reason[N]; // N=length
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 是ssrc的个数
- packetType: 203,BYE(goodbye),结束RTP传输
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- ssrc: 与sdp中的ssrc一致
- length: reason的长度
- reason: 退出原因,可选
RTCP-APP rfc3550
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| application-dependent data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
uint32_t ssrc;
/* 变长,根据count决定 */
uint32_t name;
struct AppData data;
};
/* 消息格式可以自定义,我这里只是自己列举的一个数据格式类型 */
struct AppData
{
uint8_t type;
uint8_t length;
char value[N]; // N=length
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 是name和data的个数
- packetType: 204,APP(application),应用层定义的传输控制类型
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- ssrc: 与sdp中的ssrc一致
- name: 自定义消息名
- data: 自定义数据
RTCP-RTPFB rfc4585
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| FMT | PT | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of packet sender |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of media source |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Feedback Control Information (FCI) :
: :
*/
struct RtcpHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
uint32_t senderSsrc;
uint32_t mediaSsrc;
/* FCI字段*/
};
enum FeedbackRtp
{
NACK = 1, // Generic nack。请求丢包重传
TMMBR = 3, // Temp, max media stream Bitrate Request。最大媒体流请求
TMMBN = 4, // Temp, max media stream Bitrate Notification。最大媒体流响应
SR_REQ = 5,
RAMS = 6,
TLLEI = 7,
ECN = 8,
PS = 9,
TCC = 15, // transport-cc
EXT = 31
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 取值为FeedbackRtp
- packetType: 205,RTPFB(Generic RTP Feedback),RTP反馈包,传输的控制
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- senderSsrc: 数据包发送方的ssrc
- mediaSsrc: 媒体源的ssrc
FCI字段,NACK消息的格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PID | BLP |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
PID: 丢包的RTP sequenceNumber
BLP: 继第一个序号之后的16个包的丢失情况,当丢失之后置为1
RTCP-PSFB rfc4585
图像和流媒体 -- I 帧,B帧,P帧,IDR帧的区别
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| FMT | PT | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of packet sender |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of media source |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Feedback Control Information (FCI) :
: :
*/
struct SDESHeader
{
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
uint8_t packetType;
uint16_t length;
uint32_t senderSsrc;
uint32_t mediaSsrc;
/* FCI字段*/
};
enum FeedbackPs
{
PLI = 1, // Picture Loss Indication,请求i帧,FCI字段中必须仅包含一个PLI
SLI = 2, // Slice Loss Indication,请求一个slice包
RPSI = 3, // Reference Picture Selection Indication。请求b帧
FIR = 4, // Full Intra Request Command。请求一个idr帧
TSTR = 5, // Temporal-Spatial Trade-off Request。空间换时间或时间换空间的请求
TSTN = 6, // Temporal-Spatial Trade-off Notification。空间换时间或时间换空间的响应
VBCM = 7,
PSLEI = 8,
ROI = 9,
AFB = 15,
EXT = 31
};
- version: 2
- padding: 置为1表示RTP头有填充。数据的最后一个字节表示填充了几个字节,包含这个字节本身
- count: 取值为FeedbackPs
- packetType: 206,PSFB(Payload-specific Feedback),payload反馈包,编解码的控制
- length: 指协议头和数据的长度,单位为字节。数据长度length-4
- senderSsrc: 数据包发送方的ssrc
- mediaSsrc: 媒体源的ssrc
FCI字段,SLI消息的格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| First | Number | PictureID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
First: 第一个丢失的宏块的宏块地址
Number: 丢失的宏块数
PictureID: 编解码器特定标识符的六个最低有效位
FCI字段,RPSI消息的格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PB |0| Payload Type| Native RPSI bit string |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined per codec ... | Padding (0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
DTLS-SRTP
SRTP与RTP包的主要区别是payload数据加密、SRTP MKI(主密钥标由密钥管理协议决定)、认证标签
- payload加密 加密后的数据依然保持对齐
- SRTP MKI webrtc基本没用,为0
- 认证标签 rtp头和加密payload进行哈希计算得来的
DTLS握手
- 第一次客户端发送ClientHello
- 第二次服务端发送ServerHello,发送服务端证书,服务端key,请求客户端证书,发送ServerHelloDone
- 第三次客户端发送客户端证书,客户端key,验证证书,发送加密套件,发送Finished
- 第四次服务端发送协商好的加密套件,发送Finished
数据传输
DTLS进行握手交换得到key、加密套件。然后在使用RTP进行传输,仅对payload数据进行加密