Live555-RTSP服务器

RTSP Server创建

RTSP服务器初始化:

cpp 复制代码
RTSPServer::createNew->new RTSPServer::RTSPServer->GenericMediaServer::GenericMediaServer->turnOnBackgroundReadHandling(IPV4sock/IPV6sock,incomingConnectionHandlerIPv4)

如上流程,创建RTSP服务器对象时,初始化了IPV4和IPV6的监听套接字;同时注册了套接字可读事件,设置回调incomingConnectionHandlerIPv4,

cpp 复制代码
void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) {
  struct sockaddr_storage clientAddr;
  SOCKLEN_T clientAddrLen = sizeof clientAddr;
  int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
  if (clientSocket < 0) {
    int err = envir().getErrno();
    if (err != EWOULDBLOCK) {
      envir().setResultErrMsg("accept() failed: ");
    }
    return;
  }
  ignoreSigPipeOnSocket(clientSocket); // so that clients on the same host that are killed don't also kill us
  makeSocketNonBlocking(clientSocket);
  increaseSendBufferTo(envir(), clientSocket, 50*1024);
  
#ifdef DEBUG
  envir() << "accept()ed connection from " << AddressString(clientAddr).val() << "\n";
#endif
  
  // Create a new object for handling this connection:
  (void)createNewClientConnection(clientSocket, clientAddr);
}

RTSPClientConnection又构造基类GenericMediaServer::ClientConnection对象;在基类的构造函数中调用setBackgroundHandling函数注册连接套接字的可读和异常事件,并设置回调函数ClientConnection::incomingRequestHandler;

当服务器接收到新连接时函数调用路径:

cpp 复制代码
incomingConnectionHandlerOnSocket->RTSPServer::createNewClientConnection->new RTSPClientConnection->GenericMediaServer::ClientConnection->setBackgroundHandling(incomingRequestHandler)

产生新连接时回调incomingConnectionHandlerOnSocket,处理连接套接字的初始化,并调用RTSPServer::createNewClientConnection创建一个RTSPClientConnection连接对象管理这个连接;并设置了回调函数incomingRequestHandler;

当连接接收到消息时:

cpp 复制代码
incomingRequestHandler->handleRequestBytes

连接收到消息时会回调incomingRequestHandler函数,incomingRequestHandler函数读取数据之后会调用handleRequestBytes函数对数据进行解析,然后调用相应的setup/opation命令进行处理恢复;

cpp 复制代码
void GenericMediaServer::ClientConnection::incomingRequestHandler() {
  if (fInputTLS->tlsAcceptIsNeeded) { // we need to successfully call fInputTLS->accept() first:
    if (fInputTLS->accept(fOurSocket) <= 0) return; // either an error, or we need to try again later

    fInputTLS->tlsAcceptIsNeeded = False;
    // We can now read data, as usual:
  }

  int bytesRead;
  if (fInputTLS->isNeeded) {
    bytesRead = fInputTLS->read(&fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft);
  } else {
    struct sockaddr_storage dummy; // 'from' address, meaningless in this case
  
    bytesRead = readSocket(envir(), fOurSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);
  }
  handleRequestBytes(bytesRead);
}


void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {
  int numBytesRemaining = 0;
  ++fRecursionCount; // 防止在处理中删除自身

  do {
    // 1. 检查输入数据有效性
    // 2. 处理Base64解码(如果使用HTTP隧道)
    // 3. 查找消息结束标记
    // 4. 解析请求(RTSP或HTTP)
    // 5. 根据命令类型处理
    // 6. 发送响应
    // 7. 处理剩余数据(管道化请求)
  } while (numBytesRemaining > 0);

  --fRecursionCount;
  // 检查是否需要关闭连接或删除自身
  if (!fIsActive && fScheduledDelayedTask <= 0) {
    if (fRecursionCount > 0) closeSockets();
    else delete this;
  }
}

ServerMediaSession类

cpp 复制代码
class ServerMediaSession: public Medium {
public:
  static ServerMediaSession* createNew(UsageEnvironment& env,
				       char const* streamName = NULL,
				       char const* info = NULL,
				       char const* description = NULL,
				       Boolean isSSM = False,
				       char const* miscSDPLines = NULL);
	
  //通过名称在全局介质注册表中查找ServerMediaSession对象
  static Boolean lookupByName(UsageEnvironment& env,
                              char const* mediumName,
                              ServerMediaSession*& resultSession);
  //动态构建SDP描述文件:
  char* generateSDPDescription(int addressFamily); // based on the entire session
      // Note: The caller is responsible for freeing the returned string
  //获取流名称
  char const* streamName() const { return fStreamName; }
 //添加子会话,使用​​链表结构​​管理子会话,为每个子会话分配自动递增的fTrackNumber
  Boolean addSubsession(ServerMediaSubsession* subsession);
  unsigned numSubsessions() const { return fSubsessionCounter; }

  void testScaleFactor(float& scale); // sets "scale" to the actual supported scale
  float duration() const;
    // a result == 0 means an unbounded session (the default)
    // a result < 0 means: subsession durations differ; the result is -(the largest).
    // a result > 0 means: this is the duration of a bounded session

  virtual void noteLiveness();
    // called whenever a client - accessing this media - notes liveness.
    // The default implementation does nothing, but subclasses can redefine this - e.g., if you
    // want to remove long-unused "ServerMediaSession"s from the server.

  unsigned referenceCount() const { return fReferenceCount; }
  void incrementReferenceCount() { ++fReferenceCount; }
  void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; }
  Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; }

  void deleteAllSubsessions();
    // Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state
    // Note: If you have already added this "ServerMediaSession" to a server then, before calling this function,
    //   you must first close any client connections that use it,
    //   by calling "GenericMediaServer::closeAllClientSessionsForServerMediaSession()".

  Boolean streamingUsesSRTP; // by default, False
  Boolean streamingIsEncrypted; // by default, False

protected:
  //初始化成员变量,包括会话名称、信息、描述等。如果没有提供info或description,则使用库名称和版本号。记录创建时间(用于SDP的o=行)。
  ServerMediaSession(UsageEnvironment& env, char const* streamName,
		     char const* info, char const* description,
		     Boolean isSSM, char const* miscSDPLines);
  // called only by "createNew()"

  virtual ~ServerMediaSession();

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

private:
  Boolean fIsSSM;// 是否SSM(源特定组播)

  // Linkage fields:
  friend class ServerMediaSubsessionIterator;
  ServerMediaSubsession* fSubsessionsHead;// 媒体子会话链表头
  ServerMediaSubsession* fSubsessionsTail;// 链表尾
  unsigned fSubsessionCounter;

  char* fStreamName;// 会话名称(如"liveVideo")
  char* fInfoSDPString;// SDP中的会话信息
  char* fDescriptionSDPString;// SDP中的描述信息
  char* fMiscSDPLines;// 自定义SDP参数
  struct timeval fCreationTime;
  unsigned fReferenceCount;
  Boolean fDeleteWhenUnreferenced;
};


class ServerMediaSubsessionIterator {
public:
  ServerMediaSubsessionIterator(ServerMediaSession& session);
  virtual ~ServerMediaSubsessionIterator();

  ServerMediaSubsession* next(); // NULL if none
  void reset();

private:
  ServerMediaSession& fOurSession;
  ServerMediaSubsession* fNextPtr;
};

//表示​​单条媒体轨道​​(如音频流/视频流),继承关系:
class ServerMediaSubsession: public Medium {
public:
  unsigned trackNumber() const { return fTrackNumber; }
  char const* trackId();
  virtual char const* sdpLines(int addressFamily) = 0;
  virtual void getStreamParameters(unsigned clientSessionId, // in
				   struct sockaddr_storage const& clientAddress, // in
				   Port const& clientRTPPort, // in
				   Port const& clientRTCPPort, // in
				   int tcpSocketNum, // in (-1 means use UDP, not TCP)
				   unsigned char rtpChannelId, // in (used if TCP)
				   unsigned char rtcpChannelId, // in (used if TCP)
				   TLSState* tlsState, // in (used if TCP)
				   struct sockaddr_storage& destinationAddress, // in out
				   u_int8_t& destinationTTL, // in out
				   Boolean& isMulticast, // out
				   Port& serverRTPPort, // out
				   Port& serverRTCPPort, // out
				   void*& streamToken // out
				   ) = 0;
  virtual void startStream(unsigned clientSessionId, void* streamToken,
			   TaskFunc* rtcpRRHandler,
			   void* rtcpRRHandlerClientData,
			   unsigned short& rtpSeqNum,
			   unsigned& rtpTimestamp,
			   ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,
			   void* serverRequestAlternativeByteHandlerClientData) = 0;
  virtual void pauseStream(unsigned clientSessionId, void* streamToken);
  virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT,
			  double streamDuration, u_int64_t& numBytes);
     // This routine is used to seek by relative (i.e., NPT) time.
     // "streamDuration", if >0.0, specifies how much data to stream, past "seekNPT".  (If <=0.0, all remaining data is streamed.)
     // "numBytes" returns the size (in bytes) of the data to be streamed, or 0 if unknown or unlimited.
  virtual void seekStream(unsigned clientSessionId, void* streamToken, char*& absStart, char*& absEnd);
     // This routine is used to seek by 'absolute' time.
     // "absStart" should be a string of the form "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.<frac>Z".
     // "absEnd" should be either NULL (for no end time), or a string of the same form as "absStart".
     // These strings may be modified in-place, or can be reassigned to a newly-allocated value (after delete[]ing the original).
  virtual void nullSeekStream(unsigned clientSessionId, void* streamToken,
			      double streamEndTime, u_int64_t& numBytes);
     // Called whenever we're handling a "PLAY" command without a specified start time.
  virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale);
  virtual float getCurrentNPT(void* streamToken);
  virtual FramedSource* getStreamSource(void* streamToken);
  virtual void getRTPSinkandRTCP(void* streamToken,
				 RTPSink*& rtpSink, RTCPInstance*& rtcp) = 0;
     // Returns pointers to the "RTPSink" and "RTCPInstance" objects for "streamToken".
     // (This can be useful if you want to get the associated 'Groupsock' objects, for example.)
     // You must not delete these objects, or start/stop playing them; instead, that is done
     // using the "startStream()" and "deleteStream()" functions.
  virtual void deleteStream(unsigned clientSessionId, void*& streamToken);

  virtual void testScaleFactor(float& scale); // sets "scale" to the actual supported scale
  virtual float duration() const;
    // returns 0 for an unbounded session (the default)
    // returns > 0 for a bounded session
  virtual void getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime) const;
    // Subclasses can reimplement this iff they support seeking by 'absolute' time.

protected: // we're a virtual base class
  ServerMediaSubsession(UsageEnvironment& env);
  virtual ~ServerMediaSubsession();

  char const* rangeSDPLine() const;
      // returns a string to be delete[]d

  ServerMediaSession* fParentSession;
  u_int32_t fSRTP_ROC; // horrible hack for SRTP; when the ROC changes, regenerate the SDP

private:
  friend class ServerMediaSession;
  friend class ServerMediaSubsessionIterator;
  ServerMediaSubsession* fNext;

  unsigned fTrackNumber; // within an enclosing ServerMediaSession
  char const* fTrackId;
};

#endif
相关推荐
AmosTian4 分钟前
【系统与工具】Linux——Linux简介、安装、简单使用
linux·运维·服务器
YC运维1 小时前
RIP实验以及核心原理
运维·网络·智能路由器
阿蒙Amon1 小时前
C#随机数生成全面详解:从基础到高级应用
服务器·网络·c#
leo__5202 小时前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
霖002 小时前
C++学习笔记三
运维·开发语言·c++·笔记·学习·fpga开发
CodeWithMe3 小时前
【Note】《Kafka: The Definitive Guide》 第九章:Kafka 管理与运维实战
运维·分布式·kafka
这我可不懂3 小时前
Python 项目快速部署到 Linux 服务器基础教程
linux·服务器·python
bug攻城狮4 小时前
Alloy VS Promtail:基于 Loki 的日志采集架构对比与选型指南
运维·架构·grafana·数据可视化
灋✘逞_兇4 小时前
Node.Js是什么?
服务器·javascript·node.js
kfepiza4 小时前
Linux的`if test`和`if [ ]中括号`的取反语法比较 笔记250709
linux·服务器·笔记·bash