diff -r 000000000000 -r 822a42b6c3f1 dvrengine/CommonRecordingEngine/src/CCRPacketBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvrengine/CommonRecordingEngine/src/CCRPacketBuffer.cpp Thu Dec 17 09:14:38 2009 +0200 @@ -0,0 +1,544 @@ +/* +* 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: Hold rtp packets waiting to be sent* +*/ + + + + +// INCLUDE FILES +#include "CCRPacketBuffer.h" +#include +#include "videoserviceutilsLogger.h" + +// CONSTANTS +// None. + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CCRPacketBuffer* CCRPacketBuffer::NewL( const TInt aMaxPackets ) + { + CCRPacketBuffer* self = new( ELeave ) CCRPacketBuffer( aMaxPackets ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::CCRPacketBuffer +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +// +CCRPacketBuffer::CCRPacketBuffer( const TInt aMaxPackets ) + : iMaxPackets( aMaxPackets ), + iContinousStream( EFalse ), + iMoreComing( EFalse ) + { + // None + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::ConstructL() + { + // None + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::~CCRPacketBuffer +// Destructor. +// ----------------------------------------------------------------------------- +// +CCRPacketBuffer::~CCRPacketBuffer() + { + LOG( "CCRPacketBuffer::~CCRPacketBuffer" ); + + iBuffer.ResetAndDestroy(); + iBookKeeping.Close(); + iSinkArray.Close(); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::AddSink +// +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::AddSink( CCRPacketSinkBase* aSink ) + { + LOG( "CCRPacketBuffer::AddSink() in" ); + + // Check if sink exist already? + TBool exist( EFalse ); + for ( TInt i( iBookKeeping.Count() - 1 ); i >= 0 && !exist; i-- ) + { + exist = ( aSink->Id() == iBookKeeping[i].iId ); + } + + // If not, add sink to list + TInt err( KErrNone ); + if ( !exist ) + { + SBookKeeping book; + book.iId = aSink->Id(); + book.iIndex = KErrNotFound; + err = iBookKeeping.Append( book ); + if ( !err ) + { + err = iSinkArray.Append( aSink ); + if ( err ) + { + // Remove last from book keeping, because sink append failed + LOG1( "CCRPacketBuffer::AddSink(), Sink append error: %d", err ); + iBookKeeping.Remove( iBookKeeping.Count() - 1 ); + } + } + } + + LOG3( "CCRPacketBuffer::AddSink() out, err: %d, iSinkArray count: %d, iBookKeeping count: %d", + err, iSinkArray.Count(), iBookKeeping.Count() ); + return err; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::AddPacket +// Method for add. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::AddPacket( + const MCRPacketSource::TCRPacketStreamId& aStream, + const TDesC8& aHeader, + const TDesC8& aPacket ) + { + // Room + VerifyRoom(); + + // Add packet + const TInt total( KStreamTypeBytesLength + + aHeader.Length() + aPacket.Length() ); + HBufC8* packet = HBufC8::New( total ); + if ( packet ) + { + TPtr8 ptr( packet->Des() ); + ptr.SetLength( KStreamTypeBytesLength ); + ptr[KStreamTypeBytePoint] = ( TUint8 )( aStream ); + ptr.Append( aHeader ); + ptr.Append( aPacket ); + if ( iBuffer.Insert( packet, 0 ) ) + { + delete packet; + } + else + { + PacketToBookKeeping(); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::AddPacket +// Method for add. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::AddPacket( + const MCRPacketSource::TCRPacketStreamId& aStream, + const TDesC8& aPacket ) + { + // Room + VerifyRoom(); + + // Add packet + const TInt total( KStreamTypeBytesLength + aPacket.Length() ); + HBufC8* packet = HBufC8::New( total ); + if ( packet ) + { + TPtr8 ptr( packet->Des() ); + ptr.SetLength( KStreamTypeBytesLength ); + ptr[KStreamTypeBytePoint] = ( TUint8 )( aStream ); + ptr.Append( aPacket ); + if ( iBuffer.Insert( packet, 0 ) ) + { + delete packet; + } + else + { + PacketToBookKeeping(); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::ContinousStream +// Method for set buffer estimate when it ends. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::ContinousStream( const TBool aState ) + { + LOG1( "CCRPacketBuffer::ContinousStream(), aState: %d", aState ); + iContinousStream = aState; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::ContinousStream +// Method for get the time when buffer should end. +// ----------------------------------------------------------------------------- +// +TBool CCRPacketBuffer::ContinousStream() + { + return iContinousStream; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer:::MoreComing +// Method for set more coming state. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::MoreComing( const TBool aState ) + { + iMoreComing = aState; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer:::MoreComing +// Method for get more coming state. +// ----------------------------------------------------------------------------- +// +TBool CCRPacketBuffer::MoreComing() + { + return iMoreComing; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetStream +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::GetStream( + const CCRStreamingSession::TCRSinkId& aId, + MCRPacketSource::TCRPacketStreamId& aStreamId ) + { + return GetStream( aId, 0, aStreamId ); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetStream +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::GetStream( + const CCRStreamingSession::TCRSinkId& aId, + const TInt aOffset, + MCRPacketSource::TCRPacketStreamId& aStreamId ) + { + const TInt bookKeeping( GetBookKeeping( aId ) ); + if ( bookKeeping > KErrNotFound ) + { + const TInt index( GetBufferIndex( bookKeeping ) - aOffset ); + if ( index > KErrNotFound && index < iBuffer.Count() ) + { + aStreamId = MCRPacketSource::TCRPacketStreamId( + iBuffer[index]->Des()[KStreamTypeBytePoint] ); + } + } + + return bookKeeping; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetPacket +// Method for remove +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::GetPacket( + const CCRStreamingSession::TCRSinkId& aId, + TPtr8& aReturnedData ) + { + const TInt bookKeeping( GetBookKeeping( aId ) ); + GetPacket( bookKeeping, aReturnedData ); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetPacket +// Method for remove +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::GetPacket( const TInt aBookKeeping, TPtr8& aReturnedData ) + { + PeekPacket( aBookKeeping, aReturnedData, 0 ); + + if ( aReturnedData.Ptr() || aReturnedData.Length() > 0 ) + { + // One packet used + iBookKeeping[aBookKeeping].iIndex--; + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::PeekPacket +// Method for peeking +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::PeekPacket( + const CCRStreamingSession::TCRSinkId& aId, + TPtr8& aReturnedData, + const TInt aOffset ) + { + const TInt bookKeeping( GetBookKeeping( aId ) ); + PeekPacket( bookKeeping, aReturnedData, aOffset ); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::PeekPacket +// Method for peeking +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::PeekPacket( + const TInt aBookKeeping, + TPtr8& aReturnedData, + const TInt aOffset ) + { + aReturnedData.Set( NULL, 0, 0 ); + + if ( aBookKeeping > KErrNotFound && aBookKeeping < iBookKeeping.Count() ) + { + const TInt index( GetBufferIndex( aBookKeeping ) - aOffset ); + if ( index > KErrNotFound && index < iBuffer.Count() ) + { + // Data + aReturnedData.Set( + iBuffer[index]->Des().MidTPtr( KStreamTypeBytesLength ) ); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::PacketsCount +// Method for asking count of packet available. +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::PacketsCount( const CCRStreamingSession::TCRSinkId& aId ) + { + const TInt bookKeeping( GetBookKeeping( aId ) ); + if ( bookKeeping > KErrNotFound ) + { + return iBookKeeping[bookKeeping].iIndex; + } + + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::PacketsMinCount +// Method for asking minimum count of packet available in any sink. +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::PacketsMinCount() + { + TInt ret( KMaxTInt ); + for ( TInt i( iBookKeeping.Count() - 1 ); i >= 0 ; i-- ) + { + if ( iBookKeeping[i].iIndex < ret ) + { + ret = iBookKeeping[i].iIndex; + } + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::HandleBufferSize +// Removes packets which are used in all book keepings. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::HandleBufferSize() + { + // Find maximum index + TInt max( KErrNotFound ); + for ( TInt i( 0 ); i < iBookKeeping.Count(); i++ ) + { + max = Max( max, iBookKeeping[i].iIndex ); + } + + // Delete used packets + const TInt oldCount( iBuffer.Count() ); + for ( TInt i( oldCount - 1 ); ( i > max ) && ( i > KErrNotFound ); i-- ) + { + delete iBuffer[i]; + iBuffer.Remove( i ); + } + + // Compress if packets deleted + if ( iBuffer.Count() < oldCount ) + { + iBuffer.Compress(); + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::AdjustBuffer +// Drops packets to 25% of buffers max size. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::AdjustBuffer() + { + const TInt limit( iMaxPackets / 4 ); + for ( TInt i( iBookKeeping.Count() - 1 ); i >= 0 ; i-- ) + { + if ( iBookKeeping[i].iIndex > limit ) + { + LOG3( "CCRPacketBuffer::AdjustBuffer(), book: %d, index: %d, limit: %d", + i, iBookKeeping[i].iIndex, limit ); + iBookKeeping[i].iIndex = limit; + } + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::ResetBuffer +// +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::ResetBuffer() + { + // Reset book keeping + for ( TInt i( iBookKeeping.Count() - 1 ); i >= 0 ; i-- ) + { + LOG2( "CCRPacketBuffer::ResetBuffer(), book: %d, index: %d", + i, iBookKeeping[i].iIndex ); + iBookKeeping[i].iIndex = KErrNotFound; + } + + // Notify sinks + for ( TInt i( iSinkArray.Count() - 1 ); i >= 0; i-- ) + { + iSinkArray[i]->BufferResetDone(); + } + + // Reset items + iBuffer.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::RemoveSink +// +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::RemoveSink( CCRPacketSinkBase* aSink ) + { + // Sink + for ( TInt i( iSinkArray.Count() - 1 ); i >= 0; i-- ) + { + if ( iSinkArray[i] == aSink ) + { + iSinkArray.Remove( i ); + LOG1( "CCRPacketBuffer::RemoveSink(), removed Sink: %d", i ); + } + } + + // Book keeping + for ( TInt i( iBookKeeping.Count() - 1 ); i >= 0; i-- ) + { + if ( iBookKeeping[i].iId == aSink->Id() ) + { + iBookKeeping.Remove( i ); + LOG1( "CCRPacketBuffer::RemoveSink(), removed Book keeping: %d", i ); + } + } + + return iSinkArray.Count(); + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::VerifyRoom() +// Verify maximum packets in buffer. Will drop packets count to 1/4 if maximum +// size reached. +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::VerifyRoom() + { + TInt count( iBuffer.Count() ); + if ( count >= iMaxPackets ) + { + LOG1( "CCRPacketBuffer::VerifyRoom(), Buffer full ! count: %d", count ); + AdjustBuffer(); + + // Make sure memory not run out because of asyncronous packets deleting + if ( count >= ( iMaxPackets * 2 ) ) + { + ResetBuffer(); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetBookKeeping +// Updates book keeping index basing on sink id. +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::GetBookKeeping( const CCRStreamingSession::TCRSinkId& aId ) + { + for ( TInt i( 0 ); i < iBookKeeping.Count(); i++ ) + { + if ( iBookKeeping[i].iId == aId ) + { + return i; + } + } + + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::GetBufferIndex +// Getter for buffer index from book keeping. +// ----------------------------------------------------------------------------- +// +TInt CCRPacketBuffer::GetBufferIndex( const TInt aBookKeeping ) + { + if ( aBookKeeping > KErrNotFound && aBookKeeping < iBookKeeping.Count() ) + { + return iBookKeeping[aBookKeeping].iIndex; + } + + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CCRPacketBuffer::PacketToBookKeeping +// +// ----------------------------------------------------------------------------- +// +void CCRPacketBuffer::PacketToBookKeeping() + { + // New packet to book keeping + for ( TInt i( 0 ); i < iBookKeeping.Count(); i++ ) + { + iBookKeeping[i].iIndex++; + } + + // New packet available + for ( TInt i( 0 ); i < iSinkArray.Count(); i++ ) + { + iSinkArray[i]->NewPacketAvailable(); + } + } + +// End of File