当前位置: 首页 > news >正文

Live555-RTSP服务器

RTSP Server创建

RTSP服务器初始化:

RTSPServer::createNew->new RTSPServer::RTSPServer->GenericMediaServer::GenericMediaServer->turnOnBackgroundReadHandling(IPV4sock/IPV6sock,incomingConnectionHandlerIPv4)

如上流程,创建RTSP服务器对象时,初始化了IPV4和IPV6的监听套接字;同时注册了套接字可读事件,设置回调incomingConnectionHandlerIPv4,

void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) {struct sockaddr_storage clientAddr;SOCKLEN_T clientAddrLen = sizeof clientAddr;int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);if (clientSocket < 0) {int err = envir().getErrno();if (err != EWOULDBLOCK) {envir().setResultErrMsg("accept() failed: ");}return;}ignoreSigPipeOnSocket(clientSocket); // so that clients on the same host that are killed don't also kill usmakeSocketNonBlocking(clientSocket);increaseSendBufferTo(envir(), clientSocket, 50*1024);#ifdef DEBUGenvir() << "accept()ed connection from " << AddressString(clientAddr).val() << "\n";
#endif// Create a new object for handling this connection:(void)createNewClientConnection(clientSocket, clientAddr);
}

RTSPClientConnection又构造基类GenericMediaServer::ClientConnection对象;在基类的构造函数中调用setBackgroundHandling函数注册连接套接字的可读和异常事件,并设置回调函数ClientConnection::incomingRequestHandler;

当服务器接收到新连接时函数调用路径:

incomingConnectionHandlerOnSocket->RTSPServer::createNewClientConnection->new RTSPClientConnection->GenericMediaServer::ClientConnection->setBackgroundHandling(incomingRequestHandler)

产生新连接时回调incomingConnectionHandlerOnSocket,处理连接套接字的初始化,并调用RTSPServer::createNewClientConnection创建一个RTSPClientConnection连接对象管理这个连接;并设置了回调函数incomingRequestHandler;

当连接接收到消息时:

incomingRequestHandler->handleRequestBytes

连接收到消息时会回调incomingRequestHandler函数,incomingRequestHandler函数读取数据之后会调用handleRequestBytes函数对数据进行解析,然后调用相应的setup/opation命令进行处理恢复;

void GenericMediaServer::ClientConnection::incomingRequestHandler() {if (fInputTLS->tlsAcceptIsNeeded) { // we need to successfully call fInputTLS->accept() first:if (fInputTLS->accept(fOurSocket) <= 0) return; // either an error, or we need to try again laterfInputTLS->tlsAcceptIsNeeded = False;// We can now read data, as usual:}int bytesRead;if (fInputTLS->isNeeded) {bytesRead = fInputTLS->read(&fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft);} else {struct sockaddr_storage dummy; // 'from' address, meaningless in this casebytesRead = readSocket(envir(), fOurSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);}handleRequestBytes(bytesRead);
}void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {int numBytesRemaining = 0;++fRecursionCount; // 防止在处理中删除自身do {// 1. 检查输入数据有效性// 2. 处理Base64解码(如果使用HTTP隧道)// 3. 查找消息结束标记// 4. 解析请求(RTSP或HTTP)// 5. 根据命令类型处理// 6. 发送响应// 7. 处理剩余数据(管道化请求)} while (numBytesRemaining > 0);--fRecursionCount;// 检查是否需要关闭连接或删除自身if (!fIsActive && fScheduledDelayedTask <= 0) {if (fRecursionCount > 0) closeSockets();else delete this;}
}

ServerMediaSession类


class ServerMediaSession: public Medium {
public:static ServerMediaSession* createNew(UsageEnvironment& env,char const* streamName = NULL,char const* info = NULL,char const* description = NULL,Boolean isSSM = False,char const* miscSDPLines = NULL);//通过名称在全局介质注册表中查找ServerMediaSession对象static Boolean lookupByName(UsageEnvironment& env,char const* mediumName,ServerMediaSession*& resultSession);//动态构建SDP描述文件:char* generateSDPDescription(int addressFamily); // based on the entire session// Note: The caller is responsible for freeing the returned string//获取流名称char const* streamName() const { return fStreamName; }//添加子会话,使用​​链表结构​​管理子会话,为每个子会话分配自动递增的fTrackNumberBoolean addSubsession(ServerMediaSubsession* subsession);unsigned numSubsessions() const { return fSubsessionCounter; }void testScaleFactor(float& scale); // sets "scale" to the actual supported scalefloat duration() const;// a result == 0 means an unbounded session (the default)// a result < 0 means: subsession durations differ; the result is -(the largest).// a result > 0 means: this is the duration of a bounded sessionvirtual void noteLiveness();// called whenever a client - accessing this media - notes liveness.// The default implementation does nothing, but subclasses can redefine this - e.g., if you// want to remove long-unused "ServerMediaSession"s from the server.unsigned referenceCount() const { return fReferenceCount; }void incrementReferenceCount() { ++fReferenceCount; }void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; }Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; }void deleteAllSubsessions();// Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state// Note: If you have already added this "ServerMediaSession" to a server then, before calling this function,//   you must first close any client connections that use it,//   by calling "GenericMediaServer::closeAllClientSessionsForServerMediaSession()".Boolean streamingUsesSRTP; // by default, FalseBoolean streamingIsEncrypted; // by default, Falseprotected://初始化成员变量,包括会话名称、信息、描述等。如果没有提供info或description,则使用库名称和版本号。记录创建时间(用于SDP的o=行)。ServerMediaSession(UsageEnvironment& env, char const* streamName,char const* info, char const* description,Boolean isSSM, char const* miscSDPLines);// called only by "createNew()"virtual ~ServerMediaSession();private: // redefined virtual functionsvirtual Boolean isServerMediaSession() const;private:Boolean fIsSSM;// 是否SSM(源特定组播)// Linkage fields:friend class ServerMediaSubsessionIterator;ServerMediaSubsession* fSubsessionsHead;// 媒体子会话链表头ServerMediaSubsession* fSubsessionsTail;// 链表尾unsigned fSubsessionCounter;char* fStreamName;// 会话名称(如"liveVideo")char* fInfoSDPString;// SDP中的会话信息char* fDescriptionSDPString;// SDP中的描述信息char* fMiscSDPLines;// 自定义SDP参数struct timeval fCreationTime;unsigned fReferenceCount;Boolean fDeleteWhenUnreferenced;
};class ServerMediaSubsessionIterator {
public:ServerMediaSubsessionIterator(ServerMediaSession& session);virtual ~ServerMediaSubsessionIterator();ServerMediaSubsession* next(); // NULL if nonevoid reset();private:ServerMediaSession& fOurSession;ServerMediaSubsession* fNextPtr;
};//表示​​单条媒体轨道​​(如音频流/视频流),继承关系:
class ServerMediaSubsession: public Medium {
public:unsigned trackNumber() const { return fTrackNumber; }char const* trackId();virtual char const* sdpLines(int addressFamily) = 0;virtual void getStreamParameters(unsigned clientSessionId, // instruct sockaddr_storage const& clientAddress, // inPort const& clientRTPPort, // inPort const& clientRTCPPort, // inint tcpSocketNum, // in (-1 means use UDP, not TCP)unsigned char rtpChannelId, // in (used if TCP)unsigned char rtcpChannelId, // in (used if TCP)TLSState* tlsState, // in (used if TCP)struct sockaddr_storage& destinationAddress, // in outu_int8_t& destinationTTL, // in outBoolean& isMulticast, // outPort& serverRTPPort, // outPort& serverRTCPPort, // outvoid*& streamToken // out) = 0;virtual void startStream(unsigned clientSessionId, void* streamToken,TaskFunc* rtcpRRHandler,void* rtcpRRHandlerClientData,unsigned short& rtpSeqNum,unsigned& rtpTimestamp,ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,void* serverRequestAlternativeByteHandlerClientData) = 0;virtual void pauseStream(unsigned clientSessionId, void* streamToken);virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT,double streamDuration, u_int64_t& numBytes);// This routine is used to seek by relative (i.e., NPT) time.// "streamDuration", if >0.0, specifies how much data to stream, past "seekNPT".  (If <=0.0, all remaining data is streamed.)// "numBytes" returns the size (in bytes) of the data to be streamed, or 0 if unknown or unlimited.virtual void seekStream(unsigned clientSessionId, void* streamToken, char*& absStart, char*& absEnd);// This routine is used to seek by 'absolute' time.// "absStart" should be a string of the form "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.<frac>Z".// "absEnd" should be either NULL (for no end time), or a string of the same form as "absStart".// These strings may be modified in-place, or can be reassigned to a newly-allocated value (after delete[]ing the original).virtual void nullSeekStream(unsigned clientSessionId, void* streamToken,double streamEndTime, u_int64_t& numBytes);// Called whenever we're handling a "PLAY" command without a specified start time.virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale);virtual float getCurrentNPT(void* streamToken);virtual FramedSource* getStreamSource(void* streamToken);virtual void getRTPSinkandRTCP(void* streamToken,RTPSink*& rtpSink, RTCPInstance*& rtcp) = 0;// Returns pointers to the "RTPSink" and "RTCPInstance" objects for "streamToken".// (This can be useful if you want to get the associated 'Groupsock' objects, for example.)// You must not delete these objects, or start/stop playing them; instead, that is done// using the "startStream()" and "deleteStream()" functions.virtual void deleteStream(unsigned clientSessionId, void*& streamToken);virtual void testScaleFactor(float& scale); // sets "scale" to the actual supported scalevirtual float duration() const;// returns 0 for an unbounded session (the default)// returns > 0 for a bounded sessionvirtual void getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime) const;// Subclasses can reimplement this iff they support seeking by 'absolute' time.protected: // we're a virtual base classServerMediaSubsession(UsageEnvironment& env);virtual ~ServerMediaSubsession();char const* rangeSDPLine() const;// returns a string to be delete[]dServerMediaSession* fParentSession;u_int32_t fSRTP_ROC; // horrible hack for SRTP; when the ROC changes, regenerate the SDPprivate:friend class ServerMediaSession;friend class ServerMediaSubsessionIterator;ServerMediaSubsession* fNext;unsigned fTrackNumber; // within an enclosing ServerMediaSessionchar const* fTrackId;
};#endif
http://www.xdnf.cn/news/1091269.html

相关文章:

  • Higress 上架 KubeSphere Marketplace,助力企业构建云原生流量入口
  • 【Linux】Rocky Linux 安装 Docker 与 Docker-Compose
  • React Native 状态管理方案全面对比
  • 暑假算法日记第五天
  • MySQL事务操作全解析
  • ReactNative【实战系列教程】我的小红书 6 -- 购物(含商品搜索、商品分类、商品列表)
  • uniapp真机调试“没有检测到设备,请插入设备或启动模拟器后点击刷新再试”
  • 【内核基础精讲】I2C 子系统核心概念与结构全解析
  • 从互联网电脑迁移Dify到内网部署Dify方法记录
  • 【基础算法】贪心 (四) :区间问题
  • Java——异常
  • 自然语言处理中probe探测是什么意思。
  • 从传统到智能:地质灾害风险评估、易发性分析与灾后重建;AI大语言模型DeepSeek、ChatGPT、GIS、Python和机器学习深度融合
  • 【SQL】使用UPDATE修改表字段的时候,遇到1054 或者1064的问题怎么办?
  • 使用SSL For Free 申请HTTPS证书说明文档
  • Laravel 动态生成 PDF:基于 KnpSnappy 实现多公司页眉页脚差异化配置
  • Cadence学习笔记
  • STM32继电器万能控制设备
  • ARM单片机OTA解析(一)
  • HashMap中的get,put方法源码解析(超详细)
  • PHP 基于模板动态生成 Word 文档:图片 + 表格数据填充全方案(PHPOffice 实战)
  • RabbitMQ 高级特性之延迟队列
  • SQL Server通过存储过程实现HTML页面生成
  • mac m1安装大模型工具vllm
  • 迁移Oracle SH 示例 schema 到 PostgreSQL
  • 双指针-15.三数之和-力扣(LeetCode)
  • 算法核心知识复习:排序算法对比 + 递归与递推深度解析(根据GESP四级题目总结)
  • Oracle 数据库升级踩坑:DBLink ORA-02019 问题解决思路
  • 使用 Docker 搭建 Rust Web 应用开发环境——AI教你学Docker
  • 工程改Mvvm