Distribution_Service/CC_SDK/Include/Module/Comm/RTSP/CCRTSPDataChannel.h

293 lines
12 KiB
C
Raw Normal View History

2026-03-24 14:43:26 +08:00
#ifndef SRCCTL_RTSP_DATA_CHANNEL_H
#define SRCCTL_RTSP_DATA_CHANNEL_H
#include "Socket/CCServerSocket.h"
#include "Socket/CCDatagramSocket.h"
#include "CCSDP.h"
#define CC_R_RTSP_BUFFER_SIZE 1
namespace CTL{
typedef struct RTSP_Message{
int statusCode = 0; // 状态码 (响应时使用)
int port = 0; // 客户端端口号
bool isRequest = true; // 是否为请求消息(true)还是响应消息(false)
String client_ip; // 客户端IP
String url_data; // 请求URL
String method; // RTSP方法 (OPTIONS, DESCRIBE, SETUP, PLAY等)
String uri; // 请求URI
String uri_path; // 请求URI路径
String version; // RTSP版本 (如"RTSP/1.0")
String reasonPhrase; // 原因短语 (响应时使用)
std::map<String, String> headers; // 头部字段
String body; // 消息体
String sdp_content; // SDP内容
} RTSP_Request;
class RTSPDataChannel{
ClientSocket* socket_t = nullptr;
public:
explicit RTSPDataChannel(ClientSocket* socket){
socket_t = socket;
}
~RTSPDataChannel(){
if (socket_t) {
socket_t->close();
socket_t = nullptr;
}
}
static void MessagePrint(const String& message,...){
System::Println(message);
}
int receive(char *buffer, const size_t size) const {
if (socket_t && socket_t->isConnect()) {
const auto input = socket_t->getInputStream();
if (input->available()) {
return input->read(buffer, size);
}
return -2;
}
return -1;
}
int write(const char *buffer, const size_t size) const {
if (socket_t && socket_t->isConnect()) {
const auto output = socket_t->getOutputStream();
return output->write(buffer,size);
}
return 0;
}
String readHeader() const{
if (this->socket_t) {
String data;
data.reserve(4096); // 预分配内存
int ET = 1;
while (true){
char buffer[CC_R_RTSP_BUFFER_SIZE] = {0};
if(const auto length = receive(buffer,CC_R_RTSP_BUFFER_SIZE); length > 0){
data.append(buffer, length); // 块追加代替逐个字符处理
if (const auto pos = data.find("\r\n\r\n"); pos != CTL::String::npos) {
data.resize(pos + 4); // 截断到header结束位置
break;
}
}
else if (length == -2) {
if (ET >= 1000 * 1000) {
this->MessagePrint("RTSPDataChannel readHeader -> Timeout");
break;
}
ET++;
Thread::Sleep(1);
}
else{
return "close";
}
}
return data;
}
return "Error_10030";
}
String readData(const uint64_t length) const{
if (this->socket_t) {
String data;
data.reserve(length); // 预分配内存
int ET = 1;
while (true){
char buffer[CC_R_RTSP_BUFFER_SIZE] = {0};
if(const auto len = receive(buffer,CC_R_RTSP_BUFFER_SIZE); len > 0){
data.append(buffer, len);
if (data.length() >= length) {
break;
}
}
else if (len == -2) {
if (ET >= 1000 * 300) {
this->MessagePrint("RTSPDataChannel readData -> Timeout");
break;
}
ET++;
Thread::Sleep(1);
}
else{
return "close";
}
}
return data;
}
return "Error_10030";
}
static RTSP_Message ParseRTSP(const String& data){
RTSP_Message msg;
if (data.empty()) {
return msg;
}
msg.url_data = data;
// 查找空行(\r\n\r\n)来分离头部和消息体
size_t headerEndPos = data.find("\r\n\r\n");
String headersPart;
String bodyPart;
if (headerEndPos != CTL::String::npos) {
headersPart = data.substr(0, headerEndPos);
bodyPart = data.substr(headerEndPos + 4); // 跳过"\r\n\r\n"
}
else {
headersPart = data;
}
// 分割头部行
std::vector<String> lines;
String currentLine;
for (size_t i = 0; i < headersPart.length(); ++i) {
if (headersPart[i] == '\r' && i + 1 < headersPart.length() && headersPart[i + 1] == '\n') {
lines.push_back(currentLine);
currentLine.clear();
i++; // 跳过'\n'
} else {
currentLine += headersPart[i];
}
}
if (!currentLine.empty()) {
lines.push_back(currentLine);
}
if (!lines.empty()) {
// 解析第一行 (请求行或状态行)
const String& firstLine = lines[0];
// 检查是请求还是响应
if (firstLine.find("RTSP/") == 0) {
// 这是响应行: "RTSP/1.0 200 OK"
msg.isRequest = false;
size_t firstSpace = firstLine.find(' ');
if (firstSpace != String::npos) {
size_t secondSpace = firstLine.find(' ', firstSpace + 1);
if (secondSpace != String::npos) {
msg.version = firstLine.substr(0, firstSpace);
try {
msg.statusCode = std::stoi(firstLine.substr(firstSpace + 1,
secondSpace - firstSpace - 1));
}
catch (...) {
msg.statusCode = 500; // 默认错误状态
}
msg.reasonPhrase = firstLine.substr(secondSpace + 1);
}
}
}
else {
// 这是请求行: "OPTIONS rtsp://... RTSP/1.0"
size_t firstSpace = firstLine.find(' ');
size_t lastSpace = firstLine.rfind(' ');
if (firstSpace != String::npos && lastSpace != String::npos && firstSpace < lastSpace) {
msg.method = firstLine.substr(0, firstSpace);
msg.uri = firstLine.substr(firstSpace + 1, lastSpace - firstSpace - 1);
msg.version = firstLine.substr(lastSpace + 1);
// 从URI中解析路径部分
size_t schemeEnd = msg.uri.find("://");
if (schemeEnd != String::npos) {
// 跳过协议和主机部分,找到路径
size_t hostStart = schemeEnd + 3;
size_t pathStart = msg.uri.find('/', hostStart);
if (pathStart != String::npos) {
msg.uri_path = msg.uri.substr(pathStart);
} else {
// 如果没有路径,则设置为根路径
msg.uri_path = "/";
}
} else {
// 如果没有协议前缀整个URI可能是路径
if (msg.uri.empty() || msg.uri[0] != '/') {
msg.uri_path = "/" + msg.uri;
} else {
msg.uri_path = msg.uri;
}
}
}
}
// 解析头部字段
for (size_t i = 1; i < lines.size(); ++i) {
const String& line = lines[i];
size_t colonPos = line.find(':');
if (colonPos != String::npos) {
String key = line.substr(0, colonPos);
String value = line.substr(colonPos + 1);
// 移除键和值前后的空白字符
size_t startKey = key.find_first_not_of(" \t");
size_t endKey = key.find_last_not_of(" \t");
if (startKey != String::npos && endKey != String::npos) {
key = key.substr(startKey, endKey - startKey + 1);
} else if (startKey == String::npos) {
continue; // 跳过无效行
}
size_t startPos = value.find_first_not_of(" \t");
size_t endPos = value.find_last_not_of(" \t");
if (startPos != String::npos && endPos != String::npos) {
value = value.substr(startPos, endPos - startPos + 1);
} else if (startPos == String::npos) {
value.clear();
}
// 将头部字段转换为小写作为键
String lowerKey = key;
std::transform(lowerKey.begin(), lowerKey.end(), lowerKey.begin(), ::tolower);
msg.headers[lowerKey] = value;
}
}
}
// 设置消息体
msg.body = bodyPart;
return msg;
}
};
class RTSP_Response{
RTSPDataChannel* socket_t = nullptr;
std::map<String, String> headers;
SDPBuilder sdp_builder;
public:
//-----------------------------------------------------------------------------------------
int statusCode = 200;
String reasonPhrase = "OK";
bool auto_send = true;
//-----------------------------------------------------------------------------------------
void setSocket(RTSPDataChannel* socket){
this->socket_t = socket;
}
RTSPDataChannel* getSocket() const{
return socket_t;
}
String getHeader(const String& key) const{
auto it = headers.find(key);
if (it != headers.end()) {
return it->second;
}
return "";
}
void setHeader(const String& key, const String& value){
headers[key] = value;
}
String getBuild() const{
String response = String::format("RTSP/1.0 {} {}\r\n", statusCode, reasonPhrase.c_str());
for (const auto& header : headers) {
response.append(String::format("{}: {}\r\n",header.first.c_str(),header.second.c_str()));
}
response.append("\r\n");
return response;
}
bool send(){
if(socket_t != nullptr){
int ret = socket_t->write(getBuild().c_str(), getBuild().length());
if (ret > 0) {
auto_send = false;
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------------------
};
}
#endif