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协议介绍