Live555原始碼徹底解密(根據testRTSPClient講解)
RTSP的Client建立流程(testProgs中的testRTSPClient示例)
參考文件:
testRtspClient流程圖請參考下面連結:
1)
Sink和source
Source是接收資料,Sink是消費資料;
int main(intargc,char**
argv) {
// Begin by setting up our usage environment:
TaskScheduler*
scheduler = BasicTaskScheduler::createNew();
UsageEnvironment*
env = BasicUsageEnvironment::createNew(*scheduler);
// We need at least one "rtsp://" URL argument:
if (argc < 2) {
usage(*env,argv[0]);
return 1;
}
// There are argc-1 URLs: argv[1] through argv[argc-1]. Open and start streaming each one:
for (inti = 1;i <=argc-1; ++i) {
openURL(*env,argv[0],argv[i]);
}
// All subsequent activity takes place within the event loop:
env->taskScheduler().doEventLoop(&eventLoopWatchVariable);
// This function call does not return, unless, at some point in time, "eventLoopWatchVariable" gets set to something non-zero.
return 0;
}
TestRtspClient的堆疊呼叫流程如下:
1)
首先OpenURL,函式如下:
void
openURL(UsageEnvironment&
env, char const*progName,charconst*
rtspURL) {
// Begin by creating a "RTSPClient" object. Note that there is a separate "RTSPClient" object for each stream that we wish
// to receive (even if more than stream uses the same "rtsp://" URL).
RTSPClient*
rtspClient = ourRTSPClient::createNew(env,rtspURL,RTSP_CLIENT_VERBOSITY_LEVEL,progName);
if (rtspClient ==NULL) {
env <<
"Failed to create a RTSP client for URL \"" <<
rtspURL << "\": " <<
env.getResultMsg() <<
"\n";
return;
}
++rtspClientCount;
// Next, send a RTSP "DESCRIBE" command, to get a SDP description for the stream.
// Note that this command - like all RTSP commands - is sent asynchronously; we do not block, waiting for a response.
// Instead, the following function call returns immediately, and we handle the RTSP response later, from within the event loop:
rtspClient->sendDescribeCommand(continueAfterDESCRIBE);
2) }
首先通過ourRTSPClient::createNew函式最終會呼叫ourRTSPClient的建構函式,基類RTSPClient的指標指向派生類ourRTSPClient物件,並且最終會呼叫RTSPClient的建構函式;
sendDescribeCommand函式往伺服器端傳送Describe請求;continueAfterDESCRIBE為回撥函式;在DoEventLoop中的SingleStep中呼叫;RTP over tcp 還是udp 由巨集#defineREQUEST_STREAMING_OVER_TCPFalse進行控制;
unsigned
RTSPClient::sendDescribeCommand(responseHandler*responseHandler,Authenticator*authenticator)
{
if (authenticator !=NULL)fCurrentAuthenticator = *authenticator;
return
sendRequest(new
RequestRecord(++fCSeq,
"DESCRIBE", responseHandler));
}
將continueAfterDESCRIBE函式傳遞到responseHandler,相當於continueAfterDESCRIBE為一個回撥函式;注意RequestRecord這個類的作用;在SendRequest中呼叫RequestRecord的建構函式
RTSPClient::RequestRecord::RequestRecord(unsignedcseq,char
const* commandName,
responseHandler*handler,MediaSession*session,MediaSubsession*subsession,u_int32_tbooleanFlags,doublestart,double
end, float
scale,charconst*
contentStr)
:fNext(NULL),fCSeq(cseq),fCommandName(commandName),fSession(session),fSubsession(subsession),fBooleanFlags(booleanFlags),
fStart(start),fEnd(end),fAbsStartTime(NULL),fAbsEndTime(NULL),fScale(scale),fContentStr(strDup(contentStr)),fHandler(handler)
{
}
將回調函式儲存在RequestRecord類的fHandler上; RequestRecord類定義如下:
// The state of a request-in-progress:
class
RequestRecord {
public:
RequestRecord(unsignedcseq,char
const* commandName,
responseHandler* handler,
MediaSession*
session = NULL,
MediaSubsession* subsession =
NULL, u_int32_t
booleanFlags = 0,
double
start = 0.0f, double
end = -1.0f, float
scale = 1.0f, char
const* contentStr =
NULL);
RequestRecord(unsignedcseq,responseHandler*handler,
char
const* absStartTime,
char const* absEndTime =NULL,float
scale = 1.0f,
MediaSession*
session = NULL,
MediaSubsession* subsession =
NULL);
// alternative constructor for creating "PLAY" requests that include 'absolute' time values
virtual ~RequestRecord();
RequestRecord*&
next() { return
fNext; }
unsigned&
cseq() { return
fCSeq; }
char
const* commandName()
const { return
fCommandName; }
MediaSession*
session() const {
return fSession; }
MediaSubsession*
subsession() const {
return fSubsession; }
u_int32_t
booleanFlags() const {
return fBooleanFlags; }
double
start() const { returnfStart;
}
double
end() const { returnfEnd;
}
char
const* absStartTime()
const { return
fAbsStartTime; }
char
const* absEndTime()
const { return
fAbsEndTime; }
float
scale() const { returnfScale;
}
char*
contentStr() const {
return fContentStr; }
responseHandler*&
handler() { return
fHandler; }
private:
RequestRecord*
fNext;
unsigned
fCSeq;
char
const* fCommandName;
MediaSession*
fSession;
MediaSubsession*
fSubsession;
u_int32_t
fBooleanFlags;
double
fStart, fEnd;
char *fAbsStartTime, *fAbsEndTime;// used for optional 'absolute' (i.e., "time=") range specifications
float
fScale;
char*
fContentStr;
responseHandler* fHandler;
};
在其他地方就通過RequestRecord類的fHandler 呼叫到回撥函式continueAfterDESCRIBE;注意跟蹤在哪個地方呼叫了RequestRecord類的fHandler,我猜是在DoEvent();中呼叫的。在DoEvent的函式incomingDataHandler1中的handleResponseBytes中呼叫
(*foundRequest->handler())(this,resultCode,resultString);
typedef
void (responseHandler)(RTSPClient*rtspClient,
int
resultCode, char*
resultString);
// A function that is called in response to a RTSP command. The parameters are as follows:
// "rtspClient": The "RTSPClient" object on which the original command was issued.
// "resultCode": If zero, then the command completed successfully. If non-zero, then the command did not complete
// successfully, and "resultCode" indicates the error, as follows:
// A positive "resultCode" is a RTSP error code (for example, 404 means "not found")
// A negative "resultCode" indicates a socket/network error; 0-"resultCode" is the standard "errno" code.
// "resultString": A ('\0'-terminated) string returned along with the response, or else NULL.
// In particular:
/