dvrengine/CommonRecordingEngine/DvrSdpParser/src/CDvrSdpParser.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:20:37 +0100
branchRCL_3
changeset 23 13a33d82ad98
parent 0 822a42b6c3f1
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201029 Kit: 201035

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:    Parses SDP file.*
*/




// INCLUDE FILES
#include <ipvideo/CDvrSdpParser.h>
#include <in_sock.h>
#include "videoserviceutilsLogger.h"

// CONSTANTS
_LIT8( KKeyIpv4Addr, "c=IN IP4 " );
_LIT8( KKeyIpv6Addr, "c=IN IP6 " );
_LIT8( KKeyAttribute, "a=" );
_LIT8( KKeyMedia, "m=" );
_LIT8( KKeyMediaAudio, "m=audio " );
_LIT8( KKeyMediaVideo, "m=video " );
_LIT8( KKeyMediaTitle, "m=title " );
_LIT8( KKeyDataStream, "m=data " );
_LIT8( KKeyClockRate, "a=rtpmap:" );
_LIT8( KKeyControl, "a=control:" ); 
//_LIT8( KKeyStreamId, "a=control:streamid=" );
_LIT8( KRealMediaIndicator, "/x-pn-real" ); 
_LIT8( KKeyBandWidth, "b=AS:" );
_LIT8( KCRSDPRtspUriBegin, "rtsp://" );
_LIT8( KSPStr, " ");
_LIT8( KCRStr, "\r");
_LIT8( KLFStr, "\n");
_LIT8( KCRLFStr, "\r\n");
_LIT8( KSLStr, "/" );
_LIT8( KSdpLiveStream, "a=LiveStream:integer;1");
_LIT8( KSdpRangeHeaderLiveStream, "a=range:npt=now-" );

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CDvrSdpParser::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CDvrSdpParser* CDvrSdpParser::NewL()
    {
    CDvrSdpParser* self = CDvrSdpParser::NewLC();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CDvrSdpParser* CDvrSdpParser::NewLC()
    {
    CDvrSdpParser* self = new( ELeave ) CDvrSdpParser();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::CDvrSdpParser
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CDvrSdpParser::CDvrSdpParser()
  : iAudioPort( KErrNotFound ),
    iVideoPort( KErrNotFound ),
    iTitlePort( KErrNotFound ),
    iAudioBitrate( KErrNotFound ),
    iVideoBitrate( KErrNotFound ),
    iAudioStreamId( KErrNotFound ),
    iVideoStreamId( KErrNotFound ),
    iVideoTimerGranularity( KMaxTUint32 ),
    iAudioTimerGranularity( KMaxTUint32 )
    {
    // None
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::ConstructL()
    {
    LOG( "CDvrSdpParser::ConstructL()" );
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::~CDvrSdpParser
// Destructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CDvrSdpParser::~CDvrSdpParser()
    {
    LOG( "CDvrSdpParser::~CDvrSdpParser()" );
    delete iBaseUrl; iBaseUrl = NULL; 
    DeleteVariables();
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::TryParseL
// 
// -----------------------------------------------------------------------------
//
EXPORT_C void CDvrSdpParser::TryParseL( const TDesC8& aSdp, const TDesC8& aBaseUrl ) 
    {
#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE )
    HBufC* baseLog = HBufC::NewLC( aBaseUrl.Length() );
    TPtr ptr = baseLog->Des();
    ptr.Copy( aBaseUrl );
    LOG2( "CDvrSdpParser::TryParseL(), aSdp length: %d, aBaseUrl: %S",
                                       aSdp.Length(), &ptr );
    CleanupStack::PopAndDestroy( baseLog );
#endif
    
    if ( aBaseUrl.Length() ) 
        {
        delete iBaseUrl; iBaseUrl = NULL; 
        iBaseUrl = aBaseUrl.AllocL(); 
        }

    TryParseL( aSdp ); 
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::TryParseL
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CDvrSdpParser::TryParseL( const TDesC8& aSdp )
    {
    LOG1( "CDvrSdpParser::TryParseL(), aSdp length: %d", aSdp.Length() );
    
    // Find medias
    FindMediasL( aSdp );
    
    // Append found medias to the array
    for ( TInt i( 0 ); i < iMediaBuf.Count(); i++ )
        {
        TInt port( KErrNotFound );
        TPtrC8 ptr( iMediaBuf[i] );

        // Audio media info found ?
        port = GetIntL( ptr, KKeyMediaAudio );    
        if ( port != KErrNotFound )
            {
            iAudioPort = port;
            LOG1( "CDvrSdpParser::TryParseL(), iAudioPort: %d", iAudioPort );
            UpdateMediaInfoL( ptr, iAudioIpAddr );
            // Stream id (Helix takes medias in appearance order)
            iAudioStreamId = i;
            // Audio clock rate
            iAudioTimerGranularity = GetClockRateL( ptr );
            iAudioBitrate = GetIntL( ptr, KKeyBandWidth ); 
            // Audio attributes
            FindAttributesL( ptr, iAudioAttributes ); 
            // Audio control
            GetControlL( ptr, iAudioControlAddr );
            // Find media id 97 from a=rtpmap:97 MP4A-LATM/32000/2
            iMediaIdentifierAudio = GetIntL( ptr, KKeyClockRate ); 
            }
        else
            {
            // Video media info found ?
            port = GetIntL( ptr, KKeyMediaVideo );
            if ( port != KErrNotFound )
                {
                iVideoPort = port;
                LOG1( "CDvrSdpParser::TryParseL(), iVideoPort: %d", iVideoPort );
                UpdateMediaInfoL( ptr, iVideoIpAddr );
                // Stream id (Helix takes medias in appearance order)
                iVideoStreamId = i; 
                // Video clock rate
                iVideoTimerGranularity = GetClockRateL( ptr );
                iVideoBitrate = GetIntL( ptr, KKeyBandWidth ); 
                // Video attributes
                FindAttributesL( ptr, iVideoAttributes );
                // Video control
                GetControlL( ptr, iVideoControlAddr );
                // Find media id 96 from a=rtpmap:96 H264/90000 line
	            iMediaIdentifierVideo = GetIntL( ptr, KKeyClockRate );
                }
            else
                {
                port = GetIntL( ptr, KKeyMediaTitle );
                if ( port != KErrNotFound )
                    {
                    iTitlePort = port;
                    LOG1( "CDvrSdpParser::TryParseL(), iTitlePort: %d", iTitlePort );
                    }
                }
            }
        }

    iMediaBuf.Reset();
    delete iBaseUrl; iBaseUrl = NULL; 
    delete iCommonIp; iCommonIp = NULL;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::NewLineL
// 
// -----------------------------------------------------------------------------
//
EXPORT_C void CDvrSdpParser::NewLineL(
    const TInt aStreamId,
    const TDesC8& aLine ) 
    {
    User::LeaveIfNull( iSdp );
    const TInt newLen( iSdp->Length() + aLine.Length() + KCRLFStr().Length() );
    LOG2( "CDvrSdpParser::NewLineL(), aStreamId: %d, New sdp length: %d",
                                      aStreamId, newLen );
    switch( aStreamId )
        {
        case KErrNotFound: // Common
            {
            // Alloc more room
            iSdp = iSdp->ReAllocL( newLen );
            TPtr8 ptr( iSdp->Des() );
            
            // Find first attribute for new line point
            const TInt insertPoint( ptr.Find( KKeyAttribute ) );
            User::LeaveIfError( insertPoint );
            ptr.Insert( insertPoint, KCRLFStr );
            ptr.Insert( insertPoint, aLine );
            }
            break;
            
        case 0: // Audio (usually)
        case 1: // Video (usually)
            {
            iSdp = iSdp->ReAllocL( newLen );
            InserNewLineL( aStreamId, aLine );
            }
            break;
        
        default:
            User::Leave( KErrCompletion );
        }
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::GetSdp
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::GetSdp( TPtrC8& aSdp ) 
    {
    if ( iSdp )
        {
        aSdp.Set( iSdp->Des() );
        return KErrNone;
        }
    
    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::SupportedContent
// -----------------------------------------------------------------------------
//
EXPORT_C CDvrSdpParser::TDvrPacketProvidings CDvrSdpParser::SupportedContent( void )
    {
    TDvrPacketProvidings retval( EDvrNoProgramAtAll );

    if ( iAudioPort > KErrNotFound && iVideoPort > KErrNotFound )
        {
        retval = EDvrBothAudioAndVideo;
        }
    else if ( iAudioPort > KErrNotFound && iVideoPort <= KErrNotFound )
        {
        retval = EDvrAudioOnly;
        }
    else if ( iVideoPort > KErrNotFound && iAudioPort <= KErrNotFound )
        {
        retval = EDvrVideoOnly;
        }
    else
        {
        LOG( "CDvrSdpParser::SupportedContent(), No media !" );
        }
    
    return retval;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::SessionAttributes
// 
// -----------------------------------------------------------------------------
//
EXPORT_C RArray<TPtrC8>& CDvrSdpParser::SessionAttributes( void ) 
    {
    return iSessionAttributes; 
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioAttributes
// 
// -----------------------------------------------------------------------------
//
EXPORT_C RArray<TPtrC8>& CDvrSdpParser::AudioAttributes( void ) 
    {
    return iAudioAttributes; 
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoAttributes
// 
// -----------------------------------------------------------------------------
//
EXPORT_C RArray<TPtrC8>& CDvrSdpParser::VideoAttributes( void ) 
    {
    return iVideoAttributes; 
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::DataStreams
// 
// -----------------------------------------------------------------------------
//
EXPORT_C RArray<TPtrC8>& CDvrSdpParser::DataStreams( void ) 
    {
    return iDataStreams; 
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::IsIpv4Sdp
// Checks if Ipv4 address in use.
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CDvrSdpParser::IsIpv4Sdp( void ) 
    {
    return iIsIpv4;
    }   

// -----------------------------------------------------------------------------
// CDvrSdpParser::IsMultiCastSdp
// Checks if c= line did specify a multicast addr
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CDvrSdpParser::IsMultiCastSdp( void ) 
    {
    return iIsMulticast;
    }   

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioControlAddr
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC8 CDvrSdpParser::AudioControlAddr( void ) 
    {
    return ( iAudioControlAddr )? TPtrC8( *iAudioControlAddr ): 
                                  TPtrC8( KNullDesC8 );     
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoControlAddr
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC8 CDvrSdpParser::VideoControlAddr( void ) 
    {
    return ( iVideoControlAddr )? TPtrC8( *iVideoControlAddr ):
                                  TPtrC8( KNullDesC8 );     
    }   

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioIpAddr
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC8 CDvrSdpParser::AudioIpAddr( void ) 
    {
    return ( iAudioIpAddr )? TPtrC8( *iAudioIpAddr ): TPtrC8( KNullDesC8 );     
    }   

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoIpAddr
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC8 CDvrSdpParser::VideoIpAddr( void ) 
    {
    return ( iVideoIpAddr )? TPtrC8( *iVideoIpAddr ): TPtrC8( KNullDesC8 );     
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioPort
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::AudioPort( void ) 
    {
    return iAudioPort;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoPort
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::VideoPort( void ) 
    {
    return iVideoPort;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioBitrate
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::AudioBitrate( void ) 
    {
    return iAudioBitrate;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoBitrate
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::VideoBitrate( void ) 
    {
    return iVideoBitrate;   
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioStreamId
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::AudioStreamId( void ) 
    {
    return iAudioStreamId;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoStreamId
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::VideoStreamId( void ) 
    {
    return iVideoStreamId;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::VideoTimerGranularity
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TUint32 CDvrSdpParser::VideoTimerGranularity( void )  
    {
    return iVideoTimerGranularity; 
    }       

// -----------------------------------------------------------------------------
// CDvrSdpParser::AudioTimerGranularity
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TUint32 CDvrSdpParser::AudioTimerGranularity( void ) 
    {
    return iAudioTimerGranularity; 
    }       

// -----------------------------------------------------------------------------
// CDvrSdpParser::IsRealMediaContent
// Check for realmedia content.
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CDvrSdpParser::IsRealMediaContent( void ) 
    {
    if ( iSdp && iSdp->Des().Find( KRealMediaIndicator ) != KErrNotFound )
        {
        LOG( "CDvrSdpParser::IsRealMediaContent(), Yes" );
        return ETrue;
        }   
        
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::MediaIdentifierAudio
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::MediaIdentifierAudio( void )
	{
	return iMediaIdentifierAudio ;
	}
	
// -----------------------------------------------------------------------------
// CDvrSdpParser::MediaIdentifierVideo
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CDvrSdpParser::MediaIdentifierVideo( void )
	{
	return iMediaIdentifierVideo ;
	}

// -----------------------------------------------------------------------------
// CDvrSdpParser::IsLiveStream
// 
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CDvrSdpParser::IsLiveStream( void ) 
    {
    TBool isLiveStream = EFalse;
    if ( iSdp &&
       ( iSdp->Des().Find( KSdpLiveStream ) != KErrNotFound || 
         iSdp->Des().Find( KSdpRangeHeaderLiveStream ) != KErrNotFound ) )
        {
        LOG( "CDvrSdpParser::IsLiveStream(), Yes" );
        isLiveStream = ETrue;
        }
        
    return isLiveStream;
    }
    
// -----------------------------------------------------------------------------
// CDvrSdpParser::FindMediasL
//
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::FindMediasL( const TDesC8& aSdp ) 
    {
    LOG1( "CDvrSdpParser::FindMediasL(), aSdp length: %d", aSdp.Length() );

    // Find medias from SDP
    DeleteVariables();
    iSdp = aSdp.AllocL();
    RArray<SMediaPoint> points;
    CleanupClosePushL( points );
    FindMediaPointsL( points );
    MakeMediaBuffersL( points );
    FindSessionAttributesL( points );
    CleanupStack::PopAndDestroy( &points );
    FindDataStreamsL( iSdp->Des(), iDataStreams );
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::FindMediaPointsL
// Find points of all medias.
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::FindMediaPointsL( RArray<SMediaPoint>& aPoints )
    {
    TInt lastPoint( 0 );
    User::LeaveIfNull( iSdp );
    TPtrC8 ptr( iSdp->Des() );
    TInt start( MediaSectionStart( ptr ) );
    
    // Loop all media sections
    while ( start > KErrNotFound && lastPoint < iSdp->Length() )
        {
        // Find whole media section, up to next media or EOF
        start += lastPoint;
        TInt len( MediaSectionStart( ptr.Mid( start + KKeyMedia().Length() ) ) );
        len = ( len > KErrNotFound )? len + KKeyMedia().Length() - 1:
                                      ptr.Length() - start - 1;
        // New media point
        SMediaPoint point;
        point.iStart = start;
        point.iLength = len;
        lastPoint = ( start + len );
        User::LeaveIfError( aPoints.Append( point ) );
        LOG3( "CDvrSdpParser::FindMediaPointsL(), start: %d, len: %d, lastPoint: %d",
                                                  start, len, lastPoint );
        // Next section
        start = MediaSectionStart( ptr.Mid( lastPoint ) );
        }
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::MediaSectionStart
//
// -----------------------------------------------------------------------------
//
TInt CDvrSdpParser::MediaSectionStart( const TDesC8& aPtr ) 
    {
    TInt start( aPtr.Find( KKeyMedia ) );
    while ( start > KErrNotFound )
        {
        // Verify that not data stream keyword? ( i.e not 'm=data' )
        const TInt keywordlen( KKeyDataStream().Length() );
        TPtrC8 ptr( aPtr.Mid( start, keywordlen ) );
        if ( ptr.Find( KKeyDataStream ) == KErrNotFound )
            {
            // Audio, video or subtitle
            return start;
            }
        
        start += keywordlen;
        const TInt next( aPtr.Mid( start ).Find( KKeyMedia ) );
        start = ( next > KErrNotFound )? start + next: KErrNotFound;
        }
    
    return start;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::MakeMediaBuffersL
// Make media buffers
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::MakeMediaBuffersL( RArray<SMediaPoint>& aPoints )
    {
    User::LeaveIfNull( iSdp );
    for ( TInt i( 0 ); i < aPoints.Count(); i++ )
        {
        TPtrC8 media( iSdp->Des().Mid( aPoints[i].iStart, aPoints[i].iLength ) );
        User::LeaveIfError( iMediaBuf.Append( media ) );
        }
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::FindSessionAttributesL
// Find session attributes (common section before any media) 
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::FindSessionAttributesL( RArray<SMediaPoint>& aPoints ) 
    {
    User::LeaveIfNull( iSdp );
    if ( aPoints.Count() )
        {
        TPtrC8 common( iSdp->Des().Left( aPoints[0].iStart ) );
        FindAttributesL( common, iSessionAttributes ); 
        
        // IP in common section
        delete iCommonIp; iCommonIp = NULL;
        iCommonIp = GetIpAddrL( common );
        }
    }
        
// -----------------------------------------------------------------------------
// CDvrSdpParser::InserNewLineL
//
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::InserNewLineL(
    TInt aStreamId,
    const TDesC8& aLine )
    {
    RArray<SMediaPoint> points;
    CleanupClosePushL( points );
    FindMediaPointsL( points );

    // Add new line to first after media description
    if ( aStreamId >= 0 && aStreamId < points.Count() )
        {
        User::LeaveIfNull( iSdp );
        TPtr8 ptr( iSdp->Des() );
        TInt insertPoint( GetLen( ptr.Mid( points[aStreamId].iStart,
                                           points[aStreamId].iLength ), ETrue ) );
        User::LeaveIfError( insertPoint );
        ptr.Insert( insertPoint, aLine );
        ptr.Insert( insertPoint, KCRLFStr );
        }
    else
        {
        User::Leave( KErrCompletion );
        }

    CleanupStack::PopAndDestroy( &points );
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::UpdateMediaInfoL
//
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::UpdateMediaInfoL(
    const TDesC8& aMediaPtr,
    HBufC8*& aAddress )
    {
    // Search for IP address (Ipv6/Ipv4)
    aAddress = GetIpAddrL( aMediaPtr );
    if ( !aAddress && iCommonIp )
        {
        aAddress = iCommonIp->AllocL();
        }
    User::LeaveIfNull( aAddress );
    TPtr8 ptr( aAddress->Des() );

    // IP Address
    if ( iIsIpv4 )
        {
        LOG( "CDvrSdpParser::UpdateMediaInfoL(), Removing v4 subnet mask" );
        // Remove possible subnet mask (e.g. c=IN IP4 225.0.1.15/64)
        const TInt maskPos( aAddress->Find( KSLStr ) ); 
        if ( maskPos != KErrNotFound )
            {
            ptr.SetLength( maskPos );
            }
        }

#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE )
    TName buf; buf.Copy( ptr );
    LOG1( "CDvrSdpParser::UpdateMediaInfoL(), aAddress: %S", &buf );
#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE

    /* Stream Id
    const TInt streamId( GetIntL( aMediaPtr, KKeyStreamId ) );
    LOG1( "CDvrSdpParser::UpdateMediaInfoL(), Stream Id: %d", streamId );
    return streamId;
    */
    }
    
// -----------------------------------------------------------------------------
// CDvrSdpParser::GetIpAddrL
//
// -----------------------------------------------------------------------------
//
HBufC8* CDvrSdpParser::GetIpAddrL( const TDesC8& aPtr ) 
    {
    iIsIpv4 = EFalse;
    HBufC8* ipAddr = GetStringL( aPtr, KKeyIpv6Addr );
    if ( !ipAddr )
        {
        ipAddr = GetStringL( aPtr, KKeyIpv4Addr );
        if ( ipAddr )
            {
            iIsIpv4 = ETrue;
            }
        }
        
    // Verify multicast
    if ( ipAddr )
        {
        TPtrC8 addr( ipAddr->Des() );
        if ( addr.Length() <= KMaxName )
            {
            CheckForMulticast( addr ); 
            }
        else
            {
            LOG1( "Ipaddress length too long: %d, leaving....", addr.Length() );
            delete ipAddr; ipAddr = NULL;
            User::Leave( KErrOverflow );
            }   
        }
    
    return ipAddr;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::GetClockRateL
//
// -----------------------------------------------------------------------------
//
TUint CDvrSdpParser::GetClockRateL( const TDesC8& aPtr )
    {
    // Find clock rate keyword
    TInt start( FindStart( aPtr, KKeyClockRate ) );
    User::LeaveIfError( start );

    // Len up to first slash ( i.e: rtpmap:97 MP4A-LATM/32000/2 )
    TInt slash( aPtr.Mid( start ).Find( KSLStr ) ); 
    User::LeaveIfError( slash );
    start += ( slash + KSLStr().Length() );
    TInt len( GetLen( aPtr, start ) );
    
    // Len up to second slash ( i.e: rtpmap:97 MP4A-LATM/32000/2 )
    slash = aPtr.Mid( start, len ).Find( KSLStr );
    len = ( slash != KErrNotFound )? slash: len;
    return StrToUint( aPtr.Mid( start, len ) );
    }
    
// -----------------------------------------------------------------------------
// CDvrSdpParser::GetControlL() 
// Checks if a=control line specifies a control for media.
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::GetControlL( const TDesC8& aMediaPtr, HBufC8*& aControlAddr )
    {
    delete aControlAddr; aControlAddr = NULL;
    HBufC8* control = GetStringL( aMediaPtr, KKeyControl ); 
    if ( control ) 
        {
        CleanupStack::PushL( control ); 
        if ( control->Des().FindC( KCRSDPRtspUriBegin ) == KErrNotFound )
            { 
            // relative url
            if ( iBaseUrl ) 
                {
                aControlAddr = HBufC8::NewL( iBaseUrl->Des().Length() + 
                                             control->Des().Length() + 
                                             KSLStr().Length() );
                aControlAddr->Des().Append ( iBaseUrl->Des() ); 
                aControlAddr->Des().Append ( KSLStr ) ; 
                aControlAddr->Des().Append ( control->Des() );
                }
            }
        else
            { 
            // absolute url
            aControlAddr = control->Des().AllocL();                     
            }
        
        CleanupStack::PopAndDestroy( control ); 
        }
    }
                
// -----------------------------------------------------------------------------
// CDvrSdpParser::CheckForMulticast() 
// Checks if c= line specifies a multicast addr
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::CheckForMulticast( const TDesC8& aLine )
    {
    TInetAddr controladdr;
    TName addr( KNullDesC );
    addr.Copy( aLine ); 
    TInt err( controladdr.Input( addr ) );
    if ( err != KErrNone )
        {
        LOG1( "CDvrSdpParser: invalid control address in SDP connection line '%S'", &addr );
        }
    else
        {
        // just do check for multicast, actual address is taken from SETUP response
        iIsMulticast = controladdr.IsMulticast();

#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE )
        /* Commented out, for some reason can crash with RTP playback in debug.
        if ( iIsMulticast )
            { 
            LOG1( "CDvrSdpParser: detected MULTICAST (%S) control address in SDP", &addr );
            }
        else
            {
            LOG1( "CDvrSdpParser: detected unicast (%S) control address in SDP", &addr );
            }
        */
#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE
        }
    }   

// -----------------------------------------------------------------------------
// CDvrSdpParser::FindAttributesL
// 
// -----------------------------------------------------------------------------
//  
void CDvrSdpParser::FindAttributesL(
    const TDesC8& aSdpSection,
    RArray<TPtrC8>& aAttributeList ) 
    {
    TInt last( 0 );
    TInt start( KErrNotFound );
    do
        {
        // Rest of the SDP section
        TPtrC8 rest( aSdpSection.Mid( last ) );
        start = rest.Find( KKeyAttribute );
        if ( start > KErrNotFound )
            {
            last += start;
            TInt len( GetLen( rest, start, ETrue ) );
            if ( len > 0 )
                { 
                // Add other than control attribute
                if ( rest.Mid( start, len ).Find( KKeyControl ) == KErrNotFound )
                    {
                    TPtrC8 ptr( rest.Mid( start, len ) );
                    User::LeaveIfError( aAttributeList.Append( ptr ) ); 
                    }
                
                last += len;
                }
            }
        }
        while( start > KErrNotFound );
    }                           
                               
// -----------------------------------------------------------------------------
// CDvrSdpParser::FindDataStreamsL
// 
// -----------------------------------------------------------------------------
//  
void CDvrSdpParser::FindDataStreamsL(
    const TDesC8& aSdpSection,
    RArray<TPtrC8>& aStreamsList )
    {
    TInt last( 0 );
    TInt start( KErrNotFound );
    do
        {
        // Rest of the SDP block
        TPtrC8 rest( aSdpSection.Mid( last ) );
        start = rest.Find( KKeyDataStream );
        if ( start > KErrNotFound )
            {
            last += start;
            TInt len( GetLen( rest, start, ETrue ) );
            if ( len > 0 )
                { 
                TPtrC8 ptr( rest.Mid( start, len ) );
                User::LeaveIfError( aStreamsList.Append( ptr ) ); 
                last += len;
                }
            }
        }
        while( start > KErrNotFound );
    }                           
                               
// -----------------------------------------------------------------------------
// CDvrSdpParser::GetIntL
//
// -----------------------------------------------------------------------------
//
TInt CDvrSdpParser::GetIntL( const TDesC8& aPtr, const TDesC8& aKeyword ) 
    {
    TInt ret( KErrNotFound );
    HBufC8* buf = GetStringL( aPtr, aKeyword );
    if ( buf )
        {
        ret = StrToUint( buf->Des() );
        delete buf;
        }
   
    return ret;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::GetStringL
//
// -----------------------------------------------------------------------------
//
HBufC8* CDvrSdpParser::GetStringL( const TDesC8& aPtr, const TDesC8& aKeyword ) 
    {
    const TInt start( FindStart( aPtr, aKeyword ) );
    const TInt len( GetLen( aPtr, start ) );

    HBufC8* buf = NULL;
    if ( start > KErrNotFound && len > 0 && ( start + len ) <= aPtr.Length() )
        {
        buf = aPtr.Mid( start, len ).AllocL();
        }
    
    return buf;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::FindStart
//
// -----------------------------------------------------------------------------
//
TInt CDvrSdpParser::FindStart( const TDesC8& aPtr, const TDesC8& aKeyword ) 
    {
    TInt start( aPtr.Find( aKeyword ) ); 
    
    if ( start > KErrNotFound )
        {
        start += aKeyword.Length();
        }
    
    return start;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::GetLen
//
// -----------------------------------------------------------------------------
//
TInt CDvrSdpParser::GetLen(
    const TDesC8& aPtr,
    const TInt aStart,
    const TBool aIgnoreSpace )
    {
    if ( aStart > KErrNotFound && aStart < aPtr.Length() )
        {
        // Find next LF, CR or CRLF combination
        TInt len1( MinNonError( aPtr.Mid( aStart ).Find( KLFStr ),
                                aPtr.Mid( aStart ).Find( KCRStr ) ) );
        // Find space
        TInt len2( ( aIgnoreSpace )? KErrNotFound: 
                                     aPtr.Mid( aStart ).Find( KSPStr ) );

        if ( len1 == KErrNotFound && len2 == KErrNotFound )
            {
            // Rest of the buffer
            return ( aPtr.Length() - aStart );
            }
        else
            {
            // CRLF or space
            return MinNonError( len1, len2 );
            }
        }
    
    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::MinNonError
//
// -----------------------------------------------------------------------------
//
TInt CDvrSdpParser::MinNonError( const TInt aValue1, const TInt aValue2 )
    {
    if ( aValue1 > KErrNotFound && aValue2 > KErrNotFound )
        {
        return Min( aValue1, aValue2 );
        }

    return ( ( aValue1 > KErrNotFound )? aValue1: 
             ( aValue2 > KErrNotFound )? aValue2: KErrNotFound );
    }
    
// -----------------------------------------------------------------------------
// CDvrSdpParser::StrToUint
// Convert string to integer.
// -----------------------------------------------------------------------------
//
TUint CDvrSdpParser::StrToUint( const TDesC8& aString ) 
    {
    TLex8 templex;
    templex.Assign( aString );
    TUint ret( KMaxTUint );
    templex.Val( ret );
    return ret;
    }

// -----------------------------------------------------------------------------
// CDvrSdpParser::DeleteVariables
// 
// -----------------------------------------------------------------------------
//
void CDvrSdpParser::DeleteVariables( void )
    {
    delete iSdp; iSdp = NULL;
    delete iCommonIp; iCommonIp = NULL;
    iMediaBuf.Reset();
    iSessionAttributes.Reset();
    iAudioAttributes.Reset();
    iVideoAttributes.Reset();
    iDataStreams.Reset();
    delete iAudioControlAddr; iAudioControlAddr = NULL;
    delete iVideoControlAddr; iVideoControlAddr = NULL;
    delete iAudioIpAddr; iAudioIpAddr = NULL;
    delete iVideoIpAddr; iVideoIpAddr = NULL;
    }

//  End of File