live555源码简介
live555
开发库源代码包括6个部分:UsageEnviroment
、BasicUsageEnviroment
、groupsock
、liveMedia
、testProgs
、mediaServer
。
UsageEnviroment
UsageEnviroment
目录中声明一些虚类class UsageEnviroment
、class HashTable
、class TaskScheduler
,这些类中包括各种纯虚函数,这些虚函数定义出这些类的整体轮廓。这些类的某些子类,如果想要实例化的,必须描绘出这些轮廓,即实现这些函数。
class UsageEnviroment
是程序运行环境的抽象描述,通过包含TaskScheduler& fScheduler
的私有变量,表示网络功能、异步事件处理等。
class TaskScheduler
是定义如何设置RTSPServer
端的网络功能、异步事件处理。
class HashTable
是定义类似于字典的功能。
BasicUsageEnviroment
BasicUsageEnviroment
目录中,主要是对UsageEnviroment
目录中的class UsageEnviroment
、class TaskScheduler
各个部分的逐步实现,在实现的过程中逐步引入相应的成员数据。
groupsock
groupsock
目录主要是对基本的socket
封装,在liveMedia
目录中涉及网络的部分会有使用。
liveMedia
liveMeida
目录是整个live555
开发库的核心部分。
class Medim class _Tables class MediaLookupTable
class Medim
,class _Tables
在Media.hh
文件中定义,在Media.cpp
文件中实现,class MediaLookupTable
在Media.cpp
文件中定义和实现。
liveMeida
目录中最基础的类是class Medium
,liveMedia
目录下很多class
类型都是class Media
的子类。class _Tables
和class MediaLookupTable
主要是实现对Medium
的管理。
#define mediumNameMaxLen 30 class Medium { public: static Boolean lookupByName(UsageEnvironment& env, char const* mediumName, Medium*& resultMedium); static void close(UsageEnvironment& env, char const* mediumName); static void close(Medium* medium); // alternative close() method using ptrs // (has no effect if medium == NULL) UsageEnvironment& envir() const {return fEnviron;} char const* name() const {return fMediumName;} // Test for specific types of media: virtual Boolean isSource() const; virtual Boolean isSink() const; virtual Boolean isRTCPInstance() const; virtual Boolean isRTSPClient() const; virtual Boolean isRTSPServer() const; virtual Boolean isMediaSession() const; virtual Boolean isServerMediaSession() const; protected: friend class MediaLookupTable; Medium(UsageEnvironment& env); // abstract base class virtual ~Medium(); // instances are deleted using close() only TaskToken& nextTask() { return fNextTask; } private: UsageEnvironment& fEnviron; char fMediumName[mediumNameMaxLen]; TaskToken fNextTask; }; // A data structure for looking up a Medium by its string name. // (It is used only to implement "Medium", but we make it visible here, in case developers want to use it to iterate over // the whole set of "Medium" objects that we've created.) class MediaLookupTable { public: static MediaLookupTable* ourMedia(UsageEnvironment& env); HashTable const& getTable() { return *fTable; } protected: MediaLookupTable(UsageEnvironment& env); virtual ~MediaLookupTable(); private: friend class Medium; Medium* lookup(char const* name) const; // Returns NULL if none already exists void addNew(Medium* medium, char* mediumName); void remove(char const* name); void generateNewName(char* mediumName, unsigned maxLen); private: UsageEnvironment& fEnv; HashTable* fTable; unsigned fNameGenerator; }; // The structure pointed to by the "liveMediaPriv" UsageEnvironment field: class _Tables { public: static _Tables* getOurTables(UsageEnvironment& env, Boolean createIfNotPresent = True); // returns a pointer to a "_Tables" structure (creating it if necessary) void reclaimIfPossible(); // used to delete ourselves when we're no longer used MediaLookupTable* mediaTable; void* socketTable; protected: _Tables(UsageEnvironment& env); virtual ~_Tables(); private: UsageEnvironment& fEnv; };
class Medium
某种媒体class _Tables
查找表,包括void *mediaTable
,class MediaLookupTable
类型class MedaLookupTable
通过HashTabel
实现的Medium
的查找表,包括所有在UsageEnviroment
中创建的Medium
实体。
上面三种类型是通过class UsageEnviroment
类型中的void *liveMediaPriv
成员变量联系起来。其中liveMediaPriv
实际上是_Tables*
类型,而在_Tables
类型中有void *mediaTable
成员变量,mediaTable
是MediaLookupTable*
类型的。如果我们知道UsageEnviroment& env
,给出key
值,即Medium
的名称,我们就可以查找相关的Medium
。
class RTSPServer class RTSPServer::class RTSPClientSession
class RTSPServer
是class Medium
的子类,是对RTSPServer
的抽象描述。RTSPServer
主要功能包括:
[ 1 ] RTSPServer
可以接收客户端TCP
连接请求,在接收客户端TCP
连接请求后会创建class RTSPServer::class RTSPClientSession
类。class RTSPClientSession
是真正负责与客户端进行RTSP
消息的接收、解包、打包、发送,是RTSP
协议在RTSPServer
端的具体实现。
接收客户端请求的socket
和端口号,在创建RTSPServer
实例时,会调用如下接口:
static int setUpOurSocket(UsageEnvironment& env, Port& ourPort);
创建RTSPServer
端的非阻塞的监听socket
,并且调用listen
,监听网络数据。如果后续有请求消息到达,RTSPServer
进行处理。这里需要特别提出RTSPServer
处理网络数据采用的是Select
模型。例如,在创建RTSPServer
实例时源代码如下:
RTSPServer::RTSPServer(UsageEnvironment& env, int ourSocket, Port ourPort, UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds) : Medium(env), fRTSPServerSocket(ourSocket), fRTSPServerPort(ourPort), fHTTPServerSocket(-1), fHTTPServerPort(0), fClientSessionsForHTTPTunneling(NULL), fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds), fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)) { #ifdef USE_SIGNALS // Ignore the SIGPIPE signal, so that clients on the same host that are killed // don't also kill us: signal(SIGPIPE, SIG_IGN); #endif // Arrange to handle connections from others: env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this); }
通过调用TaskScheduler::turnOnBackgroundReadHandling()
,开启监听SOCKET fRTSOServerSocket
的READ
功能,设置回调函数。
static void incomingConnectionHandlerRTSP(void*, int /*mask*/); //RTSPServer接收到
TaskScheduler::doEventLoop( )
循环中
void BasicTaskScheduler0::doEventLoop(char* watchVariable) { // Repeatedly loop, handling readble sockets and timed events: while (1) { if (watchVariable != NULL && *watchVariable != 0) break; SingleStep(); } }
会调用TaskScheduler::SingleStep()
函数,在SingleStep()
函数中,我们会处理网络数据的发送和接收(Select
模型)、异步事件的处理、触发事件的处理。在TaskScheduler::SingleStep()
函数中调用Select
函数,发现监听SOCKET fRTSOServerSocket
有数据需要去读,会调用如下接口:
static void incomingConnectionHandlerRTSP(void*, int /*mask*/); //RTSPServer接收到</pre>
调用accept()
函数,创建RTSPServer
端与特定的Client
通信的socket
,获取Client
的地址,之后实例化class RTSPServer::class RTSPClientSession
。
RTSPServer::RTSPClientSession ::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr) : fOurServer(ourServer), fOurSessionId(sessionId), fOurServerMediaSession(NULL), fClientInputSocket(clientSocket), fClientOutputSocket(clientSocket), fClientAddr(clientAddr), fSessionCookie(NULL), fLivenessCheckTask(NULL), fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False), fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) { // Arrange to handle incoming requests: resetRequestBuffer(); envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); //打开int fClientInputSocket的READ功能,接收Client的RTSP消息,设置处理函数。 noteLiveness(); }
赋值:
int fRTSPServerSocket; //接收客户端TCP连接请求的SOCKET Port fRTSPServerPort; //接收客户端TCP请求的端口
[ 2 ] 增加,查找,删除RTSPServer
支持的ServerMediaSession
集合。
void addServerMediaSession(ServerMediaSession* serverMediaSession); virtual ServerMediaSession* lookupServerMediaSession(char const* streamName); void removeServerMediaSession(ServerMediaSession* serverMediaSession); void removeServerMediaSession(char const* streamName);
ServerMediaSession
集合的相关数据保存在HashTable
中,在创建RTSPServer
时new HashTable
:
HashTable* fServerMediaSessions; //服务器端ServerMediaSession的查找表,(Medium名称,指向ServerMediaSession的地址)
[ 3 ] 用户验证。
UserAuthenticationDatabase* fAuthDB
[ 4 ] TCP
打洞。
实现在RTSPServer.hh
源文件。
class RTSPServer::class RTSPClientSession
是对RTSP
协议在Server
端的描述,主要功能是:接收客户端RTSP的Request
消息、解析RTSP Request
消息、封装Server
端的RTSP Reply
消息、发送Server
端的RTSP Reply
消息。
static void incomingRequestHandler(void*, int /*mask*/); //class RTSPServer::class RTSPClientSession的整体工作流程。
参考资料
live555 media server文件播放与读内存播放
live555源码分析----SETUP命令处理流程
live555 接收rtsp视频流详细源码流程详细解析
live555源码分析—-RTP的打包与发送
live555库的rtsp服务器源码分析总结,流程详解RTSPServer - Crea
Live555源代码分析之RTSP服务器端1
live555源代码简介
live555源码分析
RTP与RTCP协议介绍