接着上篇来分析。option命令完了就是
unsigned RTSPClient::sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator) {
if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler));
}
基本过程在上一篇已经分析了。在sendRequest中也没什么好看的,就是把DESCRIBE请求组装发送了,sigleSetup继续执行,因为之前已经将read加入到select监听集中,所以又会到handleResponseBytes中。handleResponseBytes中对DESCRIBE的应答也没有做特殊的处理,然后就执行到了continueAfterDESCRIBE。
在 continueAfterDESCRIBE中我们看到session = MediaSession::createNew(*env, sdpDescription);
这里主要是根据应答的sdpDescription组装session。
MediaSession* MediaSession::createNew(UsageEnvironment& env,
char const* sdpDescription) {
MediaSession* newSession = new MediaSession(env);
if (newSession != NULL) {
if (!newSession->initializeWithSDP(sdpDescription)) {
delete newSession;
return NULL;
}
}
return newSession;
}
主要是initializeWithSDP根据sdp建立session。
但是没看到RTP socket建立的过程。不过在continueAfterDESCRIBE中看到了subsession->initiate(simpleRTPoffsetArg)
Boolean MediaSubsession::initiate(int useSpecialRTPoffset) {
if (fReadSource != NULL) return True; // has already been initiated
do {
if (fCodecName == NULL) {
env().setResultMsg("Codec is unspecified");
break;
}
// Create RTP and RTCP 'Groupsocks' on which to receive incoming data.
// (Groupsocks will work even for unicast addresses)
struct in_addr tempAddr;
tempAddr.s_addr = connectionEndpointAddress();
// This could get changed later, as a result of a RTSP "SETUP"
if (fClientPortNum != 0) {
// The sockets' port numbers were specified for us. Use these:
Boolean const protocolIsRTP = strcmp(fProtocolName, "RTP") == 0;
if (protocolIsRTP) {
fClientPortNum = fClientPortNum&~1; // use an even-numbered port for RTP, and the next (odd-numbered) port for RTCP
}
if (isSSM()) {
fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, fClientPortNum);
} else {
fRTPSocket = new Groupsock(env(), tempAddr, fClientPortNum, 255);//建立RTPsocket
}
if (fRTPSocket == NULL) {
env().setResultMsg("Failed to create RTP socket");
break;
}
if (protocolIsRTP) {
// Set our RTCP port to be the RTP port +1
portNumBits const rtcpPortNum = fClientPortNum|1;
if (isSSM()) {
fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
} else {
fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
}
}
} else {
// Port numbers were not specified in advance, so we use ephemeral port numbers.
// Create sockets until we get a port-number pair (even: RTP; even+1: RTCP).
// We need to make sure that we don't keep trying to use the same bad port numbers over and over again.
// so we store bad sockets in a table, and delete them all when we're done.
HashTable* socketHashTable = HashTable::create(ONE_WORD_HASH_KEYS);
if (socketHashTable == NULL) break;
Boolean success = False;
NoReuse dummy(env()); // ensures that our new ephemeral port number won't be one that's already in use
while (1) {
// Create a new socket:
if (isSSM()) {
fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, 0);
} else {
fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);
}
if (fRTPSocket == NULL) {
env().setResultMsg("MediaSession::initiate(): unable to create RTP and RTCP sockets");
break;
}
// Get the client port number, and check whether it's even (for RTP):
Port clientPort(0);
if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) {
break;
}
fClientPortNum = ntohs(clientPort.num());
if ((fClientPortNum&1) != 0) { // it's odd
// Record this socket in our table, and keep trying:
unsigned key = (unsigned)fClientPortNum;
Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
delete existing; // in case it wasn't NULL
continue;
}
// Make sure we can use the next (i.e., odd) port number, for RTCP:
portNumBits rtcpPortNum = fClientPortNum|1;
if (isSSM()) {
fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
} else {
fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
}
if (fRTCPSocket != NULL && fRTCPSocket->socketNum() >= 0) {
// Success! Use these two sockets.
success = True;
break;
} else {
// We couldn't create the RTCP socket (perhaps that port number's already in use elsewhere?).
delete fRTCPSocket;
// Record the first socket in our table, and keep trying:
unsigned key = (unsigned)fClientPortNum;
Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
delete existing; // in case it wasn't NULL
continue;
}
}
// Clean up the socket hash table (and contents):
Groupsock* oldGS;
while ((oldGS = (Groupsock*)socketHashTable->RemoveNext()) != NULL) {
delete oldGS;
}
delete socketHashTable;
if (!success) break; // a fatal error occurred trying to create the RTP and RTCP sockets; we can't continue
}
// Try to use a big receive buffer for RTP - at least 0.1 second of
// specified bandwidth and at least 50 KB
unsigned rtpBufSize = fBandwidth * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
if (rtpBufSize < 50 * 1024)
rtpBufSize = 50 * 1024;
increaseReceiveBufferTo(env(), fRTPSocket->socketNum(), rtpBufSize);
if (isSSM() && fRTCPSocket != NULL) {
// Special case for RTCP SSM: Send RTCP packets back to the source via unicast:
fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0);
}
// Create "fRTPSource" and "fReadSource":
if (!createSourceObjects(useSpecialRTPoffset)) break;
if (fReadSource == NULL) {
env().setResultMsg("Failed to create read source");
break;
}
// Finally, create our RTCP instance. (It starts running automatically)
if (fRTPSource != NULL && fRTCPSocket != NULL) {
// If bandwidth is specified, use it and add 5% for RTCP overhead.
// Otherwise make a guess at 500 kbps.
unsigned totSessionBandwidth
= fBandwidth ? fBandwidth + fBandwidth / 20 : 500;
fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,
totSessionBandwidth,
(unsigned char const*)
fParent.CNAME(),
NULL /* we're a client */,
fRTPSource);
if (fRTCPInstance == NULL) {
env().setResultMsg("Failed to create RTCP instance");
break;
}
}
return True;
} while (0);
delete fRTPSocket; fRTPSocket = NULL;
delete fRTCPSocket; fRTCPSocket = NULL;
Medium::close(fRTCPInstance); fRTCPInstance = NULL;
Medium::close(fReadSource); fReadSource = fRTPSource = NULL;
fClientPortNum = 0;
return False;
}
这里主要建立RTP socket,
太多的代码就不一一列出,主要分析一下这个过程和线索。这里的fClientPortNum为0,故执行 fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);
fSocketNum赋值为int newSocket = createSocket(SOCK_DGRAM);
创建完rtp socket再创建fRTCPInstance。然后就是创建了RTPSource,在createSourceObjects(useSpecialRTPoffset)中
主要根据fCodecName来创建RTPSource,这里以h264为例。
fReadSource = fRTPSource
= H264VideoRTPSource::createNew(env(), fRTPSocket,
fRTPPayloadFormat,
fRTPTimestampFrequency);
至此continueAfterDESCRIBE中重要的工作已经完成,再接着往下看。然后就执行setupStreams,在这其中主要是执行下面的代码
static MediaSubsessionIterator* setupIter = NULL;
if (setupIter == NULL) setupIter = new MediaSubsessionIterator(*session);
while ((subsession = setupIter->next()) != NULL) {
// We have another subsession left to set up:
if (subsession->clientPortNum() == 0) continue; // port # was not set
setupSubsession(subsession, streamUsingTCP, continueAfterSETUP);
return;
}
sendSetupCommand(*subsession, afterFunc, False, streamUsingTCP, forceMulticastOnUnspecified, ourAuthenticator);中