handleCmd_SETUP 函数

来源:互联网 发布:php仿今日头条源码 编辑:程序博客网 时间:2024/06/10 12:44

handleCmd_SETUP函数,会在客户端发送setup时调用,如果有多个subsession客户端会每个都会发送一个setup的,主要就是创建rtp/rtcp,还有创建source.具体看代码中的注释。


void RTSPServer::RTSPClientSession::handleCmd_SETUP(RTSPServer::RTSPClientConnection* ourClientConnection,char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr){// Normally, "urlPreSuffix" should be the session (stream) name, and "urlSuffix" should be the subsession (track) name.// However (being "liberal in what we accept"), we also handle 'aggregate' SETUP requests (i.e., without a track name),// in the special case where we have only a single track.  I.e., in this case, we also handle://    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or//    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween) is the session (stream) name.char const* streamName = urlPreSuffix; // in the normal casechar const* trackId = urlSuffix; // in the normal casechar* concatenatedStreamName = NULL; // in the normal case//操作一次,更新一下时间到最新状态,默认65,如果65秒没有调用,表示连接以及失效,会删除此sessionnoteLiveness();do{//查找媒体流,一般都在初始化时创建,或者在describe中创建的// First, make sure the specified stream name exists:ServerMediaSession* sms = fOurServer.lookupServerMediaSession(streamName);if (sms == NULL){// Check for the special case (noted above), before we give up:if (urlPreSuffix[0] == '\0'){streamName = urlSuffix;}else{concatenatedStreamName = new char[strlen(urlPreSuffix) + strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix, urlSuffix);streamName = concatenatedStreamName;}trackId = NULL;// Check again:sms = fOurServer.lookupServerMediaSession(streamName);}if (sms == NULL){if (fOurServerMediaSession == NULL){// The client asked for a stream that doesn't exist (and this session descriptor has not been used before):ourClientConnection->handleCmd_notFound();}else{// The client asked for a stream that doesn't exist, but using a stream id for a stream that does exist. Bad request:ourClientConnection->handleCmd_bad();}break;}else{if (fOurServerMediaSession == NULL){// We're accessing the "ServerMediaSession" for the first time.fOurServerMediaSession = sms;fOurServerMediaSession->incrementReferenceCount();}else if (sms != fOurServerMediaSession){// The client asked for a stream that's different from the one originally requested for this stream id.  Bad request:ourClientConnection->handleCmd_bad();break;}}//第一次fStreamStates 是NULLif (fStreamStates == NULL){//计算有几个子sub session 就创建几个streamState// This is the first "SETUP" for this session.  Set up our array of states for all of this session's subsessions (tracks):ServerMediaSubsessionIterator iter(*fOurServerMediaSession);for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {} // begin by counting the number of subsessions (tracks)fStreamStates = new struct streamState[fNumStreamStates];iter.reset();//fStreamStates[i].subsession 赋值为 各个subsessionServerMediaSubsession* subsession;for (unsigned i = 0; i < fNumStreamStates; ++i){subsession = iter.next();fStreamStates[i].subsession = subsession;fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later}}// Look up information for the specified subsession (track):ServerMediaSubsession* subsession = NULL;unsigned streamNum;//如果trackid 不是空字符,找到对应的子sessionif (trackId != NULL && trackId[0] != '\0')   // normal case{for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum){subsession = fStreamStates[streamNum].subsession;if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break;}if (streamNum >= fNumStreamStates){// The specified track id doesn't exist, so this request fails:ourClientConnection->handleCmd_notFound();break;}}else{//trackid 为NULL 或者空字符// Weird case: there was no track id in the URL.// This works only if we have only one subsession://如果子任务为多个,或者没有子任务,回复命令错误if (fNumStreamStates != 1 || fStreamStates[0].subsession == NULL){ourClientConnection->handleCmd_bad();break;}//默认设置为第一个subsessionstreamNum = 0;subsession = fStreamStates[streamNum].subsession;}// ASSERT: subsession != NULL//解析setup 中的Transport 信息,使用UDP还是TCP,rtp/rtcp端口,// Look for a "Transport:" header in the request string, to extract client parameters:StreamingMode streamingMode;char* streamingModeString = NULL; // set when RAW_UDP streaming is specifiedchar* clientsDestinationAddressStr;u_int8_t clientsDestinationTTL;portNumBits clientRTPPortNum, clientRTCPPortNum;unsigned char rtpChannelId, rtcpChannelId;parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,clientsDestinationAddressStr, clientsDestinationTTL,clientRTPPortNum, clientRTCPPortNum,rtpChannelId, rtcpChannelId);if ((streamingMode == RTP_TCP && rtpChannelId == 0xFF) ||(streamingMode != RTP_TCP && ourClientConnection->fClientOutputSocket != ourClientConnection->fClientInputSocket)){// An anomolous situation, caused by a buggy client.  Either://     1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or//     2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).// In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values:streamingMode = RTP_TCP;rtpChannelId = fTCPStreamIdCount;rtcpChannelId = fTCPStreamIdCount + 1;}if (streamingMode == RTP_TCP) fTCPStreamIdCount += 2;//客户端的rtp/rtcp端口Port clientRTPPort(clientRTPPortNum);Port clientRTCPPort(clientRTCPPortNum);//播放开始时间// Next, check whether a "Range:" or "x-playNow:" header is present in the request.// This isn't legal, but some clients do this to combine "SETUP" and "PLAY":double rangeStart = 0.0, rangeEnd = 0.0;char* absStart = NULL;char* absEnd = NULL;if (parseRangeHeader(fullRequestStr, rangeStart, rangeEnd, absStart, absEnd)){delete[] absStart;delete[] absEnd;fStreamAfterSETUP = True;}else if (parsePlayNowHeader(fullRequestStr)){fStreamAfterSETUP = True;}else{fStreamAfterSETUP = False;}// Then, get server parameters from the 'subsession':int tcpSocketNum = streamingMode == RTP_TCP ? ourClientConnection->fClientOutputSocket : -1;netAddressBits destinationAddress = 0;u_int8_t destinationTTL = 255;#ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTINGif (clientsDestinationAddressStr != NULL){// Use the client-provided "destination" address.// Note: This potentially allows the server to be used in denial-of-service// attacks, so don't enable this code unless you're sure that clients are// trusted.destinationAddress = our_inet_addr(clientsDestinationAddressStr);}// Also use the client-provided TTL.destinationTTL = clientsDestinationTTL;#endifdelete[] clientsDestinationAddressStr;Port serverRTPPort(0);Port serverRTCPPort(0);// Make sure that we transmit on the same interface that's used by the client (in case we're a multi-homed server):struct sockaddr_in sourceAddr;SOCKLEN_T namelen = sizeof sourceAddr;getsockname(ourClientConnection->fClientInputSocket, (struct sockaddr*)&sourceAddr, &namelen);netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;// NOTE: The following might not work properly, so we ifdef it out for now:#ifdef HACK_FOR_MULTIHOMED_SERVERSReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;#endif//子媒体任务获取参数subsession->getStreamParameters(fOurSessionId, ourClientConnection->fClientAddr.sin_addr.s_addr,clientRTPPort, clientRTCPPort,tcpSocketNum, rtpChannelId, rtcpChannelId,destinationAddress, destinationTTL, fIsMulticast,serverRTPPort, serverRTCPPort,fStreamStates[streamNum].streamToken);SendingInterfaceAddr = origSendingInterfaceAddr;ReceivingInterfaceAddr = origReceivingInterfaceAddr;//组合rtsp包AddressString destAddrStr(destinationAddress);AddressString sourceAddrStr(sourceAddr);if (fIsMulticast){switch (streamingMode){case RTP_UDP:snprintf((char*)ourClientConnection->fResponseBuffer, sizeof ourClientConnection->fResponseBuffer,"RTSP/1.0 200 OK\r\n""CSeq: %s\r\n""%s""Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n""Session: %08X\r\n\r\n",ourClientConnection->fCurrentCSeq,dateHeader(),destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL,fOurSessionId);break;case RTP_TCP:// multicast streams can't be sent via TCPourClientConnection->handleCmd_unsupportedTransport();break;case RAW_UDP:snprintf((char*)ourClientConnection->fResponseBuffer, sizeof ourClientConnection->fResponseBuffer,"RTSP/1.0 200 OK\r\n""CSeq: %s\r\n""%s""Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n""Session: %08X\r\n\r\n",ourClientConnection->fCurrentCSeq,dateHeader(),streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), destinationTTL,fOurSessionId);break;}}else{switch (streamingMode){case RTP_UDP:{snprintf((char*)ourClientConnection->fResponseBuffer, sizeof ourClientConnection->fResponseBuffer,"RTSP/1.0 200 OK\r\n""CSeq: %s\r\n""%s""Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n""Session: %08X\r\n\r\n",ourClientConnection->fCurrentCSeq,dateHeader(),destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()),fOurSessionId);break;}case RTP_TCP:{snprintf((char*)ourClientConnection->fResponseBuffer, sizeof ourClientConnection->fResponseBuffer,"RTSP/1.0 200 OK\r\n""CSeq: %s\r\n""%s""Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n""Session: %08X\r\n\r\n",ourClientConnection->fCurrentCSeq,dateHeader(),destAddrStr.val(), sourceAddrStr.val(), rtpChannelId, rtcpChannelId,fOurSessionId);break;}case RAW_UDP:{snprintf((char*)ourClientConnection->fResponseBuffer, sizeof ourClientConnection->fResponseBuffer,"RTSP/1.0 200 OK\r\n""CSeq: %s\r\n""%s""Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n""Session: %08X\r\n\r\n",ourClientConnection->fCurrentCSeq,dateHeader(),streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),fOurSessionId);break;}}}delete[] streamingModeString;} while (0);delete[] concatenatedStreamName;}


void OnDemandServerMediaSubsession::getStreamParameters(unsigned clientSessionId,      netAddressBits clientAddress,      Port const& clientRTPPort,      Port const& clientRTCPPort,      int tcpSocketNum,      unsigned char rtpChannelId,      unsigned char rtcpChannelId,      netAddressBits& destinationAddress,      u_int8_t& /*destinationTTL*/,      Boolean& isMulticast,      Port& serverRTPPort,      Port& serverRTCPPort,      void*& streamToken,      unsigned streamNum,      char const *streamName) {if (destinationAddress == 0) destinationAddress = clientAddress;struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;isMulticast = False;// Special case: Rather than creating a new 'StreamState',// we reuse the one that we've already created://重复使用第一个source,如果是直播话可以使用fReuseFirstSource = true,在创建subsession时设置if (fLastStreamToken != NULL && fReuseFirstSource)//video{serverRTPPort = ((StreamState*)fLastStreamToken)->serverRTPPort();serverRTCPPort = ((StreamState*)fLastStreamToken)->serverRTCPPort();++((StreamState*)fLastStreamToken)->referenceCount();streamToken = fLastStreamToken;}else {//正常情况,创建一个新的media source// Normal case: Create a new media source:unsigned streamBitrate;FramedSource* mediaSource= createNewStreamSource(clientSessionId, streamBitrate);// Create 'groupsock' and 'sink' objects for the destination,// using previously unused server port numbers:RTPSink* rtpSink;BasicUDPSink* udpSink;Groupsock* rtpGroupsock;Groupsock* rtcpGroupsock;portNumBits serverPortNum;//如果没有设置客户端的rtcpportif (clientRTCPPort.num() == 0) {// We're streaming raw UDP (not RTP). Create a single groupsock:NoReuse dummy(envir()); // ensures that we skip over ports that are already in usefor (serverPortNum = fInitialPortNum;; ++serverPortNum) {struct in_addr dummyAddr; dummyAddr.s_addr = 0;serverRTPPort = serverPortNum;rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255);if (rtpGroupsock->socketNum() >= 0) break; // success}rtcpGroupsock = NULL;rtpSink = NULL;udpSink = BasicUDPSink::createNew(envir(), rtpGroupsock);}else {//服务端默认端口fInitialPortNum=6970开始 rtp和rtcp 成对出现,rtcp= rtp+1, 所以serverPortNum += 2// Normal case: We're streaming RTP (over UDP or TCP).  Create a pair of// groupsocks (RTP and RTCP), with adjacent port numbers (RTP port number even):NoReuse dummy(envir()); // ensures that we skip over ports that are already in usefor (portNumBits serverPortNum = fInitialPortNum;; serverPortNum += 2) {struct in_addr dummyAddr; dummyAddr.s_addr = 0;serverRTPPort = serverPortNum;rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255);if (rtpGroupsock->socketNum() < 0) {delete rtpGroupsock;continue; // try again}serverRTCPPort = serverPortNum + 1;rtcpGroupsock = new Groupsock(envir(), dummyAddr, serverRTCPPort, 255);if (rtcpGroupsock->socketNum() < 0) {delete rtpGroupsock;delete rtcpGroupsock;continue; // try again}break; // success}//创建rtpSink,unsigned char rtpPayloadType = 96 + trackNumber() - 1; // if dynamicrtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType, mediaSource);udpSink = NULL;}// Turn off the destinations for each groupsock.  They'll get set later// (unless TCP is used instead):if (rtpGroupsock != NULL) rtpGroupsock->removeAllDestinations();if (rtcpGroupsock != NULL) rtcpGroupsock->removeAllDestinations();if (rtpGroupsock != NULL) {// Try to use a big send buffer for RTP -  at least 0.1 second of// specified bandwidth and at least 50 KBunsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytesif (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024;//发送缓存区大小最小为50KincreaseSendBufferTo(envir(), rtpGroupsock->socketNum(), rtpBufSize);}//StreamState,包含各种流信息streamToken = fLastStreamToken= new StreamState(*this, serverRTPPort, serverRTCPPort, rtpSink, udpSink,streamBitrate, mediaSource,rtpGroupsock, rtcpGroupsock);}// Record these destinations as being for this client session id://增加目的信息到hashtableDestinations* destinations;if (tcpSocketNum < 0){ // UDPdestinations = new Destinations(destinationAddr, clientRTPPort, clientRTCPPort);}else{// TCPdestinations = new Destinations(tcpSocketNum, rtpChannelId, rtcpChannelId);}fDestinationsHashTable->Add((char const*)clientSessionId, destinations);}


0 0
原创粉丝点击