multimediacommscontroller/mmccdtmfpayloadformat/src/dtmfpayloadformatwrite.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccdtmfpayloadformat/src/dtmfpayloadformatwrite.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1108 @@
+/*
+* Copyright (c) 2006-2008 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:    Contains functionality for DTMF digit encoding and sending.
+*
+*/
+
+
+
+
+// INCLUDES
+#include <hal.h>
+#include "mmccnetworksettings.h"
+#include "dtmfpayloadformatwrite.h"
+#include "dtmfpayloadencoder.h"
+#include "dtmfeventpayloadinfo.h"
+#include "dtmftonepayloadinfo.h"
+#include "mccrtpdatasink.h"
+#include "mccinternaldef.h"
+#include "rtpdatasink.h"
+#include "mccrtpmediaclock.h"
+#include "mccinternalevents.h"
+#include "dtmfhighresolutiontimer.h"
+
+// CONSTANTS
+const TUint8 KValidDTMFDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', 
+    '8', '9', 'a', 'b', 'c', 'd', 'A', 'B', 'C', 'D', '*', '#', 'p', 'w'  };
+
+const TInt  KSignalInbandDtmf = 1;
+const TInt  KSignalOutbandDtmf = 2;
+
+const TInt  KDurationNotApplicable = 1000000000;
+
+// Pause in DTMF string sending when next digit to handle is 'p' char
+const TUint KDTMFPauseLengthInUs    = 2500000;
+const TInt  KNumOfFinalPackets      = 3;
+const TReal KUsToSecFactor          = 0.000001;
+const TReal KMsToSecFactor          = 0.001;
+const TUint KDtmfDefSampleRate      = 8000;
+const TUint KFactor1000             = 1000;
+const TInt  KDefaultTickPeriodInMs  = 1;
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::CDTMFPayloadFormatWrite
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------------------------
+//
+CDTMFPayloadFormatWrite::CDTMFPayloadFormatWrite()
+    :
+    iSampleRate( KDtmfDefSampleRate ), 
+    iTickPeriod( KDefaultTickPeriodInMs )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::CDTMFPayloadFormatWrite") );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::ConstructL
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::ConstructL( MDataSink* aSink )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::ConstructL") );
+    
+    iFourCC = TFourCC( KMccFourCCIdDTMF );
+    
+    // Set data sink
+    CMccRtpDataSink* tmp = static_cast<CMccRtpDataSink*>( aSink );
+    iRtpDataSink = static_cast<MMccRtpDataSink*>( tmp );
+    iClip = aSink;
+    
+    // Allocate buffer for payload encoder
+    iSinkBuffer = CMMFDataBuffer::NewL( KDTMFDefaultPayloadSize );
+    iPayloadEncoder = CDTMFPayloadEncoder::NewL();
+    
+    // Initialize state machine
+    iStateMachine = CDtmfEncStateMachine::NewL( *this );
+    
+    TUint validDigitCount = sizeof ( KValidDTMFDigits ) / sizeof ( TUint8 );
+    for ( TUint i = 0; i < validDigitCount; i++ )
+        {
+        iValidDigits.Append( KValidDTMFDigits[ i ] );
+        }
+    
+    TInt err = HAL::Get( HAL::ENanoTickPeriod, iTickPeriod );
+    if ( KErrNone != err )
+        {
+        DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::ConstructL HAL ERR: %d"),
+            err );
+        }
+    
+    iTickPeriod = TInt( iTickPeriod * KMsToSecFactor );
+    iSendTimer = CDtmfHighResTimer::NewL( CActive::EPriorityHigh );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::NewL
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CDTMFPayloadFormatWrite* CDTMFPayloadFormatWrite::NewL( MDataSink* aSink )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::NewL") );
+    
+    if ( !aSink ) 
+        {
+        User::Leave ( KErrArgument );
+        }
+
+    if ( KMccRtpSinkUid != aSink->DataSinkType() )
+        {
+        User::Leave ( KErrNotSupported );
+        }
+    
+    CDTMFPayloadFormatWrite* self = new( ELeave ) CDTMFPayloadFormatWrite;
+    
+    CleanupStack::PushL( self );
+    self->ConstructL( aSink );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::~CDTMFPayloadFormatWrite
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CDTMFPayloadFormatWrite::~CDTMFPayloadFormatWrite()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::~CDTMFPayloadFormatWrite") );
+    
+    delete iSinkBuffer;
+    delete iPayloadEncoder;
+    delete iSendTimer;
+    delete iStateMachine;
+    iEventHandler = NULL;
+    iRtpDataSink = NULL;
+    
+    // Media clock is not owned
+    if ( iRtpMediaClock )
+        {
+        iRtpMediaClock->UnregisterMediaFormat( iKey );
+        iRtpMediaClock = NULL;
+        }
+    
+    iSendBuffer.Close();
+    iValidDigits.Close();
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::HandleTimerEventL
+// STATIC METHOD. Passes timer events to the class instance interested
+// about them.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::HandleTimerEventL( TAny* aObjectPtr )
+    {
+    if ( aObjectPtr )
+        {
+        return static_cast<CDTMFPayloadFormatWrite*>( aObjectPtr )->
+                                                        DoHandleTimerEventL();
+        }
+    else
+        {
+        return KErrArgument;
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkThreadLogon
+// Passes the logon command to the sink clip.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::SinkThreadLogon( 
+    MAsyncEventHandler& aEventHandler )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkThreadLogon") );
+    
+    iEventHandler = &aEventHandler;
+    return iClip->SinkThreadLogon( aEventHandler );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkThreadLogoff
+// Passes the logoff command to the sink clip.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SinkThreadLogoff()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkThreadLogoff") );
+    
+    iClip->SinkThreadLogoff();
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::CanCreateSinkBuffer
+// EmptyBufferL() is not used.
+// ---------------------------------------------------------------------------
+//
+TBool CDTMFPayloadFormatWrite::CanCreateSinkBuffer()
+    {
+    return EFalse;
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::CreateSinkBufferL
+// Create a sink buffer.
+// ---------------------------------------------------------------------------
+//
+CMMFBuffer* CDTMFPayloadFormatWrite::CreateSinkBufferL( 
+    TMediaId /*aMediaId*/,
+    TBool& /*aReference*/ )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::CreateSinkBufferL") );
+    
+    User::Leave( KErrNotSupported );
+    // PC_LINT #527, for compiler warning
+    return NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SetSinkDataTypeCode
+// Set the sink data type to the given FourCC code for the given media.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::SetSinkDataTypeCode( TFourCC aSinkFourCC, 
+                                                   TMediaId aMediaId )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SetSinkDataTypeCode") );
+
+    if ( KUidMediaTypeAudio != aMediaId.iMediaType )
+        {
+        return KErrNotSupported;
+        }
+    
+    iFourCC = aSinkFourCC;
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkDataTypeCode
+// Return the sink data type (four CC code) for the given media.
+// ---------------------------------------------------------------------------
+//
+TFourCC CDTMFPayloadFormatWrite::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkDataTypeCode") );
+    
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        return iFourCC;
+        }
+    else
+        {
+        // Defaults to 'NULL' fourCC
+        return TFourCC();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::FrameTimeInterval
+// Gets audio frame size in milliseconds.
+// ---------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CDTMFPayloadFormatWrite::FrameTimeInterval( 
+    TMediaId aMediaType ) const
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::FrameTimeInterval") );
+    
+    if ( KUidMediaTypeAudio == aMediaType.iMediaType )
+        {
+        return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+        }
+    else
+        {
+        return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::Duration
+// Gets the duration of the sink clip for the specified media ID.
+// ---------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CDTMFPayloadFormatWrite::Duration( 
+    TMediaId /*aMediaType*/ ) const
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::Duration") );
+    
+    return TTimeIntervalMicroSeconds( TInt64( KDurationNotApplicable ) );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::BufferEmptiedL
+// Called by RTP data sink. Indicates that DTMF data is sent to the network.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::BufferEmptiedL") );
+    
+    // Nothing to do
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkPrimeL
+// Passes prime transition to the RTP data sink.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SinkPrimeL()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkPrimeL") );
+    
+    iClip->SinkPrimeL();
+    
+    // If the possible state machine in clip does not leave, let dtmf payload
+    // formatter also allow re-priming from any state.
+    CancelDTMFStringSending();
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkPlayL
+// Passes play transition to the RTP data sink and resets state variables.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SinkPlayL()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkPlayL") );
+    
+    iClip->SinkPlayL();
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkPauseL
+// Passes pause transition to the RTP data sink.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SinkPauseL()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkPauseL") );
+    
+    CancelDTMFStringSending();
+    iClip->SinkPauseL();
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SinkStopL
+// Passes stop transition to the RTP data sink.
+// ---------------------------------------------------------------------------
+//  
+void CDTMFPayloadFormatWrite::SinkStopL()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SinkStopL") );
+    
+    CancelDTMFStringSending();
+    iClip->SinkStopL();
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::EmptyBufferL
+// Not used because DTMF payload formatter generates DTMF independently.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::EmptyBufferL( CMMFBuffer* /*aBuffer*/, 
+                                            MDataSource* /*aSupplier*/, 
+                                            TMediaId /*aMediaId*/ )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::EmptyBufferL") );
+    
+    User::Leave( KErrNotSupported );
+    }
+                    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::PayloadFormat
+// Returns payload format used in DTMF encoding.
+// ---------------------------------------------------------------------------
+//
+TDTMFPayloadFormat CDTMFPayloadFormatWrite::PayloadFormat() const
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::PayloadFormat") );
+    
+    return iPayloadFormat;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SetPayloadFormat
+// Sets payload format used in DTMF encoding.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::SetPayloadFormat( 
+    TDTMFPayloadFormat aPayloadFormat )
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::SetPayloadFormat - Format: %d"), aPayloadFormat );
+    
+    TInt err = iPayloadEncoder->SetPayloadFormat( aPayloadFormat );
+    if ( KErrNone == err )
+        {
+        iPayloadFormat = aPayloadFormat;
+        }
+
+    return err;
+    }
+            
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::StartDTMFToneL
+// Starts a timer which sends specified DTMF digit periodically until 
+// StopDTMFTone() is called.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::StartDTMFToneL( const TChar aTone )
+    {
+    TUint32 tickCount( User::NTickCount() );
+    
+    DP_DTMF_WRITE3(  _L("CDTMFPayloadFormatWrite::StartDTMFToneL aTone = %c, tick = %u"),
+        static_cast<TUint>( aTone ), tickCount );
+    
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::StartDTMFToneL enc state %d"),
+        iStateMachine->State() );
+    
+    __ASSERT_ALWAYS( IsValidDigit( aTone ), User::Leave( KErrArgument ) );
+    
+    iSendingMode = EModeManual;
+    
+    TSendBufferElement element( aTone, tickCount );
+    iSendBuffer.AppendL( element );
+    
+    if ( EStateSendingIdle == iStateMachine->State() )
+        {
+        if ( KSignalOutbandDtmf == iGenerationMode )
+            {
+            iSinkBuffer->Data().FillZ( KDTMFDefaultPayloadSize );
+            }
+
+        iStateMachine->ChangeStateTo( EStateEncodeNextDigit );
+        }
+    else
+        {
+        DP_DTMF_WRITE( 
+            _L("CDTMFPayloadFormatWrite::StartDTMFToneL - REQ BUFFERED") );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::StopDTMFToneL
+// Stops the timer for DTMF digit update packet sending. Starts a timer for 
+// sending Final Packet three times according to RFC 2833, section 2.5.1.4.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::StopDTMFToneL()
+    {
+    TUint32 tickCount( User::NTickCount() );
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::StopDTMFTone, tick = %u"),
+        tickCount );
+    
+    // set stop time to the first unupdated element
+    TBool elementFound( EFalse );
+    TInt index( 0 );
+    while ( !elementFound && index < iSendBuffer.Count() )
+        {
+        if ( iSendBuffer[index].StopTime() == 0 )
+            {
+            iSendBuffer[index].SetStopTime( tickCount );
+            if ( iSendBuffer[index].StopTime() == 0 )
+                {
+                // mark stop time as updated to prevent update of the same 
+                // element in future
+                iSendBuffer[index].SetStopTime( 1 );
+                }
+            
+            elementFound = ETrue;
+            }
+        
+        index++;
+        }
+    
+    if ( EStateToneOn == iStateMachine->State() )
+        {
+        if ( KSignalOutbandDtmf == iGenerationMode )
+            {
+            if ( EDTMFPayloadFormatEvent == iPayloadFormat
+                || EDTMFPayloadFormatRedEvents == iPayloadFormat )
+                {
+                // Send final packet with "E" bit set. According to 
+                // RFC 2833 2.5.1.4 final packet SHOULD be sent three times.
+                iPayloadEncoder
+                    ->UpdateEventPayload( ETrue, iToneDuration, iSinkBuffer );
+                iStateMachine->ChangeStateTo( EStateToneOff );
+                }
+            else if ( EDTMFPayloadFormatTone == iPayloadFormat )
+                {
+                // Tone Payload Format doesn't have final packet redundancy
+                iPayloadEncoder->UpdateTonePayload( iToneDuration, 
+                                                                iSinkBuffer );
+                }
+            else
+                {
+                // Not acceptable payload format
+                }
+            }
+        else
+            {
+            iStateMachine->ChangeStateTo( EStateToneOff );
+            }
+        }
+    else
+        {
+        DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::StopDTMFTone OUT-OF-SYNC") );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SendDTMFTonesL
+// Starts to send DTMF string incrementally until the string is sent.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SendDTMFTonesL( const TDesC8& aTones )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SendDTMFTonesL") );
+    
+    TInt digitCount( aTones.Length() );
+    __ASSERT_ALWAYS( digitCount != 0, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( IsValidDigits( aTones ), User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( !iSendTimer->IsActive(), User::Leave( KErrNotReady ) );
+    
+    iSendingMode = EModeAutomatic;
+    
+    iSendBuffer.Reset();
+    for ( TInt i = 0; i < digitCount; i++ )
+        {
+        // in automatic mode default durations for tones are used
+        TSendBufferElement element( aTones[i], 0 );
+        iSendBuffer.AppendL( element );
+        }
+    
+    iSinkBuffer->Data().FillZ( KDTMFDefaultPayloadSize );
+    iStateMachine->ChangeStateTo( EStateEncodeNextDigit );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::NotifyStopInDTMFString
+// Request to notify client when stop in DTMF string is
+// encountered ('w' char).
+// ---------------------------------------------------------------------------
+//    
+void CDTMFPayloadFormatWrite::NotifyStopInDTMFString( TBool aFlag )
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::NotifyStopInDTMFString - Flag: %d"), aFlag );
+    
+    iNotifyStopReq = aFlag;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::ContinueDTMFStringSending
+// Allows a client to continue or cancel the sending of a DTMF string when it 
+// was stopped by the use of 'w' char in the string.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::ContinueDTMFStringSending( TBool aContinue )
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::ContinueDTMFStringSending - aContinue: %d"), aContinue );
+    
+    if ( aContinue )
+        {
+        // Start continue send rest digits incrementally
+        iStateMachine->ChangeStateTo( EStateEncodeNextDigit );
+        }
+    else
+        {
+        iSendBuffer.Reset();
+        iStateMachine->ChangeStateTo( EStateSendingIdle );
+        }
+    
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::CancelDTMFStringSending
+// 
+// ---------------------------------------------------------------------------
+//    
+void CDTMFPayloadFormatWrite::CancelDTMFStringSending()
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::CancelDTMFStringSending") );
+    
+    iSendBuffer.Reset();
+    iSendTimer->Cancel();
+    iStateMachine->ResetStateMachine();
+    }
+           
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::DeliverPacketL
+// Prepare the RTP packet header and deliver the packet to the datasink.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::DeliverPacketL( CMMFDataBuffer& aPayload, 
+                                              TBool aMarkerBit )
+    {
+    DP_DTMF_WRITE4( 
+        _L("CDTMFPayloadFormatWrite::DeliverPacketL - TSTAMP: %u, TDUR: %d, tick = %u"),
+        TUint32( aPayload.TimeToPlay().Int64() ), iToneDuration, 
+        User::NTickCount() );
+    
+    if ( KSignalOutbandDtmf == iGenerationMode )
+        {
+        // Set the marker bit if it is very first packet.
+        if ( aMarkerBit )
+            {
+            iRtpSendHeader.iMarker = 1;
+            }
+        else
+            {
+            iRtpSendHeader.iMarker = 0;
+            }
+            
+        // Construct RTP header.
+        if ( EGenRedUsed == iCInfo.iAlgoUsed )
+            {
+            iRtpSendHeader.iPayloadType = iCInfo.iRedundantPayload;
+            }
+        else
+            {
+            iRtpSendHeader.iPayloadType = iCInfo.iPayloadType;
+            }
+
+        // Timestamp must be updated before coming here
+        iRtpSendHeader.iTimestamp = TUint32( aPayload.TimeToPlay().Int64() );
+
+        // Deliver the packet
+        iRtpDataSink->EmptyBufferL( &aPayload, this,
+            TMediaId( KUidMediaTypeAudio ), iRtpSendHeader );
+
+        // Do not reset payload buffer because update packets
+        // are send based on same buffer.
+        }
+    else
+        {
+        DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::DeliverPacketL - INBAND TONE") );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::IsValidDigit
+// Check is digit valid DTMF.
+// ---------------------------------------------------------------------------
+//
+TBool CDTMFPayloadFormatWrite::IsValidDigits( 
+        const TDesC8& aDigits ) const
+    {
+    TBool isValid( ETrue );
+    TInt index( aDigits.Length() - 1 );
+    while ( isValid && 0 <= index )
+        {
+        if ( KErrNotFound == iValidDigits.Find( aDigits[ index ] ) )
+            {
+            isValid = EFalse;
+            }
+        
+        index--;
+        }
+    
+    return isValid;
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SetSinkPrioritySettings
+// Used to tell audio policy whether to mix locally played DTMFs to the record
+// stream.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SetSinkPrioritySettings( 
+    const TMMFPrioritySettings& /*aPrioritySettings*/ )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::SetSinkPrioritySettings") );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::HandleControlChar
+// Takes care of handling 'p' and 'w' chars in a DTMF string.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::HandleControlChar( const TChar& aChar )
+    {
+    if ( 'p' == aChar )
+        {
+        // 'p' char is interpreted as a 2.5 second pause
+        DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::HandleControlChar - PAUSE DETECTED") );
+        iSendTimer->Cancel();
+        iStateMachine->ChangeStateTo( EStateSendPaused );
+        TCallBack callBack( HandleTimerEventL, this );
+        iSendTimer->Start( 
+            TTimeIntervalMicroSeconds32( KDTMFPauseLengthInUs ),
+            TTimeIntervalMicroSeconds32( KDTMFPauseLengthInUs ), 
+            callBack );
+        }
+    else if ( 'w' == aChar )
+        {
+        // Stop in a DTMF string
+        DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::HandleControlChar - STOP DETECTED ") );
+
+        if ( iNotifyStopReq )
+            {
+            iSendTimer->Cancel();
+            iStateMachine->ChangeStateTo( EStateSendStopped );
+
+            SendEventSignalToClient( KMccDtmfStopInDtmfString );
+            }
+        }
+    else
+        {
+        // not a control character
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::ConfigurePayloadFormatL
+// Configure payload encoding parameters.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::ConfigurePayloadFormatL( 
+    const TDesC8& aConfigParams,
+    CMccRtpMediaClock& aClock )
+    {
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::ConfigurePayloadFormatL IN") );
+    
+    __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ),
+        User::Leave( KErrArgument ) );
+    
+    TMccCodecInfoBuffer infoBuffer;
+    infoBuffer.Copy( aConfigParams );
+    iCInfo = infoBuffer();
+    
+    if ( !iPayloadEncoder )
+        {
+        iPayloadEncoder = CDTMFPayloadEncoder::NewL();
+        }
+    
+    iPayloadEncoder->SetPayloadType( iCInfo.iPayloadType );
+    
+    // Redundancy configuration, always using generic redundacy.
+    if ( iCInfo.iRedundancyCount && KMaxDtmfRedCount >=
+         iCInfo.iRedundancyCount )
+        {
+        DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::ConfigurePayloadFormatL iAlgoUsed: %d"),
+            iCInfo.iAlgoUsed );
+        
+        __ASSERT_ALWAYS( EGenRedUsed == iCInfo.iAlgoUsed,
+            User::Leave( KErrArgument ) );
+            
+        User::LeaveIfError(
+            iPayloadEncoder->SetPayloadFormat( EDTMFPayloadFormatRedEvents ) );
+        }
+    else
+        {
+        // Make sure that the EGenRedUsed is not set
+        iCInfo.iAlgoUsed = ENoAlgoUsed;
+        }
+    
+    // Inband/Outband configuration
+    if ( EDTMFModeInband == iCInfo.iCodecMode )
+        {
+        iGenerationMode = KSignalInbandDtmf;
+        }
+    else
+        {
+        iGenerationMode = KSignalOutbandDtmf;
+        
+        // Check if we need to unreg from current media clock.
+        if ( iRtpMediaClock )
+            {
+            iRtpMediaClock->UnregisterMediaFormat( iKey );
+            }
+        
+        iKey = aClock.RegisterMediaFormat( iSampleRate, iCInfo.iPtime );
+        }
+    
+    iRtpMediaClock = &aClock;
+    
+    DP_DTMF_WRITE( _L("CDTMFPayloadFormatWrite::ConfigurePayloadFormatL OUT") );
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::DoHandleTimerEvent
+// Does actions depending on current state on timer event.
+// ---------------------------------------------------------------------------
+//
+TInt CDTMFPayloadFormatWrite::DoHandleTimerEventL()
+    {
+    switch ( iStateMachine->State() )
+        {
+        case EStateToneOn:
+            this->DoToneOnActionsL( EFalse );
+            break;
+        
+        case EStateToneOff:
+            this->DoToneOffActionsL( EFalse );
+            break;
+        
+        case EStateSendPaused:
+            iSendTimer->Cancel();
+            iStateMachine->ChangeStateTo( EStateEncodeNextDigit );
+            break;
+        
+        default:
+            DP_DTMF_WRITE(_L("CDTMFPayloadFormatWrite::DoHandleTimerEvent DEFAULT") );
+            break;
+        }
+    
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::EncodeNextDigitL
+// Encodes next digit in sequence.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::EncodeNextDigitL()
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::EncodeNextDigitL, tick = %u"),
+        User::NTickCount() );
+
+    iToneDuration = 0;
+    iToneDuration += static_cast<TUint16>
+        ( iCInfo.iPtime * iSampleRate * KMsToSecFactor );
+    
+    if ( iSendBuffer.Count() && ('p' == iSendBuffer[0].Tone() || 'w' == 
+        iSendBuffer[0].Tone() ) )
+        {
+        HandleControlChar( iSendBuffer[0].Tone() );
+        iSendBuffer.Remove( 0 );
+        }
+    else if ( iSendBuffer.Count() )
+        {
+        if ( EDTMFPayloadFormatEvent == iPayloadFormat ||
+             EDTMFPayloadFormatRedEvents == iPayloadFormat )
+            {
+            // Encode digit to RTP packet using Payload Format
+            // for Named Events
+            TDTMFEventPayloadInfo eventInfo;
+            eventInfo.SetEvent( iSendBuffer[0].Tone() );
+            eventInfo.SetVolume( KDTMFDefaultToneVolume );
+            eventInfo.SetDuration( iToneDuration );
+            
+            if ( KSignalOutbandDtmf == iGenerationMode )
+                {
+                TUint32 timeStamp( 0 );
+                User::LeaveIfError( 
+                    iRtpMediaClock->GetTimeStamp( iKey, timeStamp ) );
+                iSinkBuffer->SetTimeToPlay( 
+                    TTimeIntervalMicroSeconds( TInt64( timeStamp ) ) );
+                }
+            
+            iPayloadEncoder->EncodeEvent( eventInfo, iSinkBuffer );
+            }
+        else if ( EDTMFPayloadFormatTone == iPayloadFormat )
+            {
+            TDTMFTonePayloadInfo toneInfo;
+            toneInfo.SetModulation( KDTMFDefaultModulation );
+            toneInfo.SetVolume( KDTMFDefaultToneVolume );
+            toneInfo.SetDuration( iToneDuration );
+            iPayloadEncoder->EncodeTone( toneInfo, iSinkBuffer );
+            }
+        else
+            {
+            // Not acceptable payload format
+            DP_DTMF_WRITE2( _L("PayloadFormat not Acceptable!: %d"), 
+                iPayloadFormat );
+            }
+        
+        iStateMachine->ChangeStateTo( EStateToneOn );
+        }
+    else
+        {
+        if ( EModeAutomatic == iSendingMode )
+            {
+            SendEventSignalToClient( KMccDtmfSendingComplete );
+            }
+
+        iStateMachine->ChangeStateTo( EStateSendingIdle );
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::DoToneOnActionsL
+// Called by sendtimer. Does actions belonging to tone on state and exits
+// state when exit conditions are met. Actions to do are: Send update packets
+// at certain time interval.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::DoToneOnActionsL( TBool aEntryToState )
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::DoToneOnActionsL, tick = %u"),
+        User::NTickCount() );
+    
+    if ( aEntryToState )
+        {
+        iSendTimer->Cancel();
+        
+        if ( EModeManual == iSendingMode )
+            {
+            SendEventSignalToClient( KMccDtmfManualStart );
+            }
+        else
+            {
+            SendEventSignalToClient( KMccDtmfSequenceStart );
+            }
+        
+        DeliverPacketL( *iSinkBuffer, ETrue );
+        
+        TCallBack callBack( HandleTimerEventL, this );
+        iSendTimer->Start(
+            TTimeIntervalMicroSeconds32( iCInfo.iPtime * KFactor1000 ),
+            TTimeIntervalMicroSeconds32( iCInfo.iPtime * KFactor1000 ),
+            callBack );
+        }
+    else
+        {
+        iToneDuration += static_cast<TUint16>
+            ( iCInfo.iPtime * iSampleRate * KMsToSecFactor );
+        
+        if ( EModeAutomatic == iSendingMode )
+            {
+            TUint targetDuration = 
+                TUint( KDTMFDefToneOnLengthInUs * KUsToSecFactor * 
+                iSampleRate );
+
+            if ( iToneDuration >= targetDuration )
+                {
+                // Exit condition
+                iSendTimer->Cancel();
+                iPayloadEncoder->UpdateEventPayload( ETrue, iToneDuration, 
+                                                                iSinkBuffer );
+                iStateMachine->ChangeStateTo( EStateToneOff );
+                return;
+                }
+            }
+        else
+            {
+            if ( iSendBuffer[0].StopTime() != 0 &&
+                 iSendBuffer[0].Duration() * iTickPeriod 
+                    * iSampleRate * KUsToSecFactor <= iToneDuration )
+                {
+                // Exit condition
+                iSendTimer->Cancel();
+                iPayloadEncoder->UpdateEventPayload( ETrue, iToneDuration, 
+                                                                iSinkBuffer );
+                iStateMachine->ChangeStateTo( EStateToneOff );
+                return;
+                }
+            }
+
+        if ( EDTMFPayloadFormatEvent == iPayloadFormat
+            || EDTMFPayloadFormatRedEvents == iPayloadFormat )
+            {
+            // Check is this long duration event
+       		// Disabling a PC-lint warning due to if-statement always being false,
+       		// as it seems the possibility should be there if values are changed
+       		/*lint -e685 */
+            if ( KDTMFMaxDurationFieldValue < iToneDuration )
+                {
+                iToneDuration -= KDTMFMaxDurationFieldValue;
+                iPayloadEncoder->UpdateEventPayload( EFalse, iToneDuration, 
+                                                                iSinkBuffer );
+                DeliverPacketL( *iSinkBuffer, EFalse );
+                }
+			/*lint +e685 */                
+			
+            else
+                {
+                // The update packet MUST have the same RTP timestamp value as
+                // the initial packet for the event (RFC 2833, 2.5.1.2).
+                iPayloadEncoder->UpdateEventPayload( EFalse, iToneDuration, 
+                                                                iSinkBuffer );
+                DeliverPacketL( *iSinkBuffer, EFalse );
+                }    
+            }
+        else if ( EDTMFPayloadFormatTone == iPayloadFormat )
+            {
+            iPayloadEncoder->UpdateTonePayload( iToneDuration, iSinkBuffer );
+            DeliverPacketL( *iSinkBuffer, EFalse );
+            }
+        else
+            {
+            // Not acceptable payload format
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::DoToneOffActionsL
+// Called by sendtimer. Does actions belonging to tone off state and exits
+// state when exit conditions are met. Actions include: sending final packets.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::DoToneOffActionsL( TBool aEntryToState )
+    {
+    DP_DTMF_WRITE2( _L("CDTMFPayloadFormatWrite::DoToneOffActionsL, tick = %u"), 
+        User::NTickCount() );
+
+    #ifdef VOIP_TRACE_ENABLED
+        VoipTrace( "%x %x", MCC_TRACE, MCC_DTMF_PLF_WRITE_SENDFINALPKT );
+    #endif
+    
+    if ( aEntryToState )
+        {
+        iSendTimer->Cancel();
+        iFinalPacketCtr = 0;
+        
+        TCallBack callBack( HandleTimerEventL, this );
+        iSendTimer->Start(
+            TTimeIntervalMicroSeconds32( iCInfo.iPtime * KFactor1000 ),
+            TTimeIntervalMicroSeconds32( iCInfo.iPtime * KFactor1000 ),
+            callBack );
+        }
+    else
+        {
+        iFinalPacketCtr++;
+        if ( KNumOfFinalPackets >= iFinalPacketCtr )
+            {
+            DeliverPacketL( *iSinkBuffer, EFalse );
+            }
+        else
+            {
+            TUint curOffDur = iFinalPacketCtr * iCInfo.iPtime * KFactor1000;
+            if ( EModeManual == iSendingMode || 
+                 KDTMFDefToneOffLengthInUs <= curOffDur )
+                {
+                // Prevent audio sending during final packet retransmission by
+                // sending completion event only when also retransmissions are
+                // done.
+                if ( EModeManual == iSendingMode )
+                    {
+                    SendEventSignalToClient( KMccDtmfManualStop );
+                    }
+                else
+                    {
+                    SendEventSignalToClient( KMccDtmfSequenceStop );
+                    }
+                
+                iSendTimer->Cancel();
+                iFinalPacketCtr = 0;
+                if ( iSendBuffer.Count() > 0 )
+                	{
+                	iSendBuffer.Remove( 0 );	
+                	}
+                iStateMachine->ChangeStateTo( EStateEncodeNextDigit );
+                }
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::SendEventSignalToClient
+// Signaling about events to the client.
+// ---------------------------------------------------------------------------
+//
+void CDTMFPayloadFormatWrite::SendEventSignalToClient( 
+    TMccDtmfEventType aEventType ) const
+    {
+    TMccDtmfEventData eventSignal;
+    eventSignal.iDtmfEventType = aEventType;
+    TMccDtmfEventDataPackage signalPkg( eventSignal );
+
+    if ( iEventHandler )
+        {
+        TMccEvent event( 0,
+                         0, 
+                         0, 
+                         0, 
+                         KMccEventCategoryDtmf, 
+                         KMccDtmfControl, 
+                         KErrNone, 
+                         signalPkg );
+
+        TMccInternalEvent internalEvent( KMccDtmfFormatterUid, 
+                                         EMccInternalEventNone,
+                                         event );
+            
+        iEventHandler->SendEventToClient( internalEvent );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDTMFPayloadFormatWrite::IsValidDigit
+// ---------------------------------------------------------------------------
+//
+TBool CDTMFPayloadFormatWrite::IsValidDigit( const TChar& aTone ) const
+    {
+    return ( KErrNotFound != iValidDigits.Find( aTone ) );
+    }
+
+
+//  End of File
+