live555

最近由于项目需要,自己开始阅读live555的源码,下面是一些总结,希望和大家多多交流。

这次项目

1.live555 开发库源代码包括6个部分:UsageEnviroment、BasicUsageEnviroment、groupsock、liveMedia、testProgs、mediaServer

1)UsageEnviroment

UsageEnviroment目录中,声明一些虚类 class UsageEnviroment    class HashTable  class TaskScheduler

这些类中包括各种纯虚函数,这些虚函数定义出这些类的整体轮廓。这些类的某些子类,如果想要实例化的,必须描绘出这些轮廓。即实现这些函数。

class UsageEnviroment 是程序运行环境的抽象描述,通过包含TaskScheduler& fScheduler 的私有变量,表示网络功能、异步事件处理等。

class TaskScheduler 是定义如何设置RTSPServer端的网络功能、异步事件处理。

class HashTable 是定义类似于字典的功能。(key,value)。

注: virtual 关键字修饰的虚函数,同时不包括实现部分的函数,成为纯虚函数。带有纯虚函数的类是无法实例化的。

2)BasicUsageEnviroment

BasicUsageEnviroment目录中,主要是对UsageEnviroment目录中的class UsageEnviroment 、class TaskScheduler 各个部分的逐步实现,在实现的过程中逐步引入相应的成员数据。

3)groupsock

groupsock目录,主要是对基本的socket封装,在liveMedia目录中,涉及网络的部分会有使用。

这部分,我现在并没有太多关注。

4)liveMedia

liveMeida目录,是整个live555开发库的核心部分。

(1)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的管理


  1. #define mediumNameMaxLen 30 
  2.  
  3. class Medium { 
  4. public
  5.   static Boolean lookupByName(UsageEnvironment& env, 
  6.                   char const* mediumName, 
  7.                   Medium*& resultMedium);          //通过env.liveMediaPriv.mediaTable 这样一个MediaLookupTable里面的lookup方法查找Medium 
  8.  
  9.   static void close(UsageEnvironment& env, char const* mediumName);      //关闭特定的env中,特定的Medium,释放相关的内存 
  10.   static void close(Medium* medium); // alternative close() method using ptrs 
  11.       // (has no effect if medium == NULL) 
  12.  
  13.   UsageEnvironment& envir() const {return fEnviron;} 
  14.  
  15.   char const* name() const {return fMediumName;} 
  16.  
  17.   // Test for specific types of media: 
  18.   virtual Boolean isSource() const
  19.   virtual Boolean isSink() const
  20.   virtual Boolean isRTCPInstance() const
  21.   virtual Boolean isRTSPClient() const
  22.   virtual Boolean isRTSPServer() const
  23.   virtual Boolean isMediaSession() const
  24.   virtual Boolean isServerMediaSession() const
  25.   virtual Boolean isDarwinInjector() const
  26.  
  27. protected
  28.   Medium(UsageEnvironment& env); // abstract base class 
  29.   virtual ~Medium(); // instances are deleted using close() only 
  30.  
  31.   TaskToken& nextTask() { 
  32.     return fNextTask; 
  33.   } 
  34.  
  35. private
  36.   friend class MediaLookupTable; 
  37.   UsageEnvironment& fEnviron;                // Medium 属于的UsageEnviroment,在创建Meium实例的时候,赋值。 
  38.   char fMediumName[mediumNameMaxLen];        // Medium 的名称,例如:liveMedium0/1/2.... 
  39.   TaskToken fNextTask;                       // void*  与Medium相关的TaskToken, 
  40. }; 
#define mediumNameMaxLen 30

class Medium {
public:
  static Boolean lookupByName(UsageEnvironment& env,
			      char const* mediumName,
			      Medium*& resultMedium);          //通过env.liveMediaPriv.mediaTable 这样一个MediaLookupTable里面的lookup方法查找Medium

  static void close(UsageEnvironment& env, char const* mediumName);      //关闭特定的env中,特定的Medium,释放相关的内存
  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;
  virtual Boolean isDarwinInjector() const;

protected:
  Medium(UsageEnvironment& env); // abstract base class
  virtual ~Medium(); // instances are deleted using close() only

  TaskToken& nextTask() {
	return fNextTask;
  }

private:
  friend class MediaLookupTable;
  UsageEnvironment& fEnviron;                // Medium 属于的UsageEnviroment,在创建Meium实例的时候,赋值。
  char fMediumName[mediumNameMaxLen];        // Medium 的名称,例如:liveMedium0/1/2....
  TaskToken fNextTask;                       // void*  与Medium相关的TaskToken,
};

上面是class Medium的定义。

class Medium    某种媒体

class _Tables    查找表,包括void *mediaTable,class MediaLookupTable 类型;void* socketTable,具体类型我现在没有找到。

class MedaLookupTable    通过HashTabel实现的Medium的查找表,包括所有在UsageEnviroment 中创建的Medium实体。


上面三种类型是通过class UsageEnviroment类型中的void *liveMediaPriv 成员变量联系起来。

其中liveMediaPriv实际上是_Tables* 类型,而在_Tables类型中有void *mediaTable成员变量,mediaTable是MediaLookupTable*类型的。

如果我们知道UsageEnviroment& env,给出key值,即Medium的名称,我们就可以查找相关的Medium。


2)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实例时,会调用

  1. static int setUpOurSocket(UsageEnvironment& env, Port& ourPort); 
static int setUpOurSocket(UsageEnvironment& env, Port& ourPort);

创建RTSPServer端的非阻塞的监听Socket,并且调用listen,监听网络数据。

如果后续有请求消息到达,RTSPServer进行处理。

这里需要特别提出RTSPServer处理网络数据采用的是Select模型。

例如:在创建RTSPServer实例时,源代码如下:

  1. RTSPServer::RTSPServer(UsageEnvironment& env, 
  2.                int ourSocket, Port ourPort, 
  3.                UserAuthenticationDatabase* authDatabase, 
  4.                unsigned reclamationTestSeconds) 
  5.   : Medium(env), 
  6.     fRTSPServerSocket(ourSocket), fRTSPServerPort(ourPort), 
  7.     fHTTPServerSocket(-1), fHTTPServerPort(0), fClientSessionsForHTTPTunneling(NULL), 
  8.     fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds), 
  9.     fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)) { 
  10. #ifdef USE_SIGNALS 
  11.   // Ignore the SIGPIPE signal, so that clients on the same host that are killed 
  12.   // don't also kill us: 
  13.   signal(SIGPIPE, SIG_IGN); 
  14. #endif 
  15.  
  16.   // Arrange to handle connections from others: 
  17.   env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket, 
  18.                            (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this); 
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功能,设置回调函数,以及回调函数的参数,RTSPServer* this。
  1. static void incomingConnectionHandlerRTSP(void*, int /*mask*/);        //RTSPServer接收到 
static void incomingConnectionHandlerRTSP(void*, int /*mask*/);        //RTSPServer接收到

TaskScheduler : : doEventLoop( )循环中

  1. void BasicTaskScheduler0::doEventLoop(char* watchVariable) { 
  2.   // Repeatedly loop, handling readble sockets and timed events: 
  3.   while (1) { 
  4.     if (watchVariable != NULL && *watchVariable != 0) break
  5.     SingleStep(); 
  6.   } 
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有数据需要去读。会调用:

  1. <span style="font-family: monospace; white-space: pre;"></span><pre style="margin: 4px 0px; background-color: rgb(240, 240, 240);" class="cpp" name="code">static void incomingConnectionHandlerRTSP(void*, int /*mask*/);        //RTSPServer接收到</pre> 

 
  1. static void incomingConnectionHandlerRTSP(void*, int /*mask*/); //RTSPServer接收到

调用accept()函数,创建RTSPServer端,与特定的Client通信的SOCKET,获取Client的地址。之后实例化class RTSPServer::class RTSPClientSession。

  1. RTSPServer::RTSPClientSession 
  2. ::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr) 
  3.   : fOurServer(ourServer), fOurSessionId(sessionId), 
  4.     fOurServerMediaSession(NULL), 
  5.     fClientInputSocket(clientSocket), fClientOutputSocket(clientSocket), fClientAddr(clientAddr), 
  6.     fSessionCookie(NULL), fLivenessCheckTask(NULL), 
  7.     fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False), 
  8.     fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) { 
  9.   // Arrange to handle incoming requests: 
  10.   resetRequestBuffer();                                                      
  11.   envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket, 
  12.      (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);  //打开int fClientInputSocket的READ功能,接收Client的RTSP消息,设置处理函数。 
  13.   noteLiveness(); 
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();
}

赋值:

  1. int fRTSPServerSocket;                           //接收客户端TCP连接请求的SOCKET 
  2. Port fRTSPServerPort;                            //接收客户端TCP请求的端口 
 int fRTSPServerSocket;                           //接收客户端TCP连接请求的SOCKET
 Port fRTSPServerPort;                            //接收客户端TCP请求的端口

  [ 2 ] 增加,查找,删除RTSPServer 支持的ServerMediaSession集合。

  1. void addServerMediaSession(ServerMediaSession* serverMediaSession); 
  2. virtual ServerMediaSession* lookupServerMediaSession(char const* streamName); 
  3. void removeServerMediaSession(ServerMediaSession* serverMediaSession); 
  4. void removeServerMediaSession(char const* streamName); 
  void addServerMediaSession(ServerMediaSession* serverMediaSession);
  virtual ServerMediaSession* lookupServerMediaSession(char const* streamName);
  void removeServerMediaSession(ServerMediaSession* serverMediaSession);
  void removeServerMediaSession(char const* streamName);

ServerMediaSession集合的相关数据保存在HashTable中,在创建RTSPServer时,new HashTable:

  1. HashTable* fServerMediaSessions;          //服务器端ServerMediaSession的查找表,(Medium名称,指向ServerMediaSession的地址) 
HashTable* fServerMediaSessions;          //服务器端ServerMediaSession的查找表,(Medium名称,指向ServerMediaSession的地址)

  [ 3 ] 用户验证。

  1. UserAuthenticationDatabase* fAuthDB 
UserAuthenticationDatabase* fAuthDB

  [ 4 ]  TCP打洞。

RTSPServer.hh源文件:

  1. #define RTSP_BUFFER_SIZE 10000 // for incoming requests, and outgoing responses 
  2.  
  3. class RTSPServer: public Medium { 
  4. public
  5.   static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554, 
  6.                    UserAuthenticationDatabase* authDatabase = NULL, 
  7.                    unsigned reclamationTestSeconds = 65); 
  8.       // If ourPort.num() == 0, we'll choose the port number 
  9.       // Note: The caller is responsible for reclaiming "authDatabase" 
  10.       // If "reclamationTestSeconds" > 0, then the "RTSPClientSession" state for 
  11.       //     each client will get reclaimed (and the corresponding RTP stream(s) 
  12.       //     torn down) if no RTSP commands - or RTCP "RR" packets - from the 
  13.       //     client are received in at least "reclamationTestSeconds" seconds. 
  14.  
  15.   static Boolean lookupByName(UsageEnvironment& env, char const* name, 
  16.                   RTSPServer*& resultServer); 
  17.  
  18.   void addServerMediaSession(ServerMediaSession* serverMediaSession); 
  19.   virtual ServerMediaSession* lookupServerMediaSession(char const* streamName); 
  20.   void removeServerMediaSession(ServerMediaSession* serverMediaSession); 
  21.   void removeServerMediaSession(char const* streamName); 
  22.  
  23.   char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) const
  24.       // returns a "rtsp://" URL that could be used to access the 
  25.       // specified session (which must already have been added to 
  26.       // us using "addServerMediaSession()". 
  27.       // This string is dynamically allocated; caller should delete[] 
  28.       // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine 
  29.       //  the IP address to be used in the URL.) 
  30.   char* rtspURLPrefix(int clientSocket = -1) const
  31.       // like "rtspURL()", except that it returns just the common prefix used by 
  32.       // each session's "rtsp://" URL. 
  33.       // This string is dynamically allocated; caller should delete[] 
  34.  
  35.   UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB); 
  36.       // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one). 
  37.       // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired). 
  38.  
  39.   Boolean setUpTunnelingOverHTTP(Port httpPort); 
  40.       // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port. 
  41.       // Returns True iff the specified port can be used in this way (i.e., it's not already being used for a separate HTTP server). 
  42.       // Note: RTSP-over-HTTP tunneling is described in http://developer.apple.com/quicktime/icefloe/dispatch028.html 
  43.   portNumBits httpServerPortNum() const; // in host byte order.  (Returns 0 if not present.) 
  44.  
  45. protected
  46.   RTSPServer(UsageEnvironment& env, 
  47.          int ourSocket, Port ourPort, 
  48.          UserAuthenticationDatabase* authDatabase, 
  49.          unsigned reclamationTestSeconds); 
  50.       // called only by createNew(); 
  51.   virtual ~RTSPServer(); 
  52.  
  53.   static int setUpOurSocket(UsageEnvironment& env, Port& ourPort); 
  54.   virtual Boolean specialClientAccessCheck(int clientSocket, struct sockaddr_in& clientAddr, 
  55.                        char const* urlSuffix); 
  56.       // a hook that allows subclassed servers to do server-specific access checking 
  57.       // on each client (e.g., based on client IP address), without using 
  58.       // digest authentication. 
  59.  
  60. private: // redefined virtual functions 
  61.   virtual Boolean isRTSPServer() const
  62.  
  63. protected
  64.   // The state of each individual session handled by a RTSP server: 
  65.   class RTSPClientSession { 
  66.   public
  67.     RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, 
  68.               int clientSocket, struct sockaddr_in clientAddr); 
  69.     virtual ~RTSPClientSession(); 
  70.   protected
  71.     // Make the handler functions for each command virtual, to allow subclasses to redefine them: 
  72.     virtual void handleCmd_bad(char const* cseq); 
  73.     virtual void handleCmd_notSupported(char const* cseq); 
  74.     virtual void handleCmd_notFound(char const* cseq); 
  75.     virtual void handleCmd_unsupportedTransport(char const* cseq); 
  76.     virtual void handleCmd_OPTIONS(char const* cseq); 
  77.     virtual void handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix, 
  78.                     char const* fullRequestStr); 
  79.     virtual void handleCmd_SETUP(char const* cseq, 
  80.                  char const* urlPreSuffix, char const* urlSuffix, 
  81.                  char const* fullRequestStr); 
  82.     virtual void handleCmd_withinSession(char const* cmdName, 
  83.                      char const* urlPreSuffix, char const* urlSuffix, 
  84.                      char const* cseq, char const* fullRequestStr); 
  85.     virtual void handleCmd_TEARDOWN(ServerMediaSubsession* subsession, 
  86.                     char const* cseq); 
  87.     virtual void handleCmd_PLAY(ServerMediaSubsession* subsession, 
  88.                 char const* cseq, char const* fullRequestStr); 
  89.     virtual void handleCmd_PAUSE(ServerMediaSubsession* subsession, 
  90.                  char const* cseq); 
  91.     virtual void handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, 
  92.                      char const* cseq, char const* fullRequestStr); 
  93.     virtual void handleCmd_SET_PARAMETER(ServerMediaSubsession* subsession, 
  94.                      char const* cseq, char const* fullRequestStr); 
  95.     // Support for optional RTSP-over-HTTP tunneling: 
  96.     virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize, 
  97.                        char* urlSuffix, unsigned urlSuffixMaxSize, 
  98.                        char* sessionCookie, unsigned sessionCookieMaxSize, 
  99.                        char* acceptStr, unsigned acceptStrMaxSize); 
  100.     virtual void handleHTTPCmd_notSupported(); 
  101.     virtual void handleHTTPCmd_notFound(); 
  102.     virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie); 
  103.     virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize); 
  104.     virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr); 
  105.   protected
  106.     UsageEnvironment& envir() { return fOurServer.envir(); } 
  107.     void reclaimStreamStates(); 
  108.     void resetRequestBuffer(); 
  109.     Boolean authenticationOK(char const* cmdName, char const* cseq, 
  110.                              char const* urlSuffix, 
  111.                              char const* fullRequestStr); 
  112.     Boolean isMulticast() const { return fIsMulticast; } 
  113.     static void incomingRequestHandler(void*, int /*mask*/); 
  114.     void incomingRequestHandler1(); 
  115.     static void handleAlternativeRequestByte(void*, u_int8_t requestByte); 
  116.     void handleAlternativeRequestByte1(u_int8_t requestByte); 
  117.     void handleRequestBytes(int newBytesRead); 
  118.     void noteLiveness(); 
  119.     static void noteClientLiveness(RTSPClientSession* clientSession); 
  120.     static void livenessTimeoutTask(RTSPClientSession* clientSession); 
  121.     void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize); 
  122.   protected
  123.     RTSPServer& fOurServer; 
  124.     unsigned fOurSessionId; 
  125.     ServerMediaSession* fOurServerMediaSession; 
  126.     int fClientInputSocket, fClientOutputSocket; 
  127.     struct sockaddr_in fClientAddr; 
  128.     char* fSessionCookie; // used for optional RTSP-over-HTTP tunneling 
  129.     TaskToken fLivenessCheckTask; 
  130.     unsigned char fRequestBuffer[RTSP_BUFFER_SIZE]; 
  131.     unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft; 
  132.     unsigned char* fLastCRLF; 
  133.     unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3) 
  134.     unsigned char fResponseBuffer[RTSP_BUFFER_SIZE]; 
  135.     Boolean fIsMulticast, fSessionIsActive, fStreamAfterSETUP; 
  136.     Authenticator fCurrentAuthenticator; // used if access control is needed 
  137.     unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP 
  138.     unsigned fNumStreamStates; 
  139.     struct streamState { 
  140.       ServerMediaSubsession* subsession; 
  141.       void* streamToken; 
  142.     } * fStreamStates; 
  143.   }; 
  144.  
  145.   // If you subclass "RTSPClientSession", then you should also redefine this virtual function in order 
  146.   // to create new objects of your subclass: 
  147.   virtual RTSPClientSession* 
  148.   createNewClientSession(unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr); 
  149.  
  150.   // An iterator over our "ServerMediaSession" objects: 
  151.   class ServerMediaSessionIterator { 
  152.   public
  153.     ServerMediaSessionIterator(RTSPServer& server); 
  154.     virtual ~ServerMediaSessionIterator(); 
  155.     ServerMediaSession* next(); 
  156.   private
  157.     HashTable::Iterator *fOurIterator; 
  158.     ServerMediaSession* fNextPtr; 
  159.   }; 
  160.  
  161. private
  162.   static void incomingConnectionHandlerRTSP(void*, int /*mask*/);        //RTSPServer接收到请求 
  163.   void incomingConnectionHandlerRTSP1(); 
  164.  
  165.   static void incomingConnectionHandlerHTTP(void*, int /*mask*/); 
  166.   void incomingConnectionHandlerHTTP1(); 
  167.  
  168.   void incomingConnectionHandler(int serverSocket); 
  169.  
  170. private
  171.   friend class RTSPClientSession; 
  172.   friend class ServerMediaSessionIterator; 
  173.   int fRTSPServerSocket;                           //接收客户端TCP连接请求的SOCKET 
  174.   Port fRTSPServerPort;                            //接收客户端TCP请求的端口 
  175.   int fHTTPServerSocket; // for optional RTSP-over-HTTP tunneling 
  176.   Port fHTTPServerPort; // ditto 
  177.   HashTable* fClientSessionsForHTTPTunneling; // ditto (maps 'session cookie' strings to "RTSPClientSession"s) 
  178.   UserAuthenticationDatabase* fAuthDB;        //用户验证 
  179.   unsigned fReclamationTestSeconds; 
  180.   HashTable* fServerMediaSessions;          //服务器端ServerMediaSession的查找表,(Medium名称,指向ServerMediaSession的地址) 
  181. }; 
#define RTSP_BUFFER_SIZE 10000 // for incoming requests, and outgoing responses

class RTSPServer: public Medium {
public:
  static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554,
			       UserAuthenticationDatabase* authDatabase = NULL,
			       unsigned reclamationTestSeconds = 65);
      // If ourPort.num() == 0, we'll choose the port number
      // Note: The caller is responsible for reclaiming "authDatabase"
      // If "reclamationTestSeconds" > 0, then the "RTSPClientSession" state for
      //     each client will get reclaimed (and the corresponding RTP stream(s)
      //     torn down) if no RTSP commands - or RTCP "RR" packets - from the
      //     client are received in at least "reclamationTestSeconds" seconds.

  static Boolean lookupByName(UsageEnvironment& env, char const* name,
			      RTSPServer*& resultServer);

  void addServerMediaSession(ServerMediaSession* serverMediaSession);
  virtual ServerMediaSession* lookupServerMediaSession(char const* streamName);
  void removeServerMediaSession(ServerMediaSession* serverMediaSession);
  void removeServerMediaSession(char const* streamName);

  char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) const;
      // returns a "rtsp://" URL that could be used to access the
      // specified session (which must already have been added to
      // us using "addServerMediaSession()".
      // This string is dynamically allocated; caller should delete[]
      // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine
      //  the IP address to be used in the URL.)
  char* rtspURLPrefix(int clientSocket = -1) const;
      // like "rtspURL()", except that it returns just the common prefix used by
      // each session's "rtsp://" URL.
      // This string is dynamically allocated; caller should delete[]

  UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB);
      // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one).
      // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired).

  Boolean setUpTunnelingOverHTTP(Port httpPort);
      // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port.
      // Returns True iff the specified port can be used in this way (i.e., it's not already being used for a separate HTTP server).
      // Note: RTSP-over-HTTP tunneling is described in http://developer.apple.com/quicktime/icefloe/dispatch028.html
  portNumBits httpServerPortNum() const; // in host byte order.  (Returns 0 if not present.)

protected:
  RTSPServer(UsageEnvironment& env,
	     int ourSocket, Port ourPort,
	     UserAuthenticationDatabase* authDatabase,
	     unsigned reclamationTestSeconds);
      // called only by createNew();
  virtual ~RTSPServer();

  static int setUpOurSocket(UsageEnvironment& env, Port& ourPort);
  virtual Boolean specialClientAccessCheck(int clientSocket, struct sockaddr_in& clientAddr,
					   char const* urlSuffix);
      // a hook that allows subclassed servers to do server-specific access checking
      // on each client (e.g., based on client IP address), without using
      // digest authentication.

private: // redefined virtual functions
  virtual Boolean isRTSPServer() const;

protected:
  // The state of each individual session handled by a RTSP server:
  class RTSPClientSession {
  public:
    RTSPClientSession(RTSPServer& ourServer, unsigned sessionId,
		      int clientSocket, struct sockaddr_in clientAddr);
    virtual ~RTSPClientSession();
  protected:
    // Make the handler functions for each command virtual, to allow subclasses to redefine them:
    virtual void handleCmd_bad(char const* cseq);
    virtual void handleCmd_notSupported(char const* cseq);
    virtual void handleCmd_notFound(char const* cseq);
    virtual void handleCmd_unsupportedTransport(char const* cseq);
    virtual void handleCmd_OPTIONS(char const* cseq);
    virtual void handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,
				    char const* fullRequestStr);
    virtual void handleCmd_SETUP(char const* cseq,
				 char const* urlPreSuffix, char const* urlSuffix,
				 char const* fullRequestStr);
    virtual void handleCmd_withinSession(char const* cmdName,
					 char const* urlPreSuffix, char const* urlSuffix,
					 char const* cseq, char const* fullRequestStr);
    virtual void handleCmd_TEARDOWN(ServerMediaSubsession* subsession,
				    char const* cseq);
    virtual void handleCmd_PLAY(ServerMediaSubsession* subsession,
				char const* cseq, char const* fullRequestStr);
    virtual void handleCmd_PAUSE(ServerMediaSubsession* subsession,
				 char const* cseq);
    virtual void handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession,
					 char const* cseq, char const* fullRequestStr);
    virtual void handleCmd_SET_PARAMETER(ServerMediaSubsession* subsession,
					 char const* cseq, char const* fullRequestStr);
    // Support for optional RTSP-over-HTTP tunneling:
    virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize,
					   char* urlSuffix, unsigned urlSuffixMaxSize,
					   char* sessionCookie, unsigned sessionCookieMaxSize,
					   char* acceptStr, unsigned acceptStrMaxSize);
    virtual void handleHTTPCmd_notSupported();
    virtual void handleHTTPCmd_notFound();
    virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie);
    virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize);
    virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr);
  protected:
    UsageEnvironment& envir() { return fOurServer.envir(); }
    void reclaimStreamStates();
    void resetRequestBuffer();
    Boolean authenticationOK(char const* cmdName, char const* cseq,
                             char const* urlSuffix,
                             char const* fullRequestStr);
    Boolean isMulticast() const { return fIsMulticast; }
    static void incomingRequestHandler(void*, int /*mask*/);
    void incomingRequestHandler1();
    static void handleAlternativeRequestByte(void*, u_int8_t requestByte);
    void handleAlternativeRequestByte1(u_int8_t requestByte);
    void handleRequestBytes(int newBytesRead);
    void noteLiveness();
    static void noteClientLiveness(RTSPClientSession* clientSession);
    static void livenessTimeoutTask(RTSPClientSession* clientSession);
    void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize);
  protected:
    RTSPServer& fOurServer;
    unsigned fOurSessionId;
    ServerMediaSession* fOurServerMediaSession;
    int fClientInputSocket, fClientOutputSocket;
    struct sockaddr_in fClientAddr;
    char* fSessionCookie; // used for optional RTSP-over-HTTP tunneling
    TaskToken fLivenessCheckTask;
    unsigned char fRequestBuffer[RTSP_BUFFER_SIZE];
    unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft;
    unsigned char* fLastCRLF;
    unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3)
    unsigned char fResponseBuffer[RTSP_BUFFER_SIZE];
    Boolean fIsMulticast, fSessionIsActive, fStreamAfterSETUP;
    Authenticator fCurrentAuthenticator; // used if access control is needed
    unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP
    unsigned fNumStreamStates;
    struct streamState {
      ServerMediaSubsession* subsession;
      void* streamToken;
    } * fStreamStates;
  };

  // If you subclass "RTSPClientSession", then you should also redefine this virtual function in order
  // to create new objects of your subclass:
  virtual RTSPClientSession*
  createNewClientSession(unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr);

  // An iterator over our "ServerMediaSession" objects:
  class ServerMediaSessionIterator {
  public:
    ServerMediaSessionIterator(RTSPServer& server);
    virtual ~ServerMediaSessionIterator();
    ServerMediaSession* next();
  private:
    HashTable::Iterator *fOurIterator;
    ServerMediaSession* fNextPtr;
  };

private:
  static void incomingConnectionHandlerRTSP(void*, int /*mask*/);        //RTSPServer接收到请求
  void incomingConnectionHandlerRTSP1();

  static void incomingConnectionHandlerHTTP(void*, int /*mask*/);
  void incomingConnectionHandlerHTTP1();

  void incomingConnectionHandler(int serverSocket);

private:
  friend class RTSPClientSession;
  friend class ServerMediaSessionIterator;
  int fRTSPServerSocket;                           //接收客户端TCP连接请求的SOCKET
  Port fRTSPServerPort;                            //接收客户端TCP请求的端口
  int fHTTPServerSocket; // for optional RTSP-over-HTTP tunneling
  Port fHTTPServerPort; // ditto
  HashTable* fClientSessionsForHTTPTunneling; // ditto (maps 'session cookie' strings to "RTSPClientSession"s)
  UserAuthenticationDatabase* fAuthDB;        //用户验证
  unsigned fReclamationTestSeconds;
  HashTable* fServerMediaSessions;          //服务器端ServerMediaSession的查找表,(Medium名称,指向ServerMediaSession的地址)
};

class RTSPServer::class RTSPClientSession是对RTSP协议在Server端的描述。主要功能是:

接收客户端RTSP的Request 消息、解析RTSP Request消息、封装Server端的RTSP  Reply消息、发送Server端的RTSP  Reply消息。

  1. static void incomingRequestHandler(void*, int /*mask*/);   //class RTSPServer::class RTSPClientSession的整体工作流程。 
static void incomingRequestHandler(void*, int /*mask*/);   //class RTSPServer::class RTSPClientSession的整体工作流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值