/*
* Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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:    Implements format encode interface for redundancy plugin.
*
*/





// INCLUDE FILES
#include "rtpheader.h"
#include "mccredpayloadwrite.h"
#include "mccredencoder.h"
#include "mccrtpdatasink.h"
#include "mccredpayloadformatdefs.h"
#include "mccdef.h"
#include "mccinternaldef.h"
#include "mccrtpmediaclock.h"

// ============================= LOCAL FUNCTIONS ===============================

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

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::CMccRedPayloadWrite
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CMccRedPayloadWrite::CMccRedPayloadWrite()
    {
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::ConstructL( MDataSink* aSink )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::ConstructL" )
    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
    
    iClip = aSink;
    iRedEncoder = CMccRedEncoder::NewL();
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMccRedPayloadWrite* CMccRedPayloadWrite::NewL( MDataSink* aSink )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::NewL" )
    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
    __ASSERT_ALWAYS( KMccRtpSinkUid == aSink->DataSinkType(),
        User::Leave( KErrNotSupported ) );
    
    CMccRedPayloadWrite* self = new( ELeave ) CMccRedPayloadWrite;
    
    CleanupStack::PushL( self );
    self->ConstructL( aSink );
    CleanupStack::Pop( self );

    return self;
    }

    
// Destructor
CMccRedPayloadWrite::~CMccRedPayloadWrite()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::~CMccRedPayloadWrite" )
        
    delete iRedEncoder;
    delete iSinkBuffer;
    iDataSource = NULL;
    iBufToEmptyPtr = NULL;
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadRead::ConfigurePayloadFormatL
// Configure payload encoding parameters.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::ConfigurePayloadFormatL( const TDesC8& aConfigParams,
        CMccRtpMediaClock& /*aClock*/ )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::ConfigurePayloadFormatL" )
    __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccRedPayloadWriteConfig ),
        User::Leave( KErrArgument ) );
    
    TMccRedPayloadWritePckg cPckg;
    cPckg.Copy( aConfigParams );
    iPLConfig = cPckg();

    __ASSERT_ALWAYS( iPLConfig.iRedBlockCount <= KMaxRedCount, 
        User::Leave( KErrArgument ) );
    
    if ( iSinkBuffer )
        {
        delete iSinkBuffer;
        iSinkBuffer = NULL;
        }
    
    // Extra variables for clarity
    TInt redPayloadSize
        = iPLConfig.iMaxPayloadSize * ( 1 + iPLConfig.iRedBlockCount );
    TInt redHeadersSize 
        = iPLConfig.iRedBlockCount * KRedHeaderSize + KFinalHeaderSize;
    iSinkBuffer = CMMFDataBuffer::NewL( redPayloadSize + redHeadersSize );
                                    
    iRedEncoder->InitializeL( iPLConfig.iRedBlockCount,
                              iPLConfig.iMaxPayloadSize, 
                              iPLConfig.iNumOfEncodings );
                              
    RArray<TUint> encPTs;
    CleanupClosePushL( encPTs );

    TInt maxNumOfEncodings = iPLConfig.iEncPayloadTypes.Count();
    for ( TInt i = 0; i < maxNumOfEncodings; i++ )
        {
        if ( KPayloadNotDefined != iPLConfig.iEncPayloadTypes[i] )
            {
            encPTs.AppendL( iPLConfig.iEncPayloadTypes[i] );
            }
        }

    User::LeaveIfError( iRedEncoder->SetPayloadTypes( encPTs ) );
    CleanupStack::PopAndDestroy( &encPTs );
    }
    
// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::FrameTimeInterval
// NOT USED. Pure virtual method implementation from CMMFormatEncode needed.
// -----------------------------------------------------------------------------
//
TTimeIntervalMicroSeconds CMccRedPayloadWrite::FrameTimeInterval( 
        TMediaId /*aMediaType*/ ) const
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::FrameTimeInterval" )

    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::Duration
// NOT USED. Pure virtual method implementation from CMMFormatEncode needed.
// -----------------------------------------------------------------------------
//
TTimeIntervalMicroSeconds CMccRedPayloadWrite::Duration( 
        TMediaId /*aMediaType*/ ) const
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::Duration" )

    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::CreateSinkBufferL
// -----------------------------------------------------------------------------
//
CMMFBuffer* CMccRedPayloadWrite::CreateSinkBufferL( TMediaId /*aMediaId*/,
                                                    TBool& /*aReference*/ )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::CreateSinkBufferL" )
    User::Leave( KErrNotSupported );
    return NULL;
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::DataSinkType
//
// -----------------------------------------------------------------------------
//
TUid CMccRedPayloadWrite::DataSinkType() const
    {
    return TUid::Uid( KImplUidRedPayloadFormatEncode );
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkDataTypeCode
// NOT USED.
// -----------------------------------------------------------------------------
//
TFourCC CMccRedPayloadWrite::SinkDataTypeCode( TMediaId /*aMediaId*/ )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkDataTypeCode" )
        
    return TFourCC();
    }


// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SetSinkDataTypeCode
// NOT USED.
// -----------------------------------------------------------------------------
//
TInt CMccRedPayloadWrite::SetSinkDataTypeCode( TFourCC /*aSinkFourCC*/,
                                               TMediaId /*aMediaId*/ )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SetSinkDataTypeCode" )
        
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkThreadLogon
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
TInt CMccRedPayloadWrite::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkThreadLogon" )
        
    iClip->SinkThreadLogon( aEventHandler );
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkThreadLogoff
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::SinkThreadLogoff()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkThreadLogoff" )
        
    iClip->SinkThreadLogoff();    
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkPrimeL
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::SinkPrimeL()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkPrimeL" )
        
    iClip->SinkPrimeL();
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkPlayL
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::SinkPlayL()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkPlayL" )
        
    iClip->SinkPlayL();
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkPauseL
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::SinkPauseL()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkPauseL" )
        
    iClip->SinkPauseL();
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SinkStopL
// Passes state transition to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::SinkStopL()
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SinkStopL" )
        
    iClip->SinkStopL();
    }
    
// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::EmptyBufferL
// NOT USED.
// Overloaded emptybuffer with additional RTP header parameter used instead.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::EmptyBufferL( CMMFBuffer* /*aBuffer*/,
                                        MDataSource* /*aSupplier*/, 
                                        TMediaId /*aMediaId*/ )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::EmptyBufferL" )
        
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::BufferEmptiedL
// Called by data sink of redundancy payload plugin, when payload is emptied.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::BufferEmptiedL( CMMFBuffer* aBuffer )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::BufferEmptiedL" )
    __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) );
    __ASSERT_ALWAYS( iBufToEmptyPtr, User::Leave( KErrNotReady ) );
    
    iDataSource->BufferEmptiedL( iBufToEmptyPtr );
    }
    
// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::EmptyBufferL
// Encodes contents of source buffer with redundancy encoder and forwards
// result buffer to the data sink of redundancy payload plugin.
// -----------------------------------------------------------------------------
//
void CMccRedPayloadWrite::EmptyBufferL( CMMFBuffer* aSourceBuffer,
                                        MDataSource* aSupplier, 
                                        TMediaId aMediaId,
                                        TRtpSendHeader& aSendHeader )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::EmptyBufferL" )
    __ASSERT_ALWAYS( aSourceBuffer, User::Leave( KErrArgument ) );
    __ASSERT_ALWAYS( KUidMmfDataBuffer == aSourceBuffer->Type(),
        User::Leave( KErrNotSupported ) );
    __ASSERT_ALWAYS( aSupplier, User::Leave( KErrArgument ) );
    __ASSERT_ALWAYS( KUidMediaTypeAudio == aMediaId.iMediaType,
        User::Leave( KErrNotSupported ) );
    
    DP_RED_ENCODE( "CMccRedPayloadWrite::EmptyBufferL() - MEDIA TYPE OK" )
    
    iDataSource = aSupplier;
    iBufToEmptyPtr = static_cast<CMMFDataBuffer*>( aSourceBuffer );

    if ( KComfortNoisePT != aSendHeader.iPayloadType )
        {
        // Comfort noise packets are forwarded without encoding
        iRedEncoder->SetEncodingBlockL( 
            EMccPrimaryEncoding, iBufToEmptyPtr->Data() );
        iRedEncoder->EncodePayloadL( aSendHeader.iTimestamp );
        iRedEncoder->GetEncodingBlockL( EMccRTPPayload, iSinkBuffer->Data() );

        DP_RED_ENCODE( "CMccRedPayloadWrite::EmptyBufferL() - Buffer encoded" )
        aSendHeader.iPayloadType = iPLConfig.iRedPayloadType;
        }

    // Deliver the packet
    static_cast<CMccRtpDataSink*>( iClip )
        ->EmptyBufferL( iSinkBuffer, this, aMediaId, aSendHeader );
    }
    
// -----------------------------------------------------------------------------
// CMccRedPayloadWrite::SetPayloadTypes
// Set payload types to accept as encodings.
// -----------------------------------------------------------------------------
//
TInt CMccRedPayloadWrite::SetPayloadTypes( RArray<TUint>& aPayloadTypes )
    {
    DP_RED_ENCODE( "CMccRedPayloadWrite::SetPayloadTypes" )
        
    if ( aPayloadTypes.Count() )
        {
        iPLConfig.iRedPayloadType = aPayloadTypes[0];
        aPayloadTypes.Remove( 0 );
        
        return iRedEncoder->SetPayloadTypes( aPayloadTypes );
        }
    else
        {
        return KErrArgument;
        }        
    }
    
// ========================== OTHER EXPORTED FUNCTIONS =========================

//  End of File  
