RTSPClient
RTSPClient 是RTSP协议的客户端实现,用于发送RTSP请求命令
类接口:
static RTSPClient* createNew()
用于外部创建RTSPClient实例的方法,将构造方法进行了隐藏(protect);
unsigned sendXXXXCommand()
发送RTSP请求,会传入回调函数responseHandler;
responseHandler是类内部定义的一个函数指针,统一回调的格式
typedef void (responseHandler)(RTSPClient* rtspClient, int resultCode, char* resultString);
int socketNum() const
返回用于连接的socket;
staticBoolean lookupByName(UsageEnvironment& env,char const* sourceName,
RTSPClient*& resultClient)
查找sourceName指定的RTSPClient
staticBoolean parseRTSPURL(UsageEnvironment& env, char const* url,
char*& username, char*& password,NetAddress& address, portNumBits& portNum, char const** urlSuffix =NULL)
解析输入的RTSPURL,主要用于获取服务器地址NetAddress& address和端口号portNumBits& portNum,还会返回urlSuffix的指针,标识媒体名等信息;
voidsetUserAgentString(char const* userAgentName)
指定RTSP回应消息中的"User-Agent: %s\r\n"字段,类内部保存了fUserAgentHeaderStr,会将其内容替换为userAgentName;
charconst* url() const
返回初始请求服务器的url信息,即rtsp://…//...;就是parseRTSPURL中的URL,保存在fBaseURL中;
保护方法:
voidreset()
重置RTSPClient,1、关闭socket;2、重置responseBuffer的指示变量;3、清除分BaseURL等
voidsetBaseURL(char const* url)
设置请求的URL信息fBaseURL;
virtualunsigned sendRequest(RequestRecord* request)
发送请求,请求统一封装在RequestRecord;
------------------------------------------------------------------------------------------------------------------------------------------------------
内部类
RequestRecord 公开
该类封装了请求命令,只用来保存请求的信息,如命令名称、回调函数等;
RequestRecord(unsignedcseq, char const* commandName, responseHandler* handler,
MediaSession*session = NULL, MediaSubsession* subsession = NULL,
u_int32_t booleanFlags = 0,
doublestart = 0.0f, double end = -1.0f, float scale = 1.0f,
charconst* contentStr = NULL);
所有信息都在初始化时传入,之后类为每一个信息都提供了访问方法
RequestQueue 私有
该类定义了RequestRecord的队列,可以保存请求信息,还提供了一些工具方法如下
voidputAtHead(RequestRecord* request); // "request" must not be NULL
RequestRecord*findByCSeq(unsigned cseq);
---------------------------------------------------------------------------------------------------------------------------------------------------------
成员变量:
公开
static unsigned responseBufferSize; |
响应字符串的缓冲区大小 |
私有
portNumBits fTunnelOverHTTPPortNum; |
HTTP的传输端口,为0,否则使用HTTP通信 |
int fInputSocketNum, fOutputSocketNum; |
通信socket,一般input和output使用同一个socket |
netAddressBits fServerAddress; |
服务端地址 |
char* fBaseURL; |
初始请求URL |
unsigned char fTCPStreamIdCount; |
// used for (optional) RTP/TCP |
char* fLastSessionId; |
|
unsigned fSessionTimeoutParameter; |
// optionally set in response "Session:" headers |
char* fResponseBuffer; |
服务器回应字符串缓存 |
unsigned fResponseBytesAlreadySeen, fResponseBufferBytesLeft; |
回应字符串的读取标识,已读数和剩余空间 |
RequestQueue fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse; |
请求信息队列 |
ServerMediaSession
ServerMediaSession是RTSPServer中用于表示一个媒体信息的类,内部会包含该媒体需要的子媒体ServerMediaSubsession,例如一个MP4文件既有视频也有音频,那这个ServerMediaSession就需要包含表示视频的subSession和音频的subSession。
类接口:
staticServerMediaSession* createNew(UsageEnvironment& env,
char const* streamName = NULL,
char const* info = NULL,
char const* description = NULL,
Boolean isSSM = False,
char const* miscSDPLines = NULL);
外部创建ServerMediaSession实例的方法,在Live555中对类的实例化大多采用了这种方式,在方法内部调用类的构造函数,还不知道这么做有什么用意,为什么不直接用构造函数?
staticBoolean lookupByName(UsageEnvironment& env,
char const*mediumName,
ServerMediaSession*& resultSession);
查找mediaName对应的serverMediaSession,内部是通过Medium::lookupByName(env, mediumName, medium)这个静态方法实现的,什么时候添加的?
char*generateSDPDescription();
生成媒体的SDP信息,分配的字符串内存由调用者负责释放;
关键部分
for each serverMediaSubSession {subSesssion->sdpLines()};// 产生各个子媒体的sdp描述
char const* streamName() const;
返回fStreamName,媒体名
BooleanaddSubsession(ServerMediaSubsession* subsession);
添加subSession,在ServerMediaSession内有头尾subSession的指针,可以形成单列表,
fSubsessionsTail= subsession;
subsession->fParentSession= this;
subsession->fTrackNumber =++fSubsessionCounter; // 增加count数,并将其设置为subSession的trackNameber
unsignednumSubsessions() const
返回fSubsessionCounter,在该ServerMediaSession总subSession的数目
unsignedreferenceCount() const { return fReferenceCount; }
voidincrementReferenceCount() { ++fReferenceCount; }
voiddecrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; }
Boolean& deleteWhenUnreferenced() {return fDeleteWhenUnreferenced; } // 指示是否已经没有了引用而可以析构了
void deleteAllSubsessions(); //移除所有subSession
保护方法:
ServerMediaSession(UsageEnvironment&env, char const* streamName,
char const* info, char const* description,
Boolean isSSM, char const* miscSDPLines);
构造方法,主要初始化一些sdp需要的描述信息:fStreamName,fInfoSDPString,fDescriptionSDPString,fMiscSDPLines,fCreationTime
成员变量:
ServerMediaSubsession* fSubsessionsHead; |
指向subSession列表头 |
ServerMediaSubsession* fSubsessionsTail; |
指向subSesssion列表尾 |
unsigned fSubsessionCounter; |
该serverMediaSession下subSession总数 |
char* fStreamName; |
媒体流名称 |
char* fInfoSDPString; |
i= <info> |
char* fDescriptionSDPString; |
a=x-qt-text-nam: line |
char* fMiscSDPLines; |
|
struct timeval fCreationTime; |
用于构造sessionID;// o= <session id> |
unsigned fReferenceCount; |
该媒体流被客户端的连接数 |
Boolean fDeleteWhenUnreferenced; |
标识是否已经没有客户端连接从而可以释放 |
ServerMediaSubSession
ServerMediaSubSession是一个媒体流中表示子媒体的结构
类接口:
unsignedtrackNumber() const
返回表示该subSession的ID:fTrackNumber,这个值会在ServerMediaSession添加subSession时赋予;
charconst* trackId();
返回trackID字符串fTrackId:("track%d",fTrackNumber)
virtualchar const* sdpLines() = 0;
纯虚函数,需子类具体实现,返回sdp描述中的媒体信息,如
/*
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:500
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=4D4033;
sprop-parameter-sets=Z01AM5p0FidCAAADAAIAAAMAZR4wZUA=,aO48gA==
a=control:track1
*/
virtualvoid getStreamParameters(unsigned clientSessionId, // in
netAddressBits clientAddress, // in
Port const& clientRTPPort, // in
Port const& clientRTCPPort, // in
int tcpSocketNum, // in (-1 means use UDP,not TCP)
unsigned char rtpChannelId, // in (used ifTCP)
unsigned char rtcpChannelId, // in (used ifTCP)
netAddressBits& destinationAddress, //in out
u_int8_t& destinationTTL, // in out
Boolean& isMulticast, // out
Port& serverRTPPort, // out
Port& serverRTCPPort, // out
void*& streamToken // out
) = 0;
纯虚函数,返回各种流参数;
virtualvoid startStream(unsigned clientSessionId, void* streamToken,
TaskFunc* rtcpRRHandler,
void* rtcpRRHandlerClientData,
unsigned short& rtpSeqNum,
unsigned& rtpTimestamp,
ServerRequestAlternativeByteHandler*serverRequestAlternativeByteHandler,
void*serverRequestAlternativeByteHandlerClientData) = 0;
纯虚函数,启动流传输,即开始播放;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面这些函数都只定义了接口,没有做具体实现,子类可以根据情况完成
virtualvoid 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 byrelative (i.e., NPT) time.
// "streamDuration", if >0.0,specifies how much data to stream, past "seekNPT". (If <=0.0, all remaining data isstreamed.)
// "numBytes" returns the size(in bytes) of the data to be streamed, or 0 if unknown or unlimited.
virtualvoid seekStream(unsigned clientSessionId, void* streamToken, char*&absStart, char*& absEnd);
// This routine is used to seek by'absolute' time.
// "absStart" should be a stringof the form "YYYYMMDDTHHMMSSZ" or"YYYYMMDDTHHMMSS.<frac>Z".
// "absEnd" should be eitherNULL (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 theoriginal).
virtualvoid setStreamScale(unsigned clientSessionId, void* streamToken, float scale);
virtualFramedSource* getStreamSource(void* streamToken);
virtualvoid deleteStream(unsigned clientSessionId, void*& streamToken);
virtualvoid testScaleFactor(float& scale); // sets "scale" to the actualsupported scale
virtualfloat duration() const;
// returns 0 for an unbounded session (thedefault)
// returns > 0 for a bounded session
virtualvoid getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime)const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
保护方法:
ServerMediaSubsession(UsageEnvironment&env);
构造函数,什么都没有做;
charconst* rangeSDPLine() const;
返回sdp中的区间信息:"a=range:"
ServerMediaSession* fParentSession; |
所属的媒体流ServerMediaSession |
netAddressBits fServerAddressForSDP; |
服务器地址 |
portNumBits fPortNumForSDP; |
服务器端口 |
私有成员:
ServerMediaSubsession* fNext; |
指向下一个subSession,从而形成列表 |
unsigned fTrackNumber; |
serverMediaSession为该subSession指定的id号 |
char const* fTrackId; |
id字符串,"track:id" |