dvrengine/CommonRecordingEngine/src/CCRRtpTcpStreamer.cpp
branchRCL_3
changeset 48 13a33d82ad98
parent 0 822a42b6c3f1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dvrengine/CommonRecordingEngine/src/CCRRtpTcpStreamer.cpp	Wed Sep 01 12:20:37 2010 +0100
@@ -0,0 +1,418 @@
+/*
+* 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:    RTP/TCP streamer for RTSP source.*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "CCRRtpTcpStreamer.h"
+#include "CCRRtpTcpObserver.h"
+#include "CCRRtpTcpStream.h"
+#include "CRRTSPCommon.h"
+#include <es_sock.h>
+#include "videoserviceutilsLogger.h"
+
+// CONSTANTS
+const TInt KCRRtpTcpHeaderLength( 4 );
+const TInt KCRRtpTcpStartMark( 0x24 );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::NewL
+// -----------------------------------------------------------------------------
+CCRRtpTcpStreamer* CCRRtpTcpStreamer::NewL( MCRRtpTcpObserver& aObserver )
+    {
+    CCRRtpTcpStreamer* self = new( ELeave ) CCRRtpTcpStreamer( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::CCRRtpTcpStreamer
+// -----------------------------------------------------------------------------
+//
+CCRRtpTcpStreamer::CCRRtpTcpStreamer( MCRRtpTcpObserver& aObserver )
+  : iObserver( aObserver ),
+    iMoreExpected( KErrNotFound ),
+    iIpData( NULL )
+    {
+    // None
+    }
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CCRRtpTcpStreamer::ConstructL()
+    {
+    // Construct streams
+    for ( TInt i( 0 ); i < KCRRtpTcpStreamCount; i++ )
+        {
+        iStreams[i] = CCRRtpTcpStream::NewL( iObserver );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::~CCRRtpTcpStreamer
+// -----------------------------------------------------------------------------
+CCRRtpTcpStreamer::~CCRRtpTcpStreamer()
+    {
+    // Buffers
+    if ( iIpData )
+        {
+        delete iIpData; iIpData = NULL;
+        }
+    if ( iRtspData )
+        {
+        delete iRtspData; iRtspData = NULL;
+        }
+
+    // Delete streams
+    for ( TInt i( 0 ); i < KCRRtpTcpStreamCount; i++ )
+        {
+        if ( iStreams[i] )
+            {
+            delete iStreams[i]; iStreams[i] = NULL;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::DataAvailable
+// -----------------------------------------------------------------------------
+//
+void CCRRtpTcpStreamer::DataAvailable(
+    const TDesC8& aIpData,
+    const TBool& aInterleaved )
+    {
+    TPtrC8 data( aIpData );
+    if ( iMoreExpected > KErrNotFound && iIpData != NULL )
+        {
+        // More data expected
+        if ( HandleMoreExpected( data ) )
+            {
+            return; // Need more
+            }
+        }
+
+    // Can't be existing IP data at this point
+    delete iIpData; iIpData = NULL;
+    iMoreExpected = KErrNotFound;
+    
+    // Find out next packet
+    do
+        {
+        // Search for $ (0x24) sign
+        TBool tcp( EFalse );
+        for ( TInt i( 0 ); aInterleaved && tcp == EFalse &&
+            i < data.Length() && i < KCRRtpTcpHeaderLength; i++ )
+            {
+            if ( data[i] == KCRRtpTcpStartMark )
+                {
+                tcp = ETrue;
+                data.Set( data.Mid( i ) );
+                
+                // Received less than full interleved header (4 bytes)
+                if ( data.Length() < KCRRtpTcpHeaderLength )
+                    {
+                    iMoreExpected = KCRRtpTcpHeaderLength - data.Length();
+                    iIpData = data.Alloc();
+                    LOG1( "CCRRtpTcpStreamer::DataAvailable(), No interleave header, len: %d", data.Length() );
+                    return; // Need more
+                    }
+                }
+            }
+        
+        if ( tcp )
+            {
+            // TCP packet
+            if ( HandleTcpPacket( data ) )
+                {
+                return; // Need more
+                }
+            }
+        else
+            {
+            // RTSP response
+            if ( HandleRtspResponse( data, aInterleaved ) )
+                {
+                return; // Need more
+                }
+        
+            delete iRtspData; iRtspData = NULL;
+            }
+        }
+        while ( data.Length() > 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::HandleMoreExpected
+// -----------------------------------------------------------------------------
+//
+TBool CCRRtpTcpStreamer::HandleMoreExpected( TPtrC8& aData )
+    {
+    TInt len( aData.Length() );
+    int used( len );
+    if ( len >= iMoreExpected || iMoreExpected == KMaxTInt )
+        {
+        if ( iMoreExpected >= KCRRtpTcpHeaderLength ||
+             iIpData->Des()[0] != KCRRtpTcpStartMark ||
+             iIpData->Length() >= KCRRtpTcpHeaderLength )
+            {
+            // KMaxTInt is indication of unknow length in RTSP response
+            if ( iMoreExpected < KMaxTInt )
+                {
+                used = iMoreExpected;
+                iMoreExpected = KErrNotFound;
+                }
+            else
+                {
+                // Combine datas and try find out RTSP response
+                delete iRtspData; iRtspData = NULL;
+                iRtspData = HBufC8::New( iIpData->Length() + len );
+                TPtr8 ptr( iRtspData->Des() );
+                ptr.Copy( iIpData->Des() );
+                ptr.Append( aData );
+                aData.Set( iRtspData->Des() );
+                return EFalse; // Continue
+                }
+            }
+        else
+            {
+            // Fill interleave header
+            iIpData = iIpData->ReAlloc( iIpData->Length() + iMoreExpected );
+            TPtr8 ptr( iIpData->Des() );
+            ptr.Append( aData.Mid( 0, iMoreExpected ) );
+            aData.Set( aData.Mid( iMoreExpected ) );
+            len = aData.Length();
+            used = len;
+            // Find real wanted packet length 
+            iMoreExpected = ( TInt )BigEndian::Get16( ptr.Ptr() + 2 );
+            if ( len == 0 )
+                {
+                return ETrue; // Need more
+                }
+            if ( len >= iMoreExpected )
+                {
+                used = iMoreExpected;
+                iMoreExpected = KErrNotFound;
+                }
+            }
+        }
+
+    // Add new data to iIpData
+    iIpData = iIpData->ReAlloc( iIpData->Length() + used );
+    TPtr8 ptr( iIpData->Des() );
+    ptr.Append( aData.Mid( 0, used ) );
+    aData.Set( aData.Mid( used ) );
+    if ( iMoreExpected == KErrNotFound )
+        {
+        ForwardPacket( ptr );
+        if ( used == len )
+            {
+            delete iIpData; iIpData = NULL;
+            return ETrue; // All handled
+            }
+        }
+    else
+        {
+        iMoreExpected -= used;
+        return ETrue; // Need more
+        }
+        
+    return EFalse; // Continue
+    }
+    
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::HandleTcpPacket
+// -----------------------------------------------------------------------------
+//
+TBool CCRRtpTcpStreamer::HandleTcpPacket( TPtrC8& aData )
+    {
+    const TInt length( KCRRtpTcpHeaderLength + 
+        ( TInt )BigEndian::Get16( aData.Ptr() + 2 ) );
+    if ( aData.Length() >= length )
+        {
+        MakePacket( aData, length );
+        }
+    else
+        {
+        // Need more data
+        iMoreExpected = length - aData.Length();
+        iIpData = aData.Alloc();
+        return ETrue; // Need more
+        }
+    
+    return EFalse; // Continue
+    }
+    
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::HandleRtspResponse
+// -----------------------------------------------------------------------------
+//
+TBool CCRRtpTcpStreamer::HandleRtspResponse(
+    TPtrC8& aData,
+    const TBool& aInterleaved )
+    {
+    TInt point( aData.FindC( KCRRTSPReplyHeader ) );
+    if ( point > KErrNotFound )
+        {
+        aData.Set( aData.Mid( point ) );
+        
+        // Search for double CRLF combination
+        TInt crlf2( aData.FindC( KCR2NewLines ) );
+		if ( crlf2 > KErrNotFound )
+		    {
+		    crlf2 += KCR2NewLines().Length();
+		    }
+
+        // Content length
+        point = aData.FindC( KCRRTSPContentLength() );
+        if ( point > KErrNotFound && crlf2 > KErrNotFound )
+            {
+            point += KCRRTSPContentLength().Length();
+            TInt contentLen( KErrNotFound );
+            TLex8 contentLenLex( aData.Mid( point, 5 ) );
+            if ( contentLenLex.Val( contentLen ) < KErrNone )
+                {
+                LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Content length parse failed, Dumped %d bytes !", aData.Length() );
+                return ETrue;
+                }
+            
+            LOG1( "CCRRtspCommon::HandleRtspResponse(), contentLen %d", contentLen );
+            // Verify that enought data in IP packet
+            if ( aData.Length() >= ( crlf2 + contentLen ) )
+                {
+                MakePacket( aData, crlf2 + contentLen );
+                }
+            else
+                {
+                // Need more
+                iIpData = aData.Alloc();
+                iMoreExpected = crlf2 + contentLen - aData.Length();
+                return ETrue;
+                }
+            }
+        else
+            {
+            // Content length not defined, RTSP command should end to double CRLF
+            if ( crlf2 > KErrNotFound )
+                {
+                MakePacket( aData, crlf2 );
+                }
+            else
+                {
+                LOG( "CCRRtpTcpStreamer::HandleRtspResponse(), No double CRLF.." );
+                
+                // Look for single CRLF
+                point = aData.FindC( KCRNewLine );
+                if ( point > KErrNotFound )
+                    {
+                    // If not interleaved, all data belongs to RTSP response
+                    if ( !aInterleaved )
+                        {
+                        if ( aData.Mid( aData.Length() - KCR2NewLines().Length() ).
+                            FindF( KCRNewLine ) > KErrNotFound )
+                            {
+                            ForwardPacket( aData );
+                            return ETrue;
+                            }
+                        
+                        // Not complete but total length unknown
+                        LOG( "CCRRtpTcpStreamer::HandleRtspResponse(), Need more without known length.." );
+                        iIpData = aData.Alloc();
+                        iMoreExpected = KMaxTInt;
+                        return ETrue;
+                        }
+
+                    // Only one CRLF after RTSP response, find last
+                    point += KCRNewLine().Length();
+                    for ( TInt i( point ); i < aData.Length(); )
+                        {
+                        TInt next( aData.Mid( point ).FindC( KCRNewLine ) );
+                        if ( next > KErrNotFound )
+                            {
+                            point += ( next + KCRNewLine().Length() );
+                            i = point;
+                            }
+                        else
+                            {
+                            i = aData.Length();
+                            }
+                        }
+
+                    LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Last CRLF at index: %d", point );
+                    MakePacket( aData, point );
+                    }
+                else
+                    {
+                    // Not any CRLF, can not be RTSP response
+                    LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), No CRLF, Dumped %d bytes !", aData.Length() );
+                    return ETrue;
+                    }
+                }
+            }
+        }
+    else
+        {
+        LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Not RTSP message, Dumped %d bytes !", aData.Length() );
+        return ETrue;
+        }
+    
+    return EFalse;
+    }
+    
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::MakePacket
+// -----------------------------------------------------------------------------
+//
+void CCRRtpTcpStreamer::MakePacket( TPtrC8& aData, const TInt aLength )
+    {
+    ForwardPacket( aData.Mid( 0, aLength ) );
+    aData.Set( aData.Mid( aLength ) );
+    }
+    
+// -----------------------------------------------------------------------------
+// CCRRtpTcpStreamer::ForwardPacket
+// -----------------------------------------------------------------------------
+//
+void CCRRtpTcpStreamer::ForwardPacket( const TDesC8& aPacket )
+    {
+    if ( aPacket[0] == KCRRtpTcpStartMark )
+        {
+        // 1. Forward (actually return or signal reception of) packet to user
+        const TInt channel( ( TInt )aPacket[1] );
+        iObserver.RtpTcpPacketAvailable(
+            channel, aPacket.Mid( KCRRtpTcpHeaderLength ) );
+
+        // 2. Map channel to internal stream, ignore non audio or video
+        const TInt streamId( channel / 2 );
+        if ( streamId >= 0 && streamId < KCRRtpTcpStreamCount )
+            {
+            iStreams[streamId]->PacketAvailable( channel );
+            }
+        }
+    else
+        {
+        // RTSP
+        iObserver.RtspMsgAvailable( aPacket );
+        }
+    }
+
+//  End of File