void    RelaySDPSourceInfo::Parse(StrPtrLen* inSDPData)
{
    // These are the lines of the SDP file that we are interested in
    static StrPtrLen sRelayAddr("a=x-qt-relay-addr");
    static StrPtrLen sRelayPort("a=x-qt-relay-port");
    
    Assert(fOutputArray == NULL);
    Assert(fStreamArray == NULL);
    
    StrPtrLen sdpLine;
    StrPtrLen outputAddrs;
    
    StringParser trackCounter(inSDPData);

    UInt32 theDestIPAddr = 0;
    UInt16 theDestTtl = 0;

    //
    // FIRST WALK THROUGH SDP
    // The first walk is to count up the number of StreamInfo & OutputInfo
    // objects that we will need.
    while (true)
    {
        // grab a line
        trackCounter.ConsumeUntil(&sdpLine, StringParser::sEOLMask);
        
        if (sdpLine.NumEqualIgnoreCase(sRelayAddr.Ptr, sRelayAddr.Len))
        {
            // there is a x-qt-relay-addr line, look for all IP addrs
            StringParser relayAddrParser(&sdpLine);
            relayAddrParser.ConsumeUntil(NULL, StringParser::sDigitMask);
            
            // The first IP addr on this line is the destination IP addr of the
            // source broadcast.
            theDestIPAddr = SDPSourceInfo::GetIPAddr(&relayAddrParser, ' ');
            relayAddrParser.ConsumeWhitespace();
            
            // Store this position so we can later go back to it
            outputAddrs.Ptr = relayAddrParser.GetCurrentPosition();
            outputAddrs.Len = relayAddrParser.GetDataRemaining();
            
            StrPtrLen theTtl;
            while (relayAddrParser.GetDataRemaining() > 0)
            {
                relayAddrParser.ConsumeUntil(&theTtl, ' '); 
                relayAddrParser.ConsumeWhitespace();
                fNumOutputs++;
            }
            fNumOutputs--;// Don't count the ttl as an output!
            
            StringParser ttlParser(&theTtl);
            theDestTtl = (UInt16) ttlParser.ConsumeInteger(NULL);
        }
        // Each x=qt-relay-port line corresponds to one source stream.
        else if (sdpLine.NumEqualIgnoreCase(sRelayPort.Ptr, sRelayPort.Len))
            fNumStreams++;

        //stop when we reach an empty line.
        if (!trackCounter.ExpectEOL())
            break;
    }
    
    // No relay info in this file!
    if ((fNumStreams == 0) || (fNumOutputs == 0))
        return;
        
    // x-qt-relay-port lines should always be in pairs (RTP & RTCP)
    if ((fNumStreams & 1) != 0)
        return;
    fNumStreams /= 2;

    //
    // CONSTRUCT fStreamInfo AND fOutputInfo ARRAYS
    fStreamArray = NEW StreamInfo[fNumStreams];
    fOutputArray = NEW OutputInfo[fNumOutputs];
    
    //
    // FILL IN ARRAYS
    
    // Filling in the output addresses is easy because the outputAddrs
    // StrPtrLen points right at the data we want
    StringParser theOutputAddrParser(&outputAddrs);
    for (UInt32 x = 0; x < fNumOutputs; x++)
    {
        fOutputArray[x].fDestAddr = SDPSourceInfo::GetIPAddr(&theOutputAddrParser, ' ');
        fOutputArray[x].fLocalAddr = INADDR_ANY;
        fOutputArray[x].fTimeToLive = theDestTtl;
        fOutputArray[x].fPortArray = NEW UInt16[fNumStreams];//Each output has one port per stream
        fOutputArray[x].fNumPorts = fNumStreams;
        ::memset(fOutputArray[x].fPortArray, 0, fNumStreams * sizeof(UInt16));
        fOutputArray[x].fAlreadySetup = false;
        theOutputAddrParser.ConsumeWhitespace();
        Assert(fOutputArray[x].fDestAddr > 0);
    }
    
    StringParser sdpParser(inSDPData);
    
    // Now go through and find all the port information on all the x-qt-relay-port lines
    for (UInt32 theStreamIndex = 0; theStreamIndex < fNumStreams; )
    {
        sdpParser.ConsumeUntil(&sdpLine, StringParser::sEOLMask);
        
        // parse through all the x-qt-relay-port lines
        if (sdpLine.NumEqualIgnoreCase(sRelayPort.Ptr, sRelayPort.Len))
        {
            // Begin parsing... find the first port on the line
            StringParser relayAddrParser(&sdpLine);
            relayAddrParser.ConsumeUntil(NULL, StringParser::sDigitMask);
        
            // The first port is the source port for this stream
            fStreamArray[theStreamIndex].fPort = (UInt16) relayAddrParser.ConsumeInteger(NULL);
            if (fStreamArray[theStreamIndex].fPort & 1)
                continue; //we only care about RTP ports
            
            // Fill in all the fields we can for this stream
            fStreamArray[theStreamIndex].fDestIPAddr = theDestIPAddr;
            fStreamArray[theStreamIndex].fTimeToLive = theDestTtl;
            fStreamArray[theStreamIndex].fTrackID = theStreamIndex + 1;
            
            // Now fill in all the output ports for this stream
            for (UInt32 x = 0; x < fNumOutputs; x++)
            {
                relayAddrParser.ConsumeWhitespace();
                fOutputArray[x].fPortArray[theStreamIndex] = (UInt16) relayAddrParser.ConsumeInteger(NULL);
            }
            
            theStreamIndex++;
        }
        //stop when we reach an empty line.
        if (!sdpParser.ExpectEOL())
            break;
    }
}
Beispiel #2
0
void SDPSourceInfo::Parse(char* sdpData, UInt32 sdpLen)
{
    //
    // There are some situations in which Parse can be called twice.
    // If that happens, just return and don't do anything the second time.
    if (fSDPData.Ptr != NULL)
        return;
        
    Assert(fStreamArray == NULL);
    
    char *sdpDataCopy = new char[sdpLen];
    Assert(sdpDataCopy != NULL);
    
    memcpy(sdpDataCopy,sdpData, sdpLen);
    fSDPData.Set(sdpDataCopy, sdpLen);

    // If there is no trackID information in this SDP, we make the track IDs start
    // at 1 -> N
    UInt32 currentTrack = 1;
    
    bool hasGlobalStreamInfo = false;
    StreamInfo theGlobalStreamInfo; //needed if there is one c= header independent of
                                    //individual streams

    StrPtrLen sdpLine;
    StringParser trackCounter(&fSDPData);
    StringParser sdpParser(&fSDPData);
    UInt32 theStreamIndex = 0;

    //walk through the SDP, counting up the number of tracks
    // Repeat until there's no more data in the SDP
    while (trackCounter.GetDataRemaining() > 0)
    {
        //each 'm' line in the SDP file corresponds to another track.
        trackCounter.GetThruEOL(&sdpLine);
        if ((sdpLine.Len > 0) && (sdpLine.Ptr[0] == 'm'))
            fNumStreams++;  
    }

    //We should scale the # of StreamInfos to the # of trax, but we can't because
    //of an annoying compiler bug...
    
    fStreamArray = new StreamInfo[fNumStreams];
	::memset(fStreamArray, 0, sizeof(StreamInfo) * fNumStreams);

    // set the default destination as our default IP address and set the default ttl
    theGlobalStreamInfo.fDestIPAddr = INADDR_ANY;
    theGlobalStreamInfo.fTimeToLive = kDefaultTTL;
        
    //Set bufferdelay to default of 3
    theGlobalStreamInfo.fBufferDelay = (Float32) eDefaultBufferDelay;
    
    //Now actually get all the data on all the streams
    while (sdpParser.GetDataRemaining() > 0)
    {
        sdpParser.GetThruEOL(&sdpLine);
        if (sdpLine.Len == 0)
            continue;//skip over any blank lines

        switch (*sdpLine.Ptr)
        {
            case 't':
            {
                StringParser mParser(&sdpLine);
                                
                mParser.ConsumeUntil(NULL, StringParser::sDigitMask);
                UInt32 ntpStart = mParser.ConsumeInteger(NULL);
                
                mParser.ConsumeUntil(NULL, StringParser::sDigitMask);               
                UInt32 ntpEnd = mParser.ConsumeInteger(NULL);
                
                SetActiveNTPTimes(ntpStart,ntpEnd);
            }
            break;
            
            case 'm':
            {
                if (hasGlobalStreamInfo)
                {
                    fStreamArray[theStreamIndex].fDestIPAddr = theGlobalStreamInfo.fDestIPAddr;
                    fStreamArray[theStreamIndex].fTimeToLive = theGlobalStreamInfo.fTimeToLive;
                }
                fStreamArray[theStreamIndex].fTrackID = currentTrack;
                currentTrack++;
                
                StringParser mParser(&sdpLine);
                
                //find out what type of track this is
                mParser.ConsumeLength(NULL, 2);//go past 'm='
                StrPtrLen theStreamType;
                mParser.ConsumeWord(&theStreamType);
                if (theStreamType.Equal(sVideoStr))
                    fStreamArray[theStreamIndex].fPayloadType = qtssVideoPayloadType;
                else if (theStreamType.Equal(sAudioStr))
                    fStreamArray[theStreamIndex].fPayloadType = qtssAudioPayloadType;
                    
                //find the port for this stream
                mParser.ConsumeUntil(NULL, StringParser::sDigitMask);
                SInt32 tempPort = mParser.ConsumeInteger(NULL);
                if ((tempPort > 0) && (tempPort < 65536))
                    fStreamArray[theStreamIndex].fPort = (UInt16) tempPort;
                    
                // find out whether this is TCP or UDP
                mParser.ConsumeWhitespace();
                StrPtrLen transportID;
                mParser.ConsumeWord(&transportID);
                
                static const StrPtrLen kTCPTransportStr("RTP/AVP/TCP");
                if (transportID.Equal(kTCPTransportStr))
                    fStreamArray[theStreamIndex].fIsTCP = true;
                    
                theStreamIndex++;
            }
            break;
            case 'a':
            {
                StringParser aParser(&sdpLine);

                aParser.ConsumeLength(NULL, 2);//go past 'a='

                StrPtrLen aLineType;

                aParser.ConsumeWord(&aLineType);



                if (aLineType.Equal(sBroadcastControlStr))

                {   // found a control line for the broadcast (delete at time or delete at end of broadcast/server startup) 

                    // qtss_printf("found =%s\n",sBroadcastControlStr);

                    aParser.ConsumeUntil(NULL,StringParser::sWordMask);

                    StrPtrLen sessionControlType;

                    aParser.ConsumeWord(&sessionControlType);

                    if (sessionControlType.Equal(sAutoDisconnect))
                    {
                       fSessionControlType = kRTSPSessionControl; 
                    }       
                    else if (sessionControlType.Equal(sAutoDisconnectTime))
                    {
                       fSessionControlType = kSDPTimeControl; 
                    }       
                    

                }

                //if we haven't even hit an 'm' line yet, just ignore all 'a' lines
                if (theStreamIndex == 0)
                    break;
                    
                if (aLineType.Equal(sRtpMapStr))
                {
                    //mark the codec type if this line has a codec name on it. If we already
                    //have a codec type for this track, just ignore this line
                    if ((fStreamArray[theStreamIndex - 1].fPayloadName.Len == 0) &&
                        (aParser.GetThru(NULL, ' ')))
                    {
                        StrPtrLen payloadNameFromParser;
                        (void)aParser.GetThruEOL(&payloadNameFromParser);
						char* temp = payloadNameFromParser.GetAsCString();
//                                                qtss_printf("payloadNameFromParser (%x) = %s\n", temp, temp);
                        (fStreamArray[theStreamIndex - 1].fPayloadName).Set(temp, payloadNameFromParser.Len);
//                                                qtss_printf("%s\n", fStreamArray[theStreamIndex - 1].fPayloadName.Ptr);
                    }
                }
                else if (aLineType.Equal(sControlStr))
                {           
					// Modify By EasyDarwin
					//if ((fStreamArray[theStreamIndex - 1].fTrackName.Len == 0) &&
     //                   (aParser.GetThru(NULL, ' ')))
					{
						StrPtrLen trackNameFromParser;
						aParser.ConsumeUntil(NULL,':');
						aParser.ConsumeLength(NULL,1);
						aParser.GetThruEOL(&trackNameFromParser);

						char* temp = trackNameFromParser.GetAsCString();
//                                                qtss_printf("trackNameFromParser (%x) = %s\n", temp, temp);
						(fStreamArray[theStreamIndex - 1].fTrackName).Set(temp, trackNameFromParser.Len);
//                                                qtss_printf("%s\n", fStreamArray[theStreamIndex - 1].fTrackName.Ptr);
					
						StringParser tParser(&trackNameFromParser);
						tParser.ConsumeUntil(NULL, '=');
						tParser.ConsumeUntil(NULL, StringParser::sDigitMask);
						fStreamArray[theStreamIndex - 1].fTrackID = tParser.ConsumeInteger(NULL);
					}
                }
                else if (aLineType.Equal(sBufferDelayStr))
                {   // if a BufferDelay is found then set all of the streams to the same buffer delay (it's global)
                    aParser.ConsumeUntil(NULL, StringParser::sDigitMask);
                    theGlobalStreamInfo.fBufferDelay = aParser.ConsumeFloat();
                }

            }
            break;
            case 'c':
            {
                //get the IP address off this header
                StringParser cParser(&sdpLine);
                cParser.ConsumeLength(NULL, 9);//strip off "c=in ip4 "
                UInt32 tempIPAddr = SDPSourceInfo::GetIPAddr(&cParser, '/');
                                
                //grab the ttl
                SInt32 tempTtl = kDefaultTTL;
                if (cParser.GetThru(NULL, '/'))
                {
                    tempTtl = cParser.ConsumeInteger(NULL);
                    Assert(tempTtl >= 0);
                    Assert(tempTtl < 65536);
                }

                if (theStreamIndex > 0)
                {
                    //if this c= line is part of a stream, it overrides the
                    //global stream information
                    fStreamArray[theStreamIndex - 1].fDestIPAddr = tempIPAddr;
                    fStreamArray[theStreamIndex - 1].fTimeToLive = (UInt16) tempTtl;
                } else {
                    theGlobalStreamInfo.fDestIPAddr = tempIPAddr;
                    theGlobalStreamInfo.fTimeToLive = (UInt16) tempTtl;
                    hasGlobalStreamInfo = true;
                }
            }
        }
    }       
    
    // Add the default buffer delay
    Float32 bufferDelay = (Float32) eDefaultBufferDelay;
    if (theGlobalStreamInfo.fBufferDelay != (Float32) eDefaultBufferDelay)
        bufferDelay = theGlobalStreamInfo.fBufferDelay;
    
    UInt32 count = 0;
    while (count < fNumStreams)
    {   fStreamArray[count].fBufferDelay = bufferDelay;
        count ++;
    }
        
}