live555学习笔记6-建立RTP会话

来源:互联网 发布:齐博cms整站系统v8 编辑:程序博客网 时间:2024/05/20 01:36
六 建立RTP会话


首先更正一个概念:
ServerMediaSession原先说代表一个流,其实是不准确的。它代表的是server端的一个媒体的名字,而说ServerMediaSubsession代表一个Track是准确的。以后流指的是那些有数据流动的组合。


RTP的建立:
RTP的建立过程无非是这样:client告诉server自己的rtp/rtcp端口号,server建立自己的rtp/rtcp socket,然后在收到PLAY请求时向客户端发数据。看起来非常简单。
在收到SETUP请求时才建立连接,让我们看一下处理这个命令的函数:
[cpp] view plaincopyprint?
  1. void RTSPServer::RTSPClientSession::handleCmd_SETUP(  
  2.         char const* cseq,  
  3.         char const* urlPreSuffix,  
  4.         char const* urlSuffix,  
  5.         char const* fullRequestStr)  
  6. {  
  7.     // Normally, "urlPreSuffix" should be the session (stream) name,  
  8.     // and "urlSuffix" should be the subsession (track) name.  
  9.     // However (being "liberal in what we accept"), we also handle  
  10.     // 'aggregate' SETUP requests (i.e., without a track name),  
  11.     // in the special case where we have only a single track.  I.e.,  
  12.     // in this case, we also handle:  
  13.     //    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or  
  14.     //    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween)  
  15.     //    is the session (stream) name.  
  16.     char const* streamName = urlPreSuffix; // in the normal case  
  17.     char const* trackId = urlSuffix; // in the normal case  
  18.     char* concatenatedStreamName = NULL; // in the normal case  
  19.   
  20.   
  21.     do {  
  22.         // First, make sure the specified stream name exists:  
  23.         fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);  
  24.         if (fOurServerMediaSession == NULL) {  
  25.             // Check for the special case (noted above), before we up:  
  26.             if (urlPreSuffix[0] == '\0') {  
  27.                 streamName = urlSuffix;  
  28.             } else {  
  29.                 concatenatedStreamName = new char[strlen(urlPreSuffix)  
  30.                         + strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'  
  31.                 sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix,  
  32.                         urlSuffix);  
  33.                 streamName = concatenatedStreamName;  
  34.             }  
  35.             trackId = NULL;  
  36.   
  37.   
  38.             // Check again:  
  39.             fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);  
  40.         }  
  41.         if (fOurServerMediaSession == NULL) {  
  42.             handleCmd_notFound(cseq);  
  43.             break;  
  44.         }  
  45.   
  46.   
  47.         fOurServerMediaSession->incrementReferenceCount();  
  48.   
  49.   
  50.         //为一个流中所有的track都分配一个stream state  
  51.         if (fStreamStates == NULL) {  
  52.             // This is the first "SETUP" for this session.  Set up our  
  53.             // array of states for all of this session's subsessions (tracks):  
  54.             ServerMediaSubsessionIterator iter(*fOurServerMediaSession);  
  55.             for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {  
  56.             } // begin by counting the number of subsessions (tracks)  
  57.   
  58.   
  59.             fStreamStates = new struct streamState[fNumStreamStates];  
  60.   
  61.   
  62.             iter.reset();  
  63.             ServerMediaSubsession* subsession;  
  64.             for (unsigned i = 0; i < fNumStreamStates; ++i) {  
  65.                 subsession = iter.next();  
  66.                 fStreamStates[i].subsession = subsession;  
  67.                 fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later  
  68.             }  
  69.         }  
  70.   
  71.   
  72.         //查找当前请求的track的信息  
  73.         // Look up information for the specified subsession (track):  
  74.         ServerMediaSubsession* subsession = NULL;  
  75.         unsigned streamNum;  
  76.         if (trackId != NULL && trackId[0] != '\0') { // normal case  
  77.             for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) {  
  78.                 subsession = fStreamStates[streamNum].subsession;  
  79.                 if (subsession != NULL  && strcmp(trackId, subsession->trackId()) == 0)  
  80.                     break//找到啦!  
  81.             }  
  82.             if (streamNum >= fNumStreamStates) {  
  83.                 // The specified track id doesn't exist, so this request fails:  
  84.                 handleCmd_notFound(cseq);  
  85.                 break;  
  86.             }  
  87.         } else {  
  88.             // Weird case: there was no track id in the URL.  
  89.             // This works only if we have only one subsession:  
  90.             if (fNumStreamStates != 1) {  
  91.                 handleCmd_bad(cseq);  
  92.                 break;  
  93.             }  
  94.             streamNum = 0;  
  95.             subsession = fStreamStates[streamNum].subsession;  
  96.         }  
  97.         // ASSERT: subsession != NULL  
  98.   
  99.   
  100.         //分析RTSP请求字符串中的传输要求  
  101.         // Look for a "Transport:" header in the request string, to extract client parameters:  
  102.         StreamingMode streamingMode;  
  103.         char* streamingModeString = NULL; // set when RAW_UDP streaming is specified  
  104.         char* clientsDestinationAddressStr;  
  105.         u_int8_t clientsDestinationTTL;  
  106.         portNumBits clientRTPPortNum, clientRTCPPortNum;  
  107.         unsigned char rtpChannelId, rtcpChannelId;  
  108.         parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,  
  109.                 clientsDestinationAddressStr, clientsDestinationTTL,  
  110.                 clientRTPPortNum, clientRTCPPortNum, rtpChannelId,  
  111.                 rtcpChannelId);  
  112.         if (streamingMode == RTP_TCP && rtpChannelId == 0xFF  
  113.                 || streamingMode != RTP_TCP &&  
  114.                 fClientOutputSocket != fClientInputSocket) {  
  115.             // An anomolous situation, caused by a buggy client.  Either:  
  116.             //     1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or  
  117.             //     2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).  
  118.             // In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values:  
  119.             streamingMode = RTP_TCP;  
  120.             rtpChannelId = fTCPStreamIdCount;  
  121.             rtcpChannelId = fTCPStreamIdCount + 1;  
  122.         }  
  123.         fTCPStreamIdCount += 2;  
  124.   
  125.   
  126.         Port clientRTPPort(clientRTPPortNum);  
  127.         Port clientRTCPPort(clientRTCPPortNum);  
  128.   
  129.   
  130.         // Next, check whether a "Range:" header is present in the request.  
  131.         // This isn't legal, but some clients do this to combine "SETUP" and "PLAY":  
  132.         double rangeStart = 0.0, rangeEnd = 0.0;  
  133.         fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart,  
  134.                 rangeEnd) || parsePlayNowHeader(fullRequestStr);  
  135.   
  136.   
  137.         // Then, get server parameters from the 'subsession':  
  138.         int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -1;  
  139.         netAddressBits destinationAddress = 0;  
  140.         u_int8_t destinationTTL = 255;  
  141. #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING  
  142.         if (clientsDestinationAddressStr != NULL) {  
  143.             // Use the client-provided "destination" address.  
  144.             // Note: This potentially allows the server to be used in denial-of-service  
  145.             // attacks, so don't enable this code unless you're sure that clients are  
  146.             // trusted.  
  147.             destinationAddress = our_inet_addr(clientsDestinationAddressStr);  
  148.         }  
  149.         // Also use the client-provided TTL.  
  150.         destinationTTL = clientsDestinationTTL;  
  151. #endif  
  152.         delete[] clientsDestinationAddressStr;  
  153.         Port serverRTPPort(0);  
  154.         Port serverRTCPPort(0);  
  155.   
  156.   
  157.         // Make sure that we transmit on the same interface that's used by  
  158.         // the client (in case we're a multi-homed server):  
  159.         struct sockaddr_in sourceAddr;  
  160.         SOCKLEN_T namelen = sizeof sourceAddr;  
  161.         getsockname(fClientInputSocket, (struct sockaddr*) &sourceAddr, &namelen);  
  162.         netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;  
  163.         netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;  
  164.         // NOTE: The following might not work properly, so we ifdef it out for now:  
  165. #ifdef HACK_FOR_MULTIHOMED_SERVERS  
  166.         ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;  
  167. #endif  
  168.   
  169.   
  170.         //获取rtp连接信息,在其中已建立起了server端的rtp和rtcp socket,返回  
  171.         //fStreamStates[streamNum].streamToken表示数据流已经建立起来了  
  172.         subsession->getStreamParameters(fOurSessionId,  
  173.                 fClientAddr.sin_addr.s_addr, clientRTPPort, clientRTCPPort,  
  174.                 tcpSocketNum, rtpChannelId, rtcpChannelId, destinationAddress,  
  175.                 destinationTTL, fIsMulticast, serverRTPPort, serverRTCPPort,  
  176.                 fStreamStates[streamNum].streamToken);  
  177.         SendingInterfaceAddr = origSendingInterfaceAddr;  
  178.         ReceivingInterfaceAddr = origReceivingInterfaceAddr;  
  179.   
  180.   
  181.         //形成RTSP回应字符串  
  182.         struct in_addr destinationAddr;  
  183.         destinationAddr.s_addr = destinationAddress;  
  184.         char* destAddrStr = strDup(our_inet_ntoa(destinationAddr));  
  185.         char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr));  
  186.         if (fIsMulticast) {  
  187.             switch (streamingMode) {  
  188.             case RTP_UDP:  
  189.                 snprintf(  
  190.                         (char*) fResponseBuffer,  
  191.                         sizeof fResponseBuffer,  
  192.                         "RTSP/1.0 200 OK\r\n"  
  193.                                 "CSeq: %s\r\n"  
  194.                                 "%s"  
  195.                                 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"  
  196.                                 "Session: %08X\r\n\r\n", cseq, dateHeader(),  
  197.                         destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()),  
  198.                         ntohs(serverRTCPPort.num()), destinationTTL,  
  199.                         fOurSessionId);  
  200.                 break;  
  201.             case RTP_TCP:  
  202.                 // multicast streams can't be sent via TCP  
  203.                 handleCmd_unsupportedTransport(cseq);  
  204.                 break;  
  205.             case RAW_UDP:  
  206.                 snprintf(  
  207.                         (char*) fResponseBuffer,  
  208.                         sizeof fResponseBuffer,  
  209.                         "RTSP/1.0 200 OK\r\n"  
  210.                                 "CSeq: %s\r\n"  
  211.                                 "%s"  
  212.                                 "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"  
  213.                                 "Session: %08X\r\n\r\n", cseq, dateHeader(),  
  214.                         streamingModeString, destAddrStr, sourceAddrStr,  
  215.                         ntohs(serverRTPPort.num()), destinationTTL,  
  216.                         fOurSessionId);  
  217.                 break;  
  218.             }  
  219.         } else {  
  220.             switch (streamingMode) {  
  221.             case RTP_UDP: {  
  222.                 snprintf(  
  223.                         (char*) fResponseBuffer,  
  224.                         sizeof fResponseBuffer,  
  225.                         "RTSP/1.0 200 OK\r\n"  
  226.                                 "CSeq: %s\r\n"  
  227.                                 "%s"  
  228.                                 "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"  
  229.                                 "Session: %08X\r\n\r\n", cseq, dateHeader(),  
  230.                         destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()),  
  231.                         ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()),  
  232.                         ntohs(serverRTCPPort.num()), fOurSessionId);  
  233.                 break;  
  234.             }  
  235.             case RTP_TCP: {  
  236.                 snprintf(  
  237.                         (char*) fResponseBuffer,  
  238.                         sizeof fResponseBuffer,  
  239.                         "RTSP/1.0 200 OK\r\n"  
  240.                                 "CSeq: %s\r\n"  
  241.                                 "%s"  
  242.                                 "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n"  
  243.                                 "Session: %08X\r\n\r\n", cseq, dateHeader(),  
  244.                         destAddrStr, sourceAddrStr, rtpChannelId, rtcpChannelId,  
  245.                         fOurSessionId);  
  246.                 break;  
  247.             }  
  248.             case RAW_UDP: {  
  249.                 snprintf(  
  250.                         (char*) fResponseBuffer,  
  251.                         sizeof fResponseBuffer,  
  252.                         "RTSP/1.0 200 OK\r\n"  
  253.                                 "CSeq: %s\r\n"  
  254.                                 "%s"  
  255.                                 "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n"  
  256.                                 "Session: %08X\r\n\r\n", cseq, dateHeader(),  
  257.                         streamingModeString, destAddrStr, sourceAddrStr,  
  258.                         ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),  
  259.                         fOurSessionId);  
  260.                 break;  
  261.             }  
  262.             }  
  263.         }  
  264.         delete[] destAddrStr;  
  265.         delete[] sourceAddrStr;  
  266.         delete[] streamingModeString;  
  267.     } while (0);  
  268.   
  269.   
  270.     delete[] concatenatedStreamName;  
  271.     //返回后,回应字符串会被立即发送  
  272. }  


live555 中有两个 streamstate,一个是类 StreamState ,一个是此处的结构 struct streamState。类 SteamState 就是 streamToken,而 struct streamState 中保存了 MediaSubsession (即track) 和类 StreamState 的对应。类 StreamState 代表一个真正流动起来的数据流。这个数据流是从源流到 Sink 。客户端与服务端的一个 rtp 会话中,有两个数据流,服务端是从 XXXFileSouce 流到 RTPSink,而客户端则是从 RTPSource 流到 XXXFileSink 。建立数据流的过程就是把 Source 与 Sink 连接起来。
为何不把 StreamToken 保存在 MediaSubsession 中呢?看起来在 struct streamState 中是一个 MediaSubsession 对应一个 streamToken 呀? 因为 MediaSubsession  代表一个 track 的静态数据,它是可以被其它 rtp 会话重用的。比如不同的用户可能会连接到同一个媒体的同一个 track 。所以 streamToken 与 MediaSubsession 独立存在,只是被 RTSPClientSession 给对应了起来。


streamToken的建立过程存在于函数subsession->getStreamParameters()中,让我们看一下下:
[cpp] view plaincopyprint?
  1. void OnDemandServerMediaSubsession::getStreamParameters(  
  2.         unsigned clientSessionId,  
  3.         netAddressBits clientAddress,  
  4.         Port const& clientRTPPort,  
  5.         Port const& clientRTCPPort,  
  6.         int tcpSocketNum,  
  7.         unsigned char rtpChannelId,  
  8.         unsigned char rtcpChannelId,  
  9.         netAddressBits& destinationAddress,  
  10.         u_int8_t& /*destinationTTL*/,  
  11.         Boolean& isMulticast,  
  12.         Port& serverRTPPort,  
  13.         Port& serverRTCPPort,  
  14.         void*& streamToken)  
  15. {  
  16.     if (destinationAddress == 0)  
  17.         destinationAddress = clientAddress;  
  18.   
  19.   
  20.     struct in_addr destinationAddr;  
  21.     destinationAddr.s_addr = destinationAddress;  
  22.     isMulticast = False;  
  23.   
  24.   
  25.     //ServerMediaSubsession并没有保存所有基于自己的数据流,而是只记录了最后一次建立的数据流。  
  26.     //利用这个变量和fReuseFirstSource可以实现多client连接到一个流的形式。  
  27.     if (fLastStreamToken != NULL && fReuseFirstSource) {  
  28.         //如果已经基于这个ServerMediaSubsession创建了一个连接,并且希望使用这个连接  
  29.         //则直接返回这个连接。  
  30.         // Special case: Rather than creating a new 'StreamState',  
  31.         // we reuse the one that we've already created:  
  32.         serverRTPPort = ((StreamState*) fLastStreamToken)->serverRTPPort();  
  33.         serverRTCPPort = ((StreamState*) fLastStreamToken)->serverRTCPPort();  
  34.         ++((StreamState*) fLastStreamToken)->referenceCount();  
  35.         streamToken = fLastStreamToken;  
  36.     } else {  
  37.         // Normal case: Create a new media source:  
  38.         unsigned streamBitrate;  
  39.         FramedSource* mediaSource = createNewStreamSource(clientSessionId,streamBitrate);  
  40.   
  41.   
  42.         // Create 'groupsock' and 'sink' objects for the destination,  
  43.         // using previously unused server port numbers:  
  44.         RTPSink* rtpSink;  
  45.         BasicUDPSink* udpSink;  
  46.         Groupsock* rtpGroupsock;  
  47.         Groupsock* rtcpGroupsock;  
  48.         portNumBits serverPortNum;  
  49.         if (clientRTCPPort.num() == 0) {  
  50.             // We're streaming raw UDP (not RTP). Create a single groupsock:  
  51.             NoReuse dummy; // ensures that we skip over ports that are already in use  
  52.             for (serverPortNum = fInitialPortNum;; ++serverPortNum) {  
  53.                 struct in_addr dummyAddr;  
  54.                 dummyAddr.s_addr = 0;  
  55.   
  56.   
  57.                 serverRTPPort = serverPortNum;  
  58.                 rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255);  
  59.                 if (rtpGroupsock->socketNum() >= 0)  
  60.                     break// success  
  61.             }  
  62.   
  63.   
  64.             rtcpGroupsock = NULL;  
  65.             rtpSink = NULL;  
  66.             udpSink = BasicUDPSink::createNew(envir(), rtpGroupsock);  
  67.         } else {  
  68.             // Normal case: We're streaming RTP (over UDP or TCP).  Create a pair of  
  69.             // groupsocks (RTP and RTCP), with adjacent port numbers (RTP port number even):  
  70.             NoReuse dummy; // ensures that we skip over ports that are already in use  
  71.             for (portNumBits serverPortNum = fInitialPortNum;; serverPortNum += 2) {  
  72.                 struct in_addr dummyAddr;  
  73.                 dummyAddr.s_addr = 0;  
  74.   
  75.   
  76.                 serverRTPPort = serverPortNum;  
  77.                 rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255);  
  78.                 if (rtpGroupsock->socketNum() < 0) {  
  79.                     delete rtpGroupsock;  
  80.                     continue// try again  
  81.                 }  
  82.   
  83.   
  84.                 serverRTCPPort = serverPortNum + 1;  
  85.                 rtcpGroupsock = new Groupsock(envir(), dummyAddr,serverRTCPPort, 255);  
  86.                 if (rtcpGroupsock->socketNum() < 0) {  
  87.                     delete rtpGroupsock;  
  88.                     delete rtcpGroupsock;  
  89.                     continue// try again  
  90.                 }  
  91.   
  92.   
  93.                 break// success  
  94.             }  
  95.   
  96.   
  97.             unsigned char rtpPayloadType = 96 + trackNumber() - 1; // if dynamic  
  98.             rtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType,mediaSource);  
  99.             udpSink = NULL;  
  100.         }  
  101.   
  102.   
  103.         // Turn off the destinations for each groupsock.  They'll get set later  
  104.         // (unless TCP is used instead):  
  105.         if (rtpGroupsock != NULL)  
  106.             rtpGroupsock->removeAllDestinations();  
  107.         if (rtcpGroupsock != NULL)  
  108.             rtcpGroupsock->removeAllDestinations();  
  109.   
  110.   
  111.         if (rtpGroupsock != NULL) {  
  112.             // Try to use a big send buffer for RTP -  at least 0.1 second of  
  113.             // specified bandwidth and at least 50 KB  
  114.             unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes  
  115.             if (rtpBufSize < 50 * 1024)  
  116.                 rtpBufSize = 50 * 1024;  
  117.             increaseSendBufferTo(envir(), rtpGroupsock->socketNum(),rtpBufSize);  
  118.         }  
  119.   
  120.   
  121.         // Set up the state of the stream.  The stream will get started later:  
  122.         streamToken = fLastStreamToken = new StreamState(*this, serverRTPPort,  
  123.                 serverRTCPPort, rtpSink, udpSink, streamBitrate, mediaSource,  
  124.                 rtpGroupsock, rtcpGroupsock);  
  125.     }  
  126.   
  127.   
  128.     // Record these destinations as being for this client session id:  
  129.     Destinations* destinations;  
  130.     if (tcpSocketNum < 0) { // UDP  
  131.         destinations = new Destinations(destinationAddr, clientRTPPort, clientRTCPPort);  
  132.     } else { // TCP  
  133.         destinations = new Destinations(tcpSocketNum, rtpChannelId, rtcpChannelId);  
  134.     }  
  135.       
  136.     //记录下所有clientSessionID对应的目的rtp/rtcp地址,是因为现在不能把目的rtp,rtcp地址加入到  
  137.     //server端rtp的groupSocket中。试想在ReuseFirstSource时,这样会引起client端立即收到rtp数据。  
  138.     //其次,也可以利用这个hash table找出client的rtp/rtcp端口等信息,好像其它地方还真没有可以保存的  
  139.     //RTSPClientSession中的streamstates在ReuseFirstSource时也不能准确找出client端的端口等信息。  
  140.     fDestinationsHashTable->Add((char const*) clientSessionId, destinations);  
  141. }  


流程不复杂:如果需要重用上一次建立的流,就利用之(这样就可以实现一rtp server对应多个rtp client的形式);如果不需要,则创建合适的source,然后创建rtp sink,然后利用它们创建streamSoken。


启动一个流:
当RTSPClientSession收到PLAY请求时,就开始传输RTP数据。下面看一下流启动的代码:
[cpp] view plaincopyprint?
  1. void RTSPServer::RTSPClientSession::handleCmd_PLAY(  
  2.         ServerMediaSubsession* subsession,  
  3.         char const* cseq,  
  4.         char const* fullRequestStr)  
  5. {  
  6.     char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession,fClientInputSocket);  
  7.     unsigned rtspURLSize = strlen(rtspURL);  
  8.   
  9.   
  10.     // Parse the client's "Scale:" header, if any:  
  11.     float scale;  
  12.     Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale);  
  13.   
  14.   
  15.     // Try to set the stream's scale factor to this value:  
  16.     if (subsession == NULL /*aggregate op*/) {  
  17.         fOurServerMediaSession->testScaleFactor(scale);  
  18.     } else {  
  19.         subsession->testScaleFactor(scale);  
  20.     }  
  21.   
  22.   
  23.     char buf[100];  
  24.     char* scaleHeader;  
  25.     if (!sawScaleHeader) {  
  26.         buf[0] = '\0'// Because we didn't see a Scale: header, don't send one back  
  27.     } else {  
  28.         sprintf(buf, "Scale: %f\r\n", scale);  
  29.     }  
  30.     scaleHeader = strDup(buf);  
  31.   
  32.   
  33.     //分析客户端对于播放范围的要求  
  34.     // Parse the client's "Range:" header, if any:  
  35.     double rangeStart = 0.0, rangeEnd = 0.0;  
  36.     Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart,rangeEnd);  
  37.   
  38.   
  39.     // Use this information, plus the stream's duration (if known), to create  
  40.     // our own "Range:" header, for the response:  
  41.     float duration = subsession == NULL /*aggregate op*/  
  42.     ? fOurServerMediaSession->duration() : subsession->duration();  
  43.     if (duration < 0.0) {  
  44.         // We're an aggregate PLAY, but the subsessions have different durations.  
  45.         // Use the largest of these durations in our header  
  46.         duration = -duration;  
  47.     }  
  48.   
  49.   
  50.     // Make sure that "rangeStart" and "rangeEnd" (from the client's "Range:" header) have sane values  
  51.     // before we send back our own "Range:" header in our response:  
  52.     if (rangeStart < 0.0)  
  53.         rangeStart = 0.0;  
  54.     else if (rangeStart > duration)  
  55.         rangeStart = duration;  
  56.     if (rangeEnd < 0.0)  
  57.         rangeEnd = 0.0;  
  58.     else if (rangeEnd > duration)  
  59.         rangeEnd = duration;  
  60.     if ((scale > 0.0 && rangeStart > rangeEnd && rangeEnd > 0.0)  
  61.             || (scale < 0.0 && rangeStart < rangeEnd)) {  
  62.         // "rangeStart" and "rangeEnd" were the wrong way around; swap them:  
  63.         double tmp = rangeStart;  
  64.         rangeStart = rangeEnd;  
  65.         rangeEnd = tmp;  
  66.     }  
  67.   
  68.   
  69.     char* rangeHeader;  
  70.     if (!sawRangeHeader) {  
  71.         buf[0] = '\0'// Because we didn't see a Range: header, don't send one back  
  72.     } else if (rangeEnd == 0.0 && scale >= 0.0) {  
  73.         sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart);  
  74.     } else {  
  75.         sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd);  
  76.     }  
  77.     rangeHeader = strDup(buf);  
  78.   
  79.   
  80.     // Create a "RTP-Info:" line.  It will get filled in from each subsession's state:  
  81.     char const* rtpInfoFmt = "%s" // "RTP-Info:", plus any preceding rtpInfo items  
  82.                     "%s"// comma separator, if needed  
  83.                     "url=%s/%s"  
  84.                     ";seq=%d"  
  85.                     ";rtptime=%u";  
  86.     unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);  
  87.     char* rtpInfo = strDup("RTP-Info: ");  
  88.     unsigned i, numRTPInfoItems = 0;  
  89.   
  90.   
  91.     // Do any required seeking/scaling on each subsession, before starting streaming:  
  92.     for (i = 0; i < fNumStreamStates; ++i) {  
  93.         if (subsession == NULL /* means: aggregated operation */  
  94.         || subsession == fStreamStates[i].subsession) {  
  95.             if (sawScaleHeader) {  
  96.                 fStreamStates[i].subsession->setStreamScale(fOurSessionId,  
  97.                         fStreamStates[i].streamToken, scale);  
  98.             }  
  99.             if (sawRangeHeader) {  
  100.                 double streamDuration = 0.0; // by default; means: stream until the end of the media  
  101.                 if (rangeEnd > 0.0 && (rangeEnd + 0.001) < duration) { // the 0.001 is because we limited the values to 3 decimal places  
  102.                     // We want the stream to end early.  Set the duration we want:  
  103.                     streamDuration = rangeEnd - rangeStart;  
  104.                     if (streamDuration < 0.0)  
  105.                         streamDuration = -streamDuration; // should happen only if scale < 0.0  
  106.                 }  
  107.                 u_int64_t numBytes;  
  108.                 fStreamStates[i].subsession->seekStream(fOurSessionId,  
  109.                         fStreamStates[i].streamToken, rangeStart,  
  110.                         streamDuration, numBytes);  
  111.             }  
  112.         }  
  113.     }  
  114.   
  115.   
  116.     // Now, start streaming:  
  117.     for (i = 0; i < fNumStreamStates; ++i) {  
  118.         if (subsession == NULL /* means: aggregated operation */  
  119.                 || subsession == fStreamStates[i].subsession) {  
  120.             unsigned short rtpSeqNum = 0;  
  121.             unsigned rtpTimestamp = 0;  
  122.             //启动流  
  123.             fStreamStates[i].subsession->startStream(fOurSessionId,  
  124.                     fStreamStates[i].streamToken,  
  125.                     (TaskFunc*) noteClientLiveness, this, rtpSeqNum,  
  126.                     rtpTimestamp, handleAlternativeRequestByte, this);  
  127.             const char *urlSuffix = fStreamStates[i].subsession->trackId();  
  128.             char* prevRTPInfo = rtpInfo;  
  129.             unsigned rtpInfoSize = rtpInfoFmtSize + strlen(prevRTPInfo) + 1  
  130.                     + rtspURLSize + strlen(urlSuffix) + 5 /*max unsigned short len*/  
  131.             + 10 /*max unsigned (32-bit) len*/  
  132.             + 2 /*allows for trailing \r\n at final end of string*/;  
  133.             rtpInfo = new char[rtpInfoSize];  
  134.             sprintf(rtpInfo, rtpInfoFmt, prevRTPInfo,  
  135.                     numRTPInfoItems++ == 0 ? "" : ",", rtspURL, urlSuffix,  
  136.                     rtpSeqNum, rtpTimestamp);  
  137.             delete[] prevRTPInfo;  
  138.         }  
  139.     }  
  140.     if (numRTPInfoItems == 0) {  
  141.         rtpInfo[0] = '\0';  
  142.     } else {  
  143.         unsigned rtpInfoLen = strlen(rtpInfo);  
  144.         rtpInfo[rtpInfoLen] = '\r';  
  145.         rtpInfo[rtpInfoLen + 1] = '\n';  
  146.         rtpInfo[rtpInfoLen + 2] = '\0';  
  147.     }  
  148.   
  149.   
  150.     // Fill in the response:  
  151.     snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,  
  152.             "RTSP/1.0 200 OK\r\n"  
  153.                     "CSeq: %s\r\n"  
  154.                     "%s"  
  155.                     "%s"  
  156.                     "%s"  
  157.                     "Session: %08X\r\n"  
  158.                     "%s\r\n", cseq, dateHeader(), scaleHeader, rangeHeader,  
  159.             fOurSessionId, rtpInfo);  
  160.     delete[] rtpInfo;  
  161.     delete[] rangeHeader;  
  162.     delete[] scaleHeader;  
  163.     delete[] rtspURL;  
  164. }  


有个问题,如果这个streamToken使用的是已存在的(还记得ReuseFirstSource吗),为它再次调用startStream()时,究竟会做什么呢?你猜啊!呵呵我猜吧:应该是把这个客户端的地址和rtp/rtcp端口传给rtp server的groupSocket,rtp server自然就开始向这个客户端发送数据了。是不是这样尼?看代码吧:
[cpp] view plaincopyprint?
  1. void StreamState::startPlaying(  
  2.         Destinations* dests,  
  3.         TaskFunc* rtcpRRHandler,  
  4.         void* rtcpRRHandlerClientData,  
  5.         ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,  
  6.         void* serverRequestAlternativeByteHandlerClientData)   
  7. {  
  8.     //目标ip address rtp && rtcp port  
  9.     if (dests == NULL)  
  10.         return;  
  11.   
  12.   
  13.     //创建RTCPInstance对象,以计算和收发RTCP包  
  14.     if (fRTCPInstance == NULL && fRTPSink != NULL) {  
  15.         // Create (and start) a 'RTCP instance' for this RTP sink:  
  16.         fRTCPInstance = RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs,  
  17.                 fTotalBW, (unsigned char*) fMaster.fCNAME, fRTPSink,  
  18.                 NULL /* we're a server */);  
  19.         // Note: This starts RTCP running automatically  
  20.     }  
  21.   
  22.   
  23.     if (dests->isTCP) {  
  24.         //如果RTP over TCP  
  25.         // Change RTP and RTCP to use the TCP socket instead of UDP:  
  26.         if (fRTPSink != NULL) {  
  27.             fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId);  
  28.             fRTPSink->setServerRequestAlternativeByteHandler(  
  29.                     dests->tcpSocketNum, serverRequestAlternativeByteHandler,  
  30.                     serverRequestAlternativeByteHandlerClientData);  
  31.         }  
  32.         if (fRTCPInstance != NULL) {  
  33.             fRTCPInstance->addStreamSocket(dests->tcpSocketNum,  
  34.                     dests->rtcpChannelId);  
  35.             fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum,  
  36.                     dests->rtcpChannelId, rtcpRRHandler,  
  37.                     rtcpRRHandlerClientData);  
  38.         }  
  39.     } else {  
  40.         //向RTP和RTCP的groupsocket增加这个目标  
  41.         // Tell the RTP and RTCP 'groupsocks' about this destination  
  42.         // (in case they don't already have it):  
  43.         if (fRTPgs != NULL)  
  44.             fRTPgs->addDestination(dests->addr, dests->rtpPort);  
  45.         if (fRTCPgs != NULL)  
  46.             fRTCPgs->addDestination(dests->addr, dests->rtcpPort);  
  47.         if (fRTCPInstance != NULL) {  
  48.             fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr,  
  49.                     dests->rtcpPort, rtcpRRHandler, rtcpRRHandlerClientData);  
  50.         }  
  51.     }  
  52.   
  53.   
  54.     if (!fAreCurrentlyPlaying && fMediaSource != NULL) {  
  55.         //如果还没有启动传输,现在启动之。  
  56.         if (fRTPSink != NULL) {  
  57.             fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState,  
  58.                     this);  
  59.             fAreCurrentlyPlaying = True;  
  60.         } else if (fUDPSink != NULL) {  
  61.             fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState,this);  
  62.             fAreCurrentlyPlaying = True;  
  63.         }  
  64.     }  
  65. }  


嘿嘿,还真的这样嘀!
原创粉丝点击