diff -r 826cea16efd9 -r 13a33d82ad98 dvrengine/CommonRecordingEngine/src/CCRRtpTcpStreamer.cpp --- /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 +#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