RTSP Server创建
RTSP服务器初始化:
RTSPServer::createNew->new RTSPServer::RTSPServer->GenericMediaServer::GenericMediaServer->turnOnBackgroundReadHandling(IPV4sock/IPV6sock,incomingConnectionHandlerIPv4)
如上流程,创建RTSP服务器对象时,初始化了IPV4和IPV6的监听套接字;同时注册了套接字可读事件,设置回调incomingConnectionHandlerIPv4,
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;
当服务器接收到新连接时函数调用路径:
incomingConnectionHandlerOnSocket->RTSPServer::createNewClientConnection->new RTSPClientConnection->GenericMediaServer::ClientConnection->setBackgroundHandling(incomingRequestHandler)
产生新连接时回调incomingConnectionHandlerOnSocket,处理连接套接字的初始化,并调用RTSPServer::createNewClientConnection创建一个RTSPClientConnection连接对象管理这个连接;并设置了回调函数incomingRequestHandler;
当连接接收到消息时:
incomingRequestHandler->handleRequestBytes
连接收到消息时会回调incomingRequestHandler函数,incomingRequestHandler函数读取数据之后会调用handleRequestBytes函数对数据进行解析,然后调用相应的setup/opation命令进行处理恢复;
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类
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