文档章节

live555 源码分析:RTSPServer 组件结构

WolfCS
 WolfCS
发布于 2017/09/06 15:51
字数 1427
阅读 36
收藏 0

前面几篇文章分析了 live555 中 RTSP 的处理逻辑,RTSP 处理有关组件的处理逻辑有点复杂,本文就再来梳理一下它们之间的关系。

live555 中 RTSP 处理有关组件关系如下图:

事件和执行流程的源头在 TaskSchedulerGenericMediaServer 对象在创建的时候,会向 TaskScheduler 注册一个 server socket 及处理该 socket 上的事件的处理程序 GenericMediaServer::incomingConnectionHandler(void* instance, int /*mask*/)

当有客户端连接服务器时,触发 server socket 上的事件处理器执行。此时会基于客户端 socket 创建 ClientConnection 对象,及 RTSPClientConnectionRTSPClientConnection 对象在创建过程中,会将该客户端 socket 及 ClientConnection 中处理该 socket 上的事件的处理程序 GenericMediaServer::ClientConnection::incomingRequestHandler(void* instance, int /*mask*/) 注册给 TaskScheduler

在客户端发送的 RTSP 请求数据到达之后,GenericMediaServer::ClientConnection 会读取这些数据,并交给 RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) 处理。

RTSPServer::RTSPClientConnection 解析 RTSP 请求,并处理 OPTIONSDESCRIBE 和 ``SETUP 等无需流媒体会话建立即可处理的请求。

RTSPServer::RTSPClientConnection 在处理 SETUP 请求时,会创建流媒体会话的 RTSPServer::RTSPClientSession,具体的会话建立过程都会被委托给后者处理。

需要会话建立之后才能处理的请求,也会被交给 RTSPServer::RTSPClientSession 处理。

这里来看一下 RTSPServer::RTSPClientConnection 的完整定义:

class RTSPServer: public GenericMediaServer {
. . . . . .
public: // should be protected, but some old compilers complain otherwise
  // The state of a TCP connection used by a RTSP client:
  class RTSPClientSession; // forward
  class RTSPClientConnection: public GenericMediaServer::ClientConnection {
  public:
    // A data structure that's used to implement the "REGISTER" command:
    class ParamsForREGISTER {
    public:
      ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
			RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix,
			Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);
      virtual ~ParamsForREGISTER();
    private:
      friend class RTSPClientConnection;
      char const* fCmd;
      RTSPClientConnection* fOurConnection;
      char* fURL;
      char* fURLSuffix;
      Boolean fReuseConnection, fDeliverViaTCP;
      char* fProxyURLSuffix;
    };
  protected: // redefined virtual functions:
    virtual void handleRequestBytes(int newBytesRead);

  protected:
    RTSPClientConnection(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);
    virtual ~RTSPClientConnection();

    friend class RTSPServer;
    friend class RTSPClientSession;

    // Make the handler functions for each command virtual, to allow subclasses to reimplement them, if necessary:
    virtual void handleCmd_OPTIONS();
        // You probably won't need to subclass/reimplement this function; reimplement "RTSPServer::allowedCommandNames()" instead.
    virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
    virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
    virtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);
    virtual void handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
				    char const* url, char const* urlSuffix, char const* fullRequestStr,
				    Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);
        // You probably won't need to subclass/reimplement this function;
        //     reimplement "RTSPServer::weImplementREGISTER()" and "RTSPServer::implementCmd_REGISTER()" instead.
    virtual void handleCmd_bad();
    virtual void handleCmd_notSupported();
    virtual void handleCmd_notFound();
    virtual void handleCmd_sessionNotFound();
    virtual void handleCmd_unsupportedTransport();
    // 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_OPTIONS();
    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:
    void resetRequestBuffer();
    void closeSocketsRTSP();
    static void handleAlternativeRequestByte(void*, u_int8_t requestByte);
    void handleAlternativeRequestByte1(u_int8_t requestByte);
    Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr);
    void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize);
      // used to implement RTSP-over-HTTP tunneling
    static void continueHandlingREGISTER(ParamsForREGISTER* params);
    virtual void continueHandlingREGISTER1(ParamsForREGISTER* params);

    // Shortcuts for setting up a RTSP response (prior to sending it):
    void setRTSPResponse(char const* responseStr);
    void setRTSPResponse(char const* responseStr, u_int32_t sessionId);
    void setRTSPResponse(char const* responseStr, char const* contentStr);
    void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr);

    RTSPServer& fOurRTSPServer; // same as ::fOurServer
    int& fClientInputSocket; // aliased to ::fOurSocket
    int fClientOutputSocket;
    Boolean fIsActive;
    unsigned char* fLastCRLF;
    unsigned fRecursionCount;
    char const* fCurrentCSeq;
    Authenticator fCurrentAuthenticator; // used if access control is needed
    char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling
    unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3)
  };

RTSPServer::RTSPClientConnection 继承自 GenericMediaServer::ClientConnection

class GenericMediaServer: public Medium {
. . . . . .
public: // should be protected, but some old compilers complain otherwise
  // The state of a TCP connection used by a client:
  class ClientConnection {
  protected:
    ClientConnection(GenericMediaServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);
    virtual ~ClientConnection();

    UsageEnvironment& envir() { return fOurServer.envir(); }
    void closeSockets();

    static void incomingRequestHandler(void*, int /*mask*/);
    void incomingRequestHandler();
    virtual void handleRequestBytes(int newBytesRead) = 0;
    void resetRequestBuffer();

  protected:
    friend class GenericMediaServer;
    friend class ClientSession;
    friend class RTSPServer; // needed to make some broken Windows compilers work; remove this in the future when we end support for Windows
    GenericMediaServer& fOurServer;
    int fOurSocket;
    struct sockaddr_in fClientAddr;
    unsigned char fRequestBuffer[REQUEST_BUFFER_SIZE];
    unsigned char fResponseBuffer[RESPONSE_BUFFER_SIZE];
    unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft;
  };

从它们的定义,不难理解它们的职责主要在于处理网络 I/O,处理 RTSP 请求,并建立会话。

再来看 RTSPServer::RTSPClientSession 的定义:

class RTSPServer: public GenericMediaServer {
. . . . . .
  // The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server:
  class RTSPClientSession: public GenericMediaServer::ClientSession {
  protected:
    RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId);
    virtual ~RTSPClientSession();

    friend class RTSPServer;
    friend class RTSPClientConnection;
    // Make the handler functions for each command virtual, to allow subclasses to redefine them:
    virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection,
        char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);
    virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection,
        char const* cmdName,
        char const* urlPreSuffix, char const* urlSuffix,
        char const* fullRequestStr);
    virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection,
        ServerMediaSubsession* subsession);
    virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection,
        ServerMediaSubsession* subsession, char const* fullRequestStr);
    virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection,
        ServerMediaSubsession* subsession);
    virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection,
        ServerMediaSubsession* subsession, char const* fullRequestStr);
    virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection,
        ServerMediaSubsession* subsession, char const* fullRequestStr);
  protected:
    void deleteStreamByTrack(unsigned trackNum);
    void reclaimStreamStates();
    Boolean isMulticast() const { return fIsMulticast; }

    // Shortcuts for setting up a RTSP response (prior to sending it):
    void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr) { ourClientConnection->setRTSPResponse(responseStr); }
    void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId) { ourClientConnection->setRTSPResponse(responseStr, sessionId); }
    void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, contentStr); }
    void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, sessionId, contentStr); }

  protected:
    RTSPServer& fOurRTSPServer; // same as ::fOurServer
    Boolean fIsMulticast, fStreamAfterSETUP;
    unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP
    Boolean usesTCPTransport() const { return fTCPStreamIdCount > 0; }
    unsigned fNumStreamStates;
    struct streamState {
      ServerMediaSubsession* subsession;
      int tcpSocketNum;
      void* streamToken;
    } * fStreamStates;
  };

RTSPServer::RTSPClientSession 继承自 GenericMediaServer::ClientSession

  // The state of an individual client session (using one or more sequential TCP connections) handled by a server:
  class ClientSession {
  protected:
    ClientSession(GenericMediaServer& ourServer, u_int32_t sessionId);
    virtual ~ClientSession();

    UsageEnvironment& envir() { return fOurServer.envir(); }
    void noteLiveness();
    static void noteClientLiveness(ClientSession* clientSession);
    static void livenessTimeoutTask(ClientSession* clientSession);

  protected:
    friend class GenericMediaServer;
    friend class ClientConnection;
    GenericMediaServer& fOurServer;
    u_int32_t fOurSessionId;
    ServerMediaSession* fOurServerMediaSession;
    TaskToken fLivenessCheckTask;
  };

不难理解 RTSPServer::RTSPClientSession 用于封装整个流媒体会话,处理那些要求流媒体会话已经建立的 RTSP 请求,如 PLAY 等。

具体的流媒体数据的交互,如音视频文件/数据的解析,RTP/RTCP 数据的打包及收发等,则依赖于 ServerMediaSessionServerMediaSubsession

Done。

live555 源码分析系列文章

live555 源码分析:简介 live555 源码分析:基础设施 live555 源码分析:MediaSever Wireshark 抓包分析 RTSP/RTP/RTCP 基本工作过程 live555 源码分析:RTSPServer live555 源码分析:DESCRIBE 的处理 live555 源码分析:SETUP 的处理 live555 源码分析:PLAY 的处理 live555 源码分析:RTSPServer 组件结构

© 著作权归作者所有

共有 人打赏支持
WolfCS
粉丝 80
博文 147
码字总数 505099
作品 4
杭州
高级程序员
基于Live555实现RtspServer及高清高码率视频传输优化

基于Live555实现RtspServer及高清高码率视频传输优化 最近做了一些pc和嵌入式平台的RTSP服务器项目,大多数的要求是简单但是功能全面,并且性能还要强劲。综合考虑后,基本都是在基于live555...

haibindev
08/20
0
0
live555源码学习1---Socket流程架构图

怎么说呢,换了工作环境,好多软件公司禁止使用了,有道笔记也无法使用了。发现博客园还可以上传图片,以后只能在这里记录了。 越发的感觉需要尽快把live555的代码拿下。因为工作环境问题,w...

woojim
09/24
0
0
live555:RTSP实现流程记录

1、 在创建RTSPServer的时候,会预先建议一个TCP监听,端口为创建RTSPServer时传入的值,创建位置 RTSPServer::createNew- setUpOurSocket 函数,setUpOurSocket函数中 进行listen 操作,并发...

jamin-snails
2015/08/13
0
0
RTSP学习笔记(4)LiveMediaServer流程分析

Live555MediaServer 1、初始化 BasicTaskschedular BasicUsageEnvironment RTSPServer |--------new RTSPServer |------setupOurSocket创建监听客户端连接用的socket |------turnOnBackgroun......

Sean-x
2016/02/23
49
0
live555 --- vs2010编译

最近想研究下live555,在ubuntu下编译并运行,虽然有cgdb可以进行源码调试,但总感觉调试时不够直观和简便,于是想在vs2010下编译。 从http://live555sourcecontrol.googlecode.com/svn/trun...

长平狐
2012/09/20
2.4K
0

没有更多内容

加载失败,请刷新页面

加载更多

hive分区

hive为啥分区? hive为了避免全表扫描,从而引进分区技术来将数据进行划分。减少不必要数据的扫描,从而提高效率。 hive的分区和MySQL的分区的区别? mysql分区字段用的是表内字段;而hive分...

Mr_yul
28分钟前
1
0
log4j2发送消息至Kafka

title: 自定义log4j2发送日志到Kafka tags: log4j2,kafka 为了给公司的大数据平台提供各项目组的日志,而又使各项目组在改动上无感知。做了一番调研后才发现log4j2默认有支持将日志发送到kaf...

微笑向暖wx
32分钟前
0
0
LINUX中如何查看某个端口是否被占用(转发)

LINUX中如何查看某个端口是否被占用 之前查询端口是否被占用一直搞不明白,问了好多人,终于搞懂了,现在总结下: 1.netstat -anp |grep 端口号 如下,我以3306为例,netstat -anp |grep 33...

覃大光
今天
1
0
JBolt 1.5.0新版发布,升级到支持最新版JFinal和Jetty,实现了在线更新插件功能

JBolt是一个JFinal极速开发框架 定制版IDE插件 目前仅有Eclipse插件版,Idea插件版正在开发中。 JBolt的详细使用教程请移步到这里 =====版本1.5.0 更新内容 2018年10月13日10:41:52===== 注意...

山东-小木
今天
0
0
laravel 微信支付

1.composer加载laravel微信支付第三方文件 composer require "overtrue/laravel-wechat:~4.0" composer require simplesoftwareio/simple-qrcode 1.3.* //composer生成二维码文件 2.改confi......

vio小黑
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部