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协议介绍
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。