dvrengine/CommonRecordingEngine/DvrRtpClipHandler/src/CRtpClipRepairer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:14:38 +0200
changeset 0 822a42b6c3f1
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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:    Implementation of the common recording engine file repairer class.*
*/




// INCLUDE FILES
#include "CRtpClipRepairer.h"
#include <ipvideo/CRtpMetaHeader.h>
#include <ipvideo/CRtpUtil.h>
#include <e32math.h>
#include <bsp.h>
#include "videoserviceutilsLogger.h"

// CONSTANTS
const TInt KMaxGroupTime( 4000 ); // 4s

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

// -----------------------------------------------------------------------------
// CRtpClipRepairer::NewL
// Static two-phased constructor. Leaves object to cleanup stack.
// -----------------------------------------------------------------------------
//
CRtpClipRepairer* CRtpClipRepairer::NewL( MRtpClipRepairObserver* aObs )
    {
    CRtpClipRepairer* self = new( ELeave ) CRtpClipRepairer( aObs );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CRtpClipRepairer::CRtpClipRepairer
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CRtpClipRepairer::CRtpClipRepairer( MRtpClipRepairObserver* aObs )
  : CRtpFileBase(),
    iObs( aObs ),
    iSeekArrayPoint( KErrNotFound )
    {
    // None
    }

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

    CRtpFileBase::ConstructL();
    }

// -----------------------------------------------------------------------------
// Destructor
//
CRtpClipRepairer::~CRtpClipRepairer()
// -----------------------------------------------------------------------------
    {
    LOG( "CRtpClipRepairer::~CRtpClipRepairer()" );
    
    Cancel();
    delete iFileData;
    delete iMetaHeader;
    }

// -----------------------------------------------------------------------------
// CRtpClipRepairer::CurrentClipName
// Getter for the clip name under repairing.
// -----------------------------------------------------------------------------
//
TPtrC CRtpClipRepairer::CurrentClipName()
    {
    if ( iCurrentPath )
        {
        return iCurrentPath->Des();
        }
    
    return KNullDesC();
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::CheckMetaHeaderL
// Checks if corrupted meta header of clip is possible to fix.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::CheckMetaHeaderL( const TDesC& aClipName )
    {
    LOG1( "CRtpClipRepairer::CheckMetaHeaderL(), aClipName: %S", &aClipName );
    
    // Only one repair at the time
    if ( iMetaHeader || iCurrentPath )
        {
        User::Leave( KErrAlreadyExists );
        }
    
    // Open clip and read the meta header
    delete iCurrentPath; iCurrentPath = NULL;
    iCurrentPath = aClipName.AllocL();
    if ( !iFs.Handle() )
        {
        User::LeaveIfError( iFs.Connect() );
        }
    iFile.Close();
    User::LeaveIfError( iFile.Open( iFs, aClipName,
                        EFileShareExclusive | EFileStream | EFileWrite ) );
    delete iMetaHeader; iMetaHeader = NULL;
    iMetaHeader = CRtpMetaHeader::NewL( iFile, CRtpMetaHeader::EMetaUpdate );
    
    // Attributes
    CRtpMetaHeader::SAttributes att;
    TRAPD( err, iMetaHeader->ReadAttributesL( att ) );
    
    // Verify that clip version not too old?
    if ( att.iVersion < KMinValidClipVersion )
        {
        LOG( "CRtpClipRepairer::CheckMetaHeaderL(), Not Valid Clip Version" );
        User::Leave( KErrGeneral ); 
        }
    
    // If error or rec ongoing -> recording interrupted ie. battery removed
    if ( err || att.iOngoing )
        {
        att.iOngoing = EFalse;
        att.iPlayCount = 0;
        att.iPlaySpot = KErrNone;
        iMetaHeader->WriteAttributesL( att );
        }
    
    // Duration
    TInt duration( 0 );
    iMetaHeader->ReadDurationL( duration );
    LOG1( "CRtpClipRepairer::CheckMetaHeaderL(), duration: %d", duration );

    // Update seek array
    if ( ( !duration || duration > KSeekArrayInterval ) && !ValidSeekHeaderL() )
        {
        UpdateSeekArrayL();
        }
    else
        {
        // Set start time to file date
        TTime startTime( 0 );
        iMetaHeader->ReadStartTimeL( startTime );
        iFile.SetModified( startTime );
        iFile.Close();
        }
    }

// -----------------------------------------------------------------------------
// CRtpClipRepairer::RunL
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::RunL()
    {
    User::LeaveIfError( iStatus.Int() );
    const TUint prevTime( iGroupTime );
    UpdateGroupHeaderVariablesL( iDataPtr );
    delete iFileData; iFileData = NULL;

    // Current header valid?
    if ( iThisGroup > iNextGroupPoint || iThisGroup < iPrevGroupPoint ||
         iGroupTime < prevTime || iGroupTime > ( prevTime + KMaxGroupTime ) )
        {
        iLastSeekAddr = iPrevGroupPoint;
        iThisGroup = iSeekArrayPoint;
        }
    else
        {
        // Handle readed group
        GroupToSeekArrayL();
        }
    
    // Continue with next group if repair asyncronous?
    if ( iObs )
        {
        if ( iThisGroup < iSeekArrayPoint )
            {
            // Asyncronous ( normal clip repairing )
            ReadNextGroupHeaderFromFileL();
            }
        else
            {
            // All done, finalize the clip
            AddSpecialPacketL( MRtpFileWriteObserver::ERtpClipEnd );
            FinalizeSeekArrayL( KErrNone );
            iObs->RtpClipRepaired( KErrNone );
            }        
        }
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::RunError
// Returns: System wide error code of indication send leave reason
// -----------------------------------------------------------------------------
//
TInt CRtpClipRepairer::RunError( TInt aError )
    {
    LOG1( "CRtpClipRepairer::RunError(), RunL Leaved: %d", aError );

    TRAP_IGNORE( FinalizeSeekArrayL( aError ) );
    if ( iObs )
        {
        iObs->RtpClipRepaired( ( iGroupsTotalCount )? KErrNone: aError );
        }
    
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CRtpClipRepairer::DoCancel
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::DoCancel()
    {
    LOG( "CRtpClipRepairer::DoCancel()" );
    }

// -----------------------------------------------------------------------------
// CRtpClipRepairer::ValidSeekHeaderL
// Verifies if seek header and seek array are valid.
// -----------------------------------------------------------------------------
//
TBool CRtpClipRepairer::ValidSeekHeaderL()
    {
    // Seek header
    iSeekHeaderPoint = iMetaHeader->SeekHeaderPoint();
    ReadSeekHeaderL();
    
    // Seek array point
    iMetaHeader->ReadSeekArrayPointL( iSeekArrayPoint );
    
    // Verify seek array
    if ( iLastSeekAddr > iFirstSeekAddr && iSeekArrayPoint > iLastSeekAddr )
        {
        TInt count( KErrNotFound );
        TRAPD( err, count = ReadSeekArrayL( iSeekArrayPoint ) );
        if ( !err && count > 0 )
            {
            // Seek array is ok
            return ETrue; 
            }
        }
    
    return EFalse;
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::UpdateSeekArrayL
// Scans all packet groups in clip and updates seek array.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::UpdateSeekArrayL()
    {
    LOG( "CRtpClipRepairer::UpdateSeekArrayL()" );

    // Scan complete clip for seek array
    ResetSeekArray();
    User::LeaveIfError( iFile.Size( iSeekArrayPoint ) );
    iThisGroup = iFirstSeekAddr;
    iGroupTime = 0;
    iNextGroupPoint = 0;
    iGroupsTotalCount = 0;
    
    // Start reading
    if ( iObs )
        {
        // Asyncronous
        ReadNextGroupHeaderFromFileL();
        }
    else
        {
        // Syncronous
        TInt err( KErrNone );
        do
            {
            ReadNextGroupHeaderFromFileL();
            TRAP( err, RunL() );
            }
            while ( !err && iThisGroup < iSeekArrayPoint );

        // All done, finalize the clip
        AddSpecialPacketL( MRtpFileWriteObserver::ERtpClipPause );
        FinalizeSeekArrayL( KErrNone );
        }
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::ReadNextGroupHeaderFromFileL
// Reads RTP payload from a file.
// Payload is allways after data header, so read position set is not needed.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::ReadNextGroupHeaderFromFileL()
    {
    iLastSeekAddr = iThisGroup;

    iFileData = HBufC8::NewL( KGroupHeaderBytes );
    iDataPtr.Set( iFileData->Des() );
    if ( iObs )
        {
        iFile.Read( iThisGroup, iDataPtr, KGroupHeaderBytes, iStatus );
        SetActive();
        }
    else
        {
        iStatus = iFile.Read( iThisGroup, iDataPtr, KGroupHeaderBytes );
        }
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::GroupToSeekArrayL
// Appends next rec group's group time to seek array if interval time exeeded.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::GroupToSeekArrayL()
    {
    iGroupsTotalCount++;
    const TInt delta( iGroupTime - iLastGroupTime );
    if ( delta > KSeekArrayInterval )
        {
        LOG2( "CRtpClipRepairer::GroupToSeekArrayL(), iGroupsTotalCount: %d, iThisGroup: %d", 
                                                      iGroupsTotalCount, iThisGroup );
        iLastGroupTime = iGroupTime;
        AppendSeekArrayL( iGroupTime, iThisGroup );
        }
    
    iPrevGroupPoint = iThisGroup;
    iThisGroup = iNextGroupPoint;
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::AddSpecialPacketL
// Adds special packet to a new group to the end of clip.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::AddSpecialPacketL( 
    const MRtpFileWriteObserver::TRtpType aType )
    {
    LOG1( "CRtpClipRepairer::AddSpecialPacketL(), aType: %d", aType );
    
    // Read last group header
    iThisGroup = iPrevGroupPoint;
    ReadGroupHeaderL();

    // End packet
    HBufC8* bytes = CRtpUtil::SpecialPacketL( aType );
    CleanupStack::PushL( bytes );
    iFile.Write( iThisGroup + iGroupTotalLen, bytes->Des(), KSpecialPacketLength );
    CleanupStack::PopAndDestroy( bytes );

    // Update group total size (GTS)
    iGroupTotalLen+= KSpecialPacketLength;
    bytes = CRtpUtil::MakeBytesLC( iGroupTotalLen );
    iFile.Write( iThisGroup, bytes->Des(), KIntegerBytes );
    CleanupStack::PopAndDestroy( bytes );
    
    // Update next group point (NGP)
    iNextGroupPoint+= KSpecialPacketLength;
    bytes = CRtpUtil::MakeBytesLC( iNextGroupPoint );
    iFile.Write( iThisGroup + KIntegerBytes, bytes->Des(), KIntegerBytes );
    CleanupStack::PopAndDestroy( bytes );
    
    // Read packets total count (PTC)
    bytes = HBufC8::NewLC( KPacketsCountBytes );
    TPtr8 ptr( bytes->Des() );
    iFile.Read( iThisGroup + KGroupHeaderBytes, ptr, KPacketsCountBytes );
    const TInt packetsCount( CRtpUtil::GetValueL( ptr ) );
    User::LeaveIfError( packetsCount );
    CleanupStack::PopAndDestroy( bytes );
    
    // Increment packets tolal count (PTC) by one
    bytes = CRtpUtil::MakeBytesLC( packetsCount + 1 );
    iFile.Write( iThisGroup + KGroupHeaderBytes, bytes->Des(), KPacketsCountBytes );
    CleanupStack::PopAndDestroy( bytes );
    }
    
// -----------------------------------------------------------------------------
// CRtpClipRepairer::FinalizeSeekArrayL
// Appends next rec group to seek array.
// -----------------------------------------------------------------------------
//
void CRtpClipRepairer::FinalizeSeekArrayL( const TInt aError )
    {
    LOG1( "CRtpClipRepairer::FinalizeSeekArrayL(), aError: %d", aError );

    // New seek array point
    iMetaHeader->WriteSeekArrayPointL( iNextGroupPoint );

    // Update duration
    iMetaHeader->WriteDurationL( iGroupTime );

    // Last group time
    CRtpMetaHeader::SAttributes att;
    iMetaHeader->ReadAttributesL( att );
    att.iFailed = !( !aError );
    att.iOngoing = EFalse;
    att.iPlayCount = 0;
    att.iPlaySpot = KErrNone;
    iMetaHeader->WriteAttributesL( att );
    
    // Finalise
    SaveSeekArrayL();
    WriteSeekHeaderL();
    iFile.Flush();

    // Set start time to file date
    TTime startTime( 0 );
    iMetaHeader->ReadStartTimeL( startTime );
    iFile.SetModified( startTime );
    iFile.Close();
    }
    
// End of File