Distribution_Service/CC_SDK/Include/Module/Comm/CCRTCP.h
2026-03-24 14:43:26 +08:00

394 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef SRCCTL_CC_RTCP_H
#define SRCCTL_CC_RTCP_H
#include <cstdint>
#include <vector>
#include <cstring>
#include <iostream>
#ifdef _WIN32
#include "winsock2.h"
#else
#include <arpa/inet.h> // for ntohs, ntohl
#endif
namespace CTL {
#pragma pack(push, 1) // 禁用结构体对齐
// RTCP 包类型定义
enum RtcpPacketType {
RTCP_SR = 200, // Sender Report
RTCP_RR = 201, // Receiver Report
RTCP_SDES = 202, // Source Description
RTCP_BYE = 203, // Goodbye
RTCP_APP = 204 // Application-defined
};
// SDES 项类型定义
enum SdesItemType {
SDES_END = 0,
SDES_CNAME = 1,
SDES_NAME = 2,
SDES_EMAIL = 3,
SDES_PHONE = 4,
SDES_LOC = 5,
SDES_TOOL = 6,
SDES_NOTE = 7,
SDES_PRIV = 8
};
// RTCP 通用头部 (4字节)
struct RtcpCommonHeader {
uint8_t version : 2; // 版本号 (固定为2)
uint8_t padding : 1; // 填充标志
uint8_t count : 5; // 接收报告计数或源计数
uint8_t pt; // 包类型
uint16_t length; // 长度 (以32位字为单位减1)
};
// 发送者信息 (SR包专用)
struct RtcpSenderInfo {
uint32_t ntp_msw; // NTP时间戳高位
uint32_t ntp_lsw; // NTP时间戳低位
uint32_t rtp_ts; // RTP时间戳
uint32_t pkt_count; // 发送的包总数
uint32_t octet_count; // 发送的字节总数
};
// 接收报告块 (SR/RR共用)
struct RtcpReportBlock {
uint32_t ssrc; // 数据源SSRC
uint8_t fraction_lost; // 丢包率 (1/256)
int32_t cum_pkt_loss; // 累计丢包数
uint32_t ext_high_seq; // 扩展最高序列号
uint32_t jitter; // 抖动值
uint32_t lsr; // 上次SR时间戳
uint32_t dlsr; // 上次SR到现在的延迟
};
// SDES项 (源描述)
struct RtcpSdesItem {
uint8_t type; // 项类型
uint8_t len; // 数据长度
char data[256]; // 文本内容
};
// SDES块 (包含一个SSRC的所有描述项)
struct RtcpSdesChunk {
uint32_t ssrc; // 关联的SSRC
std::vector<RtcpSdesItem> items; // 描述项列表
};
#pragma pack(pop)
class RtcpPacket {
public:
RtcpPacket() = default;
~RtcpPacket() = default;
// 解析RTCP复合包
bool parse(const uint8_t* data, size_t len);
// 获取包类型
RtcpPacketType getPacketType() const { return m_packetType; }
// 获取发送者SSRC (SR包)
uint32_t getSenderSsrc() const { return m_senderSsrc; }
// 获取接收报告块数量
size_t getReportBlockCount() const { return m_reportBlocks.size(); }
// 获取接收报告块
const std::vector<RtcpReportBlock>& getReportBlocks() const { return m_reportBlocks; }
// 获取发送者信息 (SR包)
const RtcpSenderInfo* getSenderInfo() const { return m_senderInfo.get(); }
// 获取SDES块
const std::vector<RtcpSdesChunk>& getSdesChunks() const { return m_sdesChunks; }
// 打印包信息
void printInfo() const;
private:
RtcpPacketType m_packetType = RTCP_SR;
uint32_t m_senderSsrc = 0;
std::unique_ptr<RtcpSenderInfo> m_senderInfo;
std::vector<RtcpReportBlock> m_reportBlocks;
std::vector<RtcpSdesChunk> m_sdesChunks;
// 解析各个类型的RTCP包
bool parseSrPacket(const uint8_t* data, size_t len);
bool parseRrPacket(const uint8_t* data, size_t len);
bool parseSdesPacket(const uint8_t* data, size_t len);
bool parseByePacket(const uint8_t* data, size_t len);
};
// 实现解析函数
inline bool RtcpPacket::parse(const uint8_t* data, size_t len) {
if (!data || len < sizeof(RtcpCommonHeader)) {
std::cerr << "RTCP parse error: Invalid input data or insufficient length ("
<< len << " < " << sizeof(RtcpCommonHeader) << ")" << std::endl;
return false;
}
const auto* header = reinterpret_cast<const RtcpCommonHeader*>(data);
// 详细版本检查
if (header->version != 2) {
std::cerr << "RTCP parse error: Invalid version "
<< static_cast<int>(header->version)
<< " (expected 2)" << std::endl;
return false;
}
// 包类型检查
RtcpPacketType packetType = static_cast<RtcpPacketType>(header->pt);
if (packetType < RTCP_SR || packetType > RTCP_APP) {
std::cerr << "RTCP parse error: Unsupported packet type "
<< static_cast<int>(header->pt) << std::endl;
return false;
}
// 获取实际包长度(字节)
size_t declaredLen = (ntohs(header->length) + 1) * 4;
if (declaredLen > len) {
std::cerr << "RTCP parse error: Declared length (" << declaredLen
<< ") exceeds actual data length (" << len << ")" << std::endl;
return false;
}
if (declaredLen < sizeof(RtcpCommonHeader)) {
std::cerr << "RTCP parse error: Declared length too small ("
<< declaredLen << ")" << std::endl;
return false;
}
m_packetType = packetType;
// 根据包类型解析
bool result = false;
switch (m_packetType) {
case RTCP_SR:
result = parseSrPacket(data, declaredLen);
break;
case RTCP_RR:
result = parseRrPacket(data, declaredLen);
break;
case RTCP_SDES:
result = parseSdesPacket(data, declaredLen);
break;
case RTCP_BYE:
result = parseByePacket(data, declaredLen);
break;
default:
std::cerr << "RTCP parse error: Unhandled packet type "
<< static_cast<int>(header->pt) << std::endl;
return false;
}
if (!result) {
std::cerr << "RTCP parse error: Failed to parse "
<< static_cast<int>(m_packetType) << " packet" << std::endl;
}
return result;
}
inline bool RtcpPacket::parseSrPacket(const uint8_t* data, size_t len) {
if (len < sizeof(RtcpCommonHeader) + sizeof(uint32_t) + sizeof(RtcpSenderInfo)) {
return false;
}
const uint8_t* ptr = data + sizeof(RtcpCommonHeader);
// 读取发送者SSRC
m_senderSsrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
// 读取发送者信息
m_senderInfo = std::make_unique<RtcpSenderInfo>();
m_senderInfo->ntp_msw = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_senderInfo->ntp_lsw = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_senderInfo->rtp_ts = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_senderInfo->pkt_count = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_senderInfo->octet_count = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
// 读取接收报告块
uint8_t reportCount = reinterpret_cast<const RtcpCommonHeader*>(data)->count;
for (int i = 0; i < reportCount && ptr + sizeof(RtcpReportBlock) <= data + len; ++i) {
RtcpReportBlock block{};
block.ssrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.fraction_lost = *ptr++;
block.cum_pkt_loss = ntohl(*reinterpret_cast<const int32_t*>(ptr - 1)) & 0x00FFFFFF;
ptr += 3;
block.ext_high_seq = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.jitter = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.lsr = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.dlsr = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_reportBlocks.push_back(block);
}
return true;
}
inline bool RtcpPacket::parseRrPacket(const uint8_t* data, size_t len) {
if (len < sizeof(RtcpCommonHeader) + sizeof(uint32_t)) {
return false;
}
const uint8_t* ptr = data + sizeof(RtcpCommonHeader);
// 读取接收者SSRC
m_senderSsrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
// 读取接收报告块
uint8_t reportCount = reinterpret_cast<const RtcpCommonHeader*>(data)->count;
for (int i = 0; i < reportCount && ptr + sizeof(RtcpReportBlock) <= data + len; ++i) {
RtcpReportBlock block{};
block.ssrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.fraction_lost = *ptr++;
block.cum_pkt_loss = ntohl(*reinterpret_cast<const int32_t*>(ptr - 1)) & 0x00FFFFFF;
ptr += 3;
block.ext_high_seq = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.jitter = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.lsr = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
block.dlsr = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
m_reportBlocks.push_back(block);
}
return true;
}
inline bool RtcpPacket::parseSdesPacket(const uint8_t* data, size_t len) {
const uint8_t* ptr = data + sizeof(RtcpCommonHeader);
uint8_t sourceCount = reinterpret_cast<const RtcpCommonHeader*>(data)->count;
for (int i = 0; i < sourceCount && ptr < data + len; ++i) {
RtcpSdesChunk chunk{};
// 读取SSRC
if (ptr + sizeof(uint32_t) > data + len) break;
chunk.ssrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
ptr += sizeof(uint32_t);
// 读取SDES项
while (ptr < data + len) {
uint8_t itemType = *ptr++;
if (itemType == SDES_END) {
// 跳过填充字节直到4字节边界
while ((ptr - data) % 4 != 0 && ptr < data + len) {
ptr++;
}
break;
}
if (ptr >= data + len) break;
uint8_t itemLen = *ptr++;
if (ptr + itemLen > data + len) break;
RtcpSdesItem item{};
item.type = itemType;
item.len = itemLen;
memcpy(item.data, ptr, itemLen);
item.data[itemLen] = '\0';
chunk.items.push_back(item);
ptr += itemLen;
}
m_sdesChunks.push_back(chunk);
}
return true;
}
inline bool RtcpPacket::parseByePacket(const uint8_t* data, size_t len) {
const uint8_t* ptr = data + sizeof(RtcpCommonHeader);
uint8_t sourceCount = reinterpret_cast<const RtcpCommonHeader*>(data)->count;
// 读取SSRC列表
for (int i = 0; i < sourceCount && ptr + sizeof(uint32_t) <= data + len; ++i) {
uint32_t ssrc = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
// 这里可以存储SSRC列表
ptr += sizeof(uint32_t);
}
// 如果有原因短语
if (ptr < data + len) {
uint8_t reasonLen = *ptr++;
if (ptr + reasonLen <= data + len) {
std::string reason(reinterpret_cast<const char*>(ptr), reasonLen);
// 这里可以存储离开原因
}
}
return true;
}
inline void RtcpPacket::printInfo() const {
std::cout << "RTCP Packet Type: ";
switch (m_packetType) {
case RTCP_SR: std::cout << "Sender Report"; break;
case RTCP_RR: std::cout << "Receiver Report"; break;
case RTCP_SDES: std::cout << "Source Description"; break;
case RTCP_BYE: std::cout << "Goodbye"; break;
default: std::cout << "Unknown"; break;
}
std::cout << std::endl;
std::cout << "Sender SSRC: " << m_senderSsrc << std::endl;
if (m_senderInfo) {
std::cout << "Sender Info:" << std::endl;
std::cout << " NTP Timestamp: " << m_senderInfo->ntp_msw << "." << m_senderInfo->ntp_lsw << std::endl;
std::cout << " RTP Timestamp: " << m_senderInfo->rtp_ts << std::endl;
std::cout << " Packet Count: " << m_senderInfo->pkt_count << std::endl;
std::cout << " Octet Count: " << m_senderInfo->octet_count << std::endl;
}
std::cout << "Report Blocks: " << m_reportBlocks.size() << std::endl;
for (size_t i = 0; i < m_reportBlocks.size(); ++i) {
const auto& block = m_reportBlocks[i];
std::cout << " Block " << i << ":" << std::endl;
std::cout << " SSRC: " << block.ssrc << std::endl;
std::cout << " Fraction Lost: " << static_cast<int>(block.fraction_lost) << "/256" << std::endl;
std::cout << " Cumulative Packet Loss: " << block.cum_pkt_loss << std::endl;
std::cout << " Extended Highest Sequence: " << block.ext_high_seq << std::endl;
std::cout << " Jitter: " << block.jitter << std::endl;
}
std::cout << "SDES Chunks: " << m_sdesChunks.size() << std::endl;
for (size_t i = 0; i < m_sdesChunks.size(); ++i) {
const auto& chunk = m_sdesChunks[i];
std::cout << " Chunk " << i << " (SSRC: " << chunk.ssrc << "):" << std::endl;
for (const auto& item : chunk.items) {
std::cout << " Type: " << static_cast<int>(item.type)
<< ", Length: " << static_cast<int>(item.len)
<< ", Data: " << item.data << std::endl;
}
}
}
} // namespace CTL
#endif // SRCCTL_CC_RTCP_H